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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits