clayborg updated this revision to Diff 177592.
clayborg added a comment.

Add reserve and shrink to fit when parsing memory regions.


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

https://reviews.llvm.org/D55522

Files:
  include/lldb/Target/MemoryRegionInfo.h
  source/Plugins/Process/minidump/MinidumpParser.cpp
  source/Plugins/Process/minidump/MinidumpParser.h
  source/Plugins/Process/minidump/MinidumpTypes.h

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
@@ -86,7 +86,7 @@
 
   llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
 
-  llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t);
+  llvm::Optional<MemoryRegionInfo> GetMemoryRegionInfo(lldb::addr_t load_addr);
 
   // Perform consistency checks and initialize internal data structures
   Status Initialize();
@@ -94,10 +94,19 @@
 private:
   MinidumpParser(const lldb::DataBufferSP &data_buf_sp);
 
+  bool CreateRegionsCacheFromLinuxMaps();
+  bool CreateRegionsCacheFromMemoryInfoList();
+  bool CreateRegionsCacheFromMemoryList();
+  bool CreateRegionsCacheFromMemory64List();
+  llvm::Optional<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
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <map>
 #include <vector>
+#include <utility>
 
 using namespace lldb_private;
 using namespace minidump;
@@ -401,72 +402,187 @@
   return range->range_ref.slice(offset, overlap);
 }
 
-llvm::Optional<MemoryRegionInfo>
-MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
-  MemoryRegionInfo info;
+bool MinidumpParser::CreateRegionsCacheFromLinuxMaps() {
+  llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::LinuxMaps);
+  if (data.empty())
+    return false;
+  auto text = llvm::toStringRef(data);
+  llvm::StringRef line;
+  constexpr auto yes = MemoryRegionInfo::eYes;
+  constexpr auto no = MemoryRegionInfo::eNo;
+  while (!text.empty()) {
+    std::tie(line, text) = text.split('\n');
+    // Parse the linux maps line. Example line is:
+    // 400b3000-400b5000 r-xp 00000000 b3:17 159        /system/bin/app_process
+    uint64_t start_addr, end_addr, offset;
+    uint32_t device_major, device_minor, inode;
+    if (line.consumeInteger(16, start_addr))
+      continue;
+    if (!line.consume_front("-"))
+      continue;
+    if (line.consumeInteger(16, end_addr))
+      continue;
+    line = line.ltrim();
+    llvm::StringRef permissions = line.substr(0, 4);
+    line = line.drop_front(4);
+    line = line.ltrim();
+    if (line.consumeInteger(16, offset))
+      continue;
+    line = line.ltrim();
+    if (line.consumeInteger(16, device_major))
+      continue;
+    if (!line.consume_front(":"))
+      continue;
+    if (line.consumeInteger(16, device_minor))
+      continue;
+    line = line.ltrim();
+    if (line.consumeInteger(16, inode))
+      continue;
+    line = line.ltrim();
+    llvm::StringRef pathname = line;
+    MemoryRegionInfo region;
+    region.GetRange().SetRangeBase(start_addr);
+    region.GetRange().SetRangeEnd(end_addr);
+    region.SetName(pathname.str().c_str());
+    region.SetReadable(permissions[0] == 'r' ? yes : no);
+    region.SetWritable(permissions[1] == 'w' ? yes : no);
+    region.SetExecutable(permissions[2] == 'x' ? yes : no);
+    region.SetMapped(yes);
+    m_regions.push_back(region);
+  }
+  return !m_regions.empty();
+}
+
+bool MinidumpParser::CreateRegionsCacheFromMemoryInfoList() {
   llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryInfoList);
   if (data.empty())
-    return llvm::None;
-
+    return false;
   std::vector<const MinidumpMemoryInfo *> mem_info_list =
       MinidumpMemoryInfo::ParseMemoryInfoList(data);
   if (mem_info_list.empty())
-    return llvm::None;
+    return false;
+  
+  constexpr auto yes = MemoryRegionInfo::eYes;
+  constexpr auto no = MemoryRegionInfo::eNo;
 
-  const auto yes = MemoryRegionInfo::eYes;
-  const auto no = MemoryRegionInfo::eNo;
-
-  const MinidumpMemoryInfo *next_entry = nullptr;
+  m_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);
+    m_regions.push_back(region);
+  }
+  return !m_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);
+bool MinidumpParser::CreateRegionsCacheFromMemoryList() {
+  llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
+  
+  if (data.empty())
+    return false;
+  
+  llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
+      MinidumpMemoryDescriptor::ParseMemoryList(data);
+    
+  if (memory_list.empty())
+    return false;
+    
+  m_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.SetMapped(MemoryRegionInfo::eYes);
+    m_regions.push_back(region);
+  }
+  m_regions.shrink_to_fit();
+  return !m_regions.empty();
+}
 
-      const uint32_t PageNoAccess =
-          static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageNoAccess);
-      info.SetReadable((entry->protect & PageNoAccess) == 0 ? yes : no);
+bool MinidumpParser::CreateRegionsCacheFromMemory64List() {
+  llvm::ArrayRef<uint8_t> data = 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;
+    
+  m_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.SetMapped(MemoryRegionInfo::eYes);
+    m_regions.push_back(region);
+  }
+  m_regions.shrink_to_fit();
+  return !m_regions.empty();
+}
 
-      const uint32_t PageWritable =
-          static_cast<uint32_t>(MinidumpMemoryProtectionContants::PageWritable);
-      info.SetWritable((entry->protect & PageWritable) != 0 ? yes : no);
-
-      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;
-    }
+llvm::Optional<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;
+  if (pos != begin) {
+    --pos;
+    if (pos->GetRange().Contains(load_addr))
+      return *pos;
   }
+  
+  MemoryRegionInfo region;
+  if (pos == begin)
+    region.GetRange().SetRangeBase(0);
+  else {
+    auto prev = pos - 1;
+    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;
+}
 
-  // 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);
+llvm::Optional<MemoryRegionInfo>
+MinidumpParser::GetMemoryRegionInfo(lldb::addr_t load_addr) {
+  // See if we have cached our memory regions yet?
+  if (m_parsed_regions)
+    return FindMemoryRegion(load_addr);
 
-  // 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;
+  // 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
+  m_parsed_regions = true;
+  if (!CreateRegionsCacheFromLinuxMaps())
+    if (!CreateRegionsCacheFromMemoryInfoList())
+      if (!CreateRegionsCacheFromMemoryList())
+        CreateRegionsCacheFromMemory64List();
+  std::sort(m_regions.begin(), m_regions.end());
+  return FindMemoryRegion(load_addr);
 }
 
 Status MinidumpParser::Initialize() {
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