Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,19 @@
include_directories(../Utility)
add_lldb_library(lldbPluginProcessMinidump PLUGIN
MinidumpTypes.cpp
MinidumpParser.cpp
RegisterContextMinidump_x86_32.cpp
RegisterContextMinidump_x86_64.cpp
ProcessMinidump.cpp
ThreadMinidump.cpp
LINK_LIBS
lldbCore
lldbTarget
lldbUtility
lldbPluginProcessUtility
lldbPluginProcessElfCore
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,458 @@
//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Project includes
#include "MinidumpParser.h"
#include "NtStructures.h"
#include "RegisterContextMinidump_x86_32.h"
// Other libraries and framework includes
#include "lldb/Target/MemoryRegionInfo.h"
// C includes
// C++ includes
#include <map>
using namespace lldb_private;
using namespace minidump;
llvm::Optional<MinidumpParser>
MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
if (data_buf_sp->GetByteSize() < sizeof(MinidumpHeader)) {
return llvm::None;
}
llvm::ArrayRef<uint8_t> header_data(data_buf_sp->GetBytes(),
sizeof(MinidumpHeader));
const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
if (header == nullptr) {
return llvm::None;
}
lldb::offset_t directory_list_offset = header->stream_directory_rva;
// check if there is enough data for the parsing of the directory list
if ((directory_list_offset +
sizeof(MinidumpDirectory) * header->streams_count) >
data_buf_sp->GetByteSize()) {
return llvm::None;
}
const MinidumpDirectory *directory = nullptr;
Status error;
llvm::ArrayRef<uint8_t> directory_data(
data_buf_sp->GetBytes() + directory_list_offset,
sizeof(MinidumpDirectory) * header->streams_count);
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> directory_map;
for (uint32_t i = 0; i < header->streams_count; ++i) {
error = consumeObject(directory_data, directory);
if (error.Fail()) {
return llvm::None;
}
directory_map[static_cast<const uint32_t>(directory->stream_type)] =
directory->location;
}
return MinidumpParser(data_buf_sp, header, std::move(directory_map));
}
MinidumpParser::MinidumpParser(
const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map)
: m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) {
}
llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
m_data_sp->GetByteSize());
}
llvm::ArrayRef<uint8_t>
MinidumpParser::GetStream(MinidumpStreamType stream_type) {
auto iter = m_directory_map.find(static_cast<uint32_t>(stream_type));
if (iter == m_directory_map.end())
return {};
// check if there is enough data
if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
return {};
return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
iter->second.data_size);
}
llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
auto arr_ref = m_data_sp->GetData();
if (rva > arr_ref.size())
return llvm::None;
arr_ref = arr_ref.drop_front(rva);
return parseMinidumpString(arr_ref);
}
llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
if (data.size() == 0)
return llvm::None;
return MinidumpThread::ParseThreadList(data);
}
llvm::ArrayRef<uint8_t>
MinidumpParser::GetThreadContext(const MinidumpThread &td) {
if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
return {};
return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
}
llvm::ArrayRef<uint8_t>
MinidumpParser::GetThreadContextWow64(const MinidumpThread &td) {
// On Windows, a 32-bit process can run on a 64-bit machine under
// WOW64. If the minidump was captured with a 64-bit debugger, then
// the CONTEXT we just grabbed from the mini_dump_thread is the one
// for the 64-bit "native" process rather than the 32-bit "guest"
// process we care about. In this case, we can get the 32-bit CONTEXT
// from the TEB (Thread Environment Block) of the 64-bit process.
auto teb_mem = GetMemory(td.teb, sizeof(TEB64));
if (teb_mem.empty())
return {};
const TEB64 *wow64teb;
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]).
}
const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
if (data.size() == 0)
return nullptr;
return MinidumpSystemInfo::Parse(data);
}
ArchSpec MinidumpParser::GetArchitecture() {
ArchSpec arch_spec;
const MinidumpSystemInfo *system_info = GetSystemInfo();
if (!system_info)
return arch_spec;
// TODO what to do about big endiand flavors of arm ?
// TODO set the arm subarch stuff if the minidump has info about it
llvm::Triple triple;
triple.setVendor(llvm::Triple::VendorType::UnknownVendor);
const MinidumpCPUArchitecture arch =
static_cast<const MinidumpCPUArchitecture>(
static_cast<const uint32_t>(system_info->processor_arch));
switch (arch) {
case MinidumpCPUArchitecture::X86:
triple.setArch(llvm::Triple::ArchType::x86);
break;
case MinidumpCPUArchitecture::AMD64:
triple.setArch(llvm::Triple::ArchType::x86_64);
break;
case MinidumpCPUArchitecture::ARM:
triple.setArch(llvm::Triple::ArchType::arm);
break;
case MinidumpCPUArchitecture::ARM64:
triple.setArch(llvm::Triple::ArchType::aarch64);
break;
default:
triple.setArch(llvm::Triple::ArchType::UnknownArch);
break;
}
const MinidumpOSPlatform os = static_cast<const MinidumpOSPlatform>(
static_cast<const uint32_t>(system_info->platform_id));
// TODO add all of the OSes that Minidump/breakpad distinguishes?
switch (os) {
case MinidumpOSPlatform::Win32S:
case MinidumpOSPlatform::Win32Windows:
case MinidumpOSPlatform::Win32NT:
case MinidumpOSPlatform::Win32CE:
triple.setOS(llvm::Triple::OSType::Win32);
break;
case MinidumpOSPlatform::Linux:
triple.setOS(llvm::Triple::OSType::Linux);
break;
case MinidumpOSPlatform::MacOSX:
triple.setOS(llvm::Triple::OSType::MacOSX);
break;
case MinidumpOSPlatform::Android:
triple.setOS(llvm::Triple::OSType::Linux);
triple.setEnvironment(llvm::Triple::EnvironmentType::Android);
break;
default:
triple.setOS(llvm::Triple::OSType::UnknownOS);
break;
}
arch_spec.SetTriple(triple);
return arch_spec;
}
const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MiscInfo);
if (data.size() == 0)
return nullptr;
return MinidumpMiscInfo::Parse(data);
}
llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxProcStatus);
if (data.size() == 0)
return llvm::None;
return LinuxProcStatus::Parse(data);
}
llvm::Optional<lldb::pid_t> MinidumpParser::GetPid() {
const MinidumpMiscInfo *misc_info = GetMiscInfo();
if (misc_info != nullptr) {
return misc_info->GetPid();
}
llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus();
if (proc_status.hasValue()) {
return proc_status->GetPid();
}
return llvm::None;
}
llvm::ArrayRef<MinidumpModule> MinidumpParser::GetModuleList() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ModuleList);
if (data.size() == 0)
return {};
return MinidumpModule::ParseModuleList(data);
}
std::vector<const MinidumpModule *> MinidumpParser::GetFilteredModuleList() {
llvm::ArrayRef<MinidumpModule> modules = GetModuleList();
// map module_name -> pair(load_address, pointer to module struct in memory)
llvm::StringMap<std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
std::vector<const MinidumpModule *> filtered_modules;
llvm::Optional<std::string> name;
std::string module_name;
for (const auto &module : modules) {
name = GetMinidumpString(module.module_name_rva);
if (!name)
continue;
module_name = name.getValue();
auto iter = lowest_addr.end();
bool exists;
std::tie(iter, exists) = lowest_addr.try_emplace(
module_name, std::make_pair(module.base_of_image, &module));
if (exists && module.base_of_image < iter->second.first)
iter->second = std::make_pair(module.base_of_image, &module);
}
filtered_modules.reserve(lowest_addr.size());
for (const auto &module : lowest_addr) {
filtered_modules.push_back(module.second.second);
}
return filtered_modules;
}
const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);
if (data.size() == 0)
return nullptr;
return MinidumpExceptionStream::Parse(data);
}
llvm::Optional<minidump::Range>
MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
llvm::ArrayRef<uint8_t> data64 = GetStream(MinidumpStreamType::Memory64List);
if (data.empty() && data64.empty())
return llvm::None;
if (!data.empty()) {
llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
MinidumpMemoryDescriptor::ParseMemoryList(data);
if (memory_list.empty())
return llvm::None;
for (const auto &memory_desc : memory_list) {
const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
const lldb::addr_t range_start = memory_desc.start_of_memory_range;
const size_t range_size = loc_desc.data_size;
if (loc_desc.rva + loc_desc.data_size > GetData().size())
return llvm::None;
if (range_start <= addr && addr < range_start + range_size) {
return minidump::Range(range_start,
GetData().slice(loc_desc.rva, range_size));
}
}
}
// Some Minidumps have a Memory64ListStream that captures all the heap
// memory (full-memory Minidumps). We can't exactly use the same loop as
// above, because the Minidump uses slightly different data structures to
// describe those
if (!data64.empty()) {
llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
uint64_t base_rva;
std::tie(memory64_list, base_rva) =
MinidumpMemoryDescriptor64::ParseMemory64List(data64);
if (memory64_list.empty())
return llvm::None;
for (const auto &memory_desc64 : memory64_list) {
const lldb::addr_t range_start = memory_desc64.start_of_memory_range;
const size_t range_size = memory_desc64.data_size;
if (base_rva + range_size > GetData().size())
return llvm::None;
if (range_start <= addr && addr < range_start + range_size) {
return minidump::Range(range_start,
GetData().slice(base_rva, range_size));
}
base_rva += range_size;
}
}
return llvm::None;
}
llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
size_t size) {
// I don't have a sense of how frequently this is called or how many memory
// ranges a Minidump typically has, so I'm not sure if searching for the
// appropriate range linearly each time is stupid. Perhaps we should build
// an index for faster lookups.
llvm::Optional<minidump::Range> range = FindMemoryRange(addr);
if (!range)
return {};
// There's at least some overlap between the beginning of the desired range
// (addr) and the current range. Figure out where the overlap begins and
// how much overlap there is.
const size_t offset = addr - range->start;
if (addr < range->start || offset >= range->range_ref.size())
return {};
const size_t overlap = std::min(size, range->range_ref.size() - offset);
return range->range_ref.slice(offset, overlap);
}
llvm::Optional<MemoryRegionInfo>
MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
MemoryRegionInfo info;
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
if (data.empty())
return llvm::None;
std::vector<const MinidumpMemoryInfo *> mem_info_list =
MinidumpMemoryInfo::ParseMemoryInfoList(data);
if (mem_info_list.empty())
return llvm::None;
const auto yes = MemoryRegionInfo::eYes;
const auto no = MemoryRegionInfo::eNo;
const MinidumpMemoryInfo *next_entry = nullptr;
for (const auto &entry : mem_info_list) {
const auto head = entry->base_address;
const auto tail = head + entry->region_size;
if (head <= load_addr && load_addr < tail) {
info.GetRange().SetRangeBase(
(entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
? head
: load_addr);
info.GetRange().SetRangeEnd(tail);
const uint32_t PageNoAccess =
static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
const uint32_t PageWritable =
static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
const uint32_t PageExecutable = static_cast<uint32_t>(
MinidumpMemoryProtectionContants::PageExecutable);
info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
const uint32_t MemFree =
static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
info.SetMapped((entry->state != MemFree) ? yes : no);
return info;
} else if (head > load_addr &&
(next_entry == nullptr || head < next_entry->base_address)) {
// In case there is no region containing load_addr keep track of the
// nearest region after load_addr so we can return the distance to it.
next_entry = entry;
}
}
// No containing region found. Create an unmapped region that extends to the
// next region or LLDB_INVALID_ADDRESS
info.GetRange().SetRangeBase(load_addr);
info.GetRange().SetRangeEnd((next_entry != nullptr) ? next_entry->base_address
: LLDB_INVALID_ADDRESS);
info.SetReadable(no);
info.SetWritable(no);
info.SetExecutable(no);
info.SetMapped(no);
// Note that the memory info list doesn't seem to contain ranges in kernel
// space, so if you're walking a stack that has kernel frames, the stack may
// appear truncated.
return info;
}

