aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/minidump/MinidumpTypes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/minidump/MinidumpTypes.cpp')
-rw-r--r--source/Plugins/Process/minidump/MinidumpTypes.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/source/Plugins/Process/minidump/MinidumpTypes.cpp b/source/Plugins/Process/minidump/MinidumpTypes.cpp
new file mode 100644
index 000000000000..863d124a7ccc
--- /dev/null
+++ b/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -0,0 +1,235 @@
+//===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Project includes
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpHeader *header = nullptr;
+ Error error = consumeObject(data, header);
+
+ const MinidumpHeaderConstants signature =
+ static_cast<const MinidumpHeaderConstants>(
+ static_cast<const uint32_t>(header->signature));
+ const MinidumpHeaderConstants version =
+ static_cast<const MinidumpHeaderConstants>(
+ static_cast<const uint32_t>(header->version) & 0x0000ffff);
+ // the high 16 bits of the version field are implementation specific
+
+ if (error.Fail() || signature != MinidumpHeaderConstants::Signature ||
+ version != MinidumpHeaderConstants::Version)
+ return nullptr;
+
+ // TODO check for max number of streams ?
+ // TODO more sanity checks ?
+
+ return header;
+}
+
+// Minidump string
+llvm::Optional<std::string>
+lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
+ std::string result;
+
+ const uint32_t *source_length;
+ Error error = consumeObject(data, source_length);
+ if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0)
+ return llvm::None;
+
+ auto source_start = reinterpret_cast<const llvm::UTF16 *>(data.data());
+ // source_length is the length of the string in bytes
+ // we need the length of the string in UTF-16 characters/code points (16 bits
+ // per char)
+ // that's why it's divided by 2
+ const auto source_end = source_start + (*source_length) / 2;
+ // resize to worst case length
+ result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length) / 2);
+ auto result_start = reinterpret_cast<llvm::UTF8 *>(&result[0]);
+ const auto result_end = result_start + result.size();
+ llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end,
+ llvm::strictConversion);
+ const auto result_size =
+ std::distance(reinterpret_cast<llvm::UTF8 *>(&result[0]), result_start);
+ result.resize(result_size); // shrink to actual length
+
+ return result;
+}
+
+// MinidumpThread
+const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpThread *thread = nullptr;
+ Error error = consumeObject(data, thread);
+ if (error.Fail())
+ return nullptr;
+
+ return thread;
+}
+
+llvm::ArrayRef<MinidumpThread>
+MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle32_t *thread_count;
+ Error error = consumeObject(data, thread_count);
+ if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
+ return {};
+
+ return llvm::ArrayRef<MinidumpThread>(
+ reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
+}
+
+// MinidumpSystemInfo
+const MinidumpSystemInfo *
+MinidumpSystemInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpSystemInfo *system_info;
+ Error error = consumeObject(data, system_info);
+ if (error.Fail())
+ return nullptr;
+
+ return system_info;
+}
+
+// MinidumpMiscInfo
+const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpMiscInfo *misc_info;
+ Error error = consumeObject(data, misc_info);
+ if (error.Fail())
+ return nullptr;
+
+ return misc_info;
+}
+
+llvm::Optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
+ uint32_t pid_flag =
+ static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID);
+ if (flags1 & pid_flag)
+ return llvm::Optional<lldb::pid_t>(process_id);
+
+ return llvm::None;
+}
+
+// Linux Proc Status
+// it's stored as an ascii string in the file
+llvm::Optional<LinuxProcStatus>
+LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
+ LinuxProcStatus result;
+ result.proc_status =
+ llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
+ data = data.drop_front(data.size());
+
+ llvm::SmallVector<llvm::StringRef, 0> lines;
+ result.proc_status.split(lines, '\n', 42);
+ // /proc/$pid/status has 41 lines, but why not use 42?
+ for (auto line : lines) {
+ if (line.consume_front("Pid:")) {
+ line = line.trim();
+ if (!line.getAsInteger(10, result.pid))
+ return result;
+ }
+ }
+
+ return llvm::None;
+}
+
+lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
+
+// Module stuff
+const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpModule *module = nullptr;
+ Error error = consumeObject(data, module);
+ if (error.Fail())
+ return nullptr;
+
+ return module;
+}
+
+llvm::ArrayRef<MinidumpModule>
+MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
+
+ const llvm::support::ulittle32_t *modules_count;
+ Error error = consumeObject(data, modules_count);
+ if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
+ return {};
+
+ return llvm::ArrayRef<MinidumpModule>(
+ reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
+}
+
+// Exception stuff
+const MinidumpExceptionStream *
+MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpExceptionStream *exception_stream = nullptr;
+ Error error = consumeObject(data, exception_stream);
+ if (error.Fail())
+ return nullptr;
+
+ return exception_stream;
+}
+
+llvm::ArrayRef<MinidumpMemoryDescriptor>
+MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle32_t *mem_ranges_count;
+ Error error = consumeObject(data, mem_ranges_count);
+ if (error.Fail() ||
+ *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
+ return {};
+
+ return llvm::makeArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
+ *mem_ranges_count);
+}
+
+std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle64_t *mem_ranges_count;
+ Error error = consumeObject(data, mem_ranges_count);
+ if (error.Fail() ||
+ *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size())
+ return {};
+
+ const llvm::support::ulittle64_t *base_rva;
+ error = consumeObject(data, base_rva);
+ if (error.Fail())
+ return {};
+
+ return std::make_pair(
+ llvm::makeArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
+ *mem_ranges_count),
+ *base_rva);
+}
+
+std::vector<const MinidumpMemoryInfo *>
+MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpMemoryInfoListHeader *header;
+ Error error = consumeObject(data, header);
+ if (error.Fail() ||
+ header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
+ header->size_of_entry < sizeof(MinidumpMemoryInfo))
+ return {};
+
+ data = data.drop_front(header->size_of_header -
+ sizeof(MinidumpMemoryInfoListHeader));
+
+ if (header->size_of_entry * header->num_of_entries > data.size())
+ return {};
+
+ std::vector<const MinidumpMemoryInfo *> result;
+ for (uint64_t i = 0; i < header->num_of_entries; ++i) {
+ result.push_back(reinterpret_cast<const MinidumpMemoryInfo *>(
+ data.data() + i * header->size_of_entry));
+ }
+
+ return result;
+}