dvlahovski created this revision.
dvlahovski added reviewers: labath, zturner.
dvlahovski added subscribers: amccarth, lldb-commits.
Herald added subscribers: modocache, mgorny, beanz.

Now the Minidump parser can parse the:

1. MemoryInfoList - containing region info about memory ranges (readable,

writeable, executable)

2. Memory64List - this is the stuct used when the Minidump is a

full-memory one.

3. Adding filtering of the module list (shared libraries list) - there

can be mutliple records in the module list under the same name but with
different load address (e.g. when the binary has non contigious
sections). FilterModuleList eliminates the duplicated modules, leaving
the one with the lowest load addr.

Added unit tests for everything.


https://reviews.llvm.org/D25569

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_wow64.dmp
  unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp
  unittests/Process/minidump/MinidumpParserTest.cpp

Index: unittests/Process/minidump/MinidumpParserTest.cpp
===================================================================
--- unittests/Process/minidump/MinidumpParserTest.cpp
+++ unittests/Process/minidump/MinidumpParserTest.cpp
@@ -19,6 +19,7 @@
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/DataExtractor.h"
 #include "lldb/Host/FileSpec.h"
+#include "lldb/Target/MemoryRegionInfo.h"
 
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
@@ -68,7 +69,11 @@
   ASSERT_EQ(1UL, thread_list.size());
 
   const MinidumpThread thread = thread_list[0];
-  ASSERT_EQ(16001UL, thread.thread_id);
+
+  EXPECT_EQ(16001UL, thread.thread_id);
+
+  llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
+  EXPECT_EQ(1232UL, context.size());
 }
 
 TEST_F(MinidumpParserTest, GetThreadsTruncatedFile) {
@@ -131,14 +136,96 @@
   }
 }
 
+TEST_F(MinidumpParserTest, FilterModuleList) {
+  SetUpData("linux-x86_64_not_crashed.dmp");
+  llvm::ArrayRef<MinidumpModule> modules = parser->GetModuleList();
+  std::vector<const MinidumpModule *> filtered_modules = parser->FilterModuleList(modules);
+  EXPECT_GT(modules.size(), filtered_modules.size());
+  bool found = false;
+  for (size_t i = 0; i < filtered_modules.size(); ++i) {
+    llvm::Optional<std::string> name =
+        parser->GetMinidumpString(filtered_modules[i]->module_name_rva);
+    ASSERT_TRUE(name.hasValue());
+    if (name.getValue() == "/tmp/test/linux-x86_64_not_crashed") {
+      ASSERT_FALSE(found) << "There should be only one module with this name in the filtered module list";
+      found = true;
+      ASSERT_EQ(0x400000UL, filtered_modules[i]->base_of_image);
+    }
+  }
+}
+
 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);
 }
 