View File

@@ -0,0 +1,101 @@
//===-- MinidumpParser.h -----------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_MinidumpParser_h_
#define liblldb_MinidumpParser_h_
// Project includes
#include "MinidumpTypes.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/Status.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
// C includes
// C++ includes
#include <cstring>
#include <unordered_map>
namespace lldb_private {
namespace minidump {
// Describes a range of memory captured in the Minidump
struct Range {
lldb::addr_t start; // virtual address of the beginning of the range
// range_ref - absolute pointer to the first byte of the range and size
llvm::ArrayRef<uint8_t> range_ref;
Range(lldb::addr_t start, llvm::ArrayRef<uint8_t> range_ref)
: start(start), range_ref(range_ref) {}
};
class MinidumpParser {
public:
static llvm::Optional<MinidumpParser>
Create(const lldb::DataBufferSP &data_buf_sp);
llvm::ArrayRef<uint8_t> GetData();
llvm::ArrayRef<uint8_t> GetStream(MinidumpStreamType stream_type);
llvm::Optional<std::string> GetMinidumpString(uint32_t rva);
llvm::ArrayRef<MinidumpThread> GetThreads();
llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
llvm::ArrayRef<uint8_t> GetThreadContextWow64(const MinidumpThread &td);
const MinidumpSystemInfo *GetSystemInfo();
ArchSpec GetArchitecture();
const MinidumpMiscInfo *GetMiscInfo();
llvm::Optional<LinuxProcStatus> GetLinuxProcStatus();
llvm::Optional<lldb::pid_t> GetPid();
llvm::ArrayRef<MinidumpModule> GetModuleList();
// There are cases in which there is more than one record in the ModuleList
// for the same module name.(e.g. when the binary has non contiguous segments)
// So this function returns a filtered module list - if it finds records that
// have the same name, it keeps the copy with the lowest load address.
std::vector<const MinidumpModule *> GetFilteredModuleList();
const MinidumpExceptionStream *GetExceptionStream();
llvm::Optional<Range> FindMemoryRange(lldb::addr_t addr);
llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t);
private:
lldb::DataBufferSP m_data_sp;
const MinidumpHeader *m_header;
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map;
MinidumpParser(
const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map);
};
} // end namespace minidump
} // end namespace lldb_private
#endif // liblldb_MinidumpParser_h_

