clayborg updated this revision to Diff 178168.
clayborg added a comment.
Herald added a subscriber: mgorny.

Fixed errors, fully test, and make static function that are local to 
MinidumpParser.cpp that parse the region info from linux maps, memory info 
list, memory list and memory 64 list.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55522/new/

https://reviews.llvm.org/D55522

Files:
  include/lldb/Target/MemoryRegionInfo.h
  lldb.xcodeproj/project.pbxproj
  source/Plugins/Process/Utility/CMakeLists.txt
  source/Plugins/Process/Utility/LinuxProcMaps.cpp
  source/Plugins/Process/Utility/LinuxProcMaps.h
  source/Plugins/Process/minidump/MinidumpParser.cpp
  source/Plugins/Process/minidump/MinidumpParser.h
  source/Plugins/Process/minidump/MinidumpTypes.h
  source/Plugins/Process/minidump/ProcessMinidump.cpp
  unittests/Process/minidump/Inputs/regions-linux-map.dmp
  unittests/Process/minidump/Inputs/regions-memlist.dmp
  unittests/Process/minidump/Inputs/regions-memlist64.dmp
  unittests/Process/minidump/MinidumpParserTest.cpp

Index: unittests/Process/minidump/MinidumpParserTest.cpp
===================================================================
--- unittests/Process/minidump/MinidumpParserTest.cpp
+++ unittests/Process/minidump/MinidumpParserTest.cpp
@@ -300,31 +300,122 @@
   EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).hasValue());
 }
 