+
+void check_mem_range_exists(std::unique_ptr<MinidumpParser> &parser, const uint64_t range_start, const uint64_t range_size) {
+  llvm::Optional<minidump::Range> range = parser->FindMemoryRange(range_start);
+  ASSERT_TRUE(range.hasValue()) << "There is no range containing this address";
+  EXPECT_EQ(range_start, range->start);
+  EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRange) {
+  SetUpData("linux-x86_64.dmp");
+  // There are two memory ranges in the file (size is in bytes, decimal):
+  // 1) 0x401d46 256
+  // 2) 0x7ffceb34a000 12288
+  EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+  EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+
+  check_mem_range_exists(parser, 0x401d46, 256);
+  EXPECT_FALSE(parser->FindMemoryRange(0x401d46 + 256).hasValue());
+
+  check_mem_range_exists(parser, 0x7ffceb34a000, 12288);
+  EXPECT_FALSE(parser->FindMemoryRange(0x7ffceb34a000 + 12288).hasValue());
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRangeWithFullMemoryMinidump) {
+  SetUpData("fizzbuzz_wow64.dmp");
+
+  // There are a lot of ranges in the file, just testing with some of them
+  EXPECT_FALSE(parser->FindMemoryRange(0x00).hasValue());
+  EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
+  check_mem_range_exists(parser, 0x10000, 65536); // first range
+  check_mem_range_exists(parser, 0x40000, 4096);
+  EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).hasValue());
+  check_mem_range_exists(parser, 0x7ffe0000, 4096);
+  check_mem_range_exists(parser, 0x77c12000, 8192);
+  check_mem_range_exists(parser, 0x7ffe0000, 4096); // last range
+  EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
+}
+
+void check_region_info(std::unique_ptr<MinidumpParser> &parser, const uint64_t addr, bool read, bool write, bool exec) {
+  lldb_private::MemoryRegionInfo range_info;
+  Error error = parser->GetMemoryRegionInfo(addr, range_info);
+  auto yes = MemoryRegionInfo::eYes;
+  auto no = MemoryRegionInfo::eNo;
+  ASSERT_TRUE(error.Success());
+  EXPECT_EQ(read ? yes : no, range_info.GetReadable());
+  EXPECT_EQ(write ? yes : no, range_info.GetWritable());
+  EXPECT_EQ(exec ? yes : no, range_info.GetExecutable());
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
+  SetUpData("fizzbuzz_wow64.dmp");
+  // clang-format off
+  //                                 read   write  exec
+  //                                 =====  =====  =====
+  check_region_info(parser, 0x00000, false, false, false);
+  check_region_info(parser, 0x10000, true,  true,  false);
+  check_region_info(parser, 0x20000, true,  true,  false);
+  check_region_info(parser, 0x30000, true,  true,  false);
+  check_region_info(parser, 0x31000, false, false, false);
+  check_region_info(parser, 0x40000, true,  false, false);
+  // clang-format on
+}
+
+
 // Windows Minidump tests
 // fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
 TEST_F(MinidumpParserTest, GetArchitectureWindows) {
Index: unittests/Process/minidump/CMakeLists.txt
===================================================================
--- unittests/Process/minidump/CMakeLists.txt
+++ unittests/Process/minidump/CMakeLists.txt
@@ -4,6 +4,8 @@
 
 set(test_inputs
    linux-x86_64.dmp
-   fizzbuzz_no_heap.dmp)
+   linux-x86_64_not_crashed.dmp
+   fizzbuzz_no_heap.dmp
+   fizzbuzz_wow64.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
@@ -207,10 +207,22 @@
 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 {
@@ -220,6 +232,62 @@
 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,
+};
+
+enum class MinidumpMemoryInfoType : uint32_t {
+  MemImage = 0x1000000,
+  MemMapped = 0x40000,
+  MemPrivate = 0x20000,
+};
+
+// 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,
+};
+
 // Reference:
 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
 struct MinidumpThread {
Index: source/Plugins/Process/minidump/MinidumpTypes.cpp
===================================================================
--- source/Plugins/Process/minidump/MinidumpTypes.cpp
+++ source/Plugins/Process/minidump/MinidumpTypes.cpp
@@ -176,3 +176,58 @@
 
   return exception_stream;
 }
+
+llvm::ArrayRef<MinidumpMemoryDescriptor>
+MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
+  const llvm::support::ulittle32_t *mem_ranges_count;
+  Error 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;
+  Error 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;
+  Error error = consumeObject(data, header);
+  if (error.Fail() ||
+      header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) ||
+      header->size_of_entry < sizeof(MinidumpMemoryInfo))
+    return {};
+
+  if (header->size_of_header > sizeof(MinidumpMemoryInfoListHeader)) {
+    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;
+}
Index: source/Plugins/Process/minidump/MinidumpParser.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.h
+++ source/Plugins/Process/minidump/MinidumpParser.h
@@ -34,6 +34,16 @@
 
 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>
@@ -47,6 +57,8 @@
 
   llvm::ArrayRef<MinidumpThread> GetThreads();
 
+  llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
+
   const MinidumpSystemInfo *GetSystemInfo();
 
   ArchSpec GetArchitecture();
@@ -59,8 +71,20 @@
 
   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 filters the module list - if it finds records that have