View File

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

View File

@@ -0,0 +1,470 @@
//===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_MinidumpTypes_h_
#define liblldb_MinidumpTypes_h_
// Project includes
// Other libraries and framework includes
#include "lldb/Utility/Status.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Endian.h"
// C includes
// C++ includes
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
// https://chromium.googlesource.com/breakpad/breakpad/
namespace lldb_private {
namespace minidump {
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
enum class MinidumpHeaderConstants : uint32_t {
Signature = 0x504d444d, // 'PMDM'
Version = 0x0000a793, // 42899
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Signature)
};
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx
enum class MinidumpStreamType : uint32_t {
Unused = 0,
Reserved0 = 1,
Reserved1 = 2,
ThreadList = 3,
ModuleList = 4,
MemoryList = 5,
Exception = 6,
SystemInfo = 7,
ThreadExList = 8,
Memory64List = 9,
CommentA = 10,
CommentW = 11,
HandleData = 12,
FunctionTable = 13,
UnloadedModuleList = 14,
MiscInfo = 15,
MemoryInfoList = 16,
ThreadInfoList = 17,
HandleOperationList = 18,
Token = 19,
JavascriptData = 20,
SystemMemoryInfo = 21,
ProcessVMCounters = 22,
LastReserved = 0x0000ffff,
/* Breakpad extension types. 0x4767 = "Gg" */
BreakpadInfo = 0x47670001,
AssertionInfo = 0x47670002,
/* These are additional minidump stream values which are specific to
* the linux breakpad implementation. */
LinuxCPUInfo = 0x47670003, /* /proc/cpuinfo */
LinuxProcStatus = 0x47670004, /* /proc/$x/status */
LinuxLSBRelease = 0x47670005, /* /etc/lsb-release */
LinuxCMDLine = 0x47670006, /* /proc/$x/cmdline */
LinuxEnviron = 0x47670007, /* /proc/$x/environ */
LinuxAuxv = 0x47670008, /* /proc/$x/auxv */
LinuxMaps = 0x47670009, /* /proc/$x/maps */
LinuxDSODebug = 0x4767000A
};
// for MinidumpSystemInfo.processor_arch
enum class MinidumpCPUArchitecture : uint16_t {
X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */
MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */
Alpha = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */
PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */
SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */
ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */
IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */
Alpha64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */
MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL
* (Microsoft Intermediate Language) */
AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */
X86Win64 = 10, /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
SPARC = 0x8001, /* Breakpad-defined value for SPARC */
PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */
MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
Unknown = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
};
// for MinidumpSystemInfo.platform_id
enum class MinidumpOSPlatform : uint32_t {
Win32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */
Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
Win32NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
Win32CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
* (Windows CE, Windows Mobile, "Handheld") */
/* The following values are Breakpad-defined. */
Unix = 0x8000, /* Generic Unix-ish */
MacOSX = 0x8101, /* Mac OS X/Darwin */
IOS = 0x8102, /* iOS */
Linux = 0x8201, /* Linux */
Solaris = 0x8202, /* Solaris */
Android = 0x8203, /* Android */
PS3 = 0x8204, /* PS3 */
NaCl = 0x8205 /* Native Client (NaCl) */
};
// For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps.
// This matches the Linux kernel definitions from <asm/hwcaps.h>
enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t {
SWP = (1 << 0),
Half = (1 << 1),
Thumb = (1 << 2),
_26BIT = (1 << 3),
FastMult = (1 << 4),
FPA = (1 << 5),
VFP = (1 << 6),
EDSP = (1 << 7),
Java = (1 << 8),
IWMMXT = (1 << 9),
Crunch = (1 << 10),
ThumbEE = (1 << 11),
Neon = (1 << 12),
VFPv3 = (1 << 13),
VFPv3D16 = (1 << 14),
TLS = (1 << 15),
VFPv4 = (1 << 16),
IDIVA = (1 << 17),
IDIVT = (1 << 18),
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)
};
enum class MinidumpMiscInfoFlags : uint32_t {
ProcessID = (1 << 0),
ProcessTimes = (1 << 1),
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
};
template <typename T>
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;
}
// parse a MinidumpString which is with UTF-16
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680395(v=vs.85).aspx
llvm::Optional<std::string> parseMinidumpString(llvm::ArrayRef<uint8_t> &data);
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx
struct MinidumpHeader {
llvm::support::ulittle32_t signature;
llvm::support::ulittle32_t
version; // The high 16 bits of version field are implementation specific
llvm::support::ulittle32_t streams_count;
llvm::support::ulittle32_t
stream_directory_rva; // offset of the stream directory
llvm::support::ulittle32_t checksum;
llvm::support::ulittle32_t time_date_stamp; // time_t format
llvm::support::ulittle64_t flags;
static const MinidumpHeader *Parse(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpHeader) == 32,
"sizeof MinidumpHeader is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383.aspx
struct MinidumpLocationDescriptor {
llvm::support::ulittle32_t data_size;
llvm::support::ulittle32_t rva;
};
static_assert(sizeof(MinidumpLocationDescriptor) == 8,
"sizeof MinidumpLocationDescriptor is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx
struct MinidumpMemoryDescriptor {
llvm::support::ulittle64_t start_of_memory_range;
MinidumpLocationDescriptor memory;
static llvm::ArrayRef<MinidumpMemoryDescriptor>
ParseMemoryList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryDescriptor) == 16,
"sizeof MinidumpMemoryDescriptor is not correct!");
struct MinidumpMemoryDescriptor64 {
llvm::support::ulittle64_t start_of_memory_range;
llvm::support::ulittle64_t data_size;
static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
ParseMemory64List(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryDescriptor64) == 16,
"sizeof MinidumpMemoryDescriptor64 is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx
struct MinidumpDirectory {
llvm::support::ulittle32_t stream_type;
MinidumpLocationDescriptor location;
};
static_assert(sizeof(MinidumpDirectory) == 12,
"sizeof MinidumpDirectory is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx
struct MinidumpMemoryInfoListHeader {
llvm::support::ulittle32_t size_of_header;
llvm::support::ulittle32_t size_of_entry;
llvm::support::ulittle64_t num_of_entries;
};
static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16,
"sizeof MinidumpMemoryInfoListHeader is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx
struct MinidumpMemoryInfo {
llvm::support::ulittle64_t base_address;
llvm::support::ulittle64_t allocation_base;
llvm::support::ulittle32_t allocation_protect;
llvm::support::ulittle32_t alignment1;
llvm::support::ulittle64_t region_size;
llvm::support::ulittle32_t state;
llvm::support::ulittle32_t protect;
llvm::support::ulittle32_t type;
llvm::support::ulittle32_t alignment2;
static std::vector<const MinidumpMemoryInfo *>
ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryInfo) == 48,
"sizeof MinidumpMemoryInfo is not correct!");
enum class MinidumpMemoryInfoState : uint32_t {
MemCommit = 0x1000,
MemFree = 0x10000,
MemReserve = 0x2000,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)
};
enum class MinidumpMemoryInfoType : uint32_t {
MemImage = 0x1000000,
MemMapped = 0x40000,
MemPrivate = 0x20000,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)
};
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx
enum class MinidumpMemoryProtectionContants : uint32_t {
PageExecute = 0x10,
PageExecuteRead = 0x20,
PageExecuteReadWrite = 0x40,
PageExecuteWriteCopy = 0x80,
PageNoAccess = 0x01,
PageReadOnly = 0x02,
PageReadWrite = 0x04,
PageWriteCopy = 0x08,
PageTargetsInvalid = 0x40000000,
PageTargetsNoUpdate = 0x40000000,
PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite |
PageWriteCopy,
PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite |
PageExecuteWriteCopy,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)
};
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
struct MinidumpThread {
llvm::support::ulittle32_t thread_id;
llvm::support::ulittle32_t suspend_count;
llvm::support::ulittle32_t priority_class;
llvm::support::ulittle32_t priority;
llvm::support::ulittle64_t teb;
MinidumpMemoryDescriptor stack;
MinidumpLocationDescriptor thread_context;
static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data);
static llvm::ArrayRef<MinidumpThread>
ParseThreadList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpThread) == 48,
"sizeof MinidumpThread is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
union MinidumpCPUInfo {
struct {
llvm::support::ulittle32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
llvm::support::ulittle32_t version_information; /* cpuid 1: eax */
llvm::support::ulittle32_t feature_information; /* cpuid 1: edx */
llvm::support::ulittle32_t
amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
} x86_cpu_info;
struct {
llvm::support::ulittle32_t cpuid;
llvm::support::ulittle32_t elf_hwcaps; /* linux specific, 0 otherwise */
} arm_cpu_info;
struct {
llvm::support::ulittle64_t processor_features[2];
} other_cpu_info;
};
static_assert(sizeof(MinidumpCPUInfo) == 24,
"sizeof MinidumpCPUInfo is not correct!");
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
struct MinidumpSystemInfo {
llvm::support::ulittle16_t processor_arch;
llvm::support::ulittle16_t processor_level;
llvm::support::ulittle16_t processor_revision;
uint8_t number_of_processors;
uint8_t product_type;
llvm::support::ulittle32_t major_version;
llvm::support::ulittle32_t minor_version;
llvm::support::ulittle32_t build_number;
llvm::support::ulittle32_t platform_id;
llvm::support::ulittle32_t csd_version_rva;
llvm::support::ulittle16_t suit_mask;
llvm::support::ulittle16_t reserved2;
MinidumpCPUInfo cpu;
static const MinidumpSystemInfo *Parse(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpSystemInfo) == 56,
"sizeof MinidumpSystemInfo is not correct!");
// TODO misc2, misc3 ?
// Reference:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx
struct MinidumpMiscInfo {
llvm::support::ulittle32_t size;
// flags1 represents what info in the struct is valid
llvm::support::ulittle32_t flags1;
llvm::support::ulittle32_t process_id;
llvm::support::ulittle32_t process_create_time;
llvm::support::ulittle32_t process_user_time;
llvm::support::ulittle32_t process_kernel_time;
static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data);
llvm::Optional<lldb::pid_t> GetPid() const;
};
static_assert(sizeof(MinidumpMiscInfo) == 24,
"sizeof MinidumpMiscInfo is not correct!");
// The /proc/pid/status is saved as an ascii string in the file
class LinuxProcStatus {
public:
llvm::StringRef proc_status;
lldb::pid_t pid;
static llvm::Optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data);
lldb::pid_t GetPid() const;
private:
LinuxProcStatus() = default;
};
// MinidumpModule stuff
struct MinidumpVSFixedFileInfo {
llvm::support::ulittle32_t signature;
llvm::support::ulittle32_t struct_version;
llvm::support::ulittle32_t file_version_hi;
llvm::support::ulittle32_t file_version_lo;
llvm::support::ulittle32_t product_version_hi;
llvm::support::ulittle32_t product_version_lo;
// file_flags_mask - identifies valid bits in fileFlags
llvm::support::ulittle32_t file_flags_mask;
llvm::support::ulittle32_t file_flags;
llvm::support::ulittle32_t file_os;
llvm::support::ulittle32_t file_type;
llvm::support::ulittle32_t file_subtype;
llvm::support::ulittle32_t file_date_hi;
llvm::support::ulittle32_t file_date_lo;
};
static_assert(sizeof(MinidumpVSFixedFileInfo) == 52,
"sizeof MinidumpVSFixedFileInfo is not correct!");
struct MinidumpModule {
llvm::support::ulittle64_t base_of_image;
llvm::support::ulittle32_t size_of_image;
llvm::support::ulittle32_t checksum;
llvm::support::ulittle32_t time_date_stamp;
llvm::support::ulittle32_t module_name_rva;
MinidumpVSFixedFileInfo version_info;
MinidumpLocationDescriptor CV_record;
MinidumpLocationDescriptor misc_record;
llvm::support::ulittle32_t reserved0[2];
llvm::support::ulittle32_t reserved1[2];
static const MinidumpModule *Parse(llvm::ArrayRef<uint8_t> &data);
static llvm::ArrayRef<MinidumpModule>
ParseModuleList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpModule) == 108,
"sizeof MinidumpVSFixedFileInfo is not correct!");
// Exception stuff
struct MinidumpException {
enum : unsigned {
ExceptonInfoMaxParams = 15,
DumpRequested = 0xFFFFFFFF,
};
llvm::support::ulittle32_t exception_code;
llvm::support::ulittle32_t exception_flags;
llvm::support::ulittle64_t exception_record;
llvm::support::ulittle64_t exception_address;
llvm::support::ulittle32_t number_parameters;
llvm::support::ulittle32_t unused_alignment;
llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams];
};
static_assert(sizeof(MinidumpException) == 152,
"sizeof MinidumpException is not correct!");
struct MinidumpExceptionStream {
llvm::support::ulittle32_t thread_id;
llvm::support::ulittle32_t alignment;
MinidumpException exception_record;
MinidumpLocationDescriptor thread_context;
static const MinidumpExceptionStream *Parse(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpExceptionStream) == 168,
"sizeof MinidumpExceptionStream is not correct!");
} // namespace minidump
} // namespace lldb_private
#endif // liblldb_MinidumpTypes_h_