-void check_region_info(std::unique_ptr<MinidumpParser> &parser,
-                       const uint64_t addr, MemoryRegionInfo::OptionalBool read,
-                       MemoryRegionInfo::OptionalBool write,
-                       MemoryRegionInfo::OptionalBool exec) {
+void check_region(std::unique_ptr<MinidumpParser> &parser,
+                  lldb::addr_t addr, lldb::addr_t start, lldb::addr_t end,
+                  MemoryRegionInfo::OptionalBool read,
+                  MemoryRegionInfo::OptionalBool write,
+                  MemoryRegionInfo::OptionalBool exec,
+                  MemoryRegionInfo::OptionalBool mapped,
+                  ConstString name = ConstString()) {
   auto range_info = parser->GetMemoryRegionInfo(addr);
-  ASSERT_TRUE(range_info.hasValue());
-  EXPECT_EQ(read, range_info->GetReadable());
-  EXPECT_EQ(write, range_info->GetWritable());
-  EXPECT_EQ(exec, range_info->GetExecutable());
+  EXPECT_EQ(start, range_info.GetRange().GetRangeBase());
+  EXPECT_EQ(end, range_info.GetRange().GetRangeEnd());
+  EXPECT_EQ(read, range_info.GetReadable());
+  EXPECT_EQ(write, range_info.GetWritable());
+  EXPECT_EQ(exec, range_info.GetExecutable());
+  EXPECT_EQ(mapped, range_info.GetMapped());
+  EXPECT_EQ(name, range_info.GetName());
 }
 
+// Same as above function where addr == start
+void check_region(std::unique_ptr<MinidumpParser> &parser,
+                  lldb::addr_t start, lldb::addr_t end,
+                  MemoryRegionInfo::OptionalBool read,
+                  MemoryRegionInfo::OptionalBool write,
+                  MemoryRegionInfo::OptionalBool exec,
+                  MemoryRegionInfo::OptionalBool mapped,
+                  ConstString name = ConstString()) {
+  check_region(parser, start, start, end, read, write, exec, mapped, name);
+}
+
+
+constexpr auto yes = MemoryRegionInfo::eYes;
+constexpr auto no = MemoryRegionInfo::eNo;
+constexpr auto unknown = MemoryRegionInfo::eDontKnow;
+
 TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
   SetUpData("fizzbuzz_wow64.dmp");
 
-  const auto yes = MemoryRegionInfo::eYes;
-  const auto no = MemoryRegionInfo::eNo;
+  check_region(parser, 0x00000000, 0x00010000, no, no, no, no);
+  check_region(parser, 0x00010000, 0x00020000, yes, yes, no, yes);
+  check_region(parser, 0x00020000, 0x00030000, yes, yes, no, yes);
+  check_region(parser, 0x00030000, 0x00031000, yes, yes, no, yes);
+  check_region(parser, 0x00031000, 0x00040000, no, no, no, no);
+  check_region(parser, 0x00040000, 0x00041000, yes, no, no, yes);
 
-  check_region_info(parser, 0x00000, no, no, no);
-  check_region_info(parser, 0x10000, yes, yes, no);
-  check_region_info(parser, 0x20000, yes, yes, no);
-  check_region_info(parser, 0x30000, yes, yes, no);
-  check_region_info(parser, 0x31000, no, no, no);
-  check_region_info(parser, 0x40000, yes, no, no);
+  // Check addresses contained inside ranges
+  check_region(parser, 0x00000001, 0x00000000, 0x00010000, no, no, no, no);
+  check_region(parser, 0x0000ffff, 0x00000000, 0x00010000, no, no, no, no);
+  check_region(parser, 0x00010001, 0x00010000, 0x00020000, yes, yes, no, yes);
+  check_region(parser, 0x0001ffff, 0x00010000, 0x00020000, yes, yes, no, yes);
+
+  // Test that an address after the last entry maps to rest of the memory space
+  check_region(parser, 0x7fff0000, 0x7fff0000, UINT64_MAX, no, no, no, no);
 }
 
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
+  SetUpData("regions-memlist.dmp");
+  // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
+  // we don't have a MemoryInfoListStream.
+
+  // Test addres before the first entry comes back with nothing mapped up
+  // to first valid region info
+  check_region(parser, 0x00000000, 0x00001000, no, no, no, no);
+  check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes);
+  check_region(parser, 0x00001010, 0x00002000, no, no, no, no);
+  check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes);
+  check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no);
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
+  SetUpData("regions-memlist64.dmp");
+  // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
+  // we don't have a MemoryInfoListStream.
+
+  // Test addres before the first entry comes back with nothing mapped up
+  // to first valid region info
+  check_region(parser, 0x00000000, 0x00001000, no, no, no, no);
+  check_region(parser, 0x00001000, 0x00001010, yes, unknown, unknown, yes);
+  check_region(parser, 0x00001010, 0x00002000, no, no, no, no);
+  check_region(parser, 0x00002000, 0x00002020, yes, unknown, unknown, yes);
+  check_region(parser, 0x00002020, UINT64_MAX, no, no, no, no);
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
+  SetUpData("regions-linux-map.dmp");
+  // Test we can get memory regions from the linux /proc/<pid>/maps stream when
+  // we don't have a MemoryInfoListStream.
+
+  // Test addres before the first entry comes back with nothing mapped up
+  // to first valid region info
+  ConstString a("/system/bin/app_process");
+  ConstString b("/system/bin/linker");
+  ConstString c("/system/lib/liblog.so");
+  ConstString d("/system/lib/libc.so");
+  ConstString n;
+  check_region(parser, 0x00000000, 0x400d9000, no , no , no , no , n);
+  check_region(parser, 0x400d9000, 0x400db000, yes, no , yes, yes, a);
+  check_region(parser, 0x400db000, 0x400dc000, yes, no , no , yes, a);
+  check_region(parser, 0x400dc000, 0x400dd000, yes, yes, no , yes, n);
+  check_region(parser, 0x400dd000, 0x400ec000, yes, no , yes, yes, b);
+  check_region(parser, 0x400ec000, 0x400ed000, yes, no , no , yes, n);
+  check_region(parser, 0x400ed000, 0x400ee000, yes, no , no , yes, b);
+  check_region(parser, 0x400ee000, 0x400ef000, yes, yes, no , yes, b);
+  check_region(parser, 0x400ef000, 0x400fb000, yes, yes, no , yes, n);
+  check_region(parser, 0x400fb000, 0x400fc000, yes, no , yes, yes, c);
+  check_region(parser, 0x400fc000, 0x400fd000, yes, yes, yes, yes, c);
+  check_region(parser, 0x400fd000, 0x400ff000, yes, no , yes, yes, c);
+  check_region(parser, 0x400ff000, 0x40100000, yes, no , no , yes, c);
+  check_region(parser, 0x40100000, 0x40101000, yes, yes, no , yes, c);
+  check_region(parser, 0x40101000, 0x40122000, yes, no , yes, yes, d);
+  check_region(parser, 0x40122000, 0x40123000, yes, yes, yes, yes, d);
+  check_region(parser, 0x40123000, 0x40167000, yes, no , yes, yes, d);
+  check_region(parser, 0x40167000, 0x40169000, yes, no , no , yes, d);
+  check_region(parser, 0x40169000, 0x4016b000, yes, yes, no , yes, d);
+  check_region(parser, 0x4016b000, 0x40176000, yes, yes, no , yes, n);
+  check_region(parser, 0x40176000, UINT64_MAX, no , no , no , no , n);
+}
+
 // Windows Minidump tests
 // fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
 TEST_F(MinidumpParserTest, GetArchitectureWindows) {
@@ -571,3 +662,4 @@
   ASSERT_TRUE((bool)name);
   EXPECT_EQ(std::string("/tmp/b"), *name);
 }
