diff options
author | Pavel Labath <pavel@labath.sk> | 2019-10-16 10:38:10 +0200 |
---|---|---|
committer | Pavel Labath <pavel@labath.sk> | 2019-10-31 11:24:55 +0100 |
commit | 193a7bfb697b5d2adb1c3d37a9d624aa8131ec35 (patch) | |
tree | b6fe618ffc417076927ab1076cfac364936e31ce /lldb/source/Plugins/Process | |
parent | e9430231accacdb872bc4c82feb9a6a64d57941b (diff) | |
download | bcm5719-llvm-193a7bfb697b5d2adb1c3d37a9d624aa8131ec35.tar.gz bcm5719-llvm-193a7bfb697b5d2adb1c3d37a9d624aa8131ec35.zip |
minidump: Create memory regions from the sections of loaded modules
Summary:
Not all minidumps contain information about memory permissions. However,
it is still important to know which regions of memory contain
potentially executable code. This is particularly important for
unwinding on win32, as the default unwind method there relies on
scanning the stack for things which "look like" code pointers.
This patch enables ProcessMinidump to reconstruct the likely permissions
of memory regions using the sections of loaded object files. It only
does this if we don't have a better source (memory info list stream, or
linux /proc/maps) for this information, and only if the information in
the object files does not conflict with the information in the minidump.
Theoretically that last bit could be improved, since the permissions
obtained from the MemoryList streams is also only a very rough guess,
but it did not seem worthwhile to complicate the implementation because
of that because there will generally be no overlap in practice as the
MemoryList will contain the stack contents and not any module data.
The patch adds a test checking that the module section permissions are
entered into the memory region list, and also a test which demonstrate
that now the unwinder is able to correctly find return addresses even in
minidumps without memory info list streams.
There's one TODO left in this patch, which is that the "memory region"
output does not give any indication about the "don't know" values of
memory region permissions (it just prints them as if they permission bit
was set). I address this in a follow up.
Reviewers: amccarth, clayborg
Subscribers: mgrang, lldb-commits
Differential Revision: https://reviews.llvm.org/D69105
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r-- | lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp | 76 |
1 files changed, 57 insertions, 19 deletions
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 5dcaaaa34d9..5c090dc6e12 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -334,32 +334,21 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } -void ProcessMinidump::BuildMemoryRegions() { - if (m_memory_regions) - return; - m_memory_regions.emplace(); - bool is_complete; - std::tie(*m_memory_regions, is_complete) = - m_minidump_parser->BuildMemoryRegions(); - // TODO: Use loaded modules to complete the region list. -} - -Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, - MemoryRegionInfo ®ion) { - BuildMemoryRegions(); - auto pos = llvm::upper_bound(*m_memory_regions, load_addr); - if (pos != m_memory_regions->begin() && +static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr) { + MemoryRegionInfo region; + auto pos = llvm::upper_bound(regions, load_addr); + if (pos != regions.begin() && std::prev(pos)->GetRange().Contains(load_addr)) { - region = *std::prev(pos); - return Status(); + return *std::prev(pos); } - if (pos == m_memory_regions->begin()) + if (pos == regions.begin()) region.GetRange().SetRangeBase(0); else region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); - if (pos == m_memory_regions->end()) + if (pos == regions.end()) region.GetRange().SetRangeEnd(UINT64_MAX); else region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); @@ -368,6 +357,55 @@ Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, region.SetWritable(MemoryRegionInfo::eNo); region.SetExecutable(MemoryRegionInfo::eNo); region.SetMapped(MemoryRegionInfo::eNo); + return region; +} + +void ProcessMinidump::BuildMemoryRegions() { + if (m_memory_regions) + return; + m_memory_regions.emplace(); + bool is_complete; + std::tie(*m_memory_regions, is_complete) = + m_minidump_parser->BuildMemoryRegions(); + + if (is_complete) + return; + + MemoryRegionInfos to_add; + ModuleList &modules = GetTarget().GetImages(); + SectionLoadList &load_list = GetTarget().GetSectionLoadList(); + modules.ForEach([&](const ModuleSP &module_sp) { + SectionList *sections = module_sp->GetSectionList(); + for (size_t i = 0; i < sections->GetSize(); ++i) { + SectionSP section_sp = sections->GetSectionAtIndex(i); + addr_t load_addr = load_list.GetSectionLoadAddress(section_sp); + if (load_addr == LLDB_INVALID_ADDRESS) + continue; + MemoryRegionInfo::RangeType section_range(load_addr, + section_sp->GetByteSize()); + MemoryRegionInfo region = + ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + if (region.GetMapped() != MemoryRegionInfo::eYes && + region.GetRange().GetRangeBase() <= section_range.GetRangeBase() && + section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) { + to_add.emplace_back(); + to_add.back().GetRange() = section_range; + to_add.back().SetLLDBPermissions(section_sp->GetPermissions()); + to_add.back().SetMapped(MemoryRegionInfo::eYes); + to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str()); + } + } + return true; + }); + m_memory_regions->insert(m_memory_regions->end(), to_add.begin(), + to_add.end()); + llvm::sort(*m_memory_regions); +} + +Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion) { + BuildMemoryRegions(); + region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr); return Status(); } |