summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/minidump
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/minidump')
-rw-r--r--source/Plugins/Process/minidump/CMakeLists.txt10
-rw-r--r--source/Plugins/Process/minidump/MinidumpParser.cpp458
-rw-r--r--source/Plugins/Process/minidump/MinidumpParser.h102
-rw-r--r--source/Plugins/Process/minidump/MinidumpTypes.cpp235
-rw-r--r--source/Plugins/Process/minidump/MinidumpTypes.h470
-rw-r--r--source/Plugins/Process/minidump/NtStructures.h37
-rw-r--r--source/Plugins/Process/minidump/ProcessMinidump.cpp301
-rw-r--r--source/Plugins/Process/minidump/ProcessMinidump.h105
-rw-r--r--source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp99
-rw-r--r--source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h138
-rw-r--r--source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp113
-rw-r--r--source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h183
-rw-r--r--source/Plugins/Process/minidump/ThreadMinidump.cpp114
-rw-r--r--source/Plugins/Process/minidump/ThreadMinidump.h52
14 files changed, 2417 insertions, 0 deletions
diff --git a/source/Plugins/Process/minidump/CMakeLists.txt b/source/Plugins/Process/minidump/CMakeLists.txt
new file mode 100644
index 0000000000000..ddc89cbd92c15
--- /dev/null
+++ b/source/Plugins/Process/minidump/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(../Utility)
+
+add_lldb_library(lldbPluginProcessMinidump
+ MinidumpTypes.cpp
+ MinidumpParser.cpp
+ RegisterContextMinidump_x86_32.cpp
+ RegisterContextMinidump_x86_64.cpp
+ ProcessMinidump.cpp
+ ThreadMinidump.cpp
+ )
diff --git a/source/Plugins/Process/minidump/MinidumpParser.cpp b/source/Plugins/Process/minidump/MinidumpParser.cpp
new file mode 100644
index 0000000000000..37b3709c09c16
--- /dev/null
+++ b/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -0,0 +1,458 @@
+//===-- MinidumpParser.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 "MinidumpParser.h"
+#include "NtStructures.h"
+#include "RegisterContextMinidump_x86_32.h"
+
+// Other libraries and framework includes
+#include "lldb/Target/MemoryRegionInfo.h"
+
+// C includes
+// C++ includes
+#include <map>
+
+using namespace lldb_private;
+using namespace minidump;
+
+llvm::Optional<MinidumpParser>
+MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
+ if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) {
+ return llvm::None;
+ }
+
+ llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(),
+ sizeof(MinidumpHeader));
+ const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
+
+ if (header == nullptr) {
+ return llvm::None;
+ }
+
+ lldb::offset_t directory_list_offset = header->stream_directory_rva;
+ // check if there is enough data for the parsing of the directory list
+ if ((directory_list_offset +
+ sizeof(MinidumpDirectory) * header->streams_count) >
+ data_buf_sp->GetByteSize()) {
+ return llvm::None;
+ }
+
+ const MinidumpDirectory *directory = nullptr;
+ Error error;
+ llvm::ArrayRef<uint8_t> directory_data(
+ data_buf_sp->GetBytes() + directory_list_offset,
+ sizeof(MinidumpDirectory) * header->streams_count);
+ llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
+
+ for (uint32_t i = 0; i < header->streams_count; ++i) {
+ error = consumeObject(directory_data, directory);
+ if (error.Fail()) {
+ return llvm::None;
+ }
+ directory_map[static_cast<const uint32_t>(directory->stream_type)] =
+ directory->location;
+ }
+
+ return MinidumpParser(data_buf_sp, header, std::move(directory_map));
+}
+
+MinidumpParser::MinidumpParser(
+ const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
+ llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map)
+ : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) {
+}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
+ m_data_sp->GetByteSize());
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetStream(MinidumpStreamType stream_type) {
+ auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
+ if (iter == m_directory_map.end())
+ return {};
+
+ // check if there is enough data
+ if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
+ return {};
+
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
+ iter->second.data_size);
+}
+
+llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
+ auto arr_ref = m_data_sp->GetData();
+ if (rva > arr_ref.size())
+ return llvm::None;
+ arr_ref = arr_ref.drop_front(rva);
+ return parseMinidumpString(arr_ref);
+}
+
+llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
+
+ if (data.size() == 0)
+ return llvm::None;
+
+ return MinidumpThread::ParseThreadList(data);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const MinidumpThread &td) {
+ if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
+ return {};
+
+ return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
+ // On Windows, a 32-bit process can run on a 64-bit machine under
+ // WOW64. If the minidump was captured with a 64-bit debugger, then
+ // the CONTEXT we just grabbed from the mini_dump_thread is the one
+ // for the 64-bit "native" process rather than the 32-bit "guest"
+ // process we care about. In this case, we can get the 32-bit CONTEXT
+ // from the TEB (Thread Environment Block) of the 64-bit process.
+ auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
+ if (teb_mem.empty())
+ return {};
+
+ const TEB64 *wow64teb;
+ Error error = consumeObject(teb_mem, wow64teb);
+ if (error.Fail())
+ return {};
+
+ // Slot 1 of the thread-local storage in the 64-bit TEB points to a
+ // structure that includes the 32-bit CONTEXT (after a ULONG).
+ // See: https://msdn.microsoft.com/en-us/library/ms681670.aspx
+ auto context =
+ GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
+ if (context.size() < sizeof(MinidumpContext_x86_32))
+ return {};
+
+ return context;
+ // NOTE: We don't currently use the TEB for anything else. If we
+ // need it in the future, the 32-bit TEB is located according to the address
+ // stored in the first slot of the 64-bit TEB (wow64teb.Reserved1[0]).
+}
+
+const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
+
+ if (data.size() == 0)
+ return nullptr;
+
+ return MinidumpSystemInfo::Parse(data);
+}
+
+ArchSpec MinidumpParser::GetArchitecture() {
+ ArchSpec arch_spec;
+ const MinidumpSystemInfo *system_info = GetSystemInfo();
+
+ if (!system_info)
+ return arch_spec;
+
+ // TODO what to do about big endiand flavors of arm ?
+ // TODO set the arm subarch stuff if the minidump has info about it
+
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+
+ const MinidumpCPUArchitecture arch =
+ static_cast<const MinidumpCPUArchitecture>(
+ static_cast<const uint32_t>(system_info->processor_arch));
+
+ switch (arch) {
+ case MinidumpCPUArchitecture::X86:
+ triple.setArch(llvm::Triple::ArchType::x86);
+ break;
+ case MinidumpCPUArchitecture::AMD64:
+ triple.setArch(llvm::Triple::ArchType::x86_64);
+ break;
+ case MinidumpCPUArchitecture::ARM:
+ triple.setArch(llvm::Triple::ArchType::arm);
+ break;
+ case MinidumpCPUArchitecture::ARM64:
+ triple.setArch(llvm::Triple::ArchType::aarch64);
+ break;
+ default:
+ triple.setArch(llvm::Triple::ArchType::UnknownArch);
+ break;
+ }
+
+ const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
+ static_cast<const uint32_t>(system_info->platform_id));
+
+ // TODO add all of the OSes that Minidump/breakpad distinguishes?
+ switch (os) {
+ case MinidumpOSPlatform::Win32S:
+ case MinidumpOSPlatform::Win32Windows:
+ case MinidumpOSPlatform::Win32NT:
+ case MinidumpOSPlatform::Win32CE:
+ triple.setOS(llvm::Triple::OSType::Win32);
+ break;
+ case MinidumpOSPlatform::Linux:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ break;
+ case MinidumpOSPlatform::MacOSX:
+ triple.setOS(llvm::Triple::OSType::MacOSX);
+ break;
+ case MinidumpOSPlatform::Android:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
+ break;
+ default:
+ triple.setOS(llvm::Triple::OSType::UnknownOS);
+ break;
+ }
+
+ arch_spec.SetTriple(triple);
+
+ return arch_spec;
+}
+
+const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
+
+ if (data.size() == 0)
+ return nullptr;
+
+ return MinidumpMiscInfo::Parse(data);
+}
+
+llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
+
+ if (data.size() == 0)
+ return llvm::None;
+
+ return LinuxProcStatus::Parse(data);
+}
+
+llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
+ const MinidumpMiscInfo *misc_info = GetMiscInfo();
+ if (misc_info != nullptr) {
+ return misc_info->GetPid();
+ }
+
+ llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
+ if (proc_status.hasValue()) {
+ return proc_status->GetPid();
+ }
+
+ return llvm::None;
+}
+
+llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
+
+ if (data.size() == 0)
+ return {};
+
+ return MinidumpModule::ParseModuleList(data);
+}
+
+std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
+ llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
+ // map module_name -> pair(load_address, pointer to module struct in memory)
+ llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
+
+ std::vector<const MinidumpModule *> filtered_modules;
+
+ llvm::Optional<std::string> name;
+ std::string module_name;
+
+ for (const auto &module : modules) {
+ name = GetMinidumpString(module.module_name_rva);
+
+ if (!name)
+ continue;
+
+ module_name = name.getValue();
+
+ auto iter = lowest_addr.end();
+ bool exists;
+ std::tie(iter, exists) = lowest_addr.try_emplace(
+ module_name, std::make_pair(module.base_of_image, &module));
+
+ if (exists && module.base_of_image < iter->second.first)
+ iter->second = std::make_pair(module.base_of_image, &module);
+ }
+
+ filtered_modules.reserve(lowest_addr.size());
+ for (const auto &module : lowest_addr) {
+ filtered_modules.push_back(module.second.second);
+ }
+
+ return filtered_modules;
+}
+
+const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
+
+ if (data.size() == 0)
+ return nullptr;
+
+ return MinidumpExceptionStream::Parse(data);
+}
+
+llvm::Optional<minidump::Range>
+MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
+ llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
+
+ if (data.empty() && data64.empty())
+ return llvm::None;
+
+ if (!data.empty()) {
+ llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
+ MinidumpMemoryDescriptor::ParseMemoryList(data);
+
+ if (memory_list.empty())
+ return llvm::None;
+
+ for (const auto &memory_desc : memory_list) {
+ const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
+ const lldb::addr_t range_start = memory_desc.start_of_memory_range;
+ const size_t range_size = loc_desc.data_size;
+
+ if (loc_desc.rva + loc_desc.data_size > GetData().size())
+ return llvm::None;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ return minidump::Range(range_start,
+ GetData().slice(loc_desc.rva, range_size));
+ }
+ }
+ }
+
+ // Some Minidumps have a Memory64ListStream that captures all the heap
+ // memory (full-memory Minidumps). We can't exactly use the same loop as
+ // above, because the Minidump uses slightly different data structures to
+ // describe those
+
+ if (!data64.empty()) {
+ llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+ uint64_t base_rva;
+ std::tie(memory64_list, base_rva) =
+ MinidumpMemoryDescriptor64::ParseMemory64List(data64);
+
+ if (memory64_list.empty())
+ return llvm::None;
+
+ for (const auto &memory_desc64 : memory64_list) {
+ const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
+ const size_t range_size = memory_desc64.data_size;
+
+ if (base_rva + range_size > GetData().size())
+ return llvm::None;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ return minidump::Range(range_start,
+ GetData().slice(base_rva, range_size));
+ }
+ base_rva += range_size;
+ }
+ }
+
+ return llvm::None;
+}
+
+llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
+ size_t size) {
+ // I don't have a sense of how frequently this is called or how many memory
+ // ranges a Minidump typically has, so I'm not sure if searching for the
+ // appropriate range linearly each time is stupid. Perhaps we should build
+ // an index for faster lookups.
+ llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
+ if (!range)
+ return {};
+
+ // There's at least some overlap between the beginning of the desired range
+ // (addr) and the current range. Figure out where the overlap begins and
+ // how much overlap there is.
+
+ const size_t offset = addr - range->start;
+
+ if (addr < range->start || offset >= range->range_ref.size())
+ return {};
+
+ const size_t overlap = std::min(size, range->range_ref.size() - offset);
+ return range->range_ref.slice(offset, overlap);
+}
+
+llvm::Optional<MemoryRegionInfo>
+MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
+ MemoryRegionInfo info;
+ llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
+ if (data.empty())
+ return llvm::None;
+
+ std::vector<const MinidumpMemoryInfo *> mem_info_list =
+ MinidumpMemoryInfo::ParseMemoryInfoList(data);
+ if (mem_info_list.empty())
+ return llvm::None;
+
+ const auto yes = MemoryRegionInfo::eYes;
+ const auto no = MemoryRegionInfo::eNo;
+
+ const MinidumpMemoryInfo *next_entry = nullptr;
+ for (const auto &entry : mem_info_list) {
+ const auto head = entry->base_address;
+ const auto tail = head + entry->region_size;
+
+ if (head <= load_addr && load_addr < tail) {
+ info.GetRange().SetRangeBase(
+ (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
+ ? head
+ : load_addr);
+ info.GetRange().SetRangeEnd(tail);
+
+ const uint32_t PageNoAccess =
+ static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
+ info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
+
+ const uint32_t PageWritable =
+ static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
+ info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
+
+ const uint32_t PageExecutable = static_cast<uint32_t>(
+ MinidumpMemoryProtectionContants::PageExecutable);
+ info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
+
+ const uint32_t MemFree =
+ static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
+ info.SetMapped((entry->state != MemFree) ? yes : no);
+
+ return info;
+ } else if (head > load_addr &&
+ (next_entry == nullptr || head < next_entry->base_address)) {
+ // In case there is no region containing load_addr keep track of the
+ // nearest region after load_addr so we can return the distance to it.
+ next_entry = entry;
+ }
+ }
+
+ // No containing region found. Create an unmapped region that extends to the
+ // next region or LLDB_INVALID_ADDRESS
+ info.GetRange().SetRangeBase(load_addr);
+ info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address
+ : LLDB_INVALID_ADDRESS);
+ info.SetReadable(no);
+ info.SetWritable(no);
+ info.SetExecutable(no);
+ info.SetMapped(no);
+
+ // Note that the memory info list doesn't seem to contain ranges in kernel
+ // space, so if you're walking a stack that has kernel frames, the stack may
+ // appear truncated.
+ return info;
+}
diff --git a/source/Plugins/Process/minidump/MinidumpParser.h b/source/Plugins/Process/minidump/MinidumpParser.h
new file mode 100644
index 0000000000000..67523a72ad115
--- /dev/null
+++ b/source/Plugins/Process/minidump/MinidumpParser.h
@@ -0,0 +1,102 @@
+//===-- MinidumpParser.h -----------------------------------------*- C++
+//-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MinidumpParser_h_
+#define liblldb_MinidumpParser_h_
+
+// Project includes
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+
+// C includes
+
+// C++ includes
+#include <cstring>
+#include <unordered_map>
+
+namespace lldb_private {
+
+namespace minidump {
+
+// Describes a range of memory captured in the Minidump
+struct Range {
+ lldb::addr_t start; // virtual address of the beginning of the range
+ // range_ref - absolute pointer to the first byte of the range and size
+ llvm::ArrayRef<uint8_t> range_ref;
+
+ Range(lldb::addr_t start, llvm::ArrayRef<uint8_t> range_ref)
+ : start(start), range_ref(range_ref) {}
+};
+
+class MinidumpParser {
+public:
+ static llvm::Optional<MinidumpParser>
+ Create(const lldb::DataBufferSP &data_buf_sp);
+
+ llvm::ArrayRef<uint8_t> GetData();
+
+ llvm::ArrayRef<uint8_t> GetStream(MinidumpStreamType stream_type);
+
+ llvm::Optional<std::string> GetMinidumpString(uint32_t rva);
+
+ llvm::ArrayRef<MinidumpThread> GetThreads();
+
+ llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
+
+ llvm::ArrayRef<uint8_t> GetThreadContextWow64(const MinidumpThread &td);
+
+ const MinidumpSystemInfo *GetSystemInfo();
+
+ ArchSpec GetArchitecture();
+
+ const MinidumpMiscInfo *GetMiscInfo();
+
+ llvm::Optional<LinuxProcStatus> GetLinuxProcStatus();
+
+ llvm::Optional<lldb::pid_t> GetPid();
+
+ llvm::ArrayRef<MinidumpModule> GetModuleList();
+
+ // There are cases in which there is more than one record in the ModuleList
+ // for the same module name.(e.g. when the binary has non contiguous segments)
+ // So this function returns a filtered module list - if it finds records that
+ // have the same name, it keeps the copy with the lowest load address.
+ std::vector<const MinidumpModule *> GetFilteredModuleList();
+
+ const MinidumpExceptionStream *GetExceptionStream();
+
+ llvm::Optional<Range> FindMemoryRange(lldb::addr_t addr);
+
+ llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
+
+ llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t);
+
+private:
+ lldb::DataBufferSP m_data_sp;
+ const MinidumpHeader *m_header;
+ llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map;
+
+ MinidumpParser(
+ const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
+ llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map);
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // liblldb_MinidumpParser_h_
diff --git a/source/Plugins/Process/minidump/MinidumpTypes.cpp b/source/Plugins/Process/minidump/MinidumpTypes.cpp
new file mode 100644
index 0000000000000..863d124a7ccce
--- /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;
+}
diff --git a/source/Plugins/Process/minidump/MinidumpTypes.h b/source/Plugins/Process/minidump/MinidumpTypes.h
new file mode 100644
index 0000000000000..46871a1b84d88
--- /dev/null
+++ b/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -0,0 +1,470 @@
+//===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MinidumpTypes_h_
+#define liblldb_MinidumpTypes_h_
+
+// Project includes
+
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+
+// C includes
+// C++ includes
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
+// https://chromium.googlesource.com/breakpad/breakpad/
+
+namespace lldb_private {
+
+namespace minidump {
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+enum class MinidumpHeaderConstants : uint32_t {
+ Signature = 0x504d444d, // 'PMDM'
+ Version = 0x0000a793, // 42899
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Signature)
+
+};
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx
+enum class MinidumpStreamType : uint32_t {
+ Unused = 0,
+ Reserved0 = 1,
+ Reserved1 = 2,
+ ThreadList = 3,
+ ModuleList = 4,
+ MemoryList = 5,
+ Exception = 6,
+ SystemInfo = 7,
+ ThreadExList = 8,
+ Memory64List = 9,
+ CommentA = 10,
+ CommentW = 11,
+ HandleData = 12,
+ FunctionTable = 13,
+ UnloadedModuleList = 14,
+ MiscInfo = 15,
+ MemoryInfoList = 16,
+ ThreadInfoList = 17,
+ HandleOperationList = 18,
+ Token = 19,
+ JavascriptData = 20,
+ SystemMemoryInfo = 21,
+ ProcessVMCounters = 22,
+ LastReserved = 0x0000ffff,
+
+ /* Breakpad extension types. 0x4767 = "Gg" */
+ BreakpadInfo = 0x47670001,
+ AssertionInfo = 0x47670002,
+ /* These are additional minidump stream values which are specific to
+ * the linux breakpad implementation. */
+ LinuxCPUInfo = 0x47670003, /* /proc/cpuinfo */
+ LinuxProcStatus = 0x47670004, /* /proc/$x/status */
+ LinuxLSBRelease = 0x47670005, /* /etc/lsb-release */
+ LinuxCMDLine = 0x47670006, /* /proc/$x/cmdline */
+ LinuxEnviron = 0x47670007, /* /proc/$x/environ */
+ LinuxAuxv = 0x47670008, /* /proc/$x/auxv */
+ LinuxMaps = 0x47670009, /* /proc/$x/maps */
+ LinuxDSODebug = 0x4767000A
+};
+
+// for MinidumpSystemInfo.processor_arch
+enum class MinidumpCPUArchitecture : uint16_t {
+ X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */
+ MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */
+ Alpha = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */
+ PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */
+ SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */
+ ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */
+ IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */
+ Alpha64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */
+ MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL
+ * (Microsoft Intermediate Language) */
+ AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */
+ X86Win64 = 10, /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
+ SPARC = 0x8001, /* Breakpad-defined value for SPARC */
+ PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
+ ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */
+ MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
+ Unknown = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
+};
+
+// for MinidumpSystemInfo.platform_id
+enum class MinidumpOSPlatform : uint32_t {
+ Win32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */
+ Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
+ Win32NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
+ Win32CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
+ * (Windows CE, Windows Mobile, "Handheld") */
+
+ /* The following values are Breakpad-defined. */
+ Unix = 0x8000, /* Generic Unix-ish */
+ MacOSX = 0x8101, /* Mac OS X/Darwin */
+ IOS = 0x8102, /* iOS */
+ Linux = 0x8201, /* Linux */
+ Solaris = 0x8202, /* Solaris */
+ Android = 0x8203, /* Android */
+ PS3 = 0x8204, /* PS3 */
+ NaCl = 0x8205 /* Native Client (NaCl) */
+};
+
+// For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps.
+// This matches the Linux kernel definitions from <asm/hwcaps.h>
+enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t {
+ SWP = (1 << 0),
+ Half = (1 << 1),
+ Thumb = (1 << 2),
+ _26BIT = (1 << 3),
+ FastMult = (1 << 4),
+ FPA = (1 << 5),
+ VFP = (1 << 6),
+ EDSP = (1 << 7),
+ Java = (1 << 8),
+ IWMMXT = (1 << 9),
+ Crunch = (1 << 10),
+ ThumbEE = (1 << 11),
+ Neon = (1 << 12),
+ VFPv3 = (1 << 13),
+ VFPv3D16 = (1 << 14),
+ TLS = (1 << 15),
+ VFPv4 = (1 << 16),
+ IDIVA = (1 << 17),
+ IDIVT = (1 << 18),
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)
+};
+
+enum class MinidumpMiscInfoFlags : uint32_t {
+ ProcessID = (1 << 0),
+ ProcessTimes = (1 << 1),
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
+};
+
+template <typename T>
+Error consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
+ Error error;
+ if (Buffer.size() < sizeof(T)) {
+ error.SetErrorString("Insufficient buffer!");
+ return error;
+ }
+
+ Object = reinterpret_cast<const T *>(Buffer.data());
+ Buffer = Buffer.drop_front(sizeof(T));
+ return error;
+}
+
+// parse a MinidumpString which is with UTF-16
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680395(v=vs.85).aspx
+llvm::Optional<std::string> parseMinidumpString(llvm::ArrayRef<uint8_t> &data);
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx
+struct MinidumpHeader {
+ llvm::support::ulittle32_t signature;
+ llvm::support::ulittle32_t
+ version; // The high 16 bits of version field are implementation specific
+ llvm::support::ulittle32_t streams_count;
+ llvm::support::ulittle32_t
+ stream_directory_rva; // offset of the stream directory
+ llvm::support::ulittle32_t checksum;
+ llvm::support::ulittle32_t time_date_stamp; // time_t format
+ llvm::support::ulittle64_t flags;
+
+ static const MinidumpHeader *Parse(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpHeader) == 32,
+ "sizeof MinidumpHeader is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383.aspx
+struct MinidumpLocationDescriptor {
+ llvm::support::ulittle32_t data_size;
+ llvm::support::ulittle32_t rva;
+};
+static_assert(sizeof(MinidumpLocationDescriptor) == 8,
+ "sizeof MinidumpLocationDescriptor is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx
+struct MinidumpMemoryDescriptor {
+ llvm::support::ulittle64_t start_of_memory_range;
+ MinidumpLocationDescriptor memory;
+
+ static llvm::ArrayRef<MinidumpMemoryDescriptor>
+ ParseMemoryList(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpMemoryDescriptor) == 16,
+ "sizeof MinidumpMemoryDescriptor is not correct!");
+
+struct MinidumpMemoryDescriptor64 {
+ llvm::support::ulittle64_t start_of_memory_range;
+ llvm::support::ulittle64_t data_size;
+
+ static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+ ParseMemory64List(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpMemoryDescriptor64) == 16,
+ "sizeof MinidumpMemoryDescriptor64 is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx
+struct MinidumpDirectory {
+ llvm::support::ulittle32_t stream_type;
+ MinidumpLocationDescriptor location;
+};
+static_assert(sizeof(MinidumpDirectory) == 12,
+ "sizeof MinidumpDirectory is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx
+struct MinidumpMemoryInfoListHeader {
+ llvm::support::ulittle32_t size_of_header;
+ llvm::support::ulittle32_t size_of_entry;
+ llvm::support::ulittle64_t num_of_entries;
+};
+static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16,
+ "sizeof MinidumpMemoryInfoListHeader is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx
+struct MinidumpMemoryInfo {
+ llvm::support::ulittle64_t base_address;
+ llvm::support::ulittle64_t allocation_base;
+ llvm::support::ulittle32_t allocation_protect;
+ llvm::support::ulittle32_t alignment1;
+ llvm::support::ulittle64_t region_size;
+ llvm::support::ulittle32_t state;
+ llvm::support::ulittle32_t protect;
+ llvm::support::ulittle32_t type;
+ llvm::support::ulittle32_t alignment2;
+
+ static std::vector<const MinidumpMemoryInfo *>
+ ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpMemoryInfo) == 48,
+ "sizeof MinidumpMemoryInfo is not correct!");
+
+enum class MinidumpMemoryInfoState : uint32_t {
+ MemCommit = 0x1000,
+ MemFree = 0x10000,
+ MemReserve = 0x2000,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)
+};
+
+enum class MinidumpMemoryInfoType : uint32_t {
+ MemImage = 0x1000000,
+ MemMapped = 0x40000,
+ MemPrivate = 0x20000,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)
+};
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx
+enum class MinidumpMemoryProtectionContants : uint32_t {
+ PageExecute = 0x10,
+ PageExecuteRead = 0x20,
+ PageExecuteReadWrite = 0x40,
+ PageExecuteWriteCopy = 0x80,
+ PageNoAccess = 0x01,
+ PageReadOnly = 0x02,
+ PageReadWrite = 0x04,
+ PageWriteCopy = 0x08,
+ PageTargetsInvalid = 0x40000000,
+ PageTargetsNoUpdate = 0x40000000,
+
+ PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite |
+ PageWriteCopy,
+ PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite |
+ PageExecuteWriteCopy,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)
+};
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
+struct MinidumpThread {
+ llvm::support::ulittle32_t thread_id;
+ llvm::support::ulittle32_t suspend_count;
+ llvm::support::ulittle32_t priority_class;
+ llvm::support::ulittle32_t priority;
+ llvm::support::ulittle64_t teb;
+ MinidumpMemoryDescriptor stack;
+ MinidumpLocationDescriptor thread_context;
+
+ static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data);
+
+ static llvm::ArrayRef<MinidumpThread>
+ ParseThreadList(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpThread) == 48,
+ "sizeof MinidumpThread is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
+union MinidumpCPUInfo {
+ struct {
+ llvm::support::ulittle32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
+ llvm::support::ulittle32_t version_information; /* cpuid 1: eax */
+ llvm::support::ulittle32_t feature_information; /* cpuid 1: edx */
+ llvm::support::ulittle32_t
+ amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
+ } x86_cpu_info;
+ struct {
+ llvm::support::ulittle32_t cpuid;
+ llvm::support::ulittle32_t elf_hwcaps; /* linux specific, 0 otherwise */
+ } arm_cpu_info;
+ struct {
+ llvm::support::ulittle64_t processor_features[2];
+ } other_cpu_info;
+};
+static_assert(sizeof(MinidumpCPUInfo) == 24,
+ "sizeof MinidumpCPUInfo is not correct!");
+
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
+struct MinidumpSystemInfo {
+ llvm::support::ulittle16_t processor_arch;
+ llvm::support::ulittle16_t processor_level;
+ llvm::support::ulittle16_t processor_revision;
+
+ uint8_t number_of_processors;
+ uint8_t product_type;
+
+ llvm::support::ulittle32_t major_version;
+ llvm::support::ulittle32_t minor_version;
+ llvm::support::ulittle32_t build_number;
+ llvm::support::ulittle32_t platform_id;
+ llvm::support::ulittle32_t csd_version_rva;
+
+ llvm::support::ulittle16_t suit_mask;
+ llvm::support::ulittle16_t reserved2;
+
+ MinidumpCPUInfo cpu;
+
+ static const MinidumpSystemInfo *Parse(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpSystemInfo) == 56,
+ "sizeof MinidumpSystemInfo is not correct!");
+
+// TODO misc2, misc3 ?
+// Reference:
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx
+struct MinidumpMiscInfo {
+ llvm::support::ulittle32_t size;
+ // flags1 represents what info in the struct is valid
+ llvm::support::ulittle32_t flags1;
+ llvm::support::ulittle32_t process_id;
+ llvm::support::ulittle32_t process_create_time;
+ llvm::support::ulittle32_t process_user_time;
+ llvm::support::ulittle32_t process_kernel_time;
+
+ static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data);
+
+ llvm::Optional<lldb::pid_t> GetPid() const;
+};
+static_assert(sizeof(MinidumpMiscInfo) == 24,
+ "sizeof MinidumpMiscInfo is not correct!");
+
+// The /proc/pid/status is saved as an ascii string in the file
+class LinuxProcStatus {
+public:
+ llvm::StringRef proc_status;
+ lldb::pid_t pid;
+
+ static llvm::Optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data);
+
+ lldb::pid_t GetPid() const;
+
+private:
+ LinuxProcStatus() = default;
+};
+
+// MinidumpModule stuff
+struct MinidumpVSFixedFileInfo {
+ llvm::support::ulittle32_t signature;
+ llvm::support::ulittle32_t struct_version;
+ llvm::support::ulittle32_t file_version_hi;
+ llvm::support::ulittle32_t file_version_lo;
+ llvm::support::ulittle32_t product_version_hi;
+ llvm::support::ulittle32_t product_version_lo;
+ // file_flags_mask - identifies valid bits in fileFlags
+ llvm::support::ulittle32_t file_flags_mask;
+ llvm::support::ulittle32_t file_flags;
+ llvm::support::ulittle32_t file_os;
+ llvm::support::ulittle32_t file_type;
+ llvm::support::ulittle32_t file_subtype;
+ llvm::support::ulittle32_t file_date_hi;
+ llvm::support::ulittle32_t file_date_lo;
+};
+static_assert(sizeof(MinidumpVSFixedFileInfo) == 52,
+ "sizeof MinidumpVSFixedFileInfo is not correct!");
+
+struct MinidumpModule {
+ llvm::support::ulittle64_t base_of_image;
+ llvm::support::ulittle32_t size_of_image;
+ llvm::support::ulittle32_t checksum;
+ llvm::support::ulittle32_t time_date_stamp;
+ llvm::support::ulittle32_t module_name_rva;
+ MinidumpVSFixedFileInfo version_info;
+ MinidumpLocationDescriptor CV_record;
+ MinidumpLocationDescriptor misc_record;
+ llvm::support::ulittle32_t reserved0[2];
+ llvm::support::ulittle32_t reserved1[2];
+
+ static const MinidumpModule *Parse(llvm::ArrayRef<uint8_t> &data);
+
+ static llvm::ArrayRef<MinidumpModule>
+ ParseModuleList(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpModule) == 108,
+ "sizeof MinidumpVSFixedFileInfo is not correct!");
+
+// Exception stuff
+struct MinidumpException {
+ enum : unsigned {
+ ExceptonInfoMaxParams = 15,
+ DumpRequested = 0xFFFFFFFF,
+ };
+
+ llvm::support::ulittle32_t exception_code;
+ llvm::support::ulittle32_t exception_flags;
+ llvm::support::ulittle64_t exception_record;
+ llvm::support::ulittle64_t exception_address;
+ llvm::support::ulittle32_t number_parameters;
+ llvm::support::ulittle32_t unused_alignment;
+ llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams];
+};
+static_assert(sizeof(MinidumpException) == 152,
+ "sizeof MinidumpException is not correct!");
+
+struct MinidumpExceptionStream {
+ llvm::support::ulittle32_t thread_id;
+ llvm::support::ulittle32_t alignment;
+ MinidumpException exception_record;
+ MinidumpLocationDescriptor thread_context;
+
+ static const MinidumpExceptionStream *Parse(llvm::ArrayRef<uint8_t> &data);
+};
+static_assert(sizeof(MinidumpExceptionStream) == 168,
+ "sizeof MinidumpExceptionStream is not correct!");
+
+} // namespace minidump
+} // namespace lldb_private
+#endif // liblldb_MinidumpTypes_h_
diff --git a/source/Plugins/Process/minidump/NtStructures.h b/source/Plugins/Process/minidump/NtStructures.h
new file mode 100644
index 0000000000000..c0afd77358cd6
--- /dev/null
+++ b/source/Plugins/Process/minidump/NtStructures.h
@@ -0,0 +1,37 @@
+//===-- NtStructures.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Plugins_Process_Minidump_NtStructures_h_
+#define liblldb_Plugins_Process_Minidump_NtStructures_h_
+
+#include "llvm/Support/Endian.h"
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This describes the layout of a TEB (Thread Environment Block) for a 64-bit
+// process. It's adapted from the 32-bit TEB in winternl.h. Currently, we care
+// only about the position of the tls_slots.
+struct TEB64 {
+ llvm::support::ulittle64_t reserved1[12];
+ llvm::support::ulittle64_t process_environment_block;
+ llvm::support::ulittle64_t reserved2[399];
+ uint8_t reserved3[1952];
+ llvm::support::ulittle64_t tls_slots[64];
+ uint8_t reserved4[8];
+ llvm::support::ulittle64_t reserved5[26];
+ llvm::support::ulittle64_t reserved_for_ole; // Windows 2000 only
+ llvm::support::ulittle64_t reserved6[4];
+ llvm::support::ulittle64_t tls_expansion_slots;
+};
+
+#endif // liblldb_Plugins_Process_Minidump_NtStructures_h_
+} // namespace minidump
+} // namespace lldb_private
diff --git a/source/Plugins/Process/minidump/ProcessMinidump.cpp b/source/Plugins/Process/minidump/ProcessMinidump.cpp
new file mode 100644
index 0000000000000..46d8df8b16f12
--- /dev/null
+++ b/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -0,0 +1,301 @@
+//===-- ProcessMinidump.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 "ProcessMinidump.h"
+#include "ThreadMinidump.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+ConstString ProcessMinidump::GetPluginNameStatic() {
+ static ConstString g_name("minidump");
+ return g_name;
+}
+
+const char *ProcessMinidump::GetPluginDescriptionStatic() {
+ return "Minidump plug-in.";
+}
+
+lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file) {
+ if (!crash_file)
+ return nullptr;
+
+ lldb::ProcessSP process_sp;
+ // Read enough data for the Minidump header
+ const size_t header_size = sizeof(MinidumpHeader);
+ lldb::DataBufferSP data_sp(crash_file->MemoryMapFileContents(0, header_size));
+ if (!data_sp)
+ return nullptr;
+
+ // first, only try to parse the header, beacuse we need to be fast
+ llvm::ArrayRef<uint8_t> header_data(data_sp->GetBytes(), header_size);
+ const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
+
+ if (data_sp->GetByteSize() != header_size || header == nullptr)
+ return nullptr;
+
+ lldb::DataBufferSP all_data_sp(crash_file->MemoryMapFileContents());
+ auto minidump_parser = MinidumpParser::Create(all_data_sp);
+ // check if the parser object is valid
+ if (!minidump_parser)
+ return nullptr;
+
+ return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
+ minidump_parser.getValue());
+}
+
+bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ return true;
+}
+
+ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec &core_file,
+ MinidumpParser minidump_parser)
+ : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
+ m_core_file(core_file), m_is_wow64(false) {}
+
+ProcessMinidump::~ProcessMinidump() {
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+void ProcessMinidump::Initialize() {
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ ProcessMinidump::CreateInstance);
+ });
+}
+
+void ProcessMinidump::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
+}
+
+Error ProcessMinidump::DoLoadCore() {
+ Error error;
+
+ m_thread_list = m_minidump_parser.GetThreads();
+ m_active_exception = m_minidump_parser.GetExceptionStream();
+ ReadModuleList();
+ GetTarget().SetArchitecture(GetArchitecture());
+
+ llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
+ if (!pid) {
+ error.SetErrorString("failed to parse PID");
+ return error;
+ }
+ SetID(pid.getValue());
+
+ return error;
+}
+
+DynamicLoader *ProcessMinidump::GetDynamicLoader() {
+ if (m_dyld_ap.get() == nullptr)
+ m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr));
+ return m_dyld_ap.get();
+}
+
+ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
+
+uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
+
+Error ProcessMinidump::DoDestroy() { return Error(); }
+
+void ProcessMinidump::RefreshStateAfterStop() {
+ if (!m_active_exception)
+ return;
+
+ if (m_active_exception->exception_record.exception_code ==
+ MinidumpException::DumpRequested) {
+ return;
+ }
+
+ lldb::StopInfoSP stop_info;
+ lldb::ThreadSP stop_thread;
+
+ Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
+ stop_thread = Process::m_thread_list.GetSelectedThread();
+ ArchSpec arch = GetArchitecture();
+
+ if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
+ stop_info = StopInfo::CreateStopReasonWithSignal(
+ *stop_thread, m_active_exception->exception_record.exception_code);
+ } else {
+ std::string desc;
+ llvm::raw_string_ostream desc_stream(desc);
+ desc_stream << "Exception "
+ << llvm::format_hex(
+ m_active_exception->exception_record.exception_code, 8)
+ << " encountered at address "
+ << llvm::format_hex(
+ m_active_exception->exception_record.exception_address,
+ 8);
+ stop_info = StopInfo::CreateStopReasonWithException(
+ *stop_thread, desc_stream.str().c_str());
+ }
+
+ stop_thread->SetStopInfo(stop_info);
+}
+
+bool ProcessMinidump::IsAlive() { return true; }
+
+bool ProcessMinidump::WarnBeforeDetach() const { return false; }
+
+size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Error &error) {
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since we have it all cached in our dump file anyway.
+ return DoReadMemory(addr, buf, size, error);
+}
+
+size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Error &error) {
+
+ llvm::ArrayRef<uint8_t> mem = m_minidump_parser.GetMemory(addr, size);
+ if (mem.empty()) {
+ error.SetErrorString("could not parse memory info");
+ return 0;
+ }
+
+ std::memcpy(buf, mem.data(), mem.size());
+ return mem.size();
+}
+
+ArchSpec ProcessMinidump::GetArchitecture() {
+ if (!m_is_wow64) {
+ return m_minidump_parser.GetArchitecture();
+ }
+
+ llvm::Triple triple;
+ triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
+ triple.setArch(llvm::Triple::ArchType::x86);
+ triple.setOS(llvm::Triple::OSType::Win32);
+ return ArchSpec(triple);
+}
+
+Error ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ Error error;
+ auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
+ if (!info) {
+ error.SetErrorString("No valid MemoryRegionInfo found!");
+ return error;
+ }
+ range_info = info.getValue();
+ return error;
+}
+
+void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
+
+bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ uint32_t num_threads = 0;
+ if (m_thread_list.size() > 0)
+ num_threads = m_thread_list.size();
+
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
+ llvm::ArrayRef<uint8_t> context;
+ if (!m_is_wow64)
+ context = m_minidump_parser.GetThreadContext(m_thread_list[tid]);
+ else
+ context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]);
+
+ lldb::ThreadSP thread_sp(
+ new ThreadMinidump(*this, m_thread_list[tid], context));
+ new_thread_list.AddThread(thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void ProcessMinidump::ReadModuleList() {
+ std::vector<const MinidumpModule *> filtered_modules =
+ m_minidump_parser.GetFilteredModuleList();
+
+ for (auto module : filtered_modules) {
+ llvm::Optional<std::string> name =
+ m_minidump_parser.GetMinidumpString(module->module_name_rva);
+
+ if (!name)
+ continue;
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
+ if (log) {
+ log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
+ "-%#010" PRIx64 " size: %" PRIu32,
+ __FUNCTION__, name.getValue().c_str(),
+ uint64_t(module->base_of_image),
+ module->base_of_image + module->size_of_image,
+ uint32_t(module->size_of_image));
+ }
+
+ // check if the process is wow64 - a 32 bit windows process running on a
+ // 64 bit windows
+ if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
+ m_is_wow64 = true;
+ }
+
+ const auto file_spec = FileSpec(name.getValue(), true);
+ ModuleSpec module_spec = file_spec;
+ Error error;
+ lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
+ if (!module_sp || error.Fail()) {
+ continue;
+ }
+
+ if (log) {
+ log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
+ name.getValue().c_str());
+ }
+
+ bool load_addr_changed = false;
+ module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
+ load_addr_changed);
+ }
+}
+
+bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
+ info.Clear();
+ info.SetProcessID(GetID());
+ info.SetArchitecture(GetArchitecture());
+ lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
+ if (module_sp) {
+ const bool add_exe_file_as_first_arg = false;
+ info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
+ add_exe_file_as_first_arg);
+ }
+ return true;
+}
diff --git a/source/Plugins/Process/minidump/ProcessMinidump.h b/source/Plugins/Process/minidump/ProcessMinidump.h
new file mode 100644
index 0000000000000..78eadc809a4de
--- /dev/null
+++ b/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -0,0 +1,105 @@
+//===-- ProcessMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMinidump_h_
+#define liblldb_ProcessMinidump_h_
+
+// Project includes
+#include "MinidumpParser.h"
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+// C Includes
+// C++ Includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ProcessMinidump : public Process {
+public:
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static ConstString GetPluginNameStatic();
+
+ static const char *GetPluginDescriptionStatic();
+
+ ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const FileSpec &core_file, MinidumpParser minidump_parser);
+
+ ~ProcessMinidump() override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ Error DoLoadCore() override;
+
+ DynamicLoader *GetDynamicLoader() override;
+
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override;
+
+ Error DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ bool IsAlive() override;
+
+ bool WarnBeforeDetach() const override;
+
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Error &error) override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Error &error) override;
+
+ ArchSpec GetArchitecture();
+
+ Error GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ bool GetProcessInfo(ProcessInstanceInfo &info) override;
+
+ MinidumpParser m_minidump_parser;
+
+protected:
+ void Clear();
+
+ bool UpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ void ReadModuleList();
+
+private:
+ FileSpec m_core_file;
+ llvm::ArrayRef<MinidumpThread> m_thread_list;
+ const MinidumpExceptionStream *m_active_exception;
+ bool m_is_wow64;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+
+#endif // liblldb_ProcessMinidump_h_
diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
new file mode 100644
index 0000000000000..7f3768216f3a9
--- /dev/null
+++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
@@ -0,0 +1,99 @@
+//===-- RegisterContextMinidump_x86_32.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 "RegisterContextMinidump_x86_32.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+static void writeRegister(const void *reg_src,
+ llvm::MutableArrayRef<uint8_t> reg_dest) {
+ memcpy(reg_dest.data(), reg_src, reg_dest.size());
+}
+
+lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_32(
+ llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface) {
+
+ const RegisterInfo *reg_info = target_reg_interface->GetRegisterInfo();
+
+ lldb::DataBufferSP result_context_buf(
+ new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
+ uint8_t *result_base = result_context_buf->GetBytes();
+
+ if (source_data.size() < sizeof(MinidumpContext_x86_32))
+ return nullptr;
+
+ const MinidumpContext_x86_32 *context;
+ consumeObject(source_data, context);
+
+ const MinidumpContext_x86_32_Flags context_flags =
+ static_cast<MinidumpContext_x86_32_Flags>(
+ static_cast<uint32_t>(context->context_flags));
+ auto x86_32_Flag = MinidumpContext_x86_32_Flags::x86_32_Flag;
+ auto ControlFlag = MinidumpContext_x86_32_Flags::Control;
+ auto IntegerFlag = MinidumpContext_x86_32_Flags::Integer;
+ auto SegmentsFlag = MinidumpContext_x86_32_Flags::Segments;
+
+ if ((context_flags & x86_32_Flag) != x86_32_Flag) {
+ return nullptr;
+ }
+
+ if ((context_flags & ControlFlag) == ControlFlag) {
+ writeRegister(&context->ebp,
+ reg_info[lldb_ebp_i386].mutable_data(result_base));
+ writeRegister(&context->eip,
+ reg_info[lldb_eip_i386].mutable_data(result_base));
+ writeRegister(&context->cs,
+ reg_info[lldb_cs_i386].mutable_data(result_base));
+ writeRegister(&context->eflags,
+ reg_info[lldb_eflags_i386].mutable_data(result_base));
+ writeRegister(&context->esp,
+ reg_info[lldb_esp_i386].mutable_data(result_base));
+ writeRegister(&context->ss,
+ reg_info[lldb_ss_i386].mutable_data(result_base));
+ }
+
+ if ((context_flags & SegmentsFlag) == SegmentsFlag) {
+ writeRegister(&context->ds,
+ reg_info[lldb_ds_i386].mutable_data(result_base));
+ writeRegister(&context->es,
+ reg_info[lldb_es_i386].mutable_data(result_base));
+ writeRegister(&context->fs,
+ reg_info[lldb_fs_i386].mutable_data(result_base));
+ writeRegister(&context->gs,
+ reg_info[lldb_gs_i386].mutable_data(result_base));
+ }
+
+ if ((context_flags & IntegerFlag) == IntegerFlag) {
+ writeRegister(&context->eax,
+ reg_info[lldb_eax_i386].mutable_data(result_base));
+ writeRegister(&context->ecx,
+ reg_info[lldb_ecx_i386].mutable_data(result_base));
+ writeRegister(&context->edx,
+ reg_info[lldb_edx_i386].mutable_data(result_base));
+ writeRegister(&context->ebx,
+ reg_info[lldb_ebx_i386].mutable_data(result_base));
+ writeRegister(&context->esi,
+ reg_info[lldb_esi_i386].mutable_data(result_base));
+ writeRegister(&context->edi,
+ reg_info[lldb_edi_i386].mutable_data(result_base));
+ }
+
+ // TODO parse the floating point registers
+
+ return result_context_buf;
+}
diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
new file mode 100644
index 0000000000000..e18bb3b4f5d98
--- /dev/null
+++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
@@ -0,0 +1,138 @@
+//===-- RegisterContextMinidump_x86_32.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMinidump_x86_32_h_
+#define liblldb_RegisterContextMinidump_x86_32_h_
+
+// Project includes
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/Endian.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This function receives an ArrayRef pointing to the bytes of the Minidump
+// register context and returns a DataBuffer that's ordered by the offsets
+// specified in the RegisterInfoInterface argument
+// This way we can reuse the already existing register contexts
+lldb::DataBufferSP
+ConvertMinidumpContext_x86_32(llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface);
+
+// Reference: see breakpad/crashpad source or WinNT.h
+struct MinidumpFloatingSaveAreaX86 {
+ llvm::support::ulittle32_t control_word;
+ llvm::support::ulittle32_t status_word;
+ llvm::support::ulittle32_t tag_word;
+ llvm::support::ulittle32_t error_offset;
+ llvm::support::ulittle32_t error_selector;
+ llvm::support::ulittle32_t data_offset;
+ llvm::support::ulittle32_t data_selector;
+
+ enum {
+ RegisterAreaSize = 80,
+ };
+ // register_area contains eight 80-bit (x87 "long double") quantities for
+ // floating-point registers %st0 (%mm0) through %st7 (%mm7).
+ uint8_t register_area[RegisterAreaSize];
+ llvm::support::ulittle32_t cr0_npx_state;
+};
+
+struct MinidumpContext_x86_32 {
+ // The context_flags field determines which parts
+ // of the structure are populated (have valid values)
+ llvm::support::ulittle32_t context_flags;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::DebugRegisters
+ llvm::support::ulittle32_t dr0;
+ llvm::support::ulittle32_t dr1;
+ llvm::support::ulittle32_t dr2;
+ llvm::support::ulittle32_t dr3;
+ llvm::support::ulittle32_t dr6;
+ llvm::support::ulittle32_t dr7;
+
+ // The next field is included with
+ // MinidumpContext_x86_32_Flags::FloatingPoint
+ MinidumpFloatingSaveAreaX86 float_save;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_32_Flags::Segments
+ llvm::support::ulittle32_t gs;
+ llvm::support::ulittle32_t fs;
+ llvm::support::ulittle32_t es;
+ llvm::support::ulittle32_t ds;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::Integer
+ llvm::support::ulittle32_t edi;
+ llvm::support::ulittle32_t esi;
+ llvm::support::ulittle32_t ebx;
+ llvm::support::ulittle32_t edx;
+ llvm::support::ulittle32_t ecx;
+ llvm::support::ulittle32_t eax;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_32_Flags::Control
+ llvm::support::ulittle32_t ebp;
+ llvm::support::ulittle32_t eip;
+ llvm::support::ulittle32_t cs; // WinNT.h says "must be sanitized"
+ llvm::support::ulittle32_t eflags; // WinNT.h says "must be sanitized"
+ llvm::support::ulittle32_t esp;
+ llvm::support::ulittle32_t ss;
+
+ // The next field is included with
+ // MinidumpContext_x86_32_Flags::ExtendedRegisters
+ // It contains vector (MMX/SSE) registers. It it laid out in the
+ // format used by the fxsave and fsrstor instructions, so it includes
+ // a copy of the x87 floating-point registers as well. See FXSAVE in
+ // "Intel Architecture Software Developer's Manual, Volume 2."
+ enum {
+ ExtendedRegistersSize = 512,
+ };
+ uint8_t extended_registers[ExtendedRegistersSize];
+};
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+// For context_flags. These values indicate the type of
+// context stored in the structure. The high 24 bits identify the CPU, the
+// low 8 bits identify the type of context saved.
+enum class MinidumpContext_x86_32_Flags : uint32_t {
+ x86_32_Flag = 0x00010000, // CONTEXT_i386, CONTEXT_i486
+ Control = x86_32_Flag | 0x00000001,
+ Integer = x86_32_Flag | 0x00000002,
+ Segments = x86_32_Flag | 0x00000004,
+ FloatingPoint = x86_32_Flag | 0x00000008,
+ DebugRegisters = x86_32_Flag | 0x00000010,
+ ExtendedRegisters = x86_32_Flag | 0x00000020,
+ XState = x86_32_Flag | 0x00000040,
+
+ Full = Control | Integer | Segments,
+ All = Full | FloatingPoint | DebugRegisters | ExtendedRegisters,
+
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // liblldb_RegisterContextMinidump_x86_32_h_
diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
new file mode 100644
index 0000000000000..881c26a5774a6
--- /dev/null
+++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
@@ -0,0 +1,113 @@
+//===-- RegisterContextMinidump_x86_64.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 "RegisterContextMinidump_x86_64.h"
+
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+static llvm::MutableArrayRef<uint8_t> getDestRegister(uint8_t *context,
+ const RegisterInfo &reg) {
+ auto bytes = reg.mutable_data(context);
+
+ switch (reg.kinds[lldb::eRegisterKindLLDB]) {
+ case lldb_cs_x86_64:
+ case lldb_ds_x86_64:
+ case lldb_es_x86_64:
+ case lldb_fs_x86_64:
+ case lldb_gs_x86_64:
+ case lldb_ss_x86_64:
+ return bytes.take_front(2);
+ break;
+ case lldb_rflags_x86_64:
+ return bytes.take_front(4);
+ break;
+ default:
+ return bytes.take_front(8);
+ break;
+ }
+}
+
+static void writeRegister(const void *reg_src, uint8_t *context,
+ const RegisterInfo &reg) {
+ llvm::MutableArrayRef<uint8_t> reg_dest = getDestRegister(context, reg);
+ memcpy(reg_dest.data(), reg_src, reg_dest.size());
+}
+
+lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_64(
+ llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface) {
+
+ const RegisterInfo *reg_info = target_reg_interface->GetRegisterInfo();
+
+ lldb::DataBufferSP result_context_buf(
+ new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
+ uint8_t *result_base = result_context_buf->GetBytes();
+
+ if (source_data.size() < sizeof(MinidumpContext_x86_64))
+ return nullptr;
+
+ const MinidumpContext_x86_64 *context;
+ consumeObject(source_data, context);
+
+ const MinidumpContext_x86_64_Flags context_flags =
+ static_cast<MinidumpContext_x86_64_Flags>(
+ static_cast<uint32_t>(context->context_flags));
+ auto x86_64_Flag = MinidumpContext_x86_64_Flags::x86_64_Flag;
+ auto ControlFlag = MinidumpContext_x86_64_Flags::Control;
+ auto IntegerFlag = MinidumpContext_x86_64_Flags::Integer;
+ auto SegmentsFlag = MinidumpContext_x86_64_Flags::Segments;
+
+ if ((context_flags & x86_64_Flag) != x86_64_Flag)
+ return nullptr;
+
+ if ((context_flags & ControlFlag) == ControlFlag) {
+ writeRegister(&context->cs, result_base, reg_info[lldb_cs_x86_64]);
+ writeRegister(&context->ss, result_base, reg_info[lldb_ss_x86_64]);
+ writeRegister(&context->eflags, result_base, reg_info[lldb_rflags_x86_64]);
+ writeRegister(&context->rsp, result_base, reg_info[lldb_rsp_x86_64]);
+ writeRegister(&context->rip, result_base, reg_info[lldb_rip_x86_64]);
+ }
+
+ if ((context_flags & SegmentsFlag) == SegmentsFlag) {
+ writeRegister(&context->ds, result_base, reg_info[lldb_ds_x86_64]);
+ writeRegister(&context->es, result_base, reg_info[lldb_es_x86_64]);
+ writeRegister(&context->fs, result_base, reg_info[lldb_fs_x86_64]);
+ writeRegister(&context->gs, result_base, reg_info[lldb_gs_x86_64]);
+ }
+
+ if ((context_flags & IntegerFlag) == IntegerFlag) {
+ writeRegister(&context->rax, result_base, reg_info[lldb_rax_x86_64]);
+ writeRegister(&context->rcx, result_base, reg_info[lldb_rcx_x86_64]);
+ writeRegister(&context->rdx, result_base, reg_info[lldb_rdx_x86_64]);
+ writeRegister(&context->rbx, result_base, reg_info[lldb_rbx_x86_64]);
+ writeRegister(&context->rbp, result_base, reg_info[lldb_rbp_x86_64]);
+ writeRegister(&context->rsi, result_base, reg_info[lldb_rsi_x86_64]);
+ writeRegister(&context->rdi, result_base, reg_info[lldb_rdi_x86_64]);
+ writeRegister(&context->r8, result_base, reg_info[lldb_r8_x86_64]);
+ writeRegister(&context->r9, result_base, reg_info[lldb_r9_x86_64]);
+ writeRegister(&context->r10, result_base, reg_info[lldb_r10_x86_64]);
+ writeRegister(&context->r11, result_base, reg_info[lldb_r11_x86_64]);
+ writeRegister(&context->r12, result_base, reg_info[lldb_r12_x86_64]);
+ writeRegister(&context->r13, result_base, reg_info[lldb_r13_x86_64]);
+ writeRegister(&context->r14, result_base, reg_info[lldb_r14_x86_64]);
+ writeRegister(&context->r15, result_base, reg_info[lldb_r15_x86_64]);
+ }
+
+ // TODO parse the floating point registers
+
+ return result_context_buf;
+}
diff --git a/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
new file mode 100644
index 0000000000000..9ba2ee9f29ad1
--- /dev/null
+++ b/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
@@ -0,0 +1,183 @@
+//===-- RegisterContextMinidump_x86_64.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMinidump_h_
+#define liblldb_RegisterContextMinidump_h_
+
+// Project includes
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/Endian.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+// This function receives an ArrayRef pointing to the bytes of the Minidump
+// register context and returns a DataBuffer that's ordered by the offsets
+// specified in the RegisterInfoInterface argument
+// This way we can reuse the already existing register contexts
+lldb::DataBufferSP
+ConvertMinidumpContext_x86_64(llvm::ArrayRef<uint8_t> source_data,
+ RegisterInfoInterface *target_reg_interface);
+
+struct Uint128 {
+ llvm::support::ulittle64_t high;
+ llvm::support::ulittle64_t low;
+};
+
+// Reference: see breakpad/crashpad source or WinNT.h
+struct MinidumpXMMSaveArea32AMD64 {
+ llvm::support::ulittle16_t control_word;
+ llvm::support::ulittle16_t status_word;
+ uint8_t tag_word;
+ uint8_t reserved1;
+ llvm::support::ulittle16_t error_opcode;
+ llvm::support::ulittle32_t error_offset;
+ llvm::support::ulittle16_t error_selector;
+ llvm::support::ulittle16_t reserved2;
+ llvm::support::ulittle32_t data_offset;
+ llvm::support::ulittle16_t data_selector;
+ llvm::support::ulittle16_t reserved3;
+ llvm::support::ulittle32_t mx_csr;
+ llvm::support::ulittle32_t mx_csr_mask;
+ Uint128 float_registers[8];
+ Uint128 xmm_registers[16];
+ uint8_t reserved4[96];
+};
+
+struct MinidumpContext_x86_64 {
+ // Register parameter home addresses.
+ llvm::support::ulittle64_t p1_home;
+ llvm::support::ulittle64_t p2_home;
+ llvm::support::ulittle64_t p3_home;
+ llvm::support::ulittle64_t p4_home;
+ llvm::support::ulittle64_t p5_home;
+ llvm::support::ulittle64_t p6_home;
+
+ // The context_flags field determines which parts
+ // of the structure are populated (have valid values)
+ llvm::support::ulittle32_t context_flags;
+ llvm::support::ulittle32_t mx_csr;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle16_t cs;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_64_Flags::Segments
+ llvm::support::ulittle16_t ds;
+ llvm::support::ulittle16_t es;
+ llvm::support::ulittle16_t fs;
+ llvm::support::ulittle16_t gs;
+
+ // The next 2 registers are included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle16_t ss;
+ llvm::support::ulittle32_t eflags;
+
+ // The next 6 registers are included with
+ // MinidumpContext_x86_64_Flags::DebugRegisters
+ llvm::support::ulittle64_t dr0;
+ llvm::support::ulittle64_t dr1;
+ llvm::support::ulittle64_t dr2;
+ llvm::support::ulittle64_t dr3;
+ llvm::support::ulittle64_t dr6;
+ llvm::support::ulittle64_t dr7;
+
+ // The next 4 registers are included with
+ // MinidumpContext_x86_64_Flags::Integer
+ llvm::support::ulittle64_t rax;
+ llvm::support::ulittle64_t rcx;
+ llvm::support::ulittle64_t rdx;
+ llvm::support::ulittle64_t rbx;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle64_t rsp;
+
+ // The next 11 registers are included with
+ // MinidumpContext_x86_64_Flags::Integer
+ llvm::support::ulittle64_t rbp;
+ llvm::support::ulittle64_t rsi;
+ llvm::support::ulittle64_t rdi;
+ llvm::support::ulittle64_t r8;
+ llvm::support::ulittle64_t r9;
+ llvm::support::ulittle64_t r10;
+ llvm::support::ulittle64_t r11;
+ llvm::support::ulittle64_t r12;
+ llvm::support::ulittle64_t r13;
+ llvm::support::ulittle64_t r14;
+ llvm::support::ulittle64_t r15;
+
+ // The next register is included with
+ // MinidumpContext_x86_64_Flags::Control
+ llvm::support::ulittle64_t rip;
+
+ // The next set of registers are included with
+ // MinidumpContext_x86_64_Flags:FloatingPoint
+ union FPR {
+ MinidumpXMMSaveArea32AMD64 flt_save;
+ struct {
+ Uint128 header[2];
+ Uint128 legacy[8];
+ Uint128 xmm[16];
+ } sse_registers;
+ };
+
+ enum {
+ VRCount = 26,
+ };
+
+ Uint128 vector_register[VRCount];
+ llvm::support::ulittle64_t vector_control;
+
+ // The next 5 registers are included with
+ // MinidumpContext_x86_64_Flags::DebugRegisters
+ llvm::support::ulittle64_t debug_control;
+ llvm::support::ulittle64_t last_branch_to_rip;
+ llvm::support::ulittle64_t last_branch_from_rip;
+ llvm::support::ulittle64_t last_exception_to_rip;
+ llvm::support::ulittle64_t last_exception_from_rip;
+};
+
+// For context_flags. These values indicate the type of
+// context stored in the structure. The high 24 bits identify the CPU, the
+// low 8 bits identify the type of context saved.
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+enum class MinidumpContext_x86_64_Flags : uint32_t {
+ x86_64_Flag = 0x00100000,
+ Control = x86_64_Flag | 0x00000001,
+ Integer = x86_64_Flag | 0x00000002,
+ Segments = x86_64_Flag | 0x00000004,
+ FloatingPoint = x86_64_Flag | 0x00000008,
+ DebugRegisters = x86_64_Flag | 0x00000010,
+ XState = x86_64_Flag | 0x00000040,
+
+ Full = Control | Integer | FloatingPoint,
+ All = Full | Segments | DebugRegisters,
+
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // liblldb_RegisterContextMinidump_h_
diff --git a/source/Plugins/Process/minidump/ThreadMinidump.cpp b/source/Plugins/Process/minidump/ThreadMinidump.cpp
new file mode 100644
index 0000000000000..e42108b9261a8
--- /dev/null
+++ b/source/Plugins/Process/minidump/ThreadMinidump.cpp
@@ -0,0 +1,114 @@
+//===-- ThreadMinidump.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 "ThreadMinidump.h"
+#include "ProcessMinidump.h"
+
+#include "RegisterContextMinidump_x86_32.h"
+#include "RegisterContextMinidump_x86_64.h"
+
+// Other libraries and framework includes
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+
+#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h"
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+
+// C Includes
+// C++ Includes
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+ThreadMinidump::ThreadMinidump(Process &process, const MinidumpThread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data)
+ : Thread(process, td.thread_id), m_thread_reg_ctx_sp(),
+ m_gpregset_data(gpregset_data) {}
+
+ThreadMinidump::~ThreadMinidump() {}
+
+void ThreadMinidump::RefreshStateAfterStop() {}
+
+void ThreadMinidump::ClearStackFrames() {}
+
+RegisterContextSP ThreadMinidump::GetRegisterContext() {
+ if (!m_reg_context_sp) {
+ m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) {
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0) {
+ if (m_thread_reg_ctx_sp)
+ return m_thread_reg_ctx_sp;
+
+ ProcessMinidump *process =
+ static_cast<ProcessMinidump *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ RegisterInfoInterface *reg_interface = nullptr;
+
+ // TODO write other register contexts and add them here
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86: {
+ reg_interface = new RegisterContextLinux_i386(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_32(m_gpregset_data, reg_interface);
+ DataExtractor gpregs(buf, lldb::eByteOrderLittle, 4);
+ DataExtractor fpregs;
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64(
+ *this, reg_interface, gpregs, fpregs));
+ break;
+ }
+ case llvm::Triple::x86_64: {
+ reg_interface = new RegisterContextLinux_x86_64(arch);
+ lldb::DataBufferSP buf =
+ ConvertMinidumpContext_x86_64(m_gpregset_data, reg_interface);
+ DataExtractor gpregs(buf, lldb::eByteOrderLittle, 8);
+ DataExtractor fpregs;
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64(
+ *this, reg_interface, gpregs, fpregs));
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!reg_interface) {
+ if (log)
+ log->Printf("elf-core::%s:: Architecture(%d) not supported",
+ __FUNCTION__, arch.GetMachine());
+ assert(false && "Architecture not supported");
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else if (m_unwinder_ap) {
+ reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool ThreadMinidump::CalculateStopInfo() { return false; }
diff --git a/source/Plugins/Process/minidump/ThreadMinidump.h b/source/Plugins/Process/minidump/ThreadMinidump.h
new file mode 100644
index 0000000000000..97db452edfffa
--- /dev/null
+++ b/source/Plugins/Process/minidump/ThreadMinidump.h
@@ -0,0 +1,52 @@
+//===-- ThreadMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadMinidump_h_
+#define liblldb_ThreadMinidump_h_
+
+// Project includes
+#include "MinidumpTypes.h"
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+
+// C Includes
+// C++ Includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ThreadMinidump : public Thread {
+public:
+ ThreadMinidump(Process &process, const MinidumpThread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data);
+
+ ~ThreadMinidump() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+ void ClearStackFrames() override;
+
+protected:
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+ llvm::ArrayRef<uint8_t> m_gpregset_data;
+
+ bool CalculateStopInfo() override;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+
+#endif // liblldb_ThreadMinidump_h_