aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Process/minidump
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process/minidump')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp711
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h113
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp79
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h107
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h42
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp929
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h123
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp550
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h98
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp833
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h83
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp96
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h135
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp110
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h180
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp118
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h45
17 files changed, 4352 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
new file mode 100644
index 000000000000..be9fae938e22
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -0,0 +1,711 @@
+//===-- MinidumpParser.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinidumpParser.h"
+#include "NtStructures.h"
+#include "RegisterContextMinidump_x86_32.h"
+
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+// C includes
+// C++ includes
+#include <algorithm>
+#include <map>
+#include <optional>
+#include <vector>
+#include <utility>
+
+using namespace lldb_private;
+using namespace minidump;
+
+llvm::Expected<MinidumpParser>
+MinidumpParser::Create(const lldb::DataBufferSP &data_sp) {
+ auto ExpectedFile = llvm::object::MinidumpFile::create(
+ llvm::MemoryBufferRef(toStringRef(data_sp->GetData()), "minidump"));
+ if (!ExpectedFile)
+ return ExpectedFile.takeError();
+
+ return MinidumpParser(data_sp, std::move(*ExpectedFile));
+}
+
+MinidumpParser::MinidumpParser(lldb::DataBufferSP data_sp,
+ std::unique_ptr<llvm::object::MinidumpFile> file)
+ : m_data_sp(std::move(data_sp)), m_file(std::move(file)) {}
+
+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(StreamType stream_type) {
+ return m_file->getRawStream(stream_type).value_or(llvm::ArrayRef<uint8_t>());
+}
+
+UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
+ auto cv_record =
+ GetData().slice(module->CvRecord.RVA, module->CvRecord.DataSize);
+
+ // Read the CV record signature
+ const llvm::support::ulittle32_t *signature = nullptr;
+ Status error = consumeObject(cv_record, signature);
+ if (error.Fail())
+ return UUID();
+
+ const CvSignature cv_signature =
+ static_cast<CvSignature>(static_cast<uint32_t>(*signature));
+
+ if (cv_signature == CvSignature::Pdb70) {
+ const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;
+ Status error = consumeObject(cv_record, pdb70_uuid);
+ if (error.Fail())
+ return UUID();
+ if (GetArchitecture().GetTriple().isOSBinFormatELF()) {
+ if (pdb70_uuid->Age != 0)
+ return UUID(pdb70_uuid, sizeof(*pdb70_uuid));
+ return UUID(&pdb70_uuid->Uuid,
+ sizeof(pdb70_uuid->Uuid));
+ }
+ return UUID(*pdb70_uuid);
+ } else if (cv_signature == CvSignature::ElfBuildId)
+ return UUID(cv_record);
+
+ return UUID();
+}
+
+llvm::ArrayRef<minidump::Thread> MinidumpParser::GetThreads() {
+ auto ExpectedThreads = GetMinidumpFile().getThreadList();
+ if (ExpectedThreads)
+ return *ExpectedThreads;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), ExpectedThreads.takeError(),
+ "Failed to read thread list: {0}");
+ return {};
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const LocationDescriptor &location) {
+ if (location.RVA + location.DataSize > GetData().size())
+ return {};
+ return GetData().slice(location.RVA, location.DataSize);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const minidump::Thread &td) {
+ return GetThreadContext(td.Context);
+}
+
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContextWow64(const minidump::Thread &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.EnvironmentBlock, sizeof(TEB64));
+ if (teb_mem.empty())
+ return {};
+
+ const TEB64 *wow64teb;
+ Status 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]).
+}
+
+ArchSpec MinidumpParser::GetArchitecture() {
+ if (m_arch.IsValid())
+ return m_arch;
+
+ // Set the architecture in m_arch
+ llvm::Expected<const SystemInfo &> system_info = m_file->getSystemInfo();
+
+ if (!system_info) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), system_info.takeError(),
+ "Failed to read SystemInfo stream: {0}");
+ return m_arch;
+ }
+
+ // 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);
+
+ switch (system_info->ProcessorArch) {
+ case ProcessorArchitecture::X86:
+ triple.setArch(llvm::Triple::ArchType::x86);
+ break;
+ case ProcessorArchitecture::AMD64:
+ triple.setArch(llvm::Triple::ArchType::x86_64);
+ break;
+ case ProcessorArchitecture::ARM:
+ triple.setArch(llvm::Triple::ArchType::arm);
+ break;
+ case ProcessorArchitecture::ARM64:
+ case ProcessorArchitecture::BP_ARM64:
+ triple.setArch(llvm::Triple::ArchType::aarch64);
+ break;
+ default:
+ triple.setArch(llvm::Triple::ArchType::UnknownArch);
+ break;
+ }
+
+ // TODO add all of the OSes that Minidump/breakpad distinguishes?
+ switch (system_info->PlatformId) {
+ case OSPlatform::Win32S:
+ case OSPlatform::Win32Windows:
+ case OSPlatform::Win32NT:
+ case OSPlatform::Win32CE:
+ triple.setOS(llvm::Triple::OSType::Win32);
+ triple.setVendor(llvm::Triple::VendorType::PC);
+ break;
+ case OSPlatform::Linux:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ break;
+ case OSPlatform::MacOSX:
+ triple.setOS(llvm::Triple::OSType::MacOSX);
+ triple.setVendor(llvm::Triple::Apple);
+ break;
+ case OSPlatform::IOS:
+ triple.setOS(llvm::Triple::OSType::IOS);
+ triple.setVendor(llvm::Triple::Apple);
+ break;
+ case OSPlatform::Android:
+ triple.setOS(llvm::Triple::OSType::Linux);
+ triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
+ break;
+ default: {
+ triple.setOS(llvm::Triple::OSType::UnknownOS);
+ auto ExpectedCSD = m_file->getString(system_info->CSDVersionRVA);
+ if (!ExpectedCSD) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedCSD.takeError(),
+ "Failed to CSD Version string: {0}");
+ } else {
+ if (ExpectedCSD->find("Linux") != std::string::npos)
+ triple.setOS(llvm::Triple::OSType::Linux);
+ }
+ break;
+ }
+ }
+ m_arch.SetTriple(triple);
+ return m_arch;
+}
+
+const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::MiscInfo);
+
+ if (data.size() == 0)
+ return nullptr;
+
+ return MinidumpMiscInfo::Parse(data);
+}
+
+std::optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
+ llvm::ArrayRef<uint8_t> data = GetStream(StreamType::LinuxProcStatus);
+
+ if (data.size() == 0)
+ return std::nullopt;
+
+ return LinuxProcStatus::Parse(data);
+}
+
+std::optional<lldb::pid_t> MinidumpParser::GetPid() {
+ const MinidumpMiscInfo *misc_info = GetMiscInfo();
+ if (misc_info != nullptr) {
+ return misc_info->GetPid();
+ }
+
+ std::optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
+ if (proc_status) {
+ return proc_status->GetPid();
+ }
+
+ return std::nullopt;
+}
+
+llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (ExpectedModules)
+ return *ExpectedModules;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Modules), ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
+}
+
+static bool
+CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ auto data = parser.GetStream(StreamType::LinuxMaps);
+ if (data.empty())
+ return false;
+
+ Log *log = GetLog(LLDBLog::Expressions);
+ ParseLinuxMapRegions(
+ llvm::toStringRef(data),
+ [&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
+ if (region)
+ regions.push_back(*region);
+ else
+ LLDB_LOG_ERROR(log, region.takeError(),
+ "Reading memory region from minidump failed: {0}");
+ return true;
+ });
+ return !regions.empty();
+}
+
+/// Check for the memory regions starting at \a load_addr for a contiguous
+/// section that has execute permissions that matches the module path.
+///
+/// When we load a breakpad generated minidump file, we might have the
+/// /proc/<pid>/maps text for a process that details the memory map of the
+/// process that the minidump is describing. This checks the sorted memory
+/// regions for a section that has execute permissions. A sample maps files
+/// might look like:
+///
+/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out
+/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out
+/// ...
+///
+/// This function should return true when given 0x00400000 and "/tmp/a.out"
+/// is passed in as the path since it has a consecutive memory region for
+/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us
+/// differentiate if a file has been memory mapped into a process for reading
+/// and breakpad ends up saving a minidump file that has two module entries for
+/// a given file: one that is read only for the entire file, and then one that
+/// is the real executable that is loaded into memory for execution. For memory
+/// mapped files they will typically show up and r--p permissions and a range
+/// matcning the entire range of the file on disk:
+///
+/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so
+///
+/// This function should return false when asked about 0x00800000 with
+/// "/tmp/a.out" as the path.
+///
+/// \param[in] path
+/// The path to the module to check for in the memory regions. Only sequential
+/// memory regions whose paths match this path will be considered when looking
+/// for execute permissions.
+///
+/// \param[in] regions
+/// A sorted list of memory regions obtained from a call to
+/// CreateRegionsCacheFromLinuxMaps.
+///
+/// \param[in] base_of_image
+/// The load address of this module from BaseOfImage in the modules list.
+///
+/// \return
+/// True if a contiguous region of memory belonging to the module with a
+/// matching path exists that has executable permissions. Returns false if
+/// \a regions is empty or if there are no regions with execute permissions
+/// that match \a path.
+
+static bool CheckForLinuxExecutable(ConstString path,
+ const MemoryRegionInfos &regions,
+ lldb::addr_t base_of_image) {
+ if (regions.empty())
+ return false;
+ lldb::addr_t addr = base_of_image;
+ MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ while (region.GetName() == path) {
+ if (region.GetExecutable() == MemoryRegionInfo::eYes)
+ return true;
+ addr += region.GetRange().GetByteSize();
+ region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ }
+ return false;
+}
+
+std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedModules = GetMinidumpFile().getModuleList();
+ if (!ExpectedModules) {
+ LLDB_LOG_ERROR(log, ExpectedModules.takeError(),
+ "Failed to read module list: {0}");
+ return {};
+ }
+
+ // Create memory regions from the linux maps only. We do this to avoid issues
+ // with breakpad generated minidumps where if someone has mmap'ed a shared
+ // library into memory to access its data in the object file, we can get a
+ // minidump with two mappings for a binary: one whose base image points to a
+ // memory region that is read + execute and one that is read only.
+ MemoryRegionInfos linux_regions;
+ if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))
+ llvm::sort(linux_regions);
+
+ // map module_name -> filtered_modules index
+ typedef llvm::StringMap<size_t> MapType;
+ MapType module_name_to_filtered_index;
+
+ std::vector<const minidump::Module *> filtered_modules;
+
+ for (const auto &module : *ExpectedModules) {
+ auto ExpectedName = m_file->getString(module.ModuleNameRVA);
+ if (!ExpectedName) {
+ LLDB_LOG_ERROR(log, ExpectedName.takeError(),
+ "Failed to get module name: {0}");
+ continue;
+ }
+
+ MapType::iterator iter;
+ bool inserted;
+ // See if we have inserted this module aready into filtered_modules. If we
+ // haven't insert an entry into module_name_to_filtered_index with the
+ // index where we will insert it if it isn't in the vector already.
+ std::tie(iter, inserted) = module_name_to_filtered_index.try_emplace(
+ *ExpectedName, filtered_modules.size());
+
+ if (inserted) {
+ // This module has not been seen yet, insert it into filtered_modules at
+ // the index that was inserted into module_name_to_filtered_index using
+ // "filtered_modules.size()" above.
+ filtered_modules.push_back(&module);
+ } else {
+ // We have a duplicate module entry. Check the linux regions to see if
+ // either module is not really a mapped executable. If one but not the
+ // other is a real mapped executable, prefer the executable one. This
+ // can happen when a process mmap's in the file for an executable in
+ // order to read bytes from the executable file. A memory region mapping
+ // will exist for the mmap'ed version and for the loaded executable, but
+ // only one will have a consecutive region that is executable in the
+ // memory regions.
+ auto dup_module = filtered_modules[iter->second];
+ ConstString name(*ExpectedName);
+ bool is_executable =
+ CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);
+ bool dup_is_executable =
+ CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);
+
+ if (is_executable != dup_is_executable) {
+ if (is_executable)
+ filtered_modules[iter->second] = &module;
+ continue;
+ }
+ // This module has been seen. Modules are sometimes mentioned multiple
+ // times when they are mapped discontiguously, so find the module with
+ // the lowest "base_of_image" and use that as the filtered module.
+ if (module.BaseOfImage < dup_module->BaseOfImage)
+ filtered_modules[iter->second] = &module;
+ }
+ }
+ return filtered_modules;
+}
+
+const minidump::ExceptionStream *MinidumpParser::GetExceptionStream() {
+ auto ExpectedStream = GetMinidumpFile().getExceptionStream();
+ if (ExpectedStream)
+ return &*ExpectedStream;
+
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Process), ExpectedStream.takeError(),
+ "Failed to read minidump exception stream: {0}");
+ return nullptr;
+}
+
+std::optional<minidump::Range>
+MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
+ llvm::ArrayRef<uint8_t> data64 = GetStream(StreamType::Memory64List);
+ Log *log = GetLog(LLDBLog::Modules);
+
+ auto ExpectedMemory = GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
+ } else {
+ for (const auto &memory_desc : *ExpectedMemory) {
+ const LocationDescriptor &loc_desc = memory_desc.Memory;
+ const lldb::addr_t range_start = memory_desc.StartOfMemoryRange;
+ const size_t range_size = loc_desc.DataSize;
+
+ if (loc_desc.RVA + loc_desc.DataSize > GetData().size())
+ return std::nullopt;
+
+ if (range_start <= addr && addr < range_start + range_size) {
+ auto ExpectedSlice = GetMinidumpFile().getRawData(loc_desc);
+ if (!ExpectedSlice) {
+ LLDB_LOG_ERROR(log, ExpectedSlice.takeError(),
+ "Failed to get memory slice: {0}");
+ return std::nullopt;
+ }
+ return minidump::Range(range_start, *ExpectedSlice);
+ }
+ }
+ }
+
+ // 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 std::nullopt;
+
+ 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 std::nullopt;
+
+ 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 std::nullopt;
+}
+
+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.
+ std::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);
+}
+
+static bool
+CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedInfo = parser.GetMinidumpFile().getMemoryInfoList();
+ if (!ExpectedInfo) {
+ LLDB_LOG_ERROR(log, ExpectedInfo.takeError(),
+ "Failed to read memory info list: {0}");
+ return false;
+ }
+ constexpr auto yes = MemoryRegionInfo::eYes;
+ constexpr auto no = MemoryRegionInfo::eNo;
+ for (const MemoryInfo &entry : *ExpectedInfo) {
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(entry.BaseAddress);
+ region.GetRange().SetByteSize(entry.RegionSize);
+
+ MemoryProtection prot = entry.Protect;
+ region.SetReadable(bool(prot & MemoryProtection::NoAccess) ? no : yes);
+ region.SetWritable(
+ bool(prot & (MemoryProtection::ReadWrite | MemoryProtection::WriteCopy |
+ MemoryProtection::ExecuteReadWrite |
+ MemoryProtection::ExeciteWriteCopy))
+ ? yes
+ : no);
+ region.SetExecutable(
+ bool(prot & (MemoryProtection::Execute | MemoryProtection::ExecuteRead |
+ MemoryProtection::ExecuteReadWrite |
+ MemoryProtection::ExeciteWriteCopy))
+ ? yes
+ : no);
+ region.SetMapped(entry.State != MemoryState::Free ? yes : no);
+ regions.push_back(region);
+ }
+ return !regions.empty();
+}
+
+static bool
+CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ Log *log = GetLog(LLDBLog::Modules);
+ auto ExpectedMemory = parser.GetMinidumpFile().getMemoryList();
+ if (!ExpectedMemory) {
+ LLDB_LOG_ERROR(log, ExpectedMemory.takeError(),
+ "Failed to read memory list: {0}");
+ return false;
+ }
+ regions.reserve(ExpectedMemory->size());
+ for (const MemoryDescriptor &memory_desc : *ExpectedMemory) {
+ if (memory_desc.Memory.DataSize == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.StartOfMemoryRange);
+ region.GetRange().SetByteSize(memory_desc.Memory.DataSize);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
+ regions.shrink_to_fit();
+ return !regions.empty();
+}
+
+static bool
+CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ llvm::ArrayRef<uint8_t> data =
+ parser.GetStream(StreamType::Memory64List);
+ if (data.empty())
+ return false;
+ llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+ uint64_t base_rva;
+ std::tie(memory64_list, base_rva) =
+ MinidumpMemoryDescriptor64::ParseMemory64List(data);
+
+ if (memory64_list.empty())
+ return false;
+
+ regions.reserve(memory64_list.size());
+ for (const auto &memory_desc : memory64_list) {
+ if (memory_desc.data_size == 0)
+ continue;
+ MemoryRegionInfo region;
+ region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
+ region.GetRange().SetByteSize(memory_desc.data_size);
+ region.SetReadable(MemoryRegionInfo::eYes);
+ region.SetMapped(MemoryRegionInfo::eYes);
+ regions.push_back(region);
+ }
+ regions.shrink_to_fit();
+ return !regions.empty();
+}
+
+std::pair<MemoryRegionInfos, bool> MinidumpParser::BuildMemoryRegions() {
+ // We create the region cache using the best source. We start with
+ // the linux maps since they are the most complete and have names for the
+ // regions. Next we try the MemoryInfoList since it has
+ // read/write/execute/map data, and then fall back to the MemoryList and
+ // Memory64List to just get a list of the memory that is mapped in this
+ // core file
+ MemoryRegionInfos result;
+ const auto &return_sorted = [&](bool is_complete) {
+ llvm::sort(result);
+ return std::make_pair(std::move(result), is_complete);
+ };
+ if (CreateRegionsCacheFromLinuxMaps(*this, result))
+ return return_sorted(true);
+ if (CreateRegionsCacheFromMemoryInfoList(*this, result))
+ return return_sorted(true);
+ if (CreateRegionsCacheFromMemoryList(*this, result))
+ return return_sorted(false);
+ CreateRegionsCacheFromMemory64List(*this, result);
+ return return_sorted(false);
+}
+
+#define ENUM_TO_CSTR(ST) \
+ case StreamType::ST: \
+ return #ST
+
+llvm::StringRef
+MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
+ switch (stream_type) {
+ ENUM_TO_CSTR(Unused);
+ ENUM_TO_CSTR(ThreadList);
+ ENUM_TO_CSTR(ModuleList);
+ ENUM_TO_CSTR(MemoryList);
+ ENUM_TO_CSTR(Exception);
+ ENUM_TO_CSTR(SystemInfo);
+ ENUM_TO_CSTR(ThreadExList);
+ ENUM_TO_CSTR(Memory64List);
+ ENUM_TO_CSTR(CommentA);
+ ENUM_TO_CSTR(CommentW);
+ ENUM_TO_CSTR(HandleData);
+ ENUM_TO_CSTR(FunctionTable);
+ ENUM_TO_CSTR(UnloadedModuleList);
+ ENUM_TO_CSTR(MiscInfo);
+ ENUM_TO_CSTR(MemoryInfoList);
+ ENUM_TO_CSTR(ThreadInfoList);
+ ENUM_TO_CSTR(HandleOperationList);
+ ENUM_TO_CSTR(Token);
+ ENUM_TO_CSTR(JavascriptData);
+ ENUM_TO_CSTR(SystemMemoryInfo);
+ ENUM_TO_CSTR(ProcessVMCounters);
+ ENUM_TO_CSTR(LastReserved);
+ ENUM_TO_CSTR(BreakpadInfo);
+ ENUM_TO_CSTR(AssertionInfo);
+ ENUM_TO_CSTR(LinuxCPUInfo);
+ ENUM_TO_CSTR(LinuxProcStatus);
+ ENUM_TO_CSTR(LinuxLSBRelease);
+ ENUM_TO_CSTR(LinuxCMDLine);
+ ENUM_TO_CSTR(LinuxEnviron);
+ ENUM_TO_CSTR(LinuxAuxv);
+ ENUM_TO_CSTR(LinuxMaps);
+ ENUM_TO_CSTR(LinuxDSODebug);
+ ENUM_TO_CSTR(LinuxProcStat);
+ ENUM_TO_CSTR(LinuxProcUptime);
+ ENUM_TO_CSTR(LinuxProcFD);
+ ENUM_TO_CSTR(FacebookAppCustomData);
+ ENUM_TO_CSTR(FacebookBuildID);
+ ENUM_TO_CSTR(FacebookAppVersionName);
+ ENUM_TO_CSTR(FacebookJavaStack);
+ ENUM_TO_CSTR(FacebookDalvikInfo);
+ ENUM_TO_CSTR(FacebookUnwindSymbols);
+ ENUM_TO_CSTR(FacebookDumpErrorLog);
+ ENUM_TO_CSTR(FacebookAppStateLog);
+ ENUM_TO_CSTR(FacebookAbortReason);
+ ENUM_TO_CSTR(FacebookThreadName);
+ ENUM_TO_CSTR(FacebookLogcat);
+ }
+ return "unknown stream type";
+}
+
+MemoryRegionInfo
+MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr) {
+ MemoryRegionInfo region;
+ auto pos = llvm::upper_bound(regions, load_addr);
+ if (pos != regions.begin() &&
+ std::prev(pos)->GetRange().Contains(load_addr)) {
+ return *std::prev(pos);
+ }
+
+ if (pos == regions.begin())
+ region.GetRange().SetRangeBase(0);
+ else
+ region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
+
+ if (pos == regions.end())
+ region.GetRange().SetRangeEnd(UINT64_MAX);
+ else
+ region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
+
+ region.SetReadable(MemoryRegionInfo::eNo);
+ region.SetWritable(MemoryRegionInfo::eNo);
+ region.SetExecutable(MemoryRegionInfo::eNo);
+ region.SetMapped(MemoryRegionInfo::eNo);
+ return region;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h
new file mode 100644
index 000000000000..050ba086f46f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -0,0 +1,113 @@
+//===-- MinidumpParser.h -----------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
+
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/UUID.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Minidump.h"
+
+// C includes
+
+// C++ includes
+#include <cstring>
+#include <optional>
+#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) {}
+
+ friend bool operator==(const Range &lhs, const Range &rhs) {
+ return lhs.start == rhs.start && lhs.range_ref == rhs.range_ref;
+ }
+};
+
+class MinidumpParser {
+public:
+ static llvm::Expected<MinidumpParser>
+ Create(const lldb::DataBufferSP &data_buf_sp);
+
+ llvm::ArrayRef<uint8_t> GetData();
+
+ llvm::ArrayRef<uint8_t> GetStream(StreamType stream_type);
+
+ UUID GetModuleUUID(const minidump::Module *module);
+
+ llvm::ArrayRef<minidump::Thread> GetThreads();
+
+ llvm::ArrayRef<uint8_t> GetThreadContext(const LocationDescriptor &location);
+
+ llvm::ArrayRef<uint8_t> GetThreadContext(const minidump::Thread &td);
+
+ llvm::ArrayRef<uint8_t> GetThreadContextWow64(const minidump::Thread &td);
+
+ ArchSpec GetArchitecture();
+
+ const MinidumpMiscInfo *GetMiscInfo();
+
+ std::optional<LinuxProcStatus> GetLinuxProcStatus();
+
+ std::optional<lldb::pid_t> GetPid();
+
+ llvm::ArrayRef<minidump::Module> 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 minidump::Module *> GetFilteredModuleList();
+
+ const llvm::minidump::ExceptionStream *GetExceptionStream();
+
+ std::optional<Range> FindMemoryRange(lldb::addr_t addr);
+
+ llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
+
+ /// Returns a list of memory regions and a flag indicating whether the list is
+ /// complete (includes all regions mapped into the process memory).
+ std::pair<MemoryRegionInfos, bool> BuildMemoryRegions();
+
+ static llvm::StringRef GetStreamTypeAsString(StreamType stream_type);
+
+ llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; }
+
+ static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr);
+
+private:
+ MinidumpParser(lldb::DataBufferSP data_sp,
+ std::unique_ptr<llvm::object::MinidumpFile> file);
+
+ lldb::DataBufferSP m_data_sp;
+ std::unique_ptr<llvm::object::MinidumpFile> m_file;
+ ArchSpec m_arch;
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
new file mode 100644
index 000000000000..5b919828428f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -0,0 +1,79 @@
+//===-- MinidumpTypes.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MinidumpTypes.h"
+#include <optional>
+
+// C includes
+// C++ includes
+
+using namespace lldb_private;
+using namespace minidump;
+
+// MinidumpMiscInfo
+const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
+ const MinidumpMiscInfo *misc_info;
+ Status error = consumeObject(data, misc_info);
+ if (error.Fail())
+ return nullptr;
+
+ return misc_info;
+}
+
+std::optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
+ uint32_t pid_flag = static_cast<uint32_t>(MinidumpMiscInfoFlags::ProcessID);
+ if (flags1 & pid_flag)
+ return std::optional<lldb::pid_t>(process_id);
+
+ return std::nullopt;
+}
+
+// Linux Proc Status
+// it's stored as an ascii string in the file
+std::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 std::nullopt;
+}
+
+lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
+
+std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
+MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef<uint8_t> &data) {
+ const llvm::support::ulittle64_t *mem_ranges_count;
+ Status 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::ArrayRef(
+ reinterpret_cast<const MinidumpMemoryDescriptor64 *>(data.data()),
+ *mem_ranges_count),
+ *base_rva);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
new file mode 100644
index 000000000000..fe99abf9e24e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -0,0 +1,107 @@
+//===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
+
+#include "lldb/Utility/Status.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Minidump.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include <optional>
+
+// 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 {
+
+using namespace llvm::minidump;
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+enum class CvSignature : uint32_t {
+ Pdb70 = 0x53445352, // RSDS
+ ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps)
+};
+
+enum class MinidumpMiscInfoFlags : uint32_t {
+ ProcessID = (1 << 0),
+ ProcessTimes = (1 << 1),
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
+};
+
+template <typename T>
+Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
+ Status 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;
+}
+
+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!");
+
+// 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);
+
+ std::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 std::optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data);
+
+ lldb::pid_t GetPid() const;
+
+private:
+ LinuxProcStatus() = default;
+};
+
+} // namespace minidump
+} // namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_MINIDUMPTYPES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h
new file mode 100644
index 000000000000..1dafbe4a4f50
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/NtStructures.h
@@ -0,0 +1,42 @@
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H
+
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_NTSTRUCTURES_H
+
+//===-- NtStructures.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
new file mode 100644
index 000000000000..13599f4a1553
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -0,0 +1,929 @@
+//===-- ProcessMinidump.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMinidump.h"
+
+#include "ThreadMinidump.h"
+
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Target/JITLoaderList.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/State.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+
+#include <memory>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+LLDB_PLUGIN_DEFINE(ProcessMinidump)
+
+namespace {
+
+/// Duplicate the HashElfTextSection() from the breakpad sources.
+///
+/// Breakpad, a Google crash log reporting tool suite, creates minidump files
+/// for many different architectures. When using Breakpad to create ELF
+/// minidumps, it will check for a GNU build ID when creating a minidump file
+/// and if one doesn't exist in the file, it will say the UUID of the file is a
+/// checksum of up to the first 4096 bytes of the .text section. Facebook also
+/// uses breakpad and modified this hash to avoid collisions so we can
+/// calculate and check for this as well.
+///
+/// The breakpad code might end up hashing up to 15 bytes that immediately
+/// follow the .text section in the file, so this code must do exactly what it
+/// does so we can get an exact match for the UUID.
+///
+/// \param[in] module_sp The module to grab the .text section from.
+///
+/// \param[in,out] breakpad_uuid A vector that will receive the calculated
+/// breakpad .text hash.
+///
+/// \param[in,out] facebook_uuid A vector that will receive the calculated
+/// facebook .text hash.
+///
+void HashElfTextSection(ModuleSP module_sp, std::vector<uint8_t> &breakpad_uuid,
+ std::vector<uint8_t> &facebook_uuid) {
+ SectionList *sect_list = module_sp->GetSectionList();
+ if (sect_list == nullptr)
+ return;
+ SectionSP sect_sp = sect_list->FindSectionByName(ConstString(".text"));
+ if (!sect_sp)
+ return;
+ constexpr size_t kMDGUIDSize = 16;
+ constexpr size_t kBreakpadPageSize = 4096;
+ // The breakpad code has a bug where it might access beyond the end of a
+ // .text section by up to 15 bytes, so we must ensure we round up to the
+ // next kMDGUIDSize byte boundary.
+ DataExtractor data;
+ const size_t text_size = sect_sp->GetFileSize();
+ const size_t read_size = std::min<size_t>(
+ llvm::alignTo(text_size, kMDGUIDSize), kBreakpadPageSize);
+ sect_sp->GetObjectFile()->GetData(sect_sp->GetFileOffset(), read_size, data);
+
+ breakpad_uuid.assign(kMDGUIDSize, 0);
+ facebook_uuid.assign(kMDGUIDSize, 0);
+
+ // The only difference between the breakpad hash and the facebook hash is the
+ // hashing of the text section size into the hash prior to hashing the .text
+ // contents.
+ for (size_t i = 0; i < kMDGUIDSize; i++)
+ facebook_uuid[i] ^= text_size % 255;
+
+ // This code carefully duplicates how the hash was created in Breakpad
+ // sources, including the error where it might has an extra 15 bytes past the
+ // end of the .text section if the .text section is less than a page size in
+ // length.
+ const uint8_t *ptr = data.GetDataStart();
+ const uint8_t *ptr_end = data.GetDataEnd();
+ while (ptr < ptr_end) {
+ for (unsigned i = 0; i < kMDGUIDSize; i++) {
+ breakpad_uuid[i] ^= ptr[i];
+ facebook_uuid[i] ^= ptr[i];
+ }
+ ptr += kMDGUIDSize;
+ }
+}
+
+} // namespace
+
+llvm::StringRef ProcessMinidump::GetPluginDescriptionStatic() {
+ return "Minidump plug-in.";
+}
+
+lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file,
+ bool can_connect) {
+ if (!crash_file || can_connect)
+ return nullptr;
+
+ lldb::ProcessSP process_sp;
+ // Read enough data for the Minidump header
+ constexpr size_t header_size = sizeof(Header);
+ auto DataPtr = FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(),
+ header_size, 0);
+ if (!DataPtr)
+ return nullptr;
+
+ lldbassert(DataPtr->GetByteSize() == header_size);
+ if (identify_magic(toStringRef(DataPtr->GetData())) != llvm::file_magic::minidump)
+ return nullptr;
+
+ auto AllData =
+ FileSystem::Instance().CreateDataBuffer(crash_file->GetPath(), -1, 0);
+ if (!AllData)
+ return nullptr;
+
+ return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
+ std::move(AllData));
+}
+
+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,
+ DataBufferSP core_data)
+ : PostMortemProcess(target_sp, listener_sp, core_file),
+ m_core_data(std::move(core_data)), m_active_exception(nullptr),
+ 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(true /* destructing */);
+}
+
+void ProcessMinidump::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ ProcessMinidump::CreateInstance);
+ });
+}
+
+void ProcessMinidump::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
+}
+
+Status ProcessMinidump::DoLoadCore() {
+ auto expected_parser = MinidumpParser::Create(m_core_data);
+ if (!expected_parser)
+ return Status(expected_parser.takeError());
+ m_minidump_parser = std::move(*expected_parser);
+
+ Status error;
+
+ // Do we support the minidump's architecture?
+ ArchSpec arch = GetArchitecture();
+ switch (arch.GetMachine()) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ // Any supported architectures must be listed here and also supported in
+ // ThreadMinidump::CreateRegisterContextForFrame().
+ break;
+ default:
+ error.SetErrorStringWithFormat("unsupported minidump architecture: %s",
+ arch.GetArchitectureName());
+ return error;
+ }
+ GetTarget().SetArchitecture(arch, true /*set_platform*/);
+
+ m_thread_list = m_minidump_parser->GetThreads();
+ m_active_exception = m_minidump_parser->GetExceptionStream();
+
+ SetUnixSignals(UnixSignals::Create(GetArchitecture()));
+
+ ReadModuleList();
+ if (ModuleSP module = GetTarget().GetExecutableModule())
+ GetTarget().MergeArchitecture(module->GetArchitecture());
+ std::optional<lldb::pid_t> pid = m_minidump_parser->GetPid();
+ if (!pid) {
+ Debugger::ReportWarning("unable to retrieve process ID from minidump file, "
+ "setting process ID to 1",
+ GetTarget().GetDebugger().GetID());
+ pid = 1;
+ }
+ SetID(*pid);
+
+ return error;
+}
+
+Status ProcessMinidump::DoDestroy() { return Status(); }
+
+void ProcessMinidump::RefreshStateAfterStop() {
+
+ if (!m_active_exception)
+ return;
+
+ constexpr uint32_t BreakpadDumpRequested = 0xFFFFFFFF;
+ if (m_active_exception->ExceptionRecord.ExceptionCode ==
+ BreakpadDumpRequested) {
+ // This "ExceptionCode" value is a sentinel that is sometimes used
+ // when generating a dump for a process that hasn't crashed.
+
+ // TODO: The definition and use of this "dump requested" constant
+ // in Breakpad are actually Linux-specific, and for similar use
+ // cases on Mac/Windows it defines different constants, referring
+ // to them as "simulated" exceptions; consider moving this check
+ // down to the OS-specific paths and checking each OS for its own
+ // constant.
+ return;
+ }
+
+ lldb::StopInfoSP stop_info;
+ lldb::ThreadSP stop_thread;
+
+ Process::m_thread_list.SetSelectedThreadByID(m_active_exception->ThreadId);
+ stop_thread = Process::m_thread_list.GetSelectedThread();
+ ArchSpec arch = GetArchitecture();
+
+ if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
+ uint32_t signo = m_active_exception->ExceptionRecord.ExceptionCode;
+
+ if (signo == 0) {
+ // No stop.
+ return;
+ }
+
+ stop_info = StopInfo::CreateStopReasonWithSignal(
+ *stop_thread, signo);
+ } else if (arch.GetTriple().getVendor() == llvm::Triple::Apple) {
+ stop_info = StopInfoMachException::CreateStopReasonWithMachException(
+ *stop_thread, m_active_exception->ExceptionRecord.ExceptionCode, 2,
+ m_active_exception->ExceptionRecord.ExceptionFlags,
+ m_active_exception->ExceptionRecord.ExceptionAddress, 0);
+ } else {
+ std::string desc;
+ llvm::raw_string_ostream desc_stream(desc);
+ desc_stream << "Exception "
+ << llvm::format_hex(
+ m_active_exception->ExceptionRecord.ExceptionCode, 8)
+ << " encountered at address "
+ << llvm::format_hex(
+ m_active_exception->ExceptionRecord.ExceptionAddress, 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,
+ Status &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,
+ Status &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);
+}
+
+void ProcessMinidump::BuildMemoryRegions() {
+ if (m_memory_regions)
+ return;
+ m_memory_regions.emplace();
+ bool is_complete;
+ std::tie(*m_memory_regions, is_complete) =
+ m_minidump_parser->BuildMemoryRegions();
+
+ if (is_complete)
+ return;
+
+ MemoryRegionInfos to_add;
+ ModuleList &modules = GetTarget().GetImages();
+ SectionLoadList &load_list = GetTarget().GetSectionLoadList();
+ modules.ForEach([&](const ModuleSP &module_sp) {
+ SectionList *sections = module_sp->GetSectionList();
+ for (size_t i = 0; i < sections->GetSize(); ++i) {
+ SectionSP section_sp = sections->GetSectionAtIndex(i);
+ addr_t load_addr = load_list.GetSectionLoadAddress(section_sp);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ continue;
+ MemoryRegionInfo::RangeType section_range(load_addr,
+ section_sp->GetByteSize());
+ MemoryRegionInfo region =
+ MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ if (region.GetMapped() != MemoryRegionInfo::eYes &&
+ region.GetRange().GetRangeBase() <= section_range.GetRangeBase() &&
+ section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) {
+ to_add.emplace_back();
+ to_add.back().GetRange() = section_range;
+ to_add.back().SetLLDBPermissions(section_sp->GetPermissions());
+ to_add.back().SetMapped(MemoryRegionInfo::eYes);
+ to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ return true;
+ });
+ m_memory_regions->insert(m_memory_regions->end(), to_add.begin(),
+ to_add.end());
+ llvm::sort(*m_memory_regions);
+}
+
+Status ProcessMinidump::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &region) {
+ BuildMemoryRegions();
+ region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ return Status();
+}
+
+Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos &region_list) {
+ BuildMemoryRegions();
+ region_list = *m_memory_regions;
+ return Status();
+}
+
+void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
+
+bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
+ for (const minidump::Thread &thread : m_thread_list) {
+ LocationDescriptor context_location = thread.Context;
+
+ // If the minidump contains an exception context, use it
+ if (m_active_exception != nullptr &&
+ m_active_exception->ThreadId == thread.ThreadId) {
+ context_location = m_active_exception->ThreadContext;
+ }
+
+ llvm::ArrayRef<uint8_t> context;
+ if (!m_is_wow64)
+ context = m_minidump_parser->GetThreadContext(context_location);
+ else
+ context = m_minidump_parser->GetThreadContextWow64(thread);
+
+ lldb::ThreadSP thread_sp(new ThreadMinidump(*this, thread, context));
+ new_thread_list.AddThread(thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ModuleSP ProcessMinidump::GetOrCreateModule(UUID minidump_uuid,
+ llvm::StringRef name,
+ ModuleSpec module_spec) {
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+ Status error;
+
+ ModuleSP module_sp =
+ GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
+ if (!module_sp)
+ return module_sp;
+ // We consider the module to be a match if the minidump UUID is a
+ // prefix of the actual UUID, or if either of the UUIDs are empty.
+ const auto dmp_bytes = minidump_uuid.GetBytes();
+ const auto mod_bytes = module_sp->GetUUID().GetBytes();
+ const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
+ mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
+ if (match) {
+ LLDB_LOG(log, "Partial uuid match for {0}.", name);
+ return module_sp;
+ }
+
+ // Breakpad generates minindump files, and if there is no GNU build
+ // ID in the binary, it will calculate a UUID by hashing first 4096
+ // bytes of the .text section and using that as the UUID for a module
+ // in the minidump. Facebook uses a modified breakpad client that
+ // uses a slightly modified this hash to avoid collisions. Check for
+ // UUIDs from the minindump that match these cases and accept the
+ // module we find if they do match.
+ std::vector<uint8_t> breakpad_uuid;
+ std::vector<uint8_t> facebook_uuid;
+ HashElfTextSection(module_sp, breakpad_uuid, facebook_uuid);
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(breakpad_uuid)) {
+ LLDB_LOG(log, "Breakpad .text hash match for {0}.", name);
+ return module_sp;
+ }
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(facebook_uuid)) {
+ LLDB_LOG(log, "Facebook .text hash match for {0}.", name);
+ return module_sp;
+ }
+ // The UUID wasn't a partial match and didn't match the .text hash
+ // so remove the module from the target, we will need to create a
+ // placeholder object file.
+ GetTarget().GetImages().Remove(module_sp);
+ module_sp.reset();
+ return module_sp;
+}
+
+void ProcessMinidump::ReadModuleList() {
+ std::vector<const minidump::Module *> filtered_modules =
+ m_minidump_parser->GetFilteredModuleList();
+
+ Log *log = GetLog(LLDBLog::DynamicLoader);
+
+ for (auto module : filtered_modules) {
+ std::string name = cantFail(m_minidump_parser->GetMinidumpFile().getString(
+ module->ModuleNameRVA));
+ const uint64_t load_addr = module->BaseOfImage;
+ const uint64_t load_size = module->SizeOfImage;
+ LLDB_LOG(log, "found module: name: {0} {1:x10}-{2:x10} size: {3}", name,
+ load_addr, load_addr + load_size, load_size);
+
+ // check if the process is wow64 - a 32 bit windows process running on a
+ // 64 bit windows
+ if (llvm::StringRef(name).ends_with_insensitive("wow64.dll")) {
+ m_is_wow64 = true;
+ }
+
+ const auto uuid = m_minidump_parser->GetModuleUUID(module);
+ auto file_spec = FileSpec(name, GetArchitecture().GetTriple());
+ ModuleSpec module_spec(file_spec, uuid);
+ module_spec.GetArchitecture() = GetArchitecture();
+ Status error;
+ // Try and find a module with a full UUID that matches. This function will
+ // add the module to the target if it finds one.
+ lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec,
+ true /* notify */, &error);
+ if (module_sp) {
+ LLDB_LOG(log, "Full uuid match for {0}.", name);
+ } else {
+ // We couldn't find a module with an exactly-matching UUID. Sometimes
+ // a minidump UUID is only a partial match or is a hash. So try again
+ // without specifying the UUID, then again without specifying the
+ // directory if that fails. This will allow us to find modules with
+ // partial matches or hash UUIDs in user-provided sysroots or search
+ // directories (target.exec-search-paths).
+ ModuleSpec partial_module_spec = module_spec;
+ partial_module_spec.GetUUID().Clear();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
+ if (!module_sp) {
+ partial_module_spec.GetFileSpec().ClearDirectory();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
+ }
+ }
+ if (module_sp) {
+ // Watch out for place holder modules that have different paths, but the
+ // same UUID. If the base address is different, create a new module. If
+ // we don't then we will end up setting the load address of a different
+ // ObjectFilePlaceholder and an assertion will fire.
+ auto *objfile = module_sp->GetObjectFile();
+ if (objfile &&
+ objfile->GetPluginName() ==
+ ObjectFilePlaceholder::GetPluginNameStatic()) {
+ if (((ObjectFilePlaceholder *)objfile)->GetBaseImageAddress() !=
+ load_addr)
+ module_sp.reset();
+ }
+ }
+ if (!module_sp) {
+ // We failed to locate a matching local object file. Fortunately, the
+ // minidump format encodes enough information about each module's memory
+ // range to allow us to create placeholder modules.
+ //
+ // This enables most LLDB functionality involving address-to-module
+ // translations (ex. identifing the module for a stack frame PC) and
+ // modules/sections commands (ex. target modules list, ...)
+ LLDB_LOG(log,
+ "Unable to locate the matching object file, creating a "
+ "placeholder module for: {0}",
+ name);
+
+ module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(
+ module_spec, load_addr, load_size);
+ GetTarget().GetImages().Append(module_sp, true /* notify */);
+ }
+
+ bool load_addr_changed = false;
+ module_sp->SetLoadAddress(GetTarget(), load_addr, 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;
+}
+
+// For minidumps there's no runtime generated code so we don't need JITLoader(s)
+// Avoiding them will also speed up minidump loading since JITLoaders normally
+// try to set up symbolic breakpoints, which in turn may force loading more
+// debug information than needed.
+JITLoaderList &ProcessMinidump::GetJITLoaders() {
+ if (!m_jit_loaders_up) {
+ m_jit_loaders_up = std::make_unique<JITLoaderList>();
+ }
+ return *m_jit_loaders_up;
+}
+
+#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
+ VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
+#define APPEND_OPT(VAR) \
+ m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
+
+class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_dump_all;
+ OptionGroupBoolean m_dump_directory;
+ OptionGroupBoolean m_dump_linux_cpuinfo;
+ OptionGroupBoolean m_dump_linux_proc_status;
+ OptionGroupBoolean m_dump_linux_lsb_release;
+ OptionGroupBoolean m_dump_linux_cmdline;
+ OptionGroupBoolean m_dump_linux_environ;
+ OptionGroupBoolean m_dump_linux_auxv;
+ OptionGroupBoolean m_dump_linux_maps;
+ OptionGroupBoolean m_dump_linux_proc_stat;
+ OptionGroupBoolean m_dump_linux_proc_uptime;
+ OptionGroupBoolean m_dump_linux_proc_fd;
+ OptionGroupBoolean m_dump_linux_all;
+ OptionGroupBoolean m_fb_app_data;
+ OptionGroupBoolean m_fb_build_id;
+ OptionGroupBoolean m_fb_version;
+ OptionGroupBoolean m_fb_java_stack;
+ OptionGroupBoolean m_fb_dalvik;
+ OptionGroupBoolean m_fb_unwind;
+ OptionGroupBoolean m_fb_error_log;
+ OptionGroupBoolean m_fb_app_state;
+ OptionGroupBoolean m_fb_abort;
+ OptionGroupBoolean m_fb_thread;
+ OptionGroupBoolean m_fb_logcat;
+ OptionGroupBoolean m_fb_all;
+
+ void SetDefaultOptionsIfNoneAreSet() {
+ if (m_dump_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
+ m_fb_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue() ||
+ m_fb_app_data.GetOptionValue().GetCurrentValue() ||
+ m_fb_build_id.GetOptionValue().GetCurrentValue() ||
+ m_fb_version.GetOptionValue().GetCurrentValue() ||
+ m_fb_java_stack.GetOptionValue().GetCurrentValue() ||
+ m_fb_dalvik.GetOptionValue().GetCurrentValue() ||
+ m_fb_unwind.GetOptionValue().GetCurrentValue() ||
+ m_fb_error_log.GetOptionValue().GetCurrentValue() ||
+ m_fb_app_state.GetOptionValue().GetCurrentValue() ||
+ m_fb_abort.GetOptionValue().GetCurrentValue() ||
+ m_fb_thread.GetOptionValue().GetCurrentValue() ||
+ m_fb_logcat.GetOptionValue().GetCurrentValue())
+ return;
+ // If no options were set, then dump everything
+ m_dump_all.GetOptionValue().SetCurrentValue(true);
+ }
+ bool DumpAll() const {
+ return m_dump_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpDirectory() const {
+ return DumpAll() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinux() const {
+ return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCPUInfo() const {
+ return DumpLinux() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStatus() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStat() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxLSBRelease() const {
+ return DumpLinux() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCMDLine() const {
+ return DumpLinux() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxEnviron() const {
+ return DumpLinux() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxAuxv() const {
+ return DumpLinux() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxMaps() const {
+ return DumpLinux() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcUptime() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcFD() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebook() const {
+ return DumpAll() || m_fb_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAppData() const {
+ return DumpFacebook() || m_fb_app_data.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookBuildID() const {
+ return DumpFacebook() || m_fb_build_id.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookVersionName() const {
+ return DumpFacebook() || m_fb_version.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookJavaStack() const {
+ return DumpFacebook() || m_fb_java_stack.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookDalvikInfo() const {
+ return DumpFacebook() || m_fb_dalvik.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookUnwindSymbols() const {
+ return DumpFacebook() || m_fb_unwind.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookErrorLog() const {
+ return DumpFacebook() || m_fb_error_log.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAppStateLog() const {
+ return DumpFacebook() || m_fb_app_state.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookAbortReason() const {
+ return DumpFacebook() || m_fb_abort.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookThreadName() const {
+ return DumpFacebook() || m_fb_thread.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpFacebookLogcat() const {
+ return DumpFacebook() || m_fb_logcat.GetOptionValue().GetCurrentValue();
+ }
+public:
+ CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin dump",
+ "Dump information from the minidump file.", nullptr),
+ m_option_group(),
+ INIT_BOOL(m_dump_all, "all", 'a',
+ "Dump the everything in the minidump."),
+ INIT_BOOL(m_dump_directory, "directory", 'd',
+ "Dump the minidump directory map."),
+ INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
+ "Dump linux /proc/cpuinfo."),
+ INIT_BOOL(m_dump_linux_proc_status, "status", 's',
+ "Dump linux /proc/<pid>/status."),
+ INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
+ "Dump linux /etc/lsb-release."),
+ INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
+ "Dump linux /proc/<pid>/cmdline."),
+ INIT_BOOL(m_dump_linux_environ, "environ", 'e',
+ "Dump linux /proc/<pid>/environ."),
+ INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
+ "Dump linux /proc/<pid>/auxv."),
+ INIT_BOOL(m_dump_linux_maps, "maps", 'm',
+ "Dump linux /proc/<pid>/maps."),
+ INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
+ "Dump linux /proc/<pid>/stat."),
+ INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
+ "Dump linux process uptime."),
+ INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
+ "Dump linux /proc/<pid>/fd."),
+ INIT_BOOL(m_dump_linux_all, "linux", 'l',
+ "Dump all linux streams."),
+ INIT_BOOL(m_fb_app_data, "fb-app-data", 1,
+ "Dump Facebook application custom data."),
+ INIT_BOOL(m_fb_build_id, "fb-build-id", 2,
+ "Dump the Facebook build ID."),
+ INIT_BOOL(m_fb_version, "fb-version", 3,
+ "Dump Facebook application version string."),
+ INIT_BOOL(m_fb_java_stack, "fb-java-stack", 4,
+ "Dump Facebook java stack."),
+ INIT_BOOL(m_fb_dalvik, "fb-dalvik-info", 5,
+ "Dump Facebook Dalvik info."),
+ INIT_BOOL(m_fb_unwind, "fb-unwind-symbols", 6,
+ "Dump Facebook unwind symbols."),
+ INIT_BOOL(m_fb_error_log, "fb-error-log", 7,
+ "Dump Facebook error log."),
+ INIT_BOOL(m_fb_app_state, "fb-app-state-log", 8,
+ "Dump Facebook java stack."),
+ INIT_BOOL(m_fb_abort, "fb-abort-reason", 9,
+ "Dump Facebook abort reason."),
+ INIT_BOOL(m_fb_thread, "fb-thread-name", 10,
+ "Dump Facebook thread name."),
+ INIT_BOOL(m_fb_logcat, "fb-logcat", 11,
+ "Dump Facebook logcat."),
+ INIT_BOOL(m_fb_all, "facebook", 12, "Dump all Facebook streams.") {
+ APPEND_OPT(m_dump_all);
+ APPEND_OPT(m_dump_directory);
+ APPEND_OPT(m_dump_linux_cpuinfo);
+ APPEND_OPT(m_dump_linux_proc_status);
+ APPEND_OPT(m_dump_linux_lsb_release);
+ APPEND_OPT(m_dump_linux_cmdline);
+ APPEND_OPT(m_dump_linux_environ);
+ APPEND_OPT(m_dump_linux_auxv);
+ APPEND_OPT(m_dump_linux_maps);
+ APPEND_OPT(m_dump_linux_proc_stat);
+ APPEND_OPT(m_dump_linux_proc_uptime);
+ APPEND_OPT(m_dump_linux_proc_fd);
+ APPEND_OPT(m_dump_linux_all);
+ APPEND_OPT(m_fb_app_data);
+ APPEND_OPT(m_fb_build_id);
+ APPEND_OPT(m_fb_version);
+ APPEND_OPT(m_fb_java_stack);
+ APPEND_OPT(m_fb_dalvik);
+ APPEND_OPT(m_fb_unwind);
+ APPEND_OPT(m_fb_error_log);
+ APPEND_OPT(m_fb_app_state);
+ APPEND_OPT(m_fb_abort);
+ APPEND_OPT(m_fb_thread);
+ APPEND_OPT(m_fb_logcat);
+ APPEND_OPT(m_fb_all);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessMinidumpDump() override = default;
+
+ Options *GetOptions() override { return &m_option_group; }
+
+ void DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0) {
+ result.AppendErrorWithFormat("'%s' take no arguments, only options",
+ m_cmd_name.c_str());
+ return;
+ }
+ SetDefaultOptionsIfNoneAreSet();
+
+ ProcessMinidump *process = static_cast<ProcessMinidump *>(
+ m_interpreter.GetExecutionContext().GetProcessPtr());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ Stream &s = result.GetOutputStream();
+ MinidumpParser &minidump = *process->m_minidump_parser;
+ if (DumpDirectory()) {
+ s.Printf("RVA SIZE TYPE StreamType\n");
+ s.Printf("---------- ---------- ---------- --------------------------\n");
+ for (const auto &stream_desc : minidump.GetMinidumpFile().streams())
+ s.Printf(
+ "0x%8.8x 0x%8.8x 0x%8.8x %s\n", (uint32_t)stream_desc.Location.RVA,
+ (uint32_t)stream_desc.Location.DataSize,
+ (unsigned)(StreamType)stream_desc.Type,
+ MinidumpParser::GetStreamTypeAsString(stream_desc.Type).data());
+ s.Printf("\n");
+ }
+ auto DumpTextStream = [&](StreamType stream_type,
+ llvm::StringRef label) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label.empty())
+ label = MinidumpParser::GetStreamTypeAsString(stream_type);
+ s.Printf("%s:\n%s\n\n", label.data(), bytes.data());
+ }
+ };
+ auto DumpBinaryStream = [&](StreamType stream_type,
+ llvm::StringRef label) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label.empty())
+ label = MinidumpParser::GetStreamTypeAsString(stream_type);
+ s.Printf("%s:\n", label.data());
+ DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
+ process->GetAddressByteSize());
+ DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
+ bytes.size(), 16, 0, 0, 0);
+ s.Printf("\n\n");
+ }
+ };
+
+ if (DumpLinuxCPUInfo())
+ DumpTextStream(StreamType::LinuxCPUInfo, "/proc/cpuinfo");
+ if (DumpLinuxProcStatus())
+ DumpTextStream(StreamType::LinuxProcStatus, "/proc/PID/status");
+ if (DumpLinuxLSBRelease())
+ DumpTextStream(StreamType::LinuxLSBRelease, "/etc/lsb-release");
+ if (DumpLinuxCMDLine())
+ DumpTextStream(StreamType::LinuxCMDLine, "/proc/PID/cmdline");
+ if (DumpLinuxEnviron())
+ DumpTextStream(StreamType::LinuxEnviron, "/proc/PID/environ");
+ if (DumpLinuxAuxv())
+ DumpBinaryStream(StreamType::LinuxAuxv, "/proc/PID/auxv");
+ if (DumpLinuxMaps())
+ DumpTextStream(StreamType::LinuxMaps, "/proc/PID/maps");
+ if (DumpLinuxProcStat())
+ DumpTextStream(StreamType::LinuxProcStat, "/proc/PID/stat");
+ if (DumpLinuxProcUptime())
+ DumpTextStream(StreamType::LinuxProcUptime, "uptime");
+ if (DumpLinuxProcFD())
+ DumpTextStream(StreamType::LinuxProcFD, "/proc/PID/fd");
+ if (DumpFacebookAppData())
+ DumpTextStream(StreamType::FacebookAppCustomData,
+ "Facebook App Data");
+ if (DumpFacebookBuildID()) {
+ auto bytes = minidump.GetStream(StreamType::FacebookBuildID);
+ if (bytes.size() >= 4) {
+ DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
+ process->GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ uint32_t build_id = data.GetU32(&offset);
+ s.Printf("Facebook Build ID:\n");
+ s.Printf("%u\n", build_id);
+ s.Printf("\n");
+ }
+ }
+ if (DumpFacebookVersionName())
+ DumpTextStream(StreamType::FacebookAppVersionName,
+ "Facebook Version String");
+ if (DumpFacebookJavaStack())
+ DumpTextStream(StreamType::FacebookJavaStack,
+ "Facebook Java Stack");
+ if (DumpFacebookDalvikInfo())
+ DumpTextStream(StreamType::FacebookDalvikInfo,
+ "Facebook Dalvik Info");
+ if (DumpFacebookUnwindSymbols())
+ DumpBinaryStream(StreamType::FacebookUnwindSymbols,
+ "Facebook Unwind Symbols Bytes");
+ if (DumpFacebookErrorLog())
+ DumpTextStream(StreamType::FacebookDumpErrorLog,
+ "Facebook Error Log");
+ if (DumpFacebookAppStateLog())
+ DumpTextStream(StreamType::FacebookAppStateLog,
+ "Faceook Application State Log");
+ if (DumpFacebookAbortReason())
+ DumpTextStream(StreamType::FacebookAbortReason,
+ "Facebook Abort Reason");
+ if (DumpFacebookThreadName())
+ DumpTextStream(StreamType::FacebookThreadName,
+ "Facebook Thread Name");
+ if (DumpFacebookLogcat())
+ DumpTextStream(StreamType::FacebookLogcat, "Facebook Logcat");
+ }
+};
+
+class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
+public:
+ CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "process plugin",
+ "Commands for operating on a ProcessMinidump process.",
+ "process plugin <subcommand> [<subcommand-options>]") {
+ LoadSubCommand("dump",
+ CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessMinidump() override = default;
+};
+
+CommandObject *ProcessMinidump::GetPluginCommandObject() {
+ if (!m_command_sp)
+ m_command_sp = std::make_shared<CommandObjectMultiwordProcessMinidump>(
+ GetTarget().GetDebugger().GetCommandInterpreter());
+ return m_command_sp.get();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
new file mode 100644
index 000000000000..3f3123a0a8b5
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -0,0 +1,123 @@
+//===-- ProcessMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
+
+#include "MinidumpParser.h"
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/PostMortemProcess.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ProcessMinidump : public PostMortemProcess {
+public:
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "minidump"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
+ const FileSpec &core_file, lldb::DataBufferSP code_data);
+
+ ~ProcessMinidump() override;
+
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+ CommandObject *GetPluginCommandObject() override;
+
+ Status DoLoadCore() override;
+
+ DynamicLoader *GetDynamicLoader() override { return nullptr; }
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ SystemRuntime *GetSystemRuntime() override { return nullptr; }
+
+ Status DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ bool IsAlive() override;
+
+ bool WarnBeforeDetach() const override;
+
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ Status &error) override;
+
+ ArchSpec GetArchitecture();
+
+ Status GetMemoryRegions(
+ lldb_private::MemoryRegionInfos &region_list) override;
+
+ bool GetProcessInfo(ProcessInstanceInfo &info) override;
+
+ Status WillResume() override {
+ Status error;
+ error.SetErrorStringWithFormatv(
+ "error: {0} does not support resuming processes", GetPluginName());
+ return error;
+ }
+
+ std::optional<MinidumpParser> m_minidump_parser;
+
+protected:
+ void Clear();
+
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ void ReadModuleList();
+
+ lldb::ModuleSP GetOrCreateModule(lldb_private::UUID minidump_uuid,
+ llvm::StringRef name,
+ lldb_private::ModuleSpec module_spec);
+
+ JITLoaderList &GetJITLoaders() override;
+
+private:
+ lldb::DataBufferSP m_core_data;
+ llvm::ArrayRef<minidump::Thread> m_thread_list;
+ const minidump::ExceptionStream *m_active_exception;
+ lldb::CommandObjectSP m_command_sp;
+ bool m_is_wow64;
+ std::optional<MemoryRegionInfos> m_memory_regions;
+
+ void BuildMemoryRegions();
+};
+
+} // namespace minidump
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_PROCESSMINIDUMP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp
new file mode 100644
index 000000000000..0004d5d8d07e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp
@@ -0,0 +1,550 @@
+//===-- RegisterContextMinidump_ARM.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_ARM.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_ehframe_Registers.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+
+// C includes
+#include <cassert>
+
+// C++ includes
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+#define INV LLDB_INVALID_REGNUM
+#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM::Context, r))
+
+#define DEF_R(i) \
+ { \
+ "r" #i, nullptr, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
+ {ehframe_r##i, dwarf_r##i, INV, INV, reg_r##i}, nullptr, nullptr, \
+ nullptr, \
+ }
+
+#define DEF_R_ARG(i, n) \
+ { \
+ "r" #i, "arg" #n, 4, OFFSET(r) + i * 4, eEncodingUint, eFormatHex, \
+ {ehframe_r##i, dwarf_r##i, LLDB_REGNUM_GENERIC_ARG1 + i, INV, \
+ reg_r##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_D(i) \
+ { \
+ "d" #i, nullptr, 8, OFFSET(d) + i * 8, eEncodingVector, \
+ eFormatVectorOfUInt8, {dwarf_d##i, dwarf_d##i, INV, INV, reg_d##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_S(i) \
+ { \
+ "s" #i, nullptr, 4, OFFSET(s) + i * 4, eEncodingIEEE754, eFormatFloat, \
+ {dwarf_s##i, dwarf_s##i, INV, INV, reg_s##i}, nullptr, nullptr, \
+ nullptr, \
+ }
+
+#define DEF_Q(i) \
+ { \
+ "q" #i, nullptr, 16, OFFSET(q) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {dwarf_q##i, dwarf_q##i, INV, INV, reg_q##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+// Zero based LLDB register numbers for this register context
+enum {
+ // General Purpose Registers
+ reg_r0,
+ reg_r1,
+ reg_r2,
+ reg_r3,
+ reg_r4,
+ reg_r5,
+ reg_r6,
+ reg_r7,
+ reg_r8,
+ reg_r9,
+ reg_r10,
+ reg_r11,
+ reg_r12,
+ reg_sp,
+ reg_lr,
+ reg_pc,
+ reg_cpsr,
+ // Floating Point Registers
+ reg_fpscr,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_q0,
+ reg_q1,
+ reg_q2,
+ reg_q3,
+ reg_q4,
+ reg_q5,
+ reg_q6,
+ reg_q7,
+ reg_q8,
+ reg_q9,
+ reg_q10,
+ reg_q11,
+ reg_q12,
+ reg_q13,
+ reg_q14,
+ reg_q15,
+ k_num_regs
+};
+
+static RegisterInfo g_reg_info_apple_fp = {
+ "fp",
+ "r7",
+ 4,
+ OFFSET(r) + 7 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, INV, reg_r7},
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+static RegisterInfo g_reg_info_fp = {
+ "fp",
+ "r11",
+ 4,
+ OFFSET(r) + 11 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, INV, reg_r11},
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+// Register info definitions for this register context
+static RegisterInfo g_reg_infos[] = {
+ DEF_R_ARG(0, 1),
+ DEF_R_ARG(1, 2),
+ DEF_R_ARG(2, 3),
+ DEF_R_ARG(3, 4),
+ DEF_R(4),
+ DEF_R(5),
+ DEF_R(6),
+ DEF_R(7),
+ DEF_R(8),
+ DEF_R(9),
+ DEF_R(10),
+ DEF_R(11),
+ DEF_R(12),
+ {"sp",
+ "r13",
+ 4,
+ OFFSET(r) + 13 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"lr",
+ "r14",
+ 4,
+ OFFSET(r) + 14 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"pc",
+ "r15",
+ 4,
+ OFFSET(r) + 15 * 4,
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"cpsr",
+ "psr",
+ 4,
+ OFFSET(cpsr),
+ eEncodingUint,
+ eFormatHex,
+ {ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpscr",
+ nullptr,
+ 8,
+ OFFSET(fpscr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpscr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ DEF_D(0),
+ DEF_D(1),
+ DEF_D(2),
+ DEF_D(3),
+ DEF_D(4),
+ DEF_D(5),
+ DEF_D(6),
+ DEF_D(7),
+ DEF_D(8),
+ DEF_D(9),
+ DEF_D(10),
+ DEF_D(11),
+ DEF_D(12),
+ DEF_D(13),
+ DEF_D(14),
+ DEF_D(15),
+ DEF_D(16),
+ DEF_D(17),
+ DEF_D(18),
+ DEF_D(19),
+ DEF_D(20),
+ DEF_D(21),
+ DEF_D(22),
+ DEF_D(23),
+ DEF_D(24),
+ DEF_D(25),
+ DEF_D(26),
+ DEF_D(27),
+ DEF_D(28),
+ DEF_D(29),
+ DEF_D(30),
+ DEF_D(31),
+ DEF_S(0),
+ DEF_S(1),
+ DEF_S(2),
+ DEF_S(3),
+ DEF_S(4),
+ DEF_S(5),
+ DEF_S(6),
+ DEF_S(7),
+ DEF_S(8),
+ DEF_S(9),
+ DEF_S(10),
+ DEF_S(11),
+ DEF_S(12),
+ DEF_S(13),
+ DEF_S(14),
+ DEF_S(15),
+ DEF_S(16),
+ DEF_S(17),
+ DEF_S(18),
+ DEF_S(19),
+ DEF_S(20),
+ DEF_S(21),
+ DEF_S(22),
+ DEF_S(23),
+ DEF_S(24),
+ DEF_S(25),
+ DEF_S(26),
+ DEF_S(27),
+ DEF_S(28),
+ DEF_S(29),
+ DEF_S(30),
+ DEF_S(31),
+ DEF_Q(0),
+ DEF_Q(1),
+ DEF_Q(2),
+ DEF_Q(3),
+ DEF_Q(4),
+ DEF_Q(5),
+ DEF_Q(6),
+ DEF_Q(7),
+ DEF_Q(8),
+ DEF_Q(9),
+ DEF_Q(10),
+ DEF_Q(11),
+ DEF_Q(12),
+ DEF_Q(13),
+ DEF_Q(14),
+ DEF_Q(15)};
+
+constexpr size_t k_num_reg_infos = std::size(g_reg_infos);
+
+// ARM general purpose registers.
+const uint32_t g_gpr_regnums[] = {
+ reg_r0,
+ reg_r1,
+ reg_r2,
+ reg_r3,
+ reg_r4,
+ reg_r5,
+ reg_r6,
+ reg_r7,
+ reg_r8,
+ reg_r9,
+ reg_r10,
+ reg_r11,
+ reg_r12,
+ reg_sp,
+ reg_lr,
+ reg_pc,
+ reg_cpsr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+const uint32_t g_fpu_regnums[] = {
+ reg_fpscr,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_q0,
+ reg_q1,
+ reg_q2,
+ reg_q3,
+ reg_q4,
+ reg_q5,
+ reg_q6,
+ reg_q7,
+ reg_q8,
+ reg_q9,
+ reg_q10,
+ reg_q11,
+ reg_q12,
+ reg_q13,
+ reg_q14,
+ reg_q15,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
+constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1;
+constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1;
+
+static RegisterSet g_reg_sets[] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
+ {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
+};
+
+constexpr size_t k_num_reg_sets = std::size(g_reg_sets);
+
+RegisterContextMinidump_ARM::RegisterContextMinidump_ARM(
+ lldb_private::Thread &thread, const DataExtractor &data, bool apple)
+ : RegisterContext(thread, 0), m_apple(apple) {
+ lldb::offset_t offset = 0;
+ m_regs.context_flags = data.GetU32(&offset);
+ for (unsigned i = 0; i < std::size(m_regs.r); ++i)
+ m_regs.r[i] = data.GetU32(&offset);
+ m_regs.cpsr = data.GetU32(&offset);
+ m_regs.fpscr = data.GetU64(&offset);
+ for (unsigned i = 0; i < std::size(m_regs.d); ++i)
+ m_regs.d[i] = data.GetU64(&offset);
+ lldbassert(k_num_regs == k_num_reg_infos);
+}
+
+size_t RegisterContextMinidump_ARM::GetRegisterCountStatic() {
+ return k_num_regs;
+}
+
+// Used for unit testing so we can verify register info is filled in for
+// all register flavors (DWARF, EH Frame, generic, etc).
+size_t RegisterContextMinidump_ARM::GetRegisterCount() {
+ return GetRegisterCountStatic();
+}
+
+// Used for unit testing so we can verify register info is filled in.
+const RegisterInfo *
+RegisterContextMinidump_ARM::GetRegisterInfoAtIndexStatic(size_t reg,
+ bool apple) {
+ if (reg < k_num_reg_infos) {
+ if (apple) {
+ if (reg == reg_r7)
+ return &g_reg_info_apple_fp;
+ } else {
+ if (reg == reg_r11)
+ return &g_reg_info_fp;
+ }
+ return &g_reg_infos[reg];
+ }
+ return nullptr;
+}
+
+const RegisterInfo *
+RegisterContextMinidump_ARM::GetRegisterInfoAtIndex(size_t reg) {
+ return GetRegisterInfoAtIndexStatic(reg, m_apple);
+}
+
+size_t RegisterContextMinidump_ARM::GetRegisterSetCount() {
+ return k_num_reg_sets;
+}
+
+const RegisterSet *RegisterContextMinidump_ARM::GetRegisterSet(size_t set) {
+ if (set < k_num_reg_sets)
+ return &g_reg_sets[set];
+ return nullptr;
+}
+
+const char *RegisterContextMinidump_ARM::GetRegisterName(unsigned reg) {
+ if (reg < k_num_reg_infos)
+ return g_reg_infos[reg].name;
+ return nullptr;
+}
+
+bool RegisterContextMinidump_ARM::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+ reg_value.SetFromMemoryData(
+ *reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ return error.Success();
+}
+
+bool RegisterContextMinidump_ARM::WriteRegister(const RegisterInfo *,
+ const RegisterValue &) {
+ return false;
+}
+
+uint32_t RegisterContextMinidump_ARM::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ for (size_t i = 0; i < k_num_regs; ++i) {
+ if (g_reg_infos[i].kinds[kind] == num)
+ return i;
+ }
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h
new file mode 100644
index 000000000000..857f9c0a3767
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.h
@@ -0,0 +1,98 @@
+//===-- RegisterContextMinidump_ARM.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class RegisterContextMinidump_ARM : public lldb_private::RegisterContext {
+public:
+ RegisterContextMinidump_ARM(lldb_private::Thread &thread,
+ const DataExtractor &data, bool apple);
+
+ ~RegisterContextMinidump_ARM() override = default;
+
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
+
+ // Used for unit testing.
+ static size_t GetRegisterCountStatic();
+ // Used for unit testing.
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndexStatic(size_t reg, bool apple);
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ // Reference: see breakpad/crashpad source
+ struct QRegValue {
+ uint64_t lo;
+ uint64_t hi;
+ };
+
+ struct Context {
+ uint32_t context_flags;
+ uint32_t r[16];
+ uint32_t cpsr;
+ uint64_t fpscr;
+ union {
+ uint64_t d[32];
+ uint32_t s[32];
+ QRegValue q[16];
+ };
+ uint32_t extra[8];
+ };
+
+protected:
+ enum class Flags : uint32_t {
+ ARM_Flag = 0x40000000,
+ Integer = ARM_Flag | 0x00000002,
+ FloatingPoint = ARM_Flag | 0x00000004,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
+ };
+ Context m_regs;
+ const bool m_apple; // True if this is an Apple ARM where FP is R7
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp
new file mode 100644
index 000000000000..a0476c962070
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp
@@ -0,0 +1,833 @@
+//===-- RegisterContextMinidump_ARM64.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_ARM64.h"
+
+#include "Utility/ARM64_DWARF_Registers.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/lldb-enumerations.h"
+
+// C includes
+#include <cassert>
+
+// C++ includes
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+#define INV LLDB_INVALID_REGNUM
+#define OFFSET(r) (offsetof(RegisterContextMinidump_ARM64::Context, r))
+
+#define DEF_X(i) \
+ { \
+ "x" #i, nullptr, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {arm64_dwarf::x##i, arm64_dwarf::x##i, INV, INV, reg_x##i}, \
+ nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_W(i) \
+ { \
+ "w" #i, nullptr, 4, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {INV, INV, INV, INV, reg_w##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_X_ARG(i, n) \
+ { \
+ "x" #i, "arg" #n, 8, OFFSET(x) + i * 8, eEncodingUint, eFormatHex, \
+ {arm64_dwarf::x##i, arm64_dwarf::x##i, LLDB_REGNUM_GENERIC_ARG1 + i, \
+ INV, reg_x##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_V(i) \
+ { \
+ "v" #i, nullptr, 16, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {arm64_dwarf::v##i, arm64_dwarf::v##i, INV, INV, \
+ reg_v##i}, nullptr, nullptr, nullptr, \
+ }
+
+#define DEF_D(i) \
+ { \
+ "d" #i, nullptr, 8, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_d##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEF_S(i) \
+ { \
+ "s" #i, nullptr, 4, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_s##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+#define DEF_H(i) \
+ { \
+ "h" #i, nullptr, 2, OFFSET(v) + i * 16, eEncodingVector, \
+ eFormatVectorOfUInt8, {INV, INV, INV, INV, reg_h##i}, nullptr, \
+ nullptr, nullptr, \
+ }
+
+// Zero based LLDB register numbers for this register context
+enum {
+ // General Purpose Registers
+ reg_x0 = 0,
+ reg_x1,
+ reg_x2,
+ reg_x3,
+ reg_x4,
+ reg_x5,
+ reg_x6,
+ reg_x7,
+ reg_x8,
+ reg_x9,
+ reg_x10,
+ reg_x11,
+ reg_x12,
+ reg_x13,
+ reg_x14,
+ reg_x15,
+ reg_x16,
+ reg_x17,
+ reg_x18,
+ reg_x19,
+ reg_x20,
+ reg_x21,
+ reg_x22,
+ reg_x23,
+ reg_x24,
+ reg_x25,
+ reg_x26,
+ reg_x27,
+ reg_x28,
+ reg_fp,
+ reg_lr,
+ reg_sp,
+ reg_pc,
+ reg_w0,
+ reg_w1,
+ reg_w2,
+ reg_w3,
+ reg_w4,
+ reg_w5,
+ reg_w6,
+ reg_w7,
+ reg_w8,
+ reg_w9,
+ reg_w10,
+ reg_w11,
+ reg_w12,
+ reg_w13,
+ reg_w14,
+ reg_w15,
+ reg_w16,
+ reg_w17,
+ reg_w18,
+ reg_w19,
+ reg_w20,
+ reg_w21,
+ reg_w22,
+ reg_w23,
+ reg_w24,
+ reg_w25,
+ reg_w26,
+ reg_w27,
+ reg_w28,
+ reg_w29,
+ reg_w30,
+ reg_w31,
+ reg_cpsr,
+ // Floating Point Registers
+ reg_fpsr,
+ reg_fpcr,
+ reg_v0,
+ reg_v1,
+ reg_v2,
+ reg_v3,
+ reg_v4,
+ reg_v5,
+ reg_v6,
+ reg_v7,
+ reg_v8,
+ reg_v9,
+ reg_v10,
+ reg_v11,
+ reg_v12,
+ reg_v13,
+ reg_v14,
+ reg_v15,
+ reg_v16,
+ reg_v17,
+ reg_v18,
+ reg_v19,
+ reg_v20,
+ reg_v21,
+ reg_v22,
+ reg_v23,
+ reg_v24,
+ reg_v25,
+ reg_v26,
+ reg_v27,
+ reg_v28,
+ reg_v29,
+ reg_v30,
+ reg_v31,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_h0,
+ reg_h1,
+ reg_h2,
+ reg_h3,
+ reg_h4,
+ reg_h5,
+ reg_h6,
+ reg_h7,
+ reg_h8,
+ reg_h9,
+ reg_h10,
+ reg_h11,
+ reg_h12,
+ reg_h13,
+ reg_h14,
+ reg_h15,
+ reg_h16,
+ reg_h17,
+ reg_h18,
+ reg_h19,
+ reg_h20,
+ reg_h21,
+ reg_h22,
+ reg_h23,
+ reg_h24,
+ reg_h25,
+ reg_h26,
+ reg_h27,
+ reg_h28,
+ reg_h29,
+ reg_h30,
+ reg_h31,
+ k_num_regs
+};
+
+// Register info definitions for this register context
+static RegisterInfo g_reg_infos[] = {
+ DEF_X_ARG(0, 1),
+ DEF_X_ARG(1, 2),
+ DEF_X_ARG(2, 3),
+ DEF_X_ARG(3, 4),
+ DEF_X_ARG(4, 5),
+ DEF_X_ARG(5, 6),
+ DEF_X_ARG(6, 7),
+ DEF_X_ARG(7, 8),
+ DEF_X(8),
+ DEF_X(9),
+ DEF_X(10),
+ DEF_X(11),
+ DEF_X(12),
+ DEF_X(13),
+ DEF_X(14),
+ DEF_X(15),
+ DEF_X(16),
+ DEF_X(17),
+ DEF_X(18),
+ DEF_X(19),
+ DEF_X(20),
+ DEF_X(21),
+ DEF_X(22),
+ DEF_X(23),
+ DEF_X(24),
+ DEF_X(25),
+ DEF_X(26),
+ DEF_X(27),
+ DEF_X(28),
+ {"fp",
+ "x29",
+ 8,
+ OFFSET(x) + 29 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x29, arm64_dwarf::x29, LLDB_REGNUM_GENERIC_FP, INV, reg_fp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"lr",
+ "x30",
+ 8,
+ OFFSET(x) + 30 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x30, arm64_dwarf::x30, LLDB_REGNUM_GENERIC_RA, INV, reg_lr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"sp",
+ "x31",
+ 8,
+ OFFSET(x) + 31 * 8,
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::x31, arm64_dwarf::x31, LLDB_REGNUM_GENERIC_SP, INV, reg_sp},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"pc",
+ nullptr,
+ 8,
+ OFFSET(pc),
+ eEncodingUint,
+ eFormatHex,
+ {arm64_dwarf::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, INV, reg_pc},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ // w0 - w31
+ DEF_W(0),
+ DEF_W(1),
+ DEF_W(2),
+ DEF_W(3),
+ DEF_W(4),
+ DEF_W(5),
+ DEF_W(6),
+ DEF_W(7),
+ DEF_W(8),
+ DEF_W(9),
+ DEF_W(10),
+ DEF_W(11),
+ DEF_W(12),
+ DEF_W(13),
+ DEF_W(14),
+ DEF_W(15),
+ DEF_W(16),
+ DEF_W(17),
+ DEF_W(18),
+ DEF_W(19),
+ DEF_W(20),
+ DEF_W(21),
+ DEF_W(22),
+ DEF_W(23),
+ DEF_W(24),
+ DEF_W(25),
+ DEF_W(26),
+ DEF_W(27),
+ DEF_W(28),
+ DEF_W(29),
+ DEF_W(30),
+ DEF_W(31),
+ {"cpsr",
+ "psr",
+ 4,
+ OFFSET(cpsr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, INV, reg_cpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpsr",
+ nullptr,
+ 4,
+ OFFSET(fpsr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpsr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ {"fpcr",
+ nullptr,
+ 4,
+ OFFSET(fpcr),
+ eEncodingUint,
+ eFormatHex,
+ {INV, INV, INV, INV, reg_fpcr},
+ nullptr,
+ nullptr,
+ nullptr,
+ },
+ // v0 - v31
+ DEF_V(0),
+ DEF_V(1),
+ DEF_V(2),
+ DEF_V(3),
+ DEF_V(4),
+ DEF_V(5),
+ DEF_V(6),
+ DEF_V(7),
+ DEF_V(8),
+ DEF_V(9),
+ DEF_V(10),
+ DEF_V(11),
+ DEF_V(12),
+ DEF_V(13),
+ DEF_V(14),
+ DEF_V(15),
+ DEF_V(16),
+ DEF_V(17),
+ DEF_V(18),
+ DEF_V(19),
+ DEF_V(20),
+ DEF_V(21),
+ DEF_V(22),
+ DEF_V(23),
+ DEF_V(24),
+ DEF_V(25),
+ DEF_V(26),
+ DEF_V(27),
+ DEF_V(28),
+ DEF_V(29),
+ DEF_V(30),
+ DEF_V(31),
+ // d0 - d31
+ DEF_D(0),
+ DEF_D(1),
+ DEF_D(2),
+ DEF_D(3),
+ DEF_D(4),
+ DEF_D(5),
+ DEF_D(6),
+ DEF_D(7),
+ DEF_D(8),
+ DEF_D(9),
+ DEF_D(10),
+ DEF_D(11),
+ DEF_D(12),
+ DEF_D(13),
+ DEF_D(14),
+ DEF_D(15),
+ DEF_D(16),
+ DEF_D(17),
+ DEF_D(18),
+ DEF_D(19),
+ DEF_D(20),
+ DEF_D(21),
+ DEF_D(22),
+ DEF_D(23),
+ DEF_D(24),
+ DEF_D(25),
+ DEF_D(26),
+ DEF_D(27),
+ DEF_D(28),
+ DEF_D(29),
+ DEF_D(30),
+ DEF_D(31),
+ // s0 - s31
+ DEF_S(0),
+ DEF_S(1),
+ DEF_S(2),
+ DEF_S(3),
+ DEF_S(4),
+ DEF_S(5),
+ DEF_S(6),
+ DEF_S(7),
+ DEF_S(8),
+ DEF_S(9),
+ DEF_S(10),
+ DEF_S(11),
+ DEF_S(12),
+ DEF_S(13),
+ DEF_S(14),
+ DEF_S(15),
+ DEF_S(16),
+ DEF_S(17),
+ DEF_S(18),
+ DEF_S(19),
+ DEF_S(20),
+ DEF_S(21),
+ DEF_S(22),
+ DEF_S(23),
+ DEF_S(24),
+ DEF_S(25),
+ DEF_S(26),
+ DEF_S(27),
+ DEF_S(28),
+ DEF_S(29),
+ DEF_S(30),
+ DEF_S(31),
+ // h0 - h31
+ DEF_H(0),
+ DEF_H(1),
+ DEF_H(2),
+ DEF_H(3),
+ DEF_H(4),
+ DEF_H(5),
+ DEF_H(6),
+ DEF_H(7),
+ DEF_H(8),
+ DEF_H(9),
+ DEF_H(10),
+ DEF_H(11),
+ DEF_H(12),
+ DEF_H(13),
+ DEF_H(14),
+ DEF_H(15),
+ DEF_H(16),
+ DEF_H(17),
+ DEF_H(18),
+ DEF_H(19),
+ DEF_H(20),
+ DEF_H(21),
+ DEF_H(22),
+ DEF_H(23),
+ DEF_H(24),
+ DEF_H(25),
+ DEF_H(26),
+ DEF_H(27),
+ DEF_H(28),
+ DEF_H(29),
+ DEF_H(30),
+ DEF_H(31),
+};
+
+constexpr size_t k_num_reg_infos = std::size(g_reg_infos);
+
+// ARM64 general purpose registers.
+const uint32_t g_gpr_regnums[] = {
+ reg_x0,
+ reg_x1,
+ reg_x2,
+ reg_x3,
+ reg_x4,
+ reg_x5,
+ reg_x6,
+ reg_x7,
+ reg_x8,
+ reg_x9,
+ reg_x10,
+ reg_x11,
+ reg_x12,
+ reg_x13,
+ reg_x14,
+ reg_x15,
+ reg_x16,
+ reg_x17,
+ reg_x18,
+ reg_x19,
+ reg_x20,
+ reg_x21,
+ reg_x22,
+ reg_x23,
+ reg_x24,
+ reg_x25,
+ reg_x26,
+ reg_x27,
+ reg_x28,
+ reg_fp,
+ reg_lr,
+ reg_sp,
+ reg_w0,
+ reg_w1,
+ reg_w2,
+ reg_w3,
+ reg_w4,
+ reg_w5,
+ reg_w6,
+ reg_w7,
+ reg_w8,
+ reg_w9,
+ reg_w10,
+ reg_w11,
+ reg_w12,
+ reg_w13,
+ reg_w14,
+ reg_w15,
+ reg_w16,
+ reg_w17,
+ reg_w18,
+ reg_w19,
+ reg_w20,
+ reg_w21,
+ reg_w22,
+ reg_w23,
+ reg_w24,
+ reg_w25,
+ reg_w26,
+ reg_w27,
+ reg_w28,
+ reg_w29,
+ reg_w30,
+ reg_w31,
+ reg_pc,
+ reg_cpsr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+const uint32_t g_fpu_regnums[] = {
+ reg_v0,
+ reg_v1,
+ reg_v2,
+ reg_v3,
+ reg_v4,
+ reg_v5,
+ reg_v6,
+ reg_v7,
+ reg_v8,
+ reg_v9,
+ reg_v10,
+ reg_v11,
+ reg_v12,
+ reg_v13,
+ reg_v14,
+ reg_v15,
+ reg_v16,
+ reg_v17,
+ reg_v18,
+ reg_v19,
+ reg_v20,
+ reg_v21,
+ reg_v22,
+ reg_v23,
+ reg_v24,
+ reg_v25,
+ reg_v26,
+ reg_v27,
+ reg_v28,
+ reg_v29,
+ reg_v30,
+ reg_v31,
+ reg_d0,
+ reg_d1,
+ reg_d2,
+ reg_d3,
+ reg_d4,
+ reg_d5,
+ reg_d6,
+ reg_d7,
+ reg_d8,
+ reg_d9,
+ reg_d10,
+ reg_d11,
+ reg_d12,
+ reg_d13,
+ reg_d14,
+ reg_d15,
+ reg_d16,
+ reg_d17,
+ reg_d18,
+ reg_d19,
+ reg_d20,
+ reg_d21,
+ reg_d22,
+ reg_d23,
+ reg_d24,
+ reg_d25,
+ reg_d26,
+ reg_d27,
+ reg_d28,
+ reg_d29,
+ reg_d30,
+ reg_d31,
+ reg_s0,
+ reg_s1,
+ reg_s2,
+ reg_s3,
+ reg_s4,
+ reg_s5,
+ reg_s6,
+ reg_s7,
+ reg_s8,
+ reg_s9,
+ reg_s10,
+ reg_s11,
+ reg_s12,
+ reg_s13,
+ reg_s14,
+ reg_s15,
+ reg_s16,
+ reg_s17,
+ reg_s18,
+ reg_s19,
+ reg_s20,
+ reg_s21,
+ reg_s22,
+ reg_s23,
+ reg_s24,
+ reg_s25,
+ reg_s26,
+ reg_s27,
+ reg_s28,
+ reg_s29,
+ reg_s30,
+ reg_s31,
+ reg_h0,
+ reg_h1,
+ reg_h2,
+ reg_h3,
+ reg_h4,
+ reg_h5,
+ reg_h6,
+ reg_h7,
+ reg_h8,
+ reg_h9,
+ reg_h10,
+ reg_h11,
+ reg_h12,
+ reg_h13,
+ reg_h14,
+ reg_h15,
+ reg_h16,
+ reg_h17,
+ reg_h18,
+ reg_h19,
+ reg_h20,
+ reg_h21,
+ reg_h22,
+ reg_h23,
+ reg_h24,
+ reg_h25,
+ reg_h26,
+ reg_h27,
+ reg_h28,
+ reg_h29,
+ reg_h30,
+ reg_h31,
+ reg_fpsr,
+ reg_fpcr,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+
+// Skip the last LLDB_INVALID_REGNUM in each count below by subtracting 1
+constexpr size_t k_num_gpr_regs = std::size(g_gpr_regnums) - 1;
+constexpr size_t k_num_fpu_regs = std::size(g_fpu_regnums) - 1;
+
+static RegisterSet g_reg_sets[] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_regs, g_gpr_regnums},
+ {"Floating Point Registers", "fpu", k_num_fpu_regs, g_fpu_regnums},
+};
+
+constexpr size_t k_num_reg_sets = std::size(g_reg_sets);
+
+RegisterContextMinidump_ARM64::RegisterContextMinidump_ARM64(
+ lldb_private::Thread &thread, const DataExtractor &data)
+ : RegisterContext(thread, 0) {
+ lldb::offset_t offset = 0;
+ m_regs.context_flags = data.GetU64(&offset);
+ for (unsigned i = 0; i < 32; ++i)
+ m_regs.x[i] = data.GetU64(&offset);
+ m_regs.pc = data.GetU64(&offset);
+ m_regs.cpsr = data.GetU32(&offset);
+ m_regs.fpsr = data.GetU32(&offset);
+ m_regs.fpcr = data.GetU32(&offset);
+ auto regs_data = data.GetData(&offset, sizeof(m_regs.v));
+ if (regs_data)
+ memcpy(m_regs.v, regs_data, sizeof(m_regs.v));
+ static_assert(k_num_regs == k_num_reg_infos);
+}
+size_t RegisterContextMinidump_ARM64::GetRegisterCount() { return k_num_regs; }
+
+const RegisterInfo *
+RegisterContextMinidump_ARM64::GetRegisterInfoAtIndex(size_t reg) {
+ if (reg < k_num_reg_infos)
+ return &g_reg_infos[reg];
+ return nullptr;
+}
+
+size_t RegisterContextMinidump_ARM64::GetRegisterSetCount() {
+ return k_num_reg_sets;
+}
+
+const RegisterSet *RegisterContextMinidump_ARM64::GetRegisterSet(size_t set) {
+ if (set < k_num_reg_sets)
+ return &g_reg_sets[set];
+ return nullptr;
+}
+
+const char *RegisterContextMinidump_ARM64::GetRegisterName(unsigned reg) {
+ if (reg < k_num_reg_infos)
+ return g_reg_infos[reg].name;
+ return nullptr;
+}
+
+bool RegisterContextMinidump_ARM64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+ reg_value.SetFromMemoryData(
+ *reg_info, (const uint8_t *)&m_regs + reg_info->byte_offset,
+ reg_info->byte_size, lldb::eByteOrderLittle, error);
+ return error.Success();
+}
+
+bool RegisterContextMinidump_ARM64::WriteRegister(const RegisterInfo *,
+ const RegisterValue &) {
+ return false;
+}
+
+uint32_t RegisterContextMinidump_ARM64::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num) {
+ for (size_t i = 0; i < k_num_regs; ++i) {
+ if (g_reg_infos[i].kinds[kind] == num)
+ return i;
+ }
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h
new file mode 100644
index 000000000000..58cf8d62fb86
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.h
@@ -0,0 +1,83 @@
+//===-- RegisterContextMinidump_ARM64.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
+
+#include "MinidumpTypes.h"
+
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+
+// C includes
+// C++ includes
+
+namespace lldb_private {
+
+namespace minidump {
+
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
+class RegisterContextMinidump_ARM64 : public lldb_private::RegisterContext {
+public:
+ RegisterContextMinidump_ARM64(lldb_private::Thread &thread,
+ const DataExtractor &data);
+
+ ~RegisterContextMinidump_ARM64() override = default;
+
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
+
+ size_t GetRegisterCount() override;
+
+ const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+ const char *GetRegisterName(unsigned reg);
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ // Reference: see breakpad/crashpad source
+ struct Context {
+ uint64_t context_flags;
+ uint64_t x[32];
+ uint64_t pc;
+ uint32_t cpsr;
+ uint32_t fpsr;
+ uint32_t fpcr;
+ uint8_t v[32 * 16]; // 32 128-bit floating point registers
+ };
+
+ enum class Flags : uint32_t {
+ ARM64_Flag = 0x80000000,
+ Integer = ARM64_Flag | 0x00000002,
+ FloatingPoint = ARM64_Flag | 0x00000004,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ FloatingPoint)
+ };
+
+protected:
+ Context m_regs;
+};
+
+} // end namespace minidump
+} // end namespace lldb_private
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_ARM64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
new file mode 100644
index 000000000000..7681002c6fb8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp
@@ -0,0 +1,96 @@
+//===-- RegisterContextMinidump_x86_32.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_x86_32.h"
+
+#include "lldb/Utility/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::WritableDataBufferSP 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/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
new file mode 100644
index 000000000000..4dffc4f9db0e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h
@@ -0,0 +1,135 @@
+//===-- RegisterContextMinidump_x86_32.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
+
+#include "MinidumpTypes.h"
+
+#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 is 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 // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_32_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
new file mode 100644
index 000000000000..917140cab297
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
@@ -0,0 +1,110 @@
+//===-- RegisterContextMinidump_x86_64.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMinidump_x86_64.h"
+
+#include "lldb/Utility/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::WritableDataBufferSP 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/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
new file mode 100644
index 000000000000..d920ea9d823f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h
@@ -0,0 +1,180 @@
+//===-- RegisterContextMinidump_x86_64.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
+
+#include "MinidumpTypes.h"
+
+#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 // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_REGISTERCONTEXTMINIDUMP_X86_64_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
new file mode 100644
index 000000000000..1fbc52815238
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp
@@ -0,0 +1,118 @@
+//===-- ThreadMinidump.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadMinidump.h"
+
+#include "ProcessMinidump.h"
+
+#include "RegisterContextMinidump_ARM.h"
+#include "RegisterContextMinidump_ARM64.h"
+#include "RegisterContextMinidump_x86_32.h"
+#include "RegisterContextMinidump_x86_64.h"
+
+#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 "Plugins/Process/elf-core/RegisterUtilities.h"
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace minidump;
+
+ThreadMinidump::ThreadMinidump(Process &process, const minidump::Thread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data)
+ : Thread(process, td.ThreadId), m_thread_reg_ctx_sp(),
+ m_gpregset_data(gpregset_data) {}
+
+ThreadMinidump::~ThreadMinidump() = default;
+
+void ThreadMinidump::RefreshStateAfterStop() {}
+
+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;
+
+ 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 gpregset(buf, lldb::eByteOrderLittle, 4);
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
+ *this, reg_interface, gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote>());
+ 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 gpregset(buf, lldb::eByteOrderLittle, 8);
+ m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>(
+ *this, reg_interface, gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote>());
+ break;
+ }
+ case llvm::Triple::aarch64: {
+ DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
+ lldb::eByteOrderLittle, 8);
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextMinidump_ARM64>(*this, data);
+ break;
+ }
+ case llvm::Triple::arm: {
+ DataExtractor data(m_gpregset_data.data(), m_gpregset_data.size(),
+ lldb::eByteOrderLittle, 8);
+ const bool apple = arch.GetTriple().getVendor() == llvm::Triple::Apple;
+ m_thread_reg_ctx_sp =
+ std::make_shared<RegisterContextMinidump_ARM>(*this, data, apple);
+ break;
+ }
+ default:
+ break;
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ } else if (m_unwinder_up) {
+ reg_ctx_sp = m_unwinder_up->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool ThreadMinidump::CalculateStopInfo() { return false; }
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h
new file mode 100644
index 000000000000..aed7cfbc1b16
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ThreadMinidump.h
@@ -0,0 +1,45 @@
+//===-- ThreadMinidump.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H
+
+#include "MinidumpTypes.h"
+
+#include "lldb/Target/Thread.h"
+
+
+namespace lldb_private {
+
+namespace minidump {
+
+class ThreadMinidump : public Thread {
+public:
+ ThreadMinidump(Process &process, const minidump::Thread &td,
+ llvm::ArrayRef<uint8_t> gpregset_data);
+
+ ~ThreadMinidump() override;
+
+ void RefreshStateAfterStop() override;
+
+ lldb::RegisterContextSP GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) 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 // LLDB_SOURCE_PLUGINS_PROCESS_MINIDUMP_THREADMINIDUMP_H