+  // the same name, it keeps the copy with the lowest load address.
+  std::vector<const MinidumpModule *> FilterModuleList(llvm::ArrayRef<MinidumpModule> &modules);
+
   const MinidumpExceptionStream *GetExceptionStream();
 
+  llvm::Optional<Range> FindMemoryRange(lldb::addr_t addr);
+
+  size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error);
+
+  Error GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &info);
+
 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
@@ -11,8 +11,12 @@
 #include "MinidumpParser.h"
 
 // Other libraries and framework includes
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/LLDBAssert.h"
+
 // C includes
 // C++ includes
+#include <map>
 
 using namespace lldb_private;
 using namespace minidump;
@@ -100,6 +104,14 @@
   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 llvm::None;
+
+  return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
+}
+
 const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
 
@@ -216,11 +228,183 @@
   return MinidumpModule::ParseModuleList(data);
 }
 
+std::vector<const MinidumpModule *> MinidumpParser::FilterModuleList(llvm::ArrayRef<MinidumpModule> &modules) {
+  std::map<std::string, std::pair<uint64_t, const MinidumpModule *>> lowest_addr;
+  std::vector<const MinidumpModule *> filtered_modules;
+
+  llvm::Optional<std::string> name;
+  std::string module_name;
+
+  for (size_t i = 0; i < modules.size(); ++i) {
+    name = GetMinidumpString(modules[i].module_name_rva);
+
+    if (!name)
+      continue;
+
+    module_name = name.getValue();
+
+    if (lowest_addr.find(module_name) == lowest_addr.end()) {
+      lowest_addr[module_name] = std::make_pair(modules[i].base_of_image, &modules[i]);
+    } else if (modules[i].base_of_image < lowest_addr[module_name].first) {
+      lowest_addr[module_name].second = &modules[i];
+    }
+  }
+
+  for (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.size() == 0 && data64.size() == 0)
+    return llvm::None;
+
+  if (data.size() > 0) {
+    llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
+        MinidumpMemoryDescriptor::ParseMemoryList(data);
+
+    if (memory_list.size() == 0)
+      return llvm::None;
+
+    for (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.size() > 0) {
+    llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+    uint64_t base_rva;
+    std::tie(memory64_list, base_rva) = MinidumpMemoryDescriptor64::ParseMemory64List(data64);
+
+    if (memory64_list.size() == 0)
+      return llvm::None;
+
+    for (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;
+}
+
+size_t MinidumpParser::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error) {
+  // 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 0;
+
+  // 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, then copy it to the destination buffer.
+  lldbassert(range->start <= addr);
+  const size_t offset = addr - range->start;
+  lldbassert(offset < range->range_ref.size());
+  const size_t overlap = std::min(size, range->range_ref.size() - offset);
+  std::memcpy(buf, range->range_ref.data() + offset, overlap);
+  return overlap;
+}
+
+Error MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &info) {
+
+  Error error;
+  llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
+  if (data.size() == 0) {
+    error.SetErrorString("Minidump doesn't have MemoryInfoList");
+    return error;
+  }
+
+  std::vector<const MinidumpMemoryInfo *> mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data);
+  if (mem_info_list.size() == 0) {
+    error.SetErrorString("error while parsing the MinidumpMemoryInfoList");
+    return error;
+  }
+
+  const MinidumpMemoryInfo *next_entry = nullptr;
+  for(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 ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+
+      const uint32_t PageWritable = static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
+      info.SetWritable((entry->protect & PageWritable) != 0 ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+
+      const uint32_t PageExecutable = static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageExecutable);
+      info.SetExecutable((entry->protect & PageExecutable) != 0 ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+
+      const uint32_t MemFree = static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
+      info.SetMapped((entry->state != MemFree) ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
+
+      return error;
+    } 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(MemoryRegionInfo::eNo);
+  info.SetWritable(MemoryRegionInfo::eNo);
+  info.SetExecutable(MemoryRegionInfo::eNo);
+  info.SetMapped(MemoryRegionInfo::eNo);
+
+  // 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 error;
+
+}
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to