View File

@@ -0,0 +1,37 @@
//===-- NtStructures.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_Plugins_Process_Minidump_NtStructures_h_
#define liblldb_Plugins_Process_Minidump_NtStructures_h_
#include "llvm/Support/Endian.h"
namespace lldb_private {
namespace minidump {
// This describes the layout of a TEB (Thread Environment Block) for a 64-bit
// process. It's adapted from the 32-bit TEB in winternl.h. Currently, we care
// only about the position of the tls_slots.
struct TEB64 {
llvm::support::ulittle64_t reserved1[12];
llvm::support::ulittle64_t process_environment_block;
llvm::support::ulittle64_t reserved2[399];
uint8_t reserved3[1952];
llvm::support::ulittle64_t tls_slots[64];
uint8_t reserved4[8];
llvm::support::ulittle64_t reserved5[26];
llvm::support::ulittle64_t reserved_for_ole; // Windows 2000 only
llvm::support::ulittle64_t reserved6[4];
llvm::support::ulittle64_t tls_expansion_slots;
};
#endif // liblldb_Plugins_Process_Minidump_NtStructures_h_
} // namespace minidump
} // namespace lldb_private

View File

@@ -0,0 +1,309 @@
//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Project includes
#include "ProcessMinidump.h"
#include "ThreadMinidump.h"
// Other libraries and framework includes
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/State.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/DataBufferLLVM.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Threading.h"
// C includes
// C++ includes
using namespace lldb_private;
using namespace minidump;
ConstString ProcessMinidump::GetPluginNameStatic() {
static ConstString g_name("minidump");
return g_name;
}
const char *ProcessMinidump::GetPluginDescriptionStatic() {
return "Minidump plug-in.";
}
lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec *crash_file) {
if (!crash_file)
return nullptr;
lldb::ProcessSP process_sp;
// Read enough data for the Minidump header
constexpr size_t header_size = sizeof(MinidumpHeader);
auto DataPtr =
DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), header_size, 0);
if (!DataPtr)
return nullptr;
assert(DataPtr->GetByteSize() == header_size);
// first, only try to parse the header, beacuse we need to be fast
llvm::ArrayRef<uint8_t> HeaderBytes = DataPtr->GetData();
const MinidumpHeader *header = MinidumpHeader::Parse(HeaderBytes);
if (header == nullptr)
return nullptr;
auto AllData = DataBufferLLVM::CreateSliceFromPath(crash_file->GetPath(), -1, 0);
if (!AllData)
return nullptr;
auto minidump_parser = MinidumpParser::Create(AllData);
// check if the parser object is valid
if (!minidump_parser)
return nullptr;
return std::make_shared<ProcessMinidump>(target_sp, listener_sp, *crash_file,
minidump_parser.getValue());
}
bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) {
return true;
}
ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec &core_file,
MinidumpParser minidump_parser)
: Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
m_core_file(core_file), m_is_wow64(false) {}
ProcessMinidump::~ProcessMinidump() {
Clear();
// We need to call finalize on the process before destroying ourselves
// to make sure all of the broadcaster cleanup goes as planned. If we
// destruct this class, then Process::~Process() might have problems
// trying to fully destroy the broadcaster.
Finalize();
}
void ProcessMinidump::Initialize() {
static 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() {
Status error;
m_thread_list = m_minidump_parser.GetThreads();
m_active_exception = m_minidump_parser.GetExceptionStream();
ReadModuleList();
GetTarget().SetArchitecture(GetArchitecture());
llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
if (!pid) {
error.SetErrorString("failed to parse PID");
return error;
}
SetID(pid.getValue());
return error;
}
DynamicLoader *ProcessMinidump::GetDynamicLoader() {
if (m_dyld_ap.get() == nullptr)
m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr));
return m_dyld_ap.get();
}
ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
Status ProcessMinidump::DoDestroy() { return Status(); }
void ProcessMinidump::RefreshStateAfterStop() {
if (!m_active_exception)
return;
if (m_active_exception->exception_record.exception_code ==
MinidumpException::DumpRequested) {
return;
}
lldb::StopInfoSP stop_info;
lldb::ThreadSP stop_thread;
Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
stop_thread = Process::m_thread_list.GetSelectedThread();
ArchSpec arch = GetArchitecture();
if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
stop_info = StopInfo::CreateStopReasonWithSignal(
*stop_thread, m_active_exception->exception_record.exception_code);
} else {
std::string desc;
llvm::raw_string_ostream desc_stream(desc);
desc_stream << "Exception "
<< llvm::format_hex(
m_active_exception->exception_record.exception_code, 8)
<< " encountered at address "
<< llvm::format_hex(
m_active_exception->exception_record.exception_address,
8);
stop_info = StopInfo::CreateStopReasonWithException(
*stop_thread, desc_stream.str().c_str());
}
stop_thread->SetStopInfo(stop_info);
}
bool ProcessMinidump::IsAlive() { return true; }
bool ProcessMinidump::WarnBeforeDetach() const { return false; }
size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
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);
}
Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) {
Status error;
auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
if (!info) {
error.SetErrorString("No valid MemoryRegionInfo found!");
return error;
}
range_info = info.getValue();
return error;
}
void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) {
uint32_t num_threads = 0;
if (m_thread_list.size() > 0)
num_threads = m_thread_list.size();
for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
llvm::ArrayRef<uint8_t> context;
if (!m_is_wow64)
context = m_minidump_parser.GetThreadContext(m_thread_list[tid]);
else
context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]);
lldb::ThreadSP thread_sp(
new ThreadMinidump(*this, m_thread_list[tid], context));
new_thread_list.AddThread(thread_sp);
}
return new_thread_list.GetSize(false) > 0;
}
void ProcessMinidump::ReadModuleList() {
std::vector<const MinidumpModule *> filtered_modules =
m_minidump_parser.GetFilteredModuleList();
for (auto module : filtered_modules) {
llvm::Optional<std::string> name =
m_minidump_parser.GetMinidumpString(module->module_name_rva);
if (!name)
continue;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
if (log) {
log->Printf("ProcessMinidump::%s found module: name: %s %#010" PRIx64
"-%#010" PRIx64 " size: %" PRIu32,
__FUNCTION__, name.getValue().c_str(),
uint64_t(module->base_of_image),
module->base_of_image + module->size_of_image,
uint32_t(module->size_of_image));
}
// check if the process is wow64 - a 32 bit windows process running on a
// 64 bit windows
if (llvm::StringRef(name.getValue()).endswith_lower("wow64.dll")) {
m_is_wow64 = true;
}
const auto file_spec = FileSpec(name.getValue(), true);
ModuleSpec module_spec = file_spec;
Status error;
lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
if (!module_sp || error.Fail()) {
continue;
}
if (log) {
log->Printf("ProcessMinidump::%s load module: name: %s", __FUNCTION__,
name.getValue().c_str());
}
bool load_addr_changed = false;
module_sp->SetLoadAddress(GetTarget(), module->base_of_image, false,
load_addr_changed);
}
}
bool ProcessMinidump::GetProcessInfo(ProcessInstanceInfo &info) {
info.Clear();
info.SetProcessID(GetID());
info.SetArchitecture(GetArchitecture());
lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
if (module_sp) {
const bool add_exe_file_as_first_arg = false;
info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
add_exe_file_as_first_arg);
}
return true;
}