+
Index: source/Plugins/Process/minidump/ProcessMinidump.cpp
===================================================================
--- source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -284,14 +284,8 @@
 
 Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
                                             MemoryRegionInfo &range_info) {
-  Status error;
-  auto info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
-  if (!info) {
-    error.SetErrorString("No valid MemoryRegionInfo found!");
-    return error;
-  }
-  range_info = info.getValue();
-  return error;
+  range_info = m_minidump_parser.GetMemoryRegionInfo(load_addr);
+  return Status();
 }
 
 void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
Index: source/Plugins/Process/minidump/MinidumpTypes.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpTypes.h
+++ source/Plugins/Process/minidump/MinidumpTypes.h
@@ -256,25 +256,6 @@
 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,
@@ -311,6 +292,45 @@
 };
 
 // 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);
+
+  bool isReadable() const {
+    const auto mask = MinidumpMemoryProtectionContants::PageNoAccess;
+    return (static_cast<uint32_t>(mask) & protect) == 0;
+  }
+
+  bool isWritable() const {
+    const auto mask = MinidumpMemoryProtectionContants::PageWritable;
+    return (static_cast<uint32_t>(mask) & protect) != 0;
+  }
+
+  bool isExecutable() const {
+    const auto mask = MinidumpMemoryProtectionContants::PageExecutable;
+    return (static_cast<uint32_t>(mask) & protect) != 0;
+  }
+  
+  bool isMapped() const {
+    return state != static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
+  }
+};
+
+static_assert(sizeof(MinidumpMemoryInfo) == 48,
+              "sizeof MinidumpMemoryInfo is not correct!");
+
+// Reference:
 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
 struct MinidumpThread {
   llvm::support::ulittle32_t thread_id;
Index: source/Plugins/Process/minidump/MinidumpParser.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.h
+++ source/Plugins/Process/minidump/MinidumpParser.h
@@ -1,5 +1,4 @@
-//===-- MinidumpParser.h -----------------------------------------*- C++
-//-*-===//
+//===-- MinidumpParser.h -----------------------------------------*- C++-*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -86,7 +85,7 @@
 
   llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
 
-  llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t);
+  MemoryRegionInfo GetMemoryRegionInfo(lldb::addr_t load_addr);
 
   // Perform consistency checks and initialize internal data structures
   Status Initialize();
@@ -94,10 +93,14 @@
 private:
   MinidumpParser(const lldb::DataBufferSP &data_buf_sp);
 
+  MemoryRegionInfo FindMemoryRegion(lldb::addr_t load_addr) const;
+
 private:
   lldb::DataBufferSP m_data_sp;
   llvm::DenseMap<uint32_t, MinidumpLocationDescriptor> m_directory_map;
   ArchSpec m_arch;
+  std::vector<MemoryRegionInfo> m_regions;
+  bool m_parsed_regions = false;
 };
 
 } // end namespace minidump
Index: source/Plugins/Process/minidump/MinidumpParser.cpp
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.cpp
+++ source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -13,12 +13,14 @@
 
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/LLDBAssert.h"
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
 
 // C includes
 // C++ includes
 #include <algorithm>
 #include <map>
 #include <vector>
+#include <utility>
 
 using namespace lldb_private;
 using namespace minidump;
@@ -410,72 +412,147 @@
   return range->range_ref.slice(offset, overlap);
 }
 
-llvm::Optional<MemoryRegionInfo>
-MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
-  MemoryRegionInfo info;
-  llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
+static bool
+CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
+                                std::vector<MemoryRegionInfo> &regions) {
+  auto data = parser.GetStream(MinidumpStreamType::LinuxMaps);
   if (data.empty())
-    return llvm::None;
+    return false;
+  ParseLinuxMapRegions(llvm::toStringRef(data),
+                       [&](const lldb_private::MemoryRegionInfo &region,
+                           const lldb_private::Status &status) -> bool {
+    if (status.Success())
+      regions.push_back(region);
+    return true;
+  });
+  return !regions.empty();
+}
 
