[Lldb-commits] [lldb] r349182 - Cache memory regions in ProcessMinidump and use the linux maps as the source of the information if available
Greg Clayton via lldb-commits
lldb-commits at lists.llvm.org
Fri Dec 14 11:36:01 PST 2018
Author: gclayton
Date: Fri Dec 14 11:36:01 2018
New Revision: 349182
URL: http://llvm.org/viewvc/llvm-project?rev=349182&view=rev
Log:
Cache memory regions in ProcessMinidump and use the linux maps as the source of the information if available
Breakpad creates minidump files that sometimes have:
- linux maps textual content
- no MemoryInfoList
Right now unless the file has a MemoryInfoList we get no region information.
This patch:
- reads and caches the memory region info one time and sorts it for easy subsequent access
- get the region info from the best source in this order:
- linux maps info (if available)
- MemoryInfoList (if available)
- MemoryList or Memory64List
- returns memory region info for the gaps between regions (before the first and after the last)
Differential Revision: https://reviews.llvm.org/D55522
Added:
lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.cpp
lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.h
lldb/trunk/unittests/Process/minidump/Inputs/regions-linux-map.dmp (with props)
lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist.dmp (with props)
lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist64.dmp (with props)
Modified:
lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
lldb/trunk/lldb.xcodeproj/project.pbxproj
lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp
lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h
lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h
lldb/trunk/source/Plugins/Process/minidump/ProcessMinidump.cpp
lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp
Modified: lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/MemoryRegionInfo.h?rev=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/MemoryRegionInfo.h (original)
+++ lldb/trunk/include/lldb/Target/MemoryRegionInfo.h Fri Dec 14 11:36:01 2018
@@ -109,6 +109,20 @@ protected:
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 {
Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Fri Dec 14 11:36:01 2018
@@ -402,6 +402,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 */; };
+ 2647B64421C43BB000A81D15 /* LinuxProcMaps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2647B64221C43BB000A81D15 /* LinuxProcMaps.cpp */; };
+ 2647B64321C43BB000A81D15 /* LinuxProcMaps.h in Headers */ = {isa = PBXBuildFile; fileRef = 2647B64121C43BAF00A81D15 /* LinuxProcMaps.h */; };
23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0519532B96007B8189 /* LinuxSignals.cpp */; };
2647B63E21C436BD00A81D15 /* Listener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2647B63D21C436BC00A81D15 /* Listener.cpp */; };
2647B63821C4369500A81D15 /* Listener.h in Headers */ = {isa = PBXBuildFile; fileRef = 2647B63721C4369500A81D15 /* Listener.h */; };
@@ -2050,6 +2052,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>"; };
+ 2647B64221C43BB000A81D15 /* LinuxProcMaps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinuxProcMaps.cpp; path = Utility/LinuxProcMaps.cpp; sourceTree = "<group>"; };
+ 2647B64121C43BAF00A81D15 /* 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>"; };
2647B63D21C436BC00A81D15 /* Listener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Listener.cpp; path = source/Utility/Listener.cpp; sourceTree = "<group>"; };
@@ -4948,6 +4952,8 @@
B28058A0139988B0002D96D0 /* InferiorCallPOSIX.cpp */,
B28058A2139988C6002D96D0 /* InferiorCallPOSIX.h */,
B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */,
+ 2647B64221C43BB000A81D15 /* LinuxProcMaps.cpp */,
+ 2647B64121C43BAF00A81D15 /* LinuxProcMaps.h */,
23059A0519532B96007B8189 /* LinuxSignals.cpp */,
23059A0619532B96007B8189 /* LinuxSignals.h */,
23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */,
@@ -6995,6 +7001,7 @@
files = (
AF8AD6381BEC28C400150209 /* PlatformRemoteAppleTV.h in Headers */,
26EFB61C1BFE8D3E00544801 /* PlatformNetBSD.h in Headers */,
+ 2647B64321C43BB000A81D15 /* LinuxProcMaps.h in Headers */,
AF3A4AD31EA05C4700B5DEB4 /* PlatformRemoteDarwinDevice.h in Headers */,
AF9113FE1FBE78EA004320CD /* RegisterContextPOSIXCore_ppc64le.h in Headers */,
AF33B4BF1C1FA441001B28D9 /* NetBSDSignals.h in Headers */,
@@ -7966,6 +7973,7 @@
AF2BA6EC1A707E3400C5248A /* UriParser.cpp in Sources */,
2689006D13353E0E00698AC0 /* IRExecutionUnit.cpp in Sources */,
304B2E461CAAA57B007829FE /* ClangUtil.cpp in Sources */,
+ 2647B64421C43BB000A81D15 /* LinuxProcMaps.cpp in Sources */,
2689006E13353E1A00698AC0 /* File.cpp in Sources */,
2689006F13353E1A00698AC0 /* FileSpec.cpp in Sources */,
AF6CA6661FBBAF28005A0DC3 /* ArchSpec.cpp in Sources */,
Modified: lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt?rev=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt Fri Dec 14 11:36:01 2018
@@ -5,6 +5,7 @@ add_lldb_library(lldbPluginProcessUtilit
HistoryThread.cpp
HistoryUnwind.cpp
InferiorCallPOSIX.cpp
+ LinuxProcMaps.cpp
LinuxSignals.cpp
MipsLinuxSignals.cpp
NativeRegisterContextRegisterInfo.cpp
Added: lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.cpp?rev=349182&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.cpp Fri Dec 14 11:36:01 2018
@@ -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;
+ }
+}
Added: lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.h?rev=349182&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxProcMaps.h Fri Dec 14 11:36:01 2018
@@ -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_
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=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.cpp Fri Dec 14 11:36:01 2018
@@ -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 @@ llvm::ArrayRef<uint8_t> MinidumpParser::
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> ®ions) {
+ auto data = parser.GetStream(MinidumpStreamType::LinuxMaps);
if (data.empty())
- return llvm::None;
+ return false;
+ ParseLinuxMapRegions(llvm::toStringRef(data),
+ [&](const lldb_private::MemoryRegionInfo ®ion,
+ 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> ®ions) {
+ 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;
+ 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) {
+ 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();
+}
- const auto yes = MemoryRegionInfo::eYes;
- const auto no = MemoryRegionInfo::eNo;
+static bool
+CreateRegionsCacheFromMemoryList(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> ®ions) {
+ 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 MinidumpMemoryInfo *next_entry = nullptr;
- for (const auto &entry : mem_info_list) {
- const auto head = entry->base_address;
- const auto tail = head + entry->region_size;
+static bool
+CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> ®ions) {
+ 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();
+}
- 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 ? yes : no);
-
- 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;
- }
+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;
+}
- // 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;
+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());
+ }
+ return FindMemoryRegion(load_addr);
}
Status MinidumpParser::Initialize() {
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=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpParser.h Fri Dec 14 11:36:01 2018
@@ -1,5 +1,4 @@
-//===-- MinidumpParser.h -----------------------------------------*- C++
-//-*-===//
+//===-- MinidumpParser.h -----------------------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -86,7 +85,7 @@ public:
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 @@ public:
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
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=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h (original)
+++ lldb/trunk/source/Plugins/Process/minidump/MinidumpTypes.h Fri Dec 14 11:36:01 2018
@@ -256,25 +256,6 @@ struct MinidumpMemoryInfoListHeader {
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 @@ enum class MinidumpMemoryProtectionConta
};
// 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;
Modified: lldb/trunk/source/Plugins/Process/minidump/ProcessMinidump.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/minidump/ProcessMinidump.cpp?rev=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/minidump/ProcessMinidump.cpp (original)
+++ lldb/trunk/source/Plugins/Process/minidump/ProcessMinidump.cpp Fri Dec 14 11:36:01 2018
@@ -284,14 +284,8 @@ ArchSpec ProcessMinidump::GetArchitectur
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(); }
Added: lldb/trunk/unittests/Process/minidump/Inputs/regions-linux-map.dmp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/Inputs/regions-linux-map.dmp?rev=349182&view=auto
==============================================================================
Binary file - no diff available.
Propchange: lldb/trunk/unittests/Process/minidump/Inputs/regions-linux-map.dmp
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist.dmp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist.dmp?rev=349182&view=auto
==============================================================================
Binary file - no diff available.
Propchange: lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist.dmp
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist64.dmp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist64.dmp?rev=349182&view=auto
==============================================================================
Binary file - no diff available.
Propchange: lldb/trunk/unittests/Process/minidump/Inputs/regions-memlist64.dmp
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Modified: lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp?rev=349182&r1=349181&r2=349182&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp (original)
+++ lldb/trunk/unittests/Process/minidump/MinidumpParserTest.cpp Fri Dec 14 11:36:01 2018
@@ -300,29 +300,120 @@ TEST_F(MinidumpParserTest, FindMemoryRan
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_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_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 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
@@ -571,3 +662,4 @@ TEST_F(MinidumpParserTest, MinidumpModul
ASSERT_TRUE((bool)name);
EXPECT_EQ(std::string("/tmp/b"), *name);
}
+
More information about the lldb-commits
mailing list