View File

@@ -0,0 +1,113 @@
//===-- ProcessMinidump.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ProcessMinidump_h_
#define liblldb_ProcessMinidump_h_
// Project includes
#include "MinidumpParser.h"
#include "MinidumpTypes.h"
// Other libraries and framework includes
#include "lldb/Target/Process.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"
// C Includes
// C++ Includes
namespace lldb_private {
namespace minidump {
class ProcessMinidump : public Process {
public:
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec *crash_file_path);
static void Initialize();
static void Terminate();
static ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
const FileSpec &core_file, MinidumpParser minidump_parser);
~ProcessMinidump() override;
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
Status DoLoadCore() override;
DynamicLoader *GetDynamicLoader() override;
ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
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 GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) override;
bool GetProcessInfo(ProcessInstanceInfo &info) override;
Status WillResume() override {
Status error;
error.SetErrorStringWithFormat(
"error: %s does not support resuming processes",
GetPluginName().GetCString());
return error;
}
MinidumpParser m_minidump_parser;
protected:
void Clear();
bool UpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override;
void ReadModuleList();
private:
FileSpec m_core_file;
llvm::ArrayRef<MinidumpThread> m_thread_list;
const MinidumpExceptionStream *m_active_exception;
bool m_is_wow64;
};
} // namespace minidump
} // namespace lldb_private
#endif // liblldb_ProcessMinidump_h_

View File

@@ -0,0 +1,99 @@
//===-- RegisterContextMinidump_x86_32.cpp ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Project includes
#include "RegisterContextMinidump_x86_32.h"
// Other libraries and framework includes
#include "lldb/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::DataBufferSP result_context_buf(
new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
uint8_t *result_base = result_context_buf->GetBytes();
if (source_data.size() < sizeof(MinidumpContext_x86_32))
return nullptr;
const MinidumpContext_x86_32 *context;
consumeObject(source_data, context);
const MinidumpContext_x86_32_Flags context_flags =
static_cast<MinidumpContext_x86_32_Flags>(
static_cast<uint32_t>(context->context_flags));
auto x86_32_Flag = MinidumpContext_x86_32_Flags::x86_32_Flag;
auto ControlFlag = MinidumpContext_x86_32_Flags::Control;
auto IntegerFlag = MinidumpContext_x86_32_Flags::Integer;
auto SegmentsFlag = MinidumpContext_x86_32_Flags::Segments;
if ((context_flags & x86_32_Flag) != x86_32_Flag) {
return nullptr;
}
if ((context_flags & ControlFlag) == ControlFlag) {
writeRegister(&context->ebp,
reg_info[lldb_ebp_i386].mutable_data(result_base));
writeRegister(&context->eip,
reg_info[lldb_eip_i386].mutable_data(result_base));
writeRegister(&context->cs,
reg_info[lldb_cs_i386].mutable_data(result_base));
writeRegister(&context->eflags,
reg_info[lldb_eflags_i386].mutable_data(result_base));
writeRegister(&context->esp,
reg_info[lldb_esp_i386].mutable_data(result_base));
writeRegister(&context->ss,
reg_info[lldb_ss_i386].mutable_data(result_base));
}
if ((context_flags & SegmentsFlag) == SegmentsFlag) {
writeRegister(&context->ds,
reg_info[lldb_ds_i386].mutable_data(result_base));
writeRegister(&context->es,
reg_info[lldb_es_i386].mutable_data(result_base));
writeRegister(&context->fs,
reg_info[lldb_fs_i386].mutable_data(result_base));
writeRegister(&context->gs,
reg_info[lldb_gs_i386].mutable_data(result_base));
}
if ((context_flags & IntegerFlag) == IntegerFlag) {
writeRegister(&context->eax,
reg_info[lldb_eax_i386].mutable_data(result_base));
writeRegister(&context->ecx,
reg_info[lldb_ecx_i386].mutable_data(result_base));
writeRegister(&context->edx,
reg_info[lldb_edx_i386].mutable_data(result_base));
writeRegister(&context->ebx,
reg_info[lldb_ebx_i386].mutable_data(result_base));
writeRegister(&context->esi,
reg_info[lldb_esi_i386].mutable_data(result_base));
writeRegister(&context->edi,
reg_info[lldb_edi_i386].mutable_data(result_base));
}
// TODO parse the floating point registers
return result_context_buf;
}

View File

@@ -0,0 +1,138 @@
//===-- RegisterContextMinidump_x86_32.h ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextMinidump_x86_32_h_
#define liblldb_RegisterContextMinidump_x86_32_h_
// Project includes
#include "MinidumpTypes.h"
// Other libraries and framework includes
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#include "lldb/Target/RegisterContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/Support/Endian.h"
// C includes
// C++ includes
namespace lldb_private {
namespace minidump {
// This function receives an ArrayRef pointing to the bytes of the Minidump
// register context and returns a DataBuffer that's ordered by the offsets
// specified in the RegisterInfoInterface argument
// This way we can reuse the already existing register contexts
lldb::DataBufferSP
ConvertMinidumpContext_x86_32(llvm::ArrayRef<uint8_t> source_data,
RegisterInfoInterface *target_reg_interface);
// Reference: see breakpad/crashpad source or WinNT.h
struct MinidumpFloatingSaveAreaX86 {
llvm::support::ulittle32_t control_word;
llvm::support::ulittle32_t status_word;
llvm::support::ulittle32_t tag_word;
llvm::support::ulittle32_t error_offset;
llvm::support::ulittle32_t error_selector;
llvm::support::ulittle32_t data_offset;
llvm::support::ulittle32_t data_selector;
enum {
RegisterAreaSize = 80,
};
// register_area contains eight 80-bit (x87 "long double") quantities for
// floating-point registers %st0 (%mm0) through %st7 (%mm7).
uint8_t register_area[RegisterAreaSize];
llvm::support::ulittle32_t cr0_npx_state;
};
struct MinidumpContext_x86_32 {
// The context_flags field determines which parts
// of the structure are populated (have valid values)
llvm::support::ulittle32_t context_flags;
// The next 6 registers are included with
// MinidumpContext_x86_32_Flags::DebugRegisters
llvm::support::ulittle32_t dr0;
llvm::support::ulittle32_t dr1;
llvm::support::ulittle32_t dr2;
llvm::support::ulittle32_t dr3;
llvm::support::ulittle32_t dr6;
llvm::support::ulittle32_t dr7;
// The next field is included with
// MinidumpContext_x86_32_Flags::FloatingPoint
MinidumpFloatingSaveAreaX86 float_save;
// The next 4 registers are included with
// MinidumpContext_x86_32_Flags::Segments
llvm::support::ulittle32_t gs;
llvm::support::ulittle32_t fs;
llvm::support::ulittle32_t es;
llvm::support::ulittle32_t ds;
// The next 6 registers are included with
// MinidumpContext_x86_32_Flags::Integer
llvm::support::ulittle32_t edi;
llvm::support::ulittle32_t esi;
llvm::support::ulittle32_t ebx;
llvm::support::ulittle32_t edx;
llvm::support::ulittle32_t ecx;
llvm::support::ulittle32_t eax;
// The next 6 registers are included with
// MinidumpContext_x86_32_Flags::Control
llvm::support::ulittle32_t ebp;
llvm::support::ulittle32_t eip;
llvm::support::ulittle32_t cs; // WinNT.h says "must be sanitized"
llvm::support::ulittle32_t eflags; // WinNT.h says "must be sanitized"
llvm::support::ulittle32_t esp;
llvm::support::ulittle32_t ss;
// The next field is included with
// MinidumpContext_x86_32_Flags::ExtendedRegisters
// It contains vector (MMX/SSE) registers. It it laid out in the
// format used by the fxsave and fsrstor instructions, so it includes
// a copy of the x87 floating-point registers as well. See FXSAVE in
// "Intel Architecture Software Developer's Manual, Volume 2."
enum {
ExtendedRegistersSize = 512,
};
uint8_t extended_registers[ExtendedRegistersSize];
};
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
// For context_flags. These values indicate the type of
// context stored in the structure. The high 24 bits identify the CPU, the
// low 8 bits identify the type of context saved.
enum class MinidumpContext_x86_32_Flags : uint32_t {
x86_32_Flag = 0x00010000, // CONTEXT_i386, CONTEXT_i486
Control = x86_32_Flag | 0x00000001,
Integer = x86_32_Flag | 0x00000002,
Segments = x86_32_Flag | 0x00000004,
FloatingPoint = x86_32_Flag | 0x00000008,
DebugRegisters = x86_32_Flag | 0x00000010,
ExtendedRegisters = x86_32_Flag | 0x00000020,
XState = x86_32_Flag | 0x00000040,
Full = Control | Integer | Segments,
All = Full | FloatingPoint | DebugRegisters | ExtendedRegisters,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
};
} // end namespace minidump
} // end namespace lldb_private
#endif // liblldb_RegisterContextMinidump_x86_32_h_

View File

@@ -0,0 +1,113 @@
//===-- RegisterContextMinidump_x86_64.cpp ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Project includes
#include "RegisterContextMinidump_x86_64.h"
// Other libraries and framework includes
#include "lldb/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::DataBufferSP result_context_buf(
new DataBufferHeap(target_reg_interface->GetGPRSize(), 0));
uint8_t *result_base = result_context_buf->GetBytes();
if (source_data.size() < sizeof(MinidumpContext_x86_64))
return nullptr;
const MinidumpContext_x86_64 *context;
consumeObject(source_data, context);
const MinidumpContext_x86_64_Flags context_flags =
static_cast<MinidumpContext_x86_64_Flags>(
static_cast<uint32_t>(context->context_flags));
auto x86_64_Flag = MinidumpContext_x86_64_Flags::x86_64_Flag;
auto ControlFlag = MinidumpContext_x86_64_Flags::Control;
auto IntegerFlag = MinidumpContext_x86_64_Flags::Integer;
auto SegmentsFlag = MinidumpContext_x86_64_Flags::Segments;
if ((context_flags & x86_64_Flag) != x86_64_Flag)
return nullptr;
if ((context_flags & ControlFlag) == ControlFlag) {
writeRegister(&context->cs, result_base, reg_info[lldb_cs_x86_64]);
writeRegister(&context->ss, result_base, reg_info[lldb_ss_x86_64]);
writeRegister(&context->eflags, result_base, reg_info[lldb_rflags_x86_64]);
writeRegister(&context->rsp, result_base, reg_info[lldb_rsp_x86_64]);
writeRegister(&context->rip, result_base, reg_info[lldb_rip_x86_64]);
}
if ((context_flags & SegmentsFlag) == SegmentsFlag) {
writeRegister(&context->ds, result_base, reg_info[lldb_ds_x86_64]);
writeRegister(&context->es, result_base, reg_info[lldb_es_x86_64]);
writeRegister(&context->fs, result_base, reg_info[lldb_fs_x86_64]);
writeRegister(&context->gs, result_base, reg_info[lldb_gs_x86_64]);
}
if ((context_flags & IntegerFlag) == IntegerFlag) {
writeRegister(&context->rax, result_base, reg_info[lldb_rax_x86_64]);
writeRegister(&context->rcx, result_base, reg_info[lldb_rcx_x86_64]);
writeRegister(&context->rdx, result_base, reg_info[lldb_rdx_x86_64]);
writeRegister(&context->rbx, result_base, reg_info[lldb_rbx_x86_64]);
writeRegister(&context->rbp, result_base, reg_info[lldb_rbp_x86_64]);
writeRegister(&context->rsi, result_base, reg_info[lldb_rsi_x86_64]);
writeRegister(&context->rdi, result_base, reg_info[lldb_rdi_x86_64]);
writeRegister(&context->r8, result_base, reg_info[lldb_r8_x86_64]);
writeRegister(&context->r9, result_base, reg_info[lldb_r9_x86_64]);
writeRegister(&context->r10, result_base, reg_info[lldb_r10_x86_64]);
writeRegister(&context->r11, result_base, reg_info[lldb_r11_x86_64]);
writeRegister(&context->r12, result_base, reg_info[lldb_r12_x86_64]);
writeRegister(&context->r13, result_base, reg_info[lldb_r13_x86_64]);
writeRegister(&context->r14, result_base, reg_info[lldb_r14_x86_64]);
writeRegister(&context->r15, result_base, reg_info[lldb_r15_x86_64]);
}
// TODO parse the floating point registers
return result_context_buf;
}

View File

@@ -0,0 +1,183 @@
//===-- RegisterContextMinidump_x86_64.h ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextMinidump_h_
#define liblldb_RegisterContextMinidump_h_
// Project includes
#include "MinidumpTypes.h"
// Other libraries and framework includes
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#include "lldb/Target/RegisterContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/Support/Endian.h"
// C includes
// C++ includes
namespace lldb_private {
namespace minidump {
// This function receives an ArrayRef pointing to the bytes of the Minidump
// register context and returns a DataBuffer that's ordered by the offsets
// specified in the RegisterInfoInterface argument
// This way we can reuse the already existing register contexts
lldb::DataBufferSP
ConvertMinidumpContext_x86_64(llvm::ArrayRef<uint8_t> source_data,
RegisterInfoInterface *target_reg_interface);
struct Uint128 {
llvm::support::ulittle64_t high;
llvm::support::ulittle64_t low;
};
// Reference: see breakpad/crashpad source or WinNT.h
struct MinidumpXMMSaveArea32AMD64 {
llvm::support::ulittle16_t control_word;
llvm::support::ulittle16_t status_word;
uint8_t tag_word;
uint8_t reserved1;
llvm::support::ulittle16_t error_opcode;
llvm::support::ulittle32_t error_offset;
llvm::support::ulittle16_t error_selector;
llvm::support::ulittle16_t reserved2;
llvm::support::ulittle32_t data_offset;
llvm::support::ulittle16_t data_selector;
llvm::support::ulittle16_t reserved3;
llvm::support::ulittle32_t mx_csr;
llvm::support::ulittle32_t mx_csr_mask;
Uint128 float_registers[8];
Uint128 xmm_registers[16];
uint8_t reserved4[96];
};
struct MinidumpContext_x86_64 {
// Register parameter home addresses.
llvm::support::ulittle64_t p1_home;
llvm::support::ulittle64_t p2_home;
llvm::support::ulittle64_t p3_home;
llvm::support::ulittle64_t p4_home;
llvm::support::ulittle64_t p5_home;
llvm::support::ulittle64_t p6_home;
// The context_flags field determines which parts
// of the structure are populated (have valid values)
llvm::support::ulittle32_t context_flags;
llvm::support::ulittle32_t mx_csr;
// The next register is included with
// MinidumpContext_x86_64_Flags::Control
llvm::support::ulittle16_t cs;
// The next 4 registers are included with
// MinidumpContext_x86_64_Flags::Segments
llvm::support::ulittle16_t ds;
llvm::support::ulittle16_t es;
llvm::support::ulittle16_t fs;
llvm::support::ulittle16_t gs;
// The next 2 registers are included with
// MinidumpContext_x86_64_Flags::Control
llvm::support::ulittle16_t ss;
llvm::support::ulittle32_t eflags;
// The next 6 registers are included with
// MinidumpContext_x86_64_Flags::DebugRegisters
llvm::support::ulittle64_t dr0;
llvm::support::ulittle64_t dr1;
llvm::support::ulittle64_t dr2;
llvm::support::ulittle64_t dr3;
llvm::support::ulittle64_t dr6;
llvm::support::ulittle64_t dr7;
// The next 4 registers are included with
// MinidumpContext_x86_64_Flags::Integer
llvm::support::ulittle64_t rax;
llvm::support::ulittle64_t rcx;
llvm::support::ulittle64_t rdx;
llvm::support::ulittle64_t rbx;
// The next register is included with
// MinidumpContext_x86_64_Flags::Control
llvm::support::ulittle64_t rsp;
// The next 11 registers are included with
// MinidumpContext_x86_64_Flags::Integer
llvm::support::ulittle64_t rbp;
llvm::support::ulittle64_t rsi;
llvm::support::ulittle64_t rdi;
llvm::support::ulittle64_t r8;
llvm::support::ulittle64_t r9;
llvm::support::ulittle64_t r10;
llvm::support::ulittle64_t r11;
llvm::support::ulittle64_t r12;
llvm::support::ulittle64_t r13;
llvm::support::ulittle64_t r14;
llvm::support::ulittle64_t r15;
// The next register is included with
// MinidumpContext_x86_64_Flags::Control
llvm::support::ulittle64_t rip;
// The next set of registers are included with
// MinidumpContext_x86_64_Flags:FloatingPoint
union FPR {
MinidumpXMMSaveArea32AMD64 flt_save;
struct {
Uint128 header[2];
Uint128 legacy[8];
Uint128 xmm[16];
} sse_registers;
};
enum {
VRCount = 26,
};
Uint128 vector_register[VRCount];
llvm::support::ulittle64_t vector_control;
// The next 5 registers are included with
// MinidumpContext_x86_64_Flags::DebugRegisters
llvm::support::ulittle64_t debug_control;
llvm::support::ulittle64_t last_branch_to_rip;
llvm::support::ulittle64_t last_branch_from_rip;
llvm::support::ulittle64_t last_exception_to_rip;
llvm::support::ulittle64_t last_exception_from_rip;
};
// For context_flags. These values indicate the type of
// context stored in the structure. The high 24 bits identify the CPU, the
// low 8 bits identify the type of context saved.
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
enum class MinidumpContext_x86_64_Flags : uint32_t {
x86_64_Flag = 0x00100000,
Control = x86_64_Flag | 0x00000001,
Integer = x86_64_Flag | 0x00000002,
Segments = x86_64_Flag | 0x00000004,
FloatingPoint = x86_64_Flag | 0x00000008,
DebugRegisters = x86_64_Flag | 0x00000010,
XState = x86_64_Flag | 0x00000040,
Full = Control | Integer | FloatingPoint,
All = Full | Segments | DebugRegisters,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ All)
};
} // end namespace minidump
} // end namespace lldb_private
#endif // liblldb_RegisterContextMinidump_h_

View File

@@ -0,0 +1,110 @@
//===-- ThreadMinidump.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Project includes
#include "ThreadMinidump.h"
#include "ProcessMinidump.h"
#include "RegisterContextMinidump_x86_32.h"
#include "RegisterContextMinidump_x86_64.h"
// Other libraries and framework includes
#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h"
#include "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"
// C Includes
// C++ Includes
using namespace lldb;
using namespace lldb_private;
using namespace minidump;
ThreadMinidump::ThreadMinidump(Process &process, const MinidumpThread &td,
llvm::ArrayRef<uint8_t> gpregset_data)
: Thread(process, td.thread_id), m_thread_reg_ctx_sp(),
m_gpregset_data(gpregset_data) {}
ThreadMinidump::~ThreadMinidump() {}
void ThreadMinidump::RefreshStateAfterStop() {}
RegisterContextSP ThreadMinidump::GetRegisterContext() {
if (!m_reg_context_sp) {
m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
}
return m_reg_context_sp;
}
RegisterContextSP
ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) {
RegisterContextSP reg_ctx_sp;
uint32_t concrete_frame_idx = 0;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (frame)
concrete_frame_idx = frame->GetConcreteFrameIndex();
if (concrete_frame_idx == 0) {
if (m_thread_reg_ctx_sp)
return m_thread_reg_ctx_sp;
ProcessMinidump *process =
static_cast<ProcessMinidump *>(GetProcess().get());
ArchSpec arch = process->GetArchitecture();
RegisterInfoInterface *reg_interface = nullptr;
// TODO write other register contexts and add them here
switch (arch.GetMachine()) {
case llvm::Triple::x86: {
reg_interface = new RegisterContextLinux_i386(arch);
lldb::DataBufferSP buf =
ConvertMinidumpContext_x86_32(m_gpregset_data, reg_interface);
DataExtractor gpregset(buf, lldb::eByteOrderLittle, 4);
m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64(
*this, reg_interface, gpregset, {}));
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.reset(new RegisterContextCorePOSIX_x86_64(
*this, reg_interface, gpregset, {}));
break;
}
default:
break;
}
if (!reg_interface) {
if (log)
log->Printf("elf-core::%s:: Architecture(%d) not supported",
__FUNCTION__, arch.GetMachine());
assert(false && "Architecture not supported");
}
reg_ctx_sp = m_thread_reg_ctx_sp;
} else if (m_unwinder_ap) {
reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame);
}
return reg_ctx_sp;
}
bool ThreadMinidump::CalculateStopInfo() { return false; }

View File

@@ -0,0 +1,50 @@
//===-- ThreadMinidump.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ThreadMinidump_h_
#define liblldb_ThreadMinidump_h_
// Project includes
#include "MinidumpTypes.h"
// Other libraries and framework includes
#include "lldb/Target/Thread.h"
// C Includes
// C++ Includes
namespace lldb_private {
namespace minidump {
class ThreadMinidump : public Thread {
public:
ThreadMinidump(Process &process, const MinidumpThread &td,
llvm::ArrayRef<uint8_t> gpregset_data);
~ThreadMinidump() override;
void RefreshStateAfterStop() override;
lldb::RegisterContextSP GetRegisterContext() override;
lldb::RegisterContextSP
CreateRegisterContextForFrame(StackFrame *frame) override;
protected:
lldb::RegisterContextSP m_thread_reg_ctx_sp;
llvm::ArrayRef<uint8_t> m_gpregset_data;
bool CalculateStopInfo() override;
};
} // namespace minidump
} // namespace lldb_private
#endif // liblldb_ThreadMinidump_h_