-  std::vector<const MinidumpMemoryInfo *> mem_info_list =
-      MinidumpMemoryInfo::ParseMemoryInfoList(data);
+static bool
+CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
+                                     std::vector<MemoryRegionInfo> &regions) {
+  auto data = parser.GetStream(MinidumpStreamType::MemoryInfoList);
+  if (data.empty())
+    return false;
+  auto mem_info_list = MinidumpMemoryInfo::ParseMemoryInfoList(data);
   if (mem_info_list.empty())
-    return llvm::None;
-
-  const auto yes = MemoryRegionInfo::eYes;
-  const auto no = MemoryRegionInfo::eNo;
-
-  const MinidumpMemoryInfo *next_entry = nullptr;
+    return false;
+  constexpr auto yes = MemoryRegionInfo::eYes;
+  constexpr auto no = MemoryRegionInfo::eNo;
+  regions.reserve(mem_info_list.size());
   for (const auto &entry : mem_info_list) {
-    const auto head = entry->base_address;
-    const auto tail = head + entry->region_size;
+    MemoryRegionInfo region;
+    region.GetRange().SetRangeBase(entry->base_address);
+    region.GetRange().SetByteSize(entry->region_size);
+    region.SetReadable(entry->isReadable() ? yes : no);
+    region.SetWritable(entry->isWritable() ? yes : no);
+    region.SetExecutable(entry->isExecutable() ? yes : no);
+    region.SetMapped(entry->isMapped() ? yes : no);
+    regions.push_back(region);
+  }
+  return !regions.empty();
+}
 
-    if (head <= load_addr && load_addr < tail) {
-      info.GetRange().SetRangeBase(
-          (entry->state != uint32_t(MinidumpMemoryInfoState::MemFree))
-              ? head
-              : load_addr);
-      info.GetRange().SetRangeEnd(tail);
+static bool
+CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
+                                 std::vector<MemoryRegionInfo> &regions) {
+  auto data = parser.GetStream(MinidumpStreamType::MemoryList);
+  if (data.empty())
+    return false;
+  auto memory_list = MinidumpMemoryDescriptor::ParseMemoryList(data);
+  if (memory_list.empty())
+    return false;
+  regions.reserve(memory_list.size());
+  for (const auto &memory_desc : memory_list) {
+    if (memory_desc.memory.data_size == 0)
+      continue;
+    MemoryRegionInfo region;
+    region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
+    region.GetRange().SetByteSize(memory_desc.memory.data_size);
+    region.SetReadable(MemoryRegionInfo::eYes);
+    region.SetMapped(MemoryRegionInfo::eYes);
+    regions.push_back(region);
+  }
+  regions.shrink_to_fit();
+  return !regions.empty();
+}
 
-      const uint32_t PageNoAccess =
-          static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
-      info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
+static bool
+CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
+                                   std::vector<MemoryRegionInfo> &regions) {
+  llvm::ArrayRef<uint8_t> data =
+      parser.GetStream(MinidumpStreamType::Memory64List);
+  if (data.empty())
+    return false;
+  llvm::ArrayRef<MinidumpMemoryDescriptor64> memory64_list;
+  uint64_t base_rva;
+  std::tie(memory64_list, base_rva) =
+      MinidumpMemoryDescriptor64::ParseMemory64List(data);
+  
+  if (memory64_list.empty())
+    return false;
+    
+  regions.reserve(memory64_list.size());
+  for (const auto &memory_desc : memory64_list) {
+    if (memory_desc.data_size == 0)
+      continue;
+    MemoryRegionInfo region;
+    region.GetRange().SetRangeBase(memory_desc.start_of_memory_range);
+    region.GetRange().SetByteSize(memory_desc.data_size);
+    region.SetReadable(MemoryRegionInfo::eYes);
+    region.SetMapped(MemoryRegionInfo::eYes);
+    regions.push_back(region);
+  }
+  regions.shrink_to_fit();
+  return !regions.empty();
+}
 
