]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
Merge ^/head r311940 through r312200.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Process / minidump / MinidumpTypes.cpp
1 //===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // Project includes
11 #include "MinidumpTypes.h"
12
13 // Other libraries and framework includes
14 // C includes
15 // C++ includes
16
17 using namespace lldb_private;
18 using namespace minidump;
19
20 const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
21   const MinidumpHeader *header = nullptr;
22   Error error = consumeObject(data, header);
23
24   const MinidumpHeaderConstants signature =
25       static_cast<const MinidumpHeaderConstants>(
26           static_cast<const uint32_t>(header->signature));
27   const MinidumpHeaderConstants version =
28       static_cast<const MinidumpHeaderConstants>(
29           static_cast<const uint32_t>(header->version) & 0x0000ffff);
30   // the high 16 bits of the version field are implementation specific
31
32   if (error.Fail() || signature != MinidumpHeaderConstants::Signature ||
33       version != MinidumpHeaderConstants::Version)
34     return nullptr;
35
36   // TODO check for max number of streams ?
37   // TODO more sanity checks ?
38
39   return header;
40 }
41
42 // Minidump string
43 llvm::Optional<std::string>
44 lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
45   std::string result;
46
47   const uint32_t *source_length;
48   Error error = consumeObject(data, source_length);
49   if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0)
50     return llvm::None;
51
52   auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data());
53   // source_length is the length of the string in bytes
54   // we need the length of the string in UTF-16 characters/code points (16 bits
55   // per char)
56   // that's why it's divided by 2
57   const auto source_end = source_start + (*source_length) / 2;
58   // resize to worst case length
59   result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length) / 2);
60   auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]);
61   const auto result_end = result_start + result.size();
62   llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end,
63                            llvm::strictConversion);
64   const auto result_size =
65       std::distance(reinterpret_cast<llvm::UTF8 *>(&result[0]), result_start);
66   result.resize(result_size); // shrink to actual length
67
68   return result;
69 }
70
71 // MinidumpThread
72 const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
73   const MinidumpThread *thread = nullptr;
74   Error error = consumeObject(data, thread);
75   if (error.Fail())
76     return nullptr;
77
78   return thread;
79 }
80
81 llvm::ArrayRef<MinidumpThread>
82 MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
83   const llvm::support::ulittle32_t *thread_count;
84   Error error = consumeObject(data, thread_count);
85   if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
86     return {};
87
88   return llvm::ArrayRef<MinidumpThread>(
89       reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
90 }
91
92 // MinidumpSystemInfo
93 const MinidumpSystemInfo *
94 MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
95   const MinidumpSystemInfo *system_info;
96   Error error = consumeObject(data, system_info);
97   if (error.Fail())
98     return nullptr;
99
100   return system_info;
101 }
102
103 // MinidumpMiscInfo
104 const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
105   const MinidumpMiscInfo *misc_info;
106   Error error = consumeObject(data, misc_info);
107   if (error.Fail())
108     return nullptr;
109
110   return misc_info;
111 }
112
113 llvm::Optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
114   uint32_t pid_flag =
115       static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID);
116   if (flags1 & pid_flag)
117     return llvm::Optional<lldb::pid_t>(process_id);
118
119   return llvm::None;
120 }
121
122 // Linux Proc Status
123 // it's stored as an ascii string in the file
124 llvm::Optional<LinuxProcStatus>
125 LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
126   LinuxProcStatus result;
127   result.proc_status =
128       llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
129   data = data.drop_front(data.size());
130
131   llvm::SmallVector<llvm::StringRef, 0> lines;
132   result.proc_status.split(lines, '\n', 42);
133   // /proc/$pid/status has 41 lines, but why not use 42?
134   for (auto line : lines) {
135     if (line.consume_front("Pid:")) {
136       line = line.trim();
137       if (!line.getAsInteger(10, result.pid))
138         return result;
139     }
140   }
141
142   return llvm::None;
143 }
144
145 lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
146
147 // Module stuff
148 const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
149   const MinidumpModule *module = nullptr;
150   Error error = consumeObject(data, module);
151   if (error.Fail())
152     return nullptr;
153
154   return module;
155 }
156
157 llvm::ArrayRef<MinidumpModule>
158 MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
159
160   const llvm::support::ulittle32_t *modules_count;
161   Error error = consumeObject(data, modules_count);
162   if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
163     return {};
164
165   return llvm::ArrayRef<MinidumpModule>(
166       reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
167 }
168
169 // Exception stuff
170 const MinidumpExceptionStream *
171 MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
172   const MinidumpExceptionStream *exception_stream = nullptr;
173   Error error = consumeObject(data, exception_stream);
174   if (error.Fail())
175     return nullptr;
176
177   return exception_stream;
178 }
179
180 llvm::ArrayRef<MinidumpMemoryDescriptor>
181 MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
182   const llvm::support::ulittle32_t *mem_ranges_count;
183   Error error = consumeObject(data, mem_ranges_count);
184   if (error.Fail() ||
185       *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
186     return {};
187
188   return llvm::makeArrayRef(
189       reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
190       *mem_ranges_count);
191 }
192
193 std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
194 MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
195   const llvm::support::ulittle64_t *mem_ranges_count;
196   Error error = consumeObject(data, mem_ranges_count);
197   if (error.Fail() ||
198       *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
199     return {};
200
201   const llvm::support::ulittle64_t *base_rva;
202   error = consumeObject(data, base_rva);
203   if (error.Fail())
204     return {};
205
206   return std::make_pair(
207       llvm::makeArrayRef(
208           reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
209           *mem_ranges_count),
210       *base_rva);
211 }
212
213 std::vector<const MinidumpMemoryInfo *>
214 MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
215   const MinidumpMemoryInfoListHeader *header;
216   Error error = consumeObject(data, header);
217   if (error.Fail() ||
218       header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
219       header->size_of_entry < sizeof(MinidumpMemoryInfo))
220     return {};
221
222   data = data.drop_front(header->size_of_header -
223                          sizeof(MinidumpMemoryInfoListHeader));
224
225   if (header->size_of_entry * header->num_of_entries > data.size())
226     return {};
227
228   std::vector<const MinidumpMemoryInfo *> result;
229   for (uint64_t i = 0; i < header->num_of_entries; ++i) {
230     result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>(
231         data.data() + i * header->size_of_entry));
232   }
233
234   return result;
235 }