MinidumpParsing: pid, modules, exceptions, strings

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
This commit is contained in:
Dimitar Vlahovski 2016-09-13 15:54:38 +00:00
parent 45b467523b
commit 1d2859ef6d
7 changed files with 412 additions and 69 deletions

View File

@ -1,5 +1,4 @@
//===-- MinidumpParser.cpp ---------------------------------------*- C++
//-*-===//
//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -56,13 +55,12 @@ 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) {
}
@ -70,50 +68,48 @@ 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 {};
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);
return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
iter->second.data_size);
}
llvm::Optional<std::vector<const MinidumpThread *>>
MinidumpParser::GetThreads() {
llvm::Optional<llvm::ArrayRef<uint8_t>> data =
GetStream(MinidumpStreamType::ThreadList);
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);
}
if (!data)
llvm::ArrayRef<MinidumpThread> MinidumpParser::GetThreads() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::ThreadList);
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)
@ -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)
if (data.size() == 0)
return nullptr;
return MinidumpMiscInfo::Parse(data.getValue());
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.size() == 0)
return nullptr;
return MinidumpExceptionStream::Parse(data);
}

View File

@ -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
@ -40,10 +41,11 @@ public:
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();
@ -51,15 +53,22 @@ public:
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

View File

@ -9,7 +9,6 @@
// Project includes
#include "MinidumpTypes.h"
#include "MinidumpParser.h"
// Other libraries and framework includes
// C includes
@ -40,6 +39,35 @@ const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) {
return header;
}
// Minidump string
llvm::Optional<std::string>
lldb_private::minidump::parseMinidumpString(llvm::ArrayRef<uint8_t> &data) {
std::string result;
const uint32_t *source_length;
Error error = consumeObject(data, source_length);
if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0)
return llvm::None;
auto source_start = reinterpret_cast<const 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<UTF8 *>(&result[0]);
const auto result_end = result_start + result.size();
ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end,
strictConversion);
const auto result_size =
std::distance(reinterpret_cast<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;
@ -50,24 +78,15 @@ const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) {
return thread;
}
llvm::Optional<std::vector<const MinidumpThread *>>
llvm::ArrayRef<MinidumpThread>
MinidumpThread::ParseThreadList(llvm::ArrayRef<uint8_t> &data) {
std::vector<const MinidumpThread *> thread_list;
const llvm::support::ulittle32_t *thread_count;
Error error = consumeObject(data, thread_count);
if (error.Fail())
return llvm::None;
if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
return {};
const MinidumpThread *thread;
for (uint32_t i = 0; i < *thread_count; ++i) {
thread = MinidumpThread::Parse(data);
if (thread == nullptr)
return llvm::None;
thread_list.push_back(thread);
}
return llvm::Optional<std::vector<const MinidumpThread *>>(thread_list);
return llvm::ArrayRef<MinidumpThread>(
reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
}
// MinidumpSystemInfo
@ -90,3 +109,70 @@ const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) {
return misc_info;
}
llvm::Optional<lldb::pid_t> MinidumpMiscInfo::GetPid() const {
uint32_t pid_flag =
static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID);
if (flags1 & pid_flag)
return llvm::Optional<lldb::pid_t>(process_id);
return llvm::None;
}
// Linux Proc Status
// it's stored as an ascii string in the file
llvm::Optional<LinuxProcStatus>
LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) {
LinuxProcStatus result;
result.proc_status =
llvm::StringRef(reinterpret_cast<const char *>(data.data()), data.size());
data = data.drop_front(data.size());
llvm::SmallVector<llvm::StringRef, 0> lines;
result.proc_status.split(lines, '\n', 42);
// /proc/$pid/status has 41 lines, but why not use 42?
for (auto line : lines) {
if (line.consume_front("Pid:")) {
line = line.trim();
if (!line.getAsInteger(10, result.pid))
return result;
}
}
return llvm::None;
}
lldb::pid_t LinuxProcStatus::GetPid() const { return pid; }
// Module stuff
const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpModule *module = nullptr;
Error error = consumeObject(data, module);
if (error.Fail())
return nullptr;
return module;
}
llvm::ArrayRef<MinidumpModule>
MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) {
const llvm::support::ulittle32_t *modules_count;
Error error = consumeObject(data, modules_count);
if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
return {};
return llvm::ArrayRef<MinidumpModule>(
reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
}
// Exception stuff
const MinidumpExceptionStream *
MinidumpExceptionStream::Parse(llvm::ArrayRef<uint8_t> &data) {
const MinidumpExceptionStream *exception_stream = nullptr;
Error error = consumeObject(data, exception_stream);
if (error.Fail())
return nullptr;
return exception_stream;
}

View File

@ -18,6 +18,9 @@
#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
@ -148,6 +151,12 @@ enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t {
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)
};
enum class MinidumpMiscInfoFlags : uint32_t {
ProcessID = (1 << 0),
ProcessTimes = (1 << 1),
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
};
template <typename T>
Error consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
Error error;
@ -161,6 +170,11 @@ Error consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
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 {
@ -219,7 +233,7 @@ struct MinidumpThread {
static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data);
static llvm::Optional<std::vector<const MinidumpThread *>>
static llvm::ArrayRef<MinidumpThread>
ParseThreadList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpThread) == 48,
@ -272,12 +286,12 @@ struct MinidumpSystemInfo {
static_assert(sizeof(MinidumpSystemInfo) == 56,
"sizeof MinidumpSystemInfo is not correct!");
// TODO check flags to see what's valid
// 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;
@ -285,10 +299,94 @@ struct MinidumpMiscInfo {
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 {
MaxParams = 15,
};
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[MaxParams];
};
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

@ -3,6 +3,7 @@ add_lldb_unittest(LLDBMinidumpTests
)
set(test_inputs
linux-x86_64.dmp)
linux-x86_64.dmp
fizzbuzz_no_heap.dmp)
add_unittest_inputs(LLDBMinidumpTests "${test_inputs}")