-      const uint32_t PageWritable =
-          static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
-      info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
+MemoryRegionInfo
+MinidumpParser::FindMemoryRegion(lldb::addr_t load_addr) const {
+  auto begin = m_regions.begin();
+  auto end = m_regions.end();
+  auto pos = std::lower_bound(begin, end, load_addr);
+  if (pos != end && pos->GetRange().Contains(load_addr))
+    return *pos;
+  
+  MemoryRegionInfo region;
+  if (pos == begin)
+    region.GetRange().SetRangeBase(0);
+  else {
+    auto prev = pos - 1;
+    if (prev->GetRange().Contains(load_addr))
+      return *prev;
+    region.GetRange().SetRangeBase(prev->GetRange().GetRangeEnd());
+  }
+  if (pos == end)
+    region.GetRange().SetRangeEnd(UINT64_MAX);
+  else
+    region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
+  region.SetReadable(MemoryRegionInfo::eNo);
+  region.SetWritable(MemoryRegionInfo::eNo);
+  region.SetExecutable(MemoryRegionInfo::eNo);
+  region.SetMapped(MemoryRegionInfo::eNo);
+  return region;
+}
 
-      const uint32_t PageExecutable = static_cast<uint32_t>(
-          MinidumpMemoryProtectionContants::PageExecutable);
-      info.SetExecutable((entry->protect & PageExecutable) != 0 ? yes : no);
-
-      const uint32_t MemFree =
-          static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
-      info.SetMapped((entry->state != MemFree) ? yes : no);
-
-      return info;
-    } 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;
-    }
+MemoryRegionInfo
+MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
+  if (!m_parsed_regions) {
+    m_parsed_regions = true;
+    // We haven't cached our memory regions yet we will create the region cache
+    // once. We create the region cache using the best source. We start with
+    // the linux maps since they are the most complete and have names for the
+    // regions. Next we try the MemoryInfoList since it has
+    // read/write/execute/map data, and then fall back to the MemoryList and
+    // Memory64List to just get a list of the memory that is mapped in this
+    // core file
+    if (!CreateRegionsCacheFromLinuxMaps(*this, m_regions))
+      if (!CreateRegionsCacheFromMemoryInfoList(*this, m_regions))
+        if (!CreateRegionsCacheFromMemoryList(*this, m_regions))
+          CreateRegionsCacheFromMemory64List(*this, m_regions);
+    std::sort(m_regions.begin(), m_regions.end());
   }
-
-  // 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(no);
-  info.SetWritable(no);
-  info.SetExecutable(no);
-  info.SetMapped(no);
-
-  // 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 info;
+  return FindMemoryRegion(load_addr);
 }
 
 Status MinidumpParser::Initialize() {
Index: source/Plugins/Process/Utility/LinuxProcMaps.h
===================================================================
--- source/Plugins/Process/Utility/LinuxProcMaps.h
+++ source/Plugins/Process/Utility/LinuxProcMaps.h
@@ -0,0 +1,28 @@
+//===-- LinuxProcMaps.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_LinuxProcMaps_H_
+#define liblldb_LinuxProcMaps_H_
+
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+
+
+namespace lldb_private {
+
+typedef std::function<bool(const lldb_private::MemoryRegionInfo &,
+                           const lldb_private::Status &)> LinuxMapCallback;
+
+void ParseLinuxMapRegions(llvm::StringRef linux_map,
+                          LinuxMapCallback const &callback);
+
+} // namespace lldb_private
+
+#endif // liblldb_LinuxProcMaps_H_
Index: source/Plugins/Process/Utility/LinuxProcMaps.cpp
===================================================================
--- source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -0,0 +1,113 @@
+//===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinuxProcMaps.h"
+#include "llvm/ADT/StringRef.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StringExtractor.h"
+
+using namespace lldb_private;
+
+static Status
+ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef &maps_line,
+                                      MemoryRegionInfo &memory_region_info) {
+  memory_region_info.Clear();
+  
+  StringExtractor line_extractor(maps_line);
+  
+  // Format: {address_start_hex}-{address_end_hex} perms offset  dev   inode
+  // pathname perms: rwxp   (letter is present if set, '-' if not, final
+  // character is p=private, s=shared).
+  
+  // Parse out the starting address
+  lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
+  
+  // Parse out hyphen separating start and end address from range.
+  if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
+    return Status(
+        "malformed /proc/{pid}/maps entry, missing dash between address range");
+  
+  // Parse out the ending address
+  lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
+  
+  // Parse out the space after the address.
+  if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
+    return Status(
+        "malformed /proc/{pid}/maps entry, missing space after range");
+  
+  // Save the range.
+  memory_region_info.GetRange().SetRangeBase(start_address);
+  memory_region_info.GetRange().SetRangeEnd(end_address);
+  
+  // Any memory region in /proc/{pid}/maps is by definition mapped into the
+  // process.
+  memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+  
+  // Parse out each permission entry.
+  if (line_extractor.GetBytesLeft() < 4)
+    return Status("malformed /proc/{pid}/maps entry, missing some portion of "
+                  "permissions");
+  
+  // Handle read permission.
+  const char read_perm_char = line_extractor.GetChar();
+  if (read_perm_char == 'r')
+    memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+  else if (read_perm_char == '-')
+    memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+  else
+    return Status("unexpected /proc/{pid}/maps read permission char");
+  
+  // Handle write permission.
+  const char write_perm_char = line_extractor.GetChar();
+  if (write_perm_char == 'w')
+    memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+  else if (write_perm_char == '-')
+    memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+  else
+    return Status("unexpected /proc/{pid}/maps write permission char");
+  
+  // Handle execute permission.
+  const char exec_perm_char = line_extractor.GetChar();
+  if (exec_perm_char == 'x')
+    memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+  else if (exec_perm_char == '-')
+    memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+  else
+    return Status("unexpected /proc/{pid}/maps exec permission char");
+  
+  line_extractor.GetChar();              // Read the private bit
+  line_extractor.SkipSpaces();           // Skip the separator
+  line_extractor.GetHexMaxU64(false, 0); // Read the offset
+  line_extractor.GetHexMaxU64(false, 0); // Read the major device number
+  line_extractor.GetChar();              // Read the device id separator
+  line_extractor.GetHexMaxU64(false, 0); // Read the major device number
+  line_extractor.SkipSpaces();           // Skip the separator
+  line_extractor.GetU64(0, 10);          // Read the inode number
+  
+  line_extractor.SkipSpaces();
+  const char *name = line_extractor.Peek();
+  if (name)
+    memory_region_info.SetName(name);
+  
+  return Status();
+}
+
+void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
+                                        LinuxMapCallback const &callback) {
+  llvm::StringRef lines(linux_map);
+  llvm::StringRef line;
+  while (!lines.empty()) {
+    std::tie(line, lines) = lines.split('\n');
+    MemoryRegionInfo region;
+    Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
+    if (!callback(region, error))
+      break;
+  }
+}
Index: source/Plugins/Process/Utility/CMakeLists.txt
===================================================================
--- source/Plugins/Process/Utility/CMakeLists.txt
+++ source/Plugins/Process/Utility/CMakeLists.txt
@@ -5,6 +5,7 @@
   HistoryThread.cpp
   HistoryUnwind.cpp
   InferiorCallPOSIX.cpp
+  LinuxProcMaps.cpp
   LinuxSignals.cpp
   MipsLinuxSignals.cpp
   NativeRegisterContextRegisterInfo.cpp
Index: lldb.xcodeproj/project.pbxproj
===================================================================
--- lldb.xcodeproj/project.pbxproj
+++ lldb.xcodeproj/project.pbxproj
@@ -110,6 +110,8 @@
 		23E2E5251D90373D006F38BB /* ArchSpecTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23E2E5161D903689006F38BB /* ArchSpecTest.cpp */; };
 		AF2E02A31FA2CEAF00A86C34 /* ArchitectureArm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF2E02A11FA2CEAF00A86C34 /* ArchitectureArm.cpp */; };
 		AF2E02A41FA2CEAF00A86C34 /* ArchitectureArm.h in Headers */ = {isa = PBXBuildFile; fileRef = AF2E02A21FA2CEAF00A86C34 /* ArchitectureArm.h */; };
+		264CDE7021C33CFF00346695 /* ArchitectureMips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264CDE6E21C33CFF00346695 /* ArchitectureMips.cpp */; };
+		264CDE6F21C33CFF00346695 /* ArchitectureMips.h in Headers */ = {isa = PBXBuildFile; fileRef = 264CDE6D21C33CFF00346695 /* ArchitectureMips.h */; };
 		4C14CEFB2057258D00DEEF94 /* ArchitecturePPC64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C14CEF82057258D00DEEF94 /* ArchitecturePPC64.cpp */; };
 		2689007D13353E2200698AC0 /* Args.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E6C10F1B85900F91463 /* Args.cpp */; };
 		23CB153C1D66DA9300EDDDE1 /* ArgsTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2321F93E1BDD33CE00BA9A93 /* ArgsTest.cpp */; };
@@ -398,6 +400,8 @@
 		4CDB8D6D1DBA91B6006C5B13 /* LibStdcppUniquePointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CDB8D671DBA91A6006C5B13 /* LibStdcppUniquePointer.cpp */; };
 		268900DA13353E6F00698AC0 /* LineEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1910F1B8EC00F91463 /* LineEntry.cpp */; };
 		268900DB13353E6F00698AC0 /* LineTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1A10F1B8EC00F91463 /* LineTable.cpp */; };
+		264CDE6721C3076300346695 /* LinuxProcMaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264CDE6521C3076300346695 /* LinuxProcMaps.cpp */; };
+		264CDE6821C3076300346695 /* LinuxProcMaps.h in Headers */ = {isa = PBXBuildFile; fileRef = 264CDE6621C3076300346695 /* LinuxProcMaps.h */; };
 		23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0519532B96007B8189 /* LinuxSignals.cpp */; };
 		2689004113353E0400698AC0 /* Listener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7E10F1B85900F91463 /* Listener.cpp */; };
 		9A3D43EC1F3237F900EB767C /* ListenerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3D43E31F3237D500EB767C /* ListenerTest.cpp */; };
@@ -1433,6 +1437,8 @@
 		23E2E5161D903689006F38BB /* ArchSpecTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchSpecTest.cpp; sourceTree = "<group>"; };
 		AF2E02A11FA2CEAF00A86C34 /* ArchitectureArm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchitectureArm.cpp; sourceTree = "<group>"; };
 		AF2E02A21FA2CEAF00A86C34 /* ArchitectureArm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchitectureArm.h; sourceTree = "<group>"; };
+		264CDE6E21C33CFF00346695 /* ArchitectureMips.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ArchitectureMips.cpp; path = source/Plugins/Architecture/Mips/ArchitectureMips.cpp; sourceTree = SOURCE_ROOT; };
+		264CDE6D21C33CFF00346695 /* ArchitectureMips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ArchitectureMips.h; path = source/Plugins/Architecture/Mips/ArchitectureMips.h; sourceTree = SOURCE_ROOT; };
 		4C14CEF82057258D00DEEF94 /* ArchitecturePPC64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArchitecturePPC64.cpp; sourceTree = "<group>"; };
 		4C14CEF72057258D00DEEF94 /* ArchitecturePPC64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArchitecturePPC64.h; sourceTree = "<group>"; };
 		26BC7E6C10F1B85900F91463 /* Args.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Args.cpp; path = source/Utility/Args.cpp; sourceTree = "<group>"; };
@@ -2043,6 +2049,8 @@
 		26BC7C5B10F1B6E900F91463 /* LineEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LineEntry.h; path = include/lldb/Symbol/LineEntry.h; sourceTree = "<group>"; };
 		26BC7F1A10F1B8EC00F91463 /* LineTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LineTable.cpp; path = source/Symbol/LineTable.cpp; sourceTree = "<group>"; };
 		26BC7C5C10F1B6E900F91463 /* LineTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LineTable.h; path = include/lldb/Symbol/LineTable.h; sourceTree = "<group>"; };
+		264CDE6521C3076300346695 /* LinuxProcMaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinuxProcMaps.cpp; path = Utility/LinuxProcMaps.cpp; sourceTree = "<group>"; };
+		264CDE6621C3076300346695 /* LinuxProcMaps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LinuxProcMaps.h; path = Utility/LinuxProcMaps.h; sourceTree = "<group>"; };
 		23059A0519532B96007B8189 /* LinuxSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinuxSignals.cpp; path = Utility/LinuxSignals.cpp; sourceTree = "<group>"; };
 		23059A0619532B96007B8189 /* LinuxSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LinuxSignals.h; path = Utility/LinuxSignals.h; sourceTree = "<group>"; };
 		26BC7E7E10F1B85900F91463 /* Listener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Listener.cpp; path = source/Core/Listener.cpp; sourceTree = "<group>"; };
@@ -4420,6 +4428,16 @@
 			name = "GDB Server";
 			sourceTree = "<group>";
 		};
+		264CDE6C21C33CE800346695 /* MIPS */ = {
+			isa = PBXGroup;
+			children = (
+				264CDE6E21C33CFF00346695 /* ArchitectureMips.cpp */,
+				264CDE6D21C33CFF00346695 /* ArchitectureMips.h */,
+			);
+			name = MIPS;
+			path = "New Group";
+			sourceTree = "<group>";
+		};
 		264E8576159BE51A00E9D7A2 /* Resources */ = {
 			isa = PBXGroup;
 			children = (
@@ -4925,6 +4943,8 @@
 				B28058A0139988B0002D96D0 /* InferiorCallPOSIX.cpp */,
 				B28058A2139988C6002D96D0 /* InferiorCallPOSIX.h */,
 				B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */,
+				264CDE6521C3076300346695 /* LinuxProcMaps.cpp */,
+				264CDE6621C3076300346695 /* LinuxProcMaps.h */,
 				23059A0519532B96007B8189 /* LinuxSignals.cpp */,
 				23059A0619532B96007B8189 /* LinuxSignals.h */,
 				23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */,
@@ -6727,6 +6747,7 @@
 		AF2E029F1FA2CE8A00A86C34 /* Architecture */ = {
 			isa = PBXGroup;
 			children = (
+				264CDE6C21C33CE800346695 /* MIPS */,
 				4C14CEF52057258D00DEEF94 /* PPC64 */,
 				AF2E02A01FA2CE9900A86C34 /* Arm */,
 			);
@@ -6975,6 +6996,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				264CDE6821C3076300346695 /* LinuxProcMaps.h in Headers */,
 				AF8AD6381BEC28C400150209 /* PlatformRemoteAppleTV.h in Headers */,
 				26EFB61C1BFE8D3E00544801 /* PlatformNetBSD.h in Headers */,
 				AF3A4AD31EA05C4700B5DEB4 /* PlatformRemoteDarwinDevice.h in Headers */,
@@ -7008,6 +7030,7 @@
 				E414F6EE21388F0300C50BC6 /* LibCxxVariant.h in Headers */,
 				267F684B1CC02DED0086832B /* ABISysV_s390x.h in Headers */,
 				AF8AD6311BEC28A400150209 /* PlatformAppleWatchSimulator.h in Headers */,
+				264CDE6F21C33CFF00346695 /* ArchitectureMips.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -7961,6 +7984,7 @@
 				2689007413353E1A00698AC0 /* Terminal.cpp in Sources */,
 				2689007613353E1A00698AC0 /* CFCBundle.cpp in Sources */,
 				9A0FDEA71E8EF5110086B2F5 /* RegisterContextLinux_mips.cpp in Sources */,
+				264CDE7021C33CFF00346695 /* ArchitectureMips.cpp in Sources */,
 				94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */,
 				2689007713353E1A00698AC0 /* CFCData.cpp in Sources */,
 				AFC67B151FBBB03600860ECB /* LibCxxBitset.cpp in Sources */,
@@ -8191,6 +8215,7 @@
 				2689011013353E8200698AC0 /* SharingPtr.cpp in Sources */,
 				2689011113353E8200698AC0 /* StringExtractor.cpp in Sources */,
 				2689011213353E8200698AC0 /* StringExtractorGDBRemote.cpp in Sources */,
+				264CDE6721C3076300346695 /* LinuxProcMaps.cpp in Sources */,
 				E7723D4C1AC4A944002BA082 /* RegisterContextPOSIX_arm64.cpp in Sources */,
 				26BC17AB18C7F4CB00D2196D /* ProcessElfCore.cpp in Sources */,
 				AF1F7B07189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp in Sources */,
Index: include/lldb/Target/MemoryRegionInfo.h
===================================================================
--- include/lldb/Target/MemoryRegionInfo.h
+++ include/lldb/Target/MemoryRegionInfo.h
@@ -109,8 +109,22 @@
   OptionalBool m_flash;
   lldb::offset_t m_blocksize;
 };
+  
+inline bool operator<(const MemoryRegionInfo &lhs,
+                      const MemoryRegionInfo &rhs) {
+  return lhs.GetRange() < rhs.GetRange();
 }
 
+inline bool operator<(const MemoryRegionInfo &lhs, lldb::addr_t rhs) {
+  return lhs.GetRange().GetRangeBase() < rhs;
+}
+
+inline bool operator<(lldb::addr_t lhs, const MemoryRegionInfo &rhs) {
+  return lhs < rhs.GetRange().GetRangeBase();
+}
+
+}
+
 namespace llvm {
 template <>
 struct format_provider<lldb_private::MemoryRegionInfo::OptionalBool> {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to