dvlahovski created this revision. dvlahovski added reviewers: labath, zturner. dvlahovski added a subscriber: lldb-commits. Herald added a subscriber: beanz.
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. Finally - parsing the exception stream. I have unit tests for all of that. Also added some tests using a Minidump generated from Windows tools (not from breakpad) https://reviews.llvm.org/D24385 Files: source/Plugins/Process/minidump/MinidumpParser.cpp source/Plugins/Process/minidump/MinidumpParser.h source/Plugins/Process/minidump/MinidumpTypes.cpp source/Plugins/Process/minidump/MinidumpTypes.h unittests/Process/minidump/CMakeLists.txt unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp unittests/Process/minidump/MinidumpParserTest.cpp
Index: unittests/Process/minidump/MinidumpParserTest.cpp =================================================================== --- unittests/Process/minidump/MinidumpParserTest.cpp +++ unittests/Process/minidump/MinidumpParserTest.cpp @@ -44,10 +44,8 @@ llvm::SmallString<128> filename = inputs_folder; llvm::sys::path::append(filename, minidump_filename); FileSpec minidump_file(filename.c_str(), false); - lldb::DataBufferSP data_sp( - minidump_file.MemoryMapFileContents(0, load_size)); - llvm::Optional<MinidumpParser> optional_parser = - MinidumpParser::Create(data_sp); + lldb::DataBufferSP data_sp(minidump_file.MemoryMapFileContents(0, load_size)); + llvm::Optional<MinidumpParser> optional_parser = MinidumpParser::Create(data_sp); ASSERT_TRUE(optional_parser.hasValue()); parser.reset(new MinidumpParser(optional_parser.getValue())); ASSERT_GT(parser->GetByteSize(), 0UL); @@ -80,12 +78,65 @@ TEST_F(MinidumpParserTest, GetArchitecture) { SetUpData("linux-x86_64.dmp"); ASSERT_EQ(llvm::Triple::ArchType::x86_64, - parser->GetArchitecture().GetTriple().getArch()); + parser->GetArchitecture().GetMachine()); } 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()); +} + +TEST_F(MinidumpParserTest, GetPid) { + SetUpData("linux-x86_64.dmp"); + llvm::Optional<pid_t> pid = parser->GetPid(); + ASSERT_TRUE(pid.hasValue()); + ASSERT_EQ(16001, pid.getValue()); +} + +TEST_F(MinidumpParserTest, GetModuleList) { + SetUpData("linux-x86_64.dmp"); + llvm::Optional<std::vector<const MinidumpModule *>> modules = parser->GetModuleList(); + ASSERT_TRUE(modules.hasValue()); + ASSERT_EQ(8UL, modules->size()); + //TODO check for specific modules here +} + +TEST_F(MinidumpParserTest, GetExceptionStream) { + SetUpData("linux-x86_64.dmp"); + llvm::Optional<llvm::ArrayRef<uint8_t>> data = parser->GetStream(MinidumpStreamType::Exception); + ASSERT_TRUE(data.hasValue()); +} + + +// 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()); +} + +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_TRUE(misc_info != nullptr); +} + +TEST_F(MinidumpParserTest, GetPidWindows) { + SetUpData("fizzbuzz_no_heap.dmp"); + llvm::Optional<pid_t> pid = parser->GetPid(); + ASSERT_TRUE(pid.hasValue()); + ASSERT_EQ(4440, pid.getValue()); } Index: unittests/Process/minidump/CMakeLists.txt =================================================================== --- unittests/Process/minidump/CMakeLists.txt +++ unittests/Process/minidump/CMakeLists.txt @@ -3,6 +3,7 @@ ) set(test_inputs - linux-x86_64.dmp) + linux-x86_64.dmp + fizzbuzz_no_heap.dmp) add_unittest_inputs(LLDBMinidumpTests "${test_inputs}") Index: source/Plugins/Process/minidump/MinidumpTypes.h =================================================================== --- source/Plugins/Process/minidump/MinidumpTypes.h +++ source/Plugins/Process/minidump/MinidumpTypes.h @@ -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 @@ 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,8 @@ return error; } +llvm::StringRef consumeString(llvm::ArrayRef<uint8_t> &Buffer); + // Reference: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx struct MinidumpHeader { @@ -206,6 +217,13 @@ static_assert(sizeof(MinidumpDirectory) == 12, "sizeof MinidumpDirectory is not correct!"); +struct MinidumpString { + std::string buffer; + + static llvm::Optional<const MinidumpString> + Parse(llvm::ArrayRef<uint8_t> &data); +}; + // Reference: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx struct MinidumpThread { @@ -272,23 +290,98 @@ 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; - llvm::support::ulittle32_t flags1; + llvm::support::ulittle32_t flags1; // represent what info in the struct is valid 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); + + static llvm::Optional<pid_t> GetPid(const MinidumpMiscInfo &misc_info); }; static_assert(sizeof(MinidumpMiscInfo) == 24, "sizeof MinidumpMiscInfo is not correct!"); +// The /proc/pid/status is saved as an ascii string in the file +struct LinuxProcStatus { + llvm::StringRef proc_status; + + static LinuxProcStatus Parse(llvm::ArrayRef<uint8_t> &data); + + static llvm::Optional<pid_t> GetPid(const LinuxProcStatus &misc_info); +}; + +// 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; + llvm::support::ulittle32_t file_flags_mask; // Identifies valid bits in fileFlags + 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::Optional<std::vector<const 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_ Index: source/Plugins/Process/minidump/MinidumpTypes.cpp =================================================================== --- source/Plugins/Process/minidump/MinidumpTypes.cpp +++ source/Plugins/Process/minidump/MinidumpTypes.cpp @@ -9,25 +9,25 @@ // Project includes #include "MinidumpTypes.h" -#include "MinidumpParser.h" // Other libraries and framework includes // C includes // C++ includes using namespace lldb_private; using namespace minidump; +llvm::StringRef +lldb_private::minidump::consumeString(llvm::ArrayRef<uint8_t> &Buffer) { + return llvm::StringRef(reinterpret_cast<const char *>(Buffer.data()), Buffer.size()); +} + const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef<uint8_t> &data) { const MinidumpHeader *header = nullptr; Error error = consumeObject(data, header); - const MinidumpHeaderConstants signature = - static_cast<const MinidumpHeaderConstants>( - static_cast<const uint32_t>(header->signature)); - const MinidumpHeaderConstants version = - static_cast<const MinidumpHeaderConstants>( - static_cast<const uint32_t>(header->version) & 0x0000ffff); + 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 || @@ -40,6 +40,31 @@ return header; } +// Minidump string +llvm::Optional<const MinidumpString> +MinidumpString::Parse(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()) + return llvm::None; + + auto source_start = reinterpret_cast<const UTF16 *>(data.data()); + const auto source_end = source_start + (*source_length); + result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length)); // worst case length + 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 + + MinidumpString str; + str.buffer = result; + + return str; +} + // MinidumpThread const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef<uint8_t> &data) { const MinidumpThread *thread = nullptr; @@ -82,11 +107,84 @@ } // MinidumpMiscInfo -const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) { +const MinidumpMiscInfo * MinidumpMiscInfo::Parse(llvm::ArrayRef<uint8_t> &data) { const MinidumpMiscInfo *misc_info; Error error = consumeObject(data, misc_info); if (error.Fail()) return nullptr; return misc_info; } + +llvm::Optional<pid_t> +MinidumpMiscInfo::GetPid(const MinidumpMiscInfo &misc_info) { + uint32_t pid_flag = static_cast<const uint32_t>(MinidumpMiscInfoFlags::ProcessID); + if (misc_info.flags1 & pid_flag) + return llvm::Optional<pid_t>(misc_info.process_id); + + return llvm::None; +} + +// Linux Proc Status +LinuxProcStatus LinuxProcStatus::Parse(llvm::ArrayRef<uint8_t> &data) { + LinuxProcStatus result; + result.proc_status = consumeString(data); + return result; +} + +llvm::Optional<pid_t> +LinuxProcStatus::GetPid(const LinuxProcStatus &proc_status) { + pid_t pid; + llvm::SmallVector<llvm::StringRef, 42> lines; + proc_status.proc_status.split(lines, '\n', 42); + for (auto line : lines) { + if (line.consume_front("Pid:")) { + line = line.trim(); + if (!line.getAsInteger(10, pid)) + return llvm::Optional<pid_t>(pid); + } + } + + return llvm::None; +} + +// 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::Optional<std::vector<const MinidumpModule *>> +MinidumpModule::ParseModuleList(llvm::ArrayRef<uint8_t> &data) { + std::vector<const MinidumpModule *> module_list; + + const llvm::support::ulittle32_t *modules_count; + Error error = consumeObject(data, modules_count); + if (error.Fail()) + return llvm::None; + + const MinidumpModule *module; + for (uint32_t i = 0; i < *modules_count; ++i) { + module = MinidumpModule::Parse(data); + if (module == nullptr) + return llvm::None; + module_list.push_back(module); + } + + return llvm::Optional<std::vector<const MinidumpModule *>>(module_list); +} + +// 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; +} Index: source/Plugins/Process/minidump/MinidumpParser.h =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.h +++ source/Plugins/Process/minidump/MinidumpParser.h @@ -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 @@ -43,14 +44,24 @@ llvm::Optional<llvm::ArrayRef<uint8_t>> GetStream(MinidumpStreamType stream_type); + llvm::Optional<const MinidumpString> GetMinidumpString(uint32_t rva); + llvm::Optional<std::vector<const MinidumpThread *>> GetThreads(); const MinidumpSystemInfo *GetSystemInfo(); ArchSpec GetArchitecture(); const MinidumpMiscInfo *GetMiscInfo(); + llvm::Optional<LinuxProcStatus> GetLinuxProcStatus(); + + llvm::Optional<pid_t> GetPid(); + + llvm::Optional<std::vector<const MinidumpModule *>> GetModuleList(); + + const MinidumpExceptionStream *GetExceptionStream(); + private: lldb::DataBufferSP m_data_sp; const MinidumpHeader *m_header; Index: source/Plugins/Process/minidump/MinidumpParser.cpp =================================================================== --- source/Plugins/Process/minidump/MinidumpParser.cpp +++ source/Plugins/Process/minidump/MinidumpParser.cpp @@ -1,5 +1,4 @@ -//===-- MinidumpParser.cpp ---------------------------------------*- C++ -//-*-===// +//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -34,37 +33,29 @@ 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()) { + if ((directory_list_offset + sizeof(MinidumpDirectory) * header->streams_count) > data_buf_sp->GetByteSize()) { return llvm::None; } const MinidumpDirectory *directory = nullptr; Error error; - llvm::ArrayRef<uint8_t> directory_data( - data_buf_sp->GetBytes() + directory_list_offset, - sizeof(MinidumpDirectory) * header->streams_count); + llvm::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; + directory_map[static_cast<const uint32_t>(directory->stream_type)] = directory->location; } - MinidumpParser parser(data_buf_sp, header, directory_map); - return llvm::Optional<MinidumpParser>(parser); + return MinidumpParser(data_buf_sp, header, directory_map); } -MinidumpParser::MinidumpParser( - const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, - const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map) - : m_data_sp(data_buf_sp), m_header(header), m_directory_map(directory_map) { -} +MinidumpParser::MinidumpParser(const lldb::DataBufferSP &data_buf_sp, const MinidumpHeader *header, const llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> &directory_map) + : m_data_sp(data_buf_sp), m_header(header), + m_directory_map(std::move(directory_map)) {} lldb::offset_t MinidumpParser::GetByteSize() { return m_data_sp->GetByteSize(); @@ -80,25 +71,28 @@ if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize()) return llvm::None; - llvm::ArrayRef<uint8_t> arr_ref(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<const MinidumpString> +MinidumpParser::GetMinidumpString(uint32_t rva) { + llvm::ArrayRef<uint8_t> arr_ref(m_data_sp->GetBytes() + rva, m_data_sp->GetByteSize() - rva); + return MinidumpString::Parse(arr_ref); +} + llvm::Optional<std::vector<const MinidumpThread *>> MinidumpParser::GetThreads() { - llvm::Optional<llvm::ArrayRef<uint8_t>> data = - GetStream(MinidumpStreamType::ThreadList); + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::ThreadList); if (!data) return llvm::None; return MinidumpThread::ParseThreadList(data.getValue()); } const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() { - llvm::Optional<llvm::ArrayRef<uint8_t>> data = - GetStream(MinidumpStreamType::SystemInfo); + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::SystemInfo); if (!data) return nullptr; @@ -122,33 +116,81 @@ // TODO what to do about big endiand flavors of arm ? // TODO set the arm subarch stuff if the minidump has info about it - const MinidumpCPUArchitecture arch = - static_cast<const MinidumpCPUArchitecture>( - static_cast<const uint32_t>(system_info->processor_arch)); + llvm::Triple triple; + + 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); - break; - case MinidumpCPUArchitecture::AMD64: - arch_spec.GetTriple().setArch(llvm::Triple::ArchType::x86_64); - break; - case MinidumpCPUArchitecture::ARM: - arch_spec.GetTriple().setArch(llvm::Triple::ArchType::arm); - break; - case MinidumpCPUArchitecture::ARM64: - arch_spec.GetTriple().setArch(llvm::Triple::ArchType::aarch64); - break; + 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; } + triple.setOS(llvm::Triple::OSType::Linux); + arch_spec.SetTriple(triple); + return arch_spec; } const MinidumpMiscInfo *MinidumpParser::GetMiscInfo() { - llvm::Optional<llvm::ArrayRef<uint8_t>> data = - GetStream(MinidumpStreamType::MiscInfo); + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::MiscInfo); if (!data) return nullptr; return MinidumpMiscInfo::Parse(data.getValue()); } + +llvm::Optional<LinuxProcStatus> MinidumpParser::GetLinuxProcStatus() { + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::LinuxProcStatus); + + if (!data) + return llvm::None; + + return LinuxProcStatus::Parse(data.getValue()); +} + +llvm::Optional<pid_t> MinidumpParser::GetPid() { + const MinidumpMiscInfo *misc_info = GetMiscInfo(); + if (misc_info != nullptr) { + return MinidumpMiscInfo::GetPid(*misc_info); + } + + llvm::Optional<LinuxProcStatus> proc_status = GetLinuxProcStatus(); + if (proc_status.hasValue()) { + return LinuxProcStatus::GetPid(proc_status.getValue()); + } + + return llvm::None; +} + +llvm::Optional<std::vector<const MinidumpModule *>> +MinidumpParser::GetModuleList() { + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::ModuleList); + + if (!data) + return llvm::None; + + return MinidumpModule::ParseModuleList(data.getValue()); +} + +const MinidumpExceptionStream * MinidumpParser::GetExceptionStream() { + llvm::Optional<llvm::ArrayRef<uint8_t>> data = GetStream(MinidumpStreamType::Exception); + + if (!data) + return nullptr; + + return MinidumpExceptionStream::Parse(data.getValue()); +}
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits