1 //===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "MinidumpTypes.h"
15 using namespace lldb_private;
16 using namespace minidump;
18 const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
19 const MinidumpHeader *header = nullptr;
20 Status error = consumeObject(data, header);
22 const MinidumpHeaderConstants signature =
23 static_cast<const MinidumpHeaderConstants>(
24 static_cast<const uint32_t>(header->signature));
25 const MinidumpHeaderConstants version =
26 static_cast<const MinidumpHeaderConstants>(
27 static_cast<const uint32_t>(header->version) & 0x0000ffff);
28 // the high 16 bits of the version field are implementation specific
30 if (error.Fail() || signature != MinidumpHeaderConstants::Signature ||
31 version != MinidumpHeaderConstants::Version)
38 llvm::Optional<std::string>
39 lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
42 const uint32_t *source_length_ptr;
43 Status error = consumeObject(data, source_length_ptr);
45 // Copy non-aligned source_length data into aligned memory.
46 uint32_t source_length;
47 std::memcpy(&source_length, source_length_ptr, sizeof(source_length));
49 if (error.Fail() || source_length > data.size() || source_length % 2 != 0)
52 auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data());
53 // source_length is the length of the string in bytes we need the length of
54 // the string in UTF-16 characters/code points (16 bits per char) that's why
56 const auto source_end = source_start + source_length / 2;
57 // resize to worst case length
58 result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * source_length / 2);
59 auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]);
60 const auto result_end = result_start + result.size();
61 llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end,
62 llvm::strictConversion);
63 const auto result_size =
64 std::distance(reinterpret_cast<llvm::UTF8 *>(&result[0]), result_start);
65 result.resize(result_size); // shrink to actual length
71 const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
72 const MinidumpThread *thread = nullptr;
73 Status error = consumeObject(data, thread);
80 llvm::ArrayRef<MinidumpThread>
81 MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
82 const auto orig_size = data.size();
83 const llvm::support::ulittle32_t *thread_count;
84 Status error = consumeObject(data, thread_count);
85 if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
88 // Compilers might end up padding an extra 4 bytes depending on how the
89 // structure is padded by the compiler and the #pragma pack settings.
90 if (4 + *thread_count * sizeof(MinidumpThread) < orig_size)
91 data = data.drop_front(4);
93 return llvm::ArrayRef<MinidumpThread>(
94 reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
98 const MinidumpSystemInfo *
99 MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
100 const MinidumpSystemInfo *system_info;
101 Status error = consumeObject(data, system_info);
109 const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
110 const MinidumpMiscInfo *misc_info;
111 Status error = consumeObject(data, misc_info);
118 llvm::Optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
120 static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID);
121 if (flags1 & pid_flag)
122 return llvm::Optional<lldb::pid_t>(process_id);
128 // it's stored as an ascii string in the file
129 llvm::Optional<LinuxProcStatus>
130 LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
131 LinuxProcStatus result;
133 llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
134 data = data.drop_front(data.size());
136 llvm::SmallVector<llvm::StringRef, 0> lines;
137 result.proc_status.split(lines, '\n', 42);
138 // /proc/$pid/status has 41 lines, but why not use 42?
139 for (auto line : lines) {
140 if (line.consume_front("Pid:")) {
142 if (!line.getAsInteger(10, result.pid))
150 lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
153 const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
154 const MinidumpModule *module = nullptr;
155 Status error = consumeObject(data, module);
162 llvm::ArrayRef<MinidumpModule>
163 MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
164 const auto orig_size = data.size();
165 const llvm::support::ulittle32_t *modules_count;
166 Status error = consumeObject(data, modules_count);
167 if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
170 // Compilers might end up padding an extra 4 bytes depending on how the
171 // structure is padded by the compiler and the #pragma pack settings.
172 if (4 + *modules_count * sizeof(MinidumpModule) < orig_size)
173 data = data.drop_front(4);
175 return llvm::ArrayRef<MinidumpModule>(
176 reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
180 const MinidumpExceptionStream *
181 MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
182 const MinidumpExceptionStream *exception_stream = nullptr;
183 Status error = consumeObject(data, exception_stream);
187 return exception_stream;
190 llvm::ArrayRef<MinidumpMemoryDescriptor>
191 MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
192 const auto orig_size = data.size();
193 const llvm::support::ulittle32_t *mem_ranges_count;
194 Status error = consumeObject(data, mem_ranges_count);
196 *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
199 // Compilers might end up padding an extra 4 bytes depending on how the
200 // structure is padded by the compiler and the #pragma pack settings.
201 if (4 + *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) < orig_size)
202 data = data.drop_front(4);
204 return llvm::makeArrayRef(
205 reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
209 std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
210 MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
211 const llvm::support::ulittle64_t *mem_ranges_count;
212 Status error = consumeObject(data, mem_ranges_count);
214 *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
217 const llvm::support::ulittle64_t *base_rva;
218 error = consumeObject(data, base_rva);
222 return std::make_pair(
224 reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
229 std::vector<const MinidumpMemoryInfo *>
230 MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
231 const MinidumpMemoryInfoListHeader *header;
232 Status error = consumeObject(data, header);
234 header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
235 header->size_of_entry < sizeof(MinidumpMemoryInfo))
238 data = data.drop_front(header->size_of_header -
239 sizeof(MinidumpMemoryInfoListHeader));
241 if (header->size_of_entry * header->num_of_entries > data.size())
244 std::vector<const MinidumpMemoryInfo *> result;
245 result.reserve(header->num_of_entries);
247 for (uint64_t i = 0; i < header->num_of_entries; ++i) {
248 result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>(
249 data.data() + i * header->size_of_entry));