View File

@ -59,33 +59,111 @@ public:
TEST_F(MinidumpParserTest, GetThreads) {
SetUpData("linux-x86_64.dmp");
llvm::Optional<std::vector<const MinidumpThread *>> thread_list;
llvm::ArrayRef<MinidumpThread> thread_list;
thread_list = parser->GetThreads();
ASSERT_TRUE(thread_list.hasValue());
ASSERT_EQ(1UL, thread_list->size());
ASSERT_EQ(1UL, thread_list.size());
const MinidumpThread *thread = thread_list.getValue()[0];
ASSERT_EQ(16001UL, thread->thread_id);
const MinidumpThread thread = thread_list[0];
ASSERT_EQ(16001UL, thread.thread_id);
}
TEST_F(MinidumpParserTest, GetThreadsTruncatedFile) {
SetUpData("linux-x86_64.dmp", 200);
llvm::Optional<std::vector<const MinidumpThread *>> thread_list;
llvm::ArrayRef<MinidumpThread> thread_list;
thread_list = parser->GetThreads();
ASSERT_FALSE(thread_list.hasValue());
ASSERT_EQ(0UL, thread_list.size());
}
TEST_F(MinidumpParserTest, GetArchitecture) {
SetUpData("linux-x86_64.dmp");
ASSERT_EQ(llvm::Triple::ArchType::x86_64,
parser->GetArchitecture().GetTriple().getArch());
parser->GetArchitecture().GetMachine());
ASSERT_EQ(llvm::Triple::OSType::Linux,
parser->GetArchitecture().GetTriple().getOS());
}
TEST_F(MinidumpParserTest, GetMiscInfo) {
SetUpData("linux-x86_64.dmp");
const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
ASSERT_EQ(nullptr, misc_info);
// linux breakpad generated minidump files don't have misc info stream
}
TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
SetUpData("linux-x86_64.dmp");
llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
ASSERT_TRUE(proc_status.hasValue());
lldb::pid_t pid = proc_status->GetPid();
ASSERT_EQ(16001UL, pid);
}
TEST_F(MinidumpParserTest, GetPid) {
SetUpData("linux-x86_64.dmp");
llvm::Optional<lldb::pid_t> pid = parser->GetPid();
ASSERT_TRUE(pid.hasValue());
ASSERT_EQ(16001UL, pid.getValue());
}
TEST_F(MinidumpParserTest, GetModuleList) {
SetUpData("linux-x86_64.dmp");
llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
ASSERT_EQ(8UL, modules.size());
std::string module_names[8] = {
"/usr/local/google/home/dvlahovski/projects/test_breakpad/a.out",
"/lib/x86_64-linux-gnu/libm-2.19.so",
"/lib/x86_64-linux-gnu/libc-2.19.so",
"/lib/x86_64-linux-gnu/libgcc_s.so.1",
"/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19",
"/lib/x86_64-linux-gnu/libpthread-2.19.so",
"/lib/x86_64-linux-gnu/ld-2.19.so",
"linux-gate.so",
};
for (int i = 0; i < 8; ++i) {
llvm::Optional<std::string> name =
parser->GetMinidumpString(modules[i].module_name_rva);
ASSERT_TRUE(name.hasValue());
ASSERT_EQ(module_names[i], name.getValue());
}
}
TEST_F(MinidumpParserTest, GetExceptionStream) {
SetUpData("linux-x86_64.dmp");
const MinidumpExceptionStream *exception_stream =
parser->GetExceptionStream();
ASSERT_NE(nullptr, exception_stream);
ASSERT_EQ(11UL, exception_stream->exception_record.exception_code);
}
// Windows Minidump tests
// fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
TEST_F(MinidumpParserTest, GetArchitectureWindows) {
SetUpData("fizzbuzz_no_heap.dmp");
ASSERT_EQ(llvm::Triple::ArchType::x86,
parser->GetArchitecture().GetMachine());
ASSERT_EQ(llvm::Triple::OSType::Win32,
parser->GetArchitecture().GetTriple().getOS());
}
TEST_F(MinidumpParserTest, GetLinuxProcStatusWindows) {
SetUpData("fizzbuzz_no_heap.dmp");
llvm::Optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
ASSERT_FALSE(proc_status.hasValue());
}
TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
SetUpData("fizzbuzz_no_heap.dmp");
const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
ASSERT_NE(nullptr, misc_info);
llvm::Optional<lldb::pid_t> pid = misc_info->GetPid();
ASSERT_TRUE(pid.hasValue());
ASSERT_EQ(4440UL, pid.getValue());
}
TEST_F(MinidumpParserTest, GetPidWindows) {
SetUpData("fizzbuzz_no_heap.dmp");
llvm::Optional<lldb::pid_t> pid = parser->GetPid();
ASSERT_TRUE(pid.hasValue());
ASSERT_EQ(4440UL, pid.getValue());
}