Skip to content

Commit

Permalink
MinidumpParsing: pid, modules, exceptions, strings
Browse files Browse the repository at this point in the history
Summary:
Added parsing of the MiscInfo data stream.
The main member of it that we care about is the process_id
On Linux generated Minidump (from breakpad) we don't have
the MiscInfo, we have the /proc/$pid/status from where we can get the
pid.
Also parsing the module list - the list of all of the loaded
modules/shared libraries.
Parsing the exception stream.
Parsing MinidumpStrings.

I have unit tests for all of that.
Also added some tests using a Minidump generated from Windows tools (not
from breakpad)

Reviewers: labath, zturner

Subscribers: beanz, lldb-commits

Differential Revision: https://reviews.llvm.org/D24385

llvm-svn: 281348
  • Loading branch information
dvlahovski committed Sep 13, 2016
1 parent 45b4675 commit 1d2859e
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 69 deletions.
141 changes: 106 additions & 35 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -1,5 +1,4 @@
//===-- MinidumpParser.cpp ---------------------------------------*- C++
//-*-===//
//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
Expand Down Expand Up @@ -56,64 +55,61 @@ MinidumpParser::Create(const lldb::DataBufferSP &data_buf_sp) {
directory->location;
}

MinidumpParser parser(data_buf_sp, header, directory_map);
return llvm::Optional<MinidumpParser>(parser);
return MinidumpParser(data_buf_sp, header, std::move(directory_map));
}

MinidumpParser::MinidumpParser(
const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map)
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map)
: m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) {
}

lldb::offset_t MinidumpParser::GetByteSize() {
return m_data_sp->GetByteSize();
}

llvm::Optional<llvm::ArrayRef<uint8_t>>
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 llvm::None;
return {};

// check if there is enough data
if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
return llvm::None;
return {};

return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
iter->second.data_size);
}

llvm::ArrayRef<uint8_t> arr_ref(m_data_sp->GetBytes() + iter->second.rva,
iter->second.data_size);
return llvm::Optional<llvm::ArrayRef<uint8_t>>(arr_ref);
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::Optional<std::vector<const MinidumpThread *>>
MinidumpParser::GetThreads() {
llvm::Optional<llvm::ArrayRef<uint8_t>> data =
GetStream(MinidumpStreamType::ThreadList);
llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);

if (!data)
if (data.size() == 0)
return llvm::None;

return MinidumpThread::ParseThreadList(data.getValue());
return MinidumpThread::ParseThreadList(data);
}

const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
llvm::Optional<llvm::ArrayRef<uint8_t>> data =
GetStream(MinidumpStreamType::SystemInfo);
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);

if (!data)
if (data.size() == 0)
return nullptr;

return MinidumpSystemInfo::Parse(data.getValue());
return MinidumpSystemInfo::Parse(data);
}

ArchSpec MinidumpParser::GetArchitecture() {
ArchSpec arch_spec;
arch_spec.GetTriple().setOS(llvm::Triple::OSType::UnknownOS);
arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
arch_spec.GetTriple().setArch(llvm::Triple::ArchType::UnknownArch);

// TODO should we add the OS type here, or somewhere else ?

const MinidumpSystemInfo *system_info = GetSystemInfo();

if (!system_info)
Expand All @@ -122,35 +118,110 @@ ArchSpec MinidumpParser::GetArchitecture() {
// 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:
arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86);
triple.setArch(llvm::Triple::ArchType::x86);
break;
case MinidumpCPUArchitecture::AMD64:
arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64);
triple.setArch(llvm::Triple::ArchType::x86_64);
break;
case MinidumpCPUArchitecture::ARM:
arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm);
triple.setArch(llvm::Triple::ArchType::arm);
break;
case MinidumpCPUArchitecture::ARM64:
arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64);
triple.setArch(llvm::Triple::ArchType::aarch64);
break;
default:
triple.setArch(llvm::Triple::ArchType::UnknownArch);
break;
default:
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::Optional<llvm::ArrayRef<uint8_t>> data =
GetStream(MinidumpStreamType::MiscInfo);
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);
}

const MinidumpExceptionStream *MinidumpParser::GetExceptionStream() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::Exception);

if (!data)
if (data.size() == 0)
return nullptr;

return MinidumpMiscInfo::Parse(data.getValue());
return MinidumpExceptionStream::Parse(data);
}
23 changes: 16 additions & 7 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.h
Expand Up @@ -22,6 +22,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"

// C includes

Expand All @@ -40,26 +41,34 @@ class MinidumpParser {

lldb::offset_t GetByteSize();

llvm::Optional<llvm::ArrayRef<uint8_t>>
GetStream(MinidumpStreamType stream_type);
llvm::ArrayRef<uint8_t> GetStream(MinidumpStreamType stream_type);

llvm::Optional<std::vector<const MinidumpThread *>> GetThreads();
llvm::Optional<std::string> GetMinidumpString(uint32_t rva);

llvm::ArrayRef<MinidumpThread> GetThreads();

const MinidumpSystemInfo *GetSystemInfo();

ArchSpec GetArchitecture();

const MinidumpMiscInfo *GetMiscInfo();

llvm::Optional<LinuxProcStatus> GetLinuxProcStatus();

llvm::Optional<lldb::pid_t> GetPid();

llvm::ArrayRef<MinidumpModule> GetModuleList();

const MinidumpExceptionStream *GetExceptionStream();

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,
const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor>
&directory_map);
MinidumpParser(
const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header,
llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &&directory_map);
};

} // namespace minidump
Expand Down

0 comments on commit 1d2859e

Please sign in to comment.