From 193a7bfb697b5d2adb1c3d37a9d624aa8131ec35 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Wed, 16 Oct 2019 10:38:10 +0200 Subject: [PATCH] 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 --- .../Plugins/Process/minidump/ProcessMinidump.cpp | 76 +++++++++--- lldb/test/Shell/Minidump/Inputs/basic-elf.yaml | 40 +++++++ .../Shell/Minidump/memory-region-from-module.yaml | 91 ++++++++++++++ .../unwind-via-stack-win-no-memory-info.yaml | 133 +++++++++++++++++++++ 4 files changed, 321 insertions(+), 19 deletions(-) create mode 100644 lldb/test/Shell/Minidump/Inputs/basic-elf.yaml create mode 100644 lldb/test/Shell/Minidump/memory-region-from-module.yaml create mode 100644 lldb/test/Shell/SymbolFile/Breakpad/unwind-via-stack-win-no-memory-info.yaml diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 5dcaaaa..5c090dc 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(); } diff --git a/lldb/test/Shell/Minidump/Inputs/basic-elf.yaml b/lldb/test/Shell/Minidump/Inputs/basic-elf.yaml new file mode 100644 index 0000000..e6dc1b5 --- /dev/null +++ b/lldb/test/Shell/Minidump/Inputs/basic-elf.yaml @@ -0,0 +1,40 @@ +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x0000000000004000 + AddressAlign: 0x0000000000001000 + Size: 0xb0 + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] + Address: 0x0000000000005000 + AddressAlign: 0x0000000000001000 + Size: 0x42 + - Name: .note.gnu.build-id + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Address: 0x0000000000005042 + AddressAlign: 0x0000000000000004 + Content: 040000000800000003000000474E5500DEADBEEFBAADF00D +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_R ] + VAddr: 0x4000 + Align: 0x1000 + Sections: + - Section: .text + - Type: PT_LOAD + Flags: [ PF_W, PF_R ] + VAddr: 0x5000 + Align: 0x1000 + Sections: + - Section: .data + - Section: .note.gnu.build-id +... diff --git a/lldb/test/Shell/Minidump/memory-region-from-module.yaml b/lldb/test/Shell/Minidump/memory-region-from-module.yaml new file mode 100644 index 0000000..0c405e8 --- /dev/null +++ b/lldb/test/Shell/Minidump/memory-region-from-module.yaml @@ -0,0 +1,91 @@ +# Check that memory region parsing works correctly, with a particular emphasis +# on the boundary conditions. + +# RUN: yaml2obj --docnum=1 %s > %t1.dmp +# RUN: yaml2obj --docnum=2 %s > %t2.dmp +# RUN: yaml2obj %S/Inputs/basic-elf.yaml >%T/memory-region-from-module.exe + +# RUN: %lldb -b -c %t1.dmp %T/memory-region-from-module.exe \ +# RUN: -o "memory region 0" -o "memory region 0x4000" \ +# RUN: -o "memory region 0x5000" -o "memory region 0x6000" \ +# RUN: | FileCheck --check-prefix=ALL --check-prefix=CHECK1 %s + +# RUN: %lldb -b -c %t2.dmp %T/memory-region-from-module.exe \ +# RUN: -o "memory region 0" -o "memory region 0x4000" \ +# RUN: -o "memory region 0x5000" -o "memory region 0x6000" \ +# RUN: | FileCheck --check-prefix=ALL --check-prefix=CHECK2 %s + +# ALL-LABEL: (lldb) memory region 0 +# ALL: [0x0000000000000000-0x0000000000004000) --- +# ALL-LABEL: (lldb) memory region 0x4000 +# CHECK1: [0x0000000000004000-0x00000000000040b0) r-x {{.*}}memory-region-from-module.exe PT_LOAD[0] +# TODO: This output does not give any indication that the region is only "potentially" writable. +# CHECK2: [0x0000000000004000-0x0000000000004010) rwx +# ALL-LABEL: (lldb) memory region 0x5000 +# ALL: [0x0000000000005000-0x000000000000505c) rw- {{.*}}memory-region-from-module.exe PT_LOAD[1] +# ALL-LABEL: (lldb) memory region 0x6000 +# ALL: [0x000000000000505c-0xffffffffffffffff) --- + +--- !minidump +Streams: + - Type: ModuleList + Modules: + - Base of Image: 0x0000000000004000 + Size of Image: 0x00002000 + Module Name: 'memory-region-from-module.exe' + CodeView Record: 4C457042DEADBEEFBAADF00D + + - Type: SystemInfo + Processor Arch: AMD64 + Platform ID: Linux + CPU: + Vendor ID: GenuineIntel + Version Info: 0x00000000 + Feature Info: 0x00000000 + - Type: LinuxProcStatus + Text: | + Name: memory-region-from-module.exe + State: t (tracing stop) + Tgid: 29939 + Ngid: 0 + Pid: 29939 + PPid: 29370 + TracerPid: 29940 + Uid: 1001 1001 1001 1001 + Gid: 1001 1001 1001 1001 + +... + +--- !minidump +Streams: + - Type: MemoryList + Memory Ranges: + - Start of Memory Range: 0x0000000000004000 + Content: 30044000000000000000000000000000 + - Type: ModuleList + Modules: + - Base of Image: 0x0000000000004000 + Size of Image: 0x00002000 + Module Name: 'memory-region-from-module.exe' + CodeView Record: 4C457042DEADBEEFBAADF00D + + - Type: SystemInfo + Processor Arch: AMD64 + Platform ID: Linux + CPU: + Vendor ID: GenuineIntel + Version Info: 0x00000000 + Feature Info: 0x00000000 + - Type: LinuxProcStatus + Text: | + Name: memory-region-from-module.exe + State: t (tracing stop) + Tgid: 29939 + Ngid: 0 + Pid: 29939 + PPid: 29370 + TracerPid: 29940 + Uid: 1001 1001 1001 1001 + Gid: 1001 1001 1001 1001 + +... diff --git a/lldb/test/Shell/SymbolFile/Breakpad/unwind-via-stack-win-no-memory-info.yaml b/lldb/test/Shell/SymbolFile/Breakpad/unwind-via-stack-win-no-memory-info.yaml new file mode 100644 index 0000000..5fb7553 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/Breakpad/unwind-via-stack-win-no-memory-info.yaml @@ -0,0 +1,133 @@ +# RUN: yaml2obj --docnum=1 %s > %t.dmp +# RUN: yaml2obj --docnum=2 %s > %t.exe +# RUN: %lldb -c %t.dmp %t.exe \ +# RUN: -o "target symbols add %S/Inputs/unwind-via-raSearch.syms" \ +# RUN: -o "thread backtrace" -b | FileCheck %s + +# CHECK-LABEL: thread backtrace +# CHECK: frame #0: 0x000b1092 unwind-via-stack-win.exe`many_pointer_args +# CHECK: frame #1: 0x000b1079 unwind-via-stack-win.exe`call_many + 105 +# CHECK: frame #2: 0x000b1085 unwind-via-stack-win.exe`main + 5 +# CHECK: frame #3: 0x77278494 kernel32.dll +# CHECK-NOT: frame + +--- !minidump +Streams: + - Type: ThreadList + Threads: + - Thread Id: 0x0000290C + Priority Class: 0x00000020 + Environment Block: 0x0000000000A98000 + Context: 3F0001000000000000000000000000000000000000000000000000007F02000000000000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002B000000530000002B0000002B00000080100B0080100B000050A90080100B0080100B0000000000E4FECF0092100B0023000000440301007CFECF002B0000007F0200000000000000000000000000000000000000000000801F0000FFFF020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000144E3D6C2000000001000000EA1E00F4C000E50700000000FC0100002CE3C014D8E202010000E507880F401D839DC60100000000400000007F00000000000000880F401D0A000000900F401D0000000000000100EA1E00009808E5077F00000000000000000000009008E507990100006002E5072CABC87708346474B42300000100000044E3C014200000000000000020532777A80F401D4F346474D00F401D6F378CCC5C4CD5010000000000000000000000000000000000000000000000003AFCD72F90E3C01418CE3470B4230000B80F401DC00F401DC80F401DD00F401D + Stack: + Start of Memory Range: 0x0000000000CFFE78 + Content: 0000000079100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0085100B0094842777 + - Type: ModuleList + Modules: + - Base of Image: 0x00000000000B1000 + Size of Image: 0x00004000 + Module Name: 'unwind-via-stack-win.exe' + CodeView Record: 525344533ED87D89C8A8184197F3A925EE4BF74101000000433A5C70726F6A656374735C746573745F6170705C436F6E736F6C654170706C69636174696F6E315C44656275675C436F6E736F6C654170706C69636174696F6E312E70646200 + - Base of Image: 0x0000000077260000 + Size of Image: 0x000E0000 + Module Name: 'C:\Windows\System32\kernel32.dll' + CodeView Record: 5253445300F90A57CF8DED8A463A90390318CD4401000000776B65726E656C33322EFFFFFFFF + - Type: MemoryList + Memory Ranges: + - Start of Memory Range: 0x0000000000CFFE78 + Content: 0000000079100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0000100B0085100B0094842777 + - Type: SystemInfo + Processor Arch: X86 + Platform ID: Win32NT + CPU: + Vendor ID: AuthenticAMD + Version Info: 0x00800F82 + Feature Info: 0x178BFBFF + - Type: MiscInfo + Content: 54050000F703000008290000C883495D0000000000000000AC0D000098080000AC0D00000200000002000000002000000D0000000000000002000000C4FFFFFF430065006E007400720061006C0020004500750072006F007000650020005300740061006E0064006100720064002000540069006D006500000000000000000000000A0000000500030000000000000000000000430065006E007400720061006C0020004500750072006F00700065002000530075006D006D00650072002000540069006D00650000000000000000000000000000000300000005000200000000000000C4FFFFFF310037003100330034002E0031002E007800380036006600720065002E007200730034005F00720065006C0065006100730065002E003100380030003400310030002D00310038003000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064006200670063006F00720065002E0069003300380036002C00310030002E0030002E00310037003100330034002E0031000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C816B92 +... + +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 0 + ImageBase: 720896 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 + ExportTable: + RelativeVirtualAddress: 8327 + Size: 90 + ImportTable: + RelativeVirtualAddress: 0 + Size: 0 + ResourceTable: + RelativeVirtualAddress: 0 + Size: 0 + ExceptionTable: + RelativeVirtualAddress: 12288 + Size: 12 + CertificateTable: + RelativeVirtualAddress: 0 + Size: 0 + BaseRelocationTable: + RelativeVirtualAddress: 0 + Size: 0 + Debug: + RelativeVirtualAddress: 8192 + Size: 28 + Architecture: + RelativeVirtualAddress: 0 + Size: 0 + GlobalPtr: + RelativeVirtualAddress: 0 + Size: 0 + TlsTable: + RelativeVirtualAddress: 0 + Size: 0 + LoadConfigTable: + RelativeVirtualAddress: 0 + Size: 0 + BoundImport: + RelativeVirtualAddress: 0 + Size: 0 + IAT: + RelativeVirtualAddress: 0 + Size: 0 + DelayImportDescriptor: + RelativeVirtualAddress: 0 + Size: 0 + ClrRuntimeHeader: + RelativeVirtualAddress: 0 + Size: 0 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 22 + SectionData: 50894C24048B4C24040FAF4C2404890C248B042459C3 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 236 + SectionData: 00000000A565B65C00000000020000006B0000001C2000001C060000525344533ED87D89C8A8184197F3A925EE4BF74101000000443A5C757073747265616D5C6275696C645C746F6F6C735C6C6C64625C6C69745C4D6F64756C65735C5045434F46465C4F75747075745C6578706F72742D646C6C66756E632E79616D6C2E746D702E70646200000000000000000000000000AF200000000000000200000001000000CB200000D3200000D72000006578706F72742D646C6C66756E632E79616D6C2E746D702E646C6C000000000000100000D92000000100446C6C46756E63000000000101010001020000 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 12 + SectionData: '0010000016100000E4200000' +symbols: [] +... -- 2.7.4