[Lldb-commits] [lldb] r281348 - MinidumpParsing: pid, modules, exceptions, strings

Dimitar Vlahovski via lldb-commits lldb-commits at lists.llvm.org
Tue Sep 13 08:54:39 PDT 2016


Author: dvlahovski
Date: Tue Sep 13 10:54:38 2016
New Revision: 281348

URL: http://llvm.org/viewvc/llvm-project?rev=281348&view=rev
Log:
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

Added:
    lldb/trunk/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
Modified:
    lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp
    lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h
    lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.cpp
    lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h
    lldb/trunk/unittests/Process/minidump/CMakeLists.txt
    lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp

Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp Tue Sep 13 10:54:38 2016
@@ -1,5 +1,4 @@
-//===-- MinidumpParser.cpp ---------------------------------------*- C++
-//-*-===//
+//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -56,13 +55,12 @@ MinidumpParser::Create(const lldb::DataB
         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::GetByteSi
   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)
@@ -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);
 }

Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h Tue Sep 13 10:54:38 2016
@@ -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

Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.cpp?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.cpp (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.cpp Tue Sep 13 10:54:38 2016
@@ -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::Pa
   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::Pa
   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
 
   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;
+}

Modified: lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h Tue Sep 13 10:54:38 2016
@@ -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 MinidumpPCPUInformationARMElf
   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
   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_

Modified: lldb/trunk/unittests/Process/minidump/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/CMakeLists.txt?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/minidump/CMakeLists.txt (original)
+++ lldb/trunk/unittests/Process/minidump/CMakeLists.txt Tue Sep 13 10:54:38 2016
@@ -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}")

Added: lldb/trunk/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp?rev=281348&view=auto
==============================================================================
Binary files lldb/trunk/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp (added) and lldb/trunk/unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp Tue Sep 13 10:54:38 2016 differ

Modified: lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp?rev=281348&r1=281347&r2=281348&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp (original)
+++ lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp Tue Sep 13 10:54:38 2016
@@ -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());
 }




More information about the lldb-commits mailing list