From 00a12585933ef63ff1204bf5cd265f0071d04642 Mon Sep 17 00:00:00 2001 From: David Spickett Date: Mon, 4 Apr 2022 14:42:24 +0100 Subject: [PATCH] [lldb][AArch64] Fix corefile memory reads when there are non-address bits Previously if you read a code/data mask before there was a valid thread you would get the top byte mask. This meant the value was "valid" as in, don't read it again. When using a corefile we ask for the data mask very early on and this meant that later once you did have a thread it wouldn't read the register to get the rest of the mask. This fixes that and adds a corefile test generated from the same program as in my previous change on this theme. Depends on D118794 Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D122411 --- .../Plugins/ABI/AArch64/ABISysV_arm64.cpp | 18 ++++-- .../Process/elf-core/ProcessElfCore.cpp | 4 ++ ...stAArch64LinuxNonAddressBitMemoryAccess.py | 52 ++++++++++++++++++ .../non_address_bit_memory_access/corefile | Bin 0 -> 24576 bytes .../non_address_bit_memory_access/main.c | 13 +++++ 5 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 lldb/test/API/linux/aarch64/non_address_bit_memory_access/corefile diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 99623ce74eff..2896f5920db9 100644 --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -794,14 +794,20 @@ lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) { // Reads code or data address mask for the current Linux process. static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp, llvm::StringRef reg_name) { - // Linux configures user-space virtual addresses with top byte ignored. - // We set default value of mask such that top byte is masked out. - uint64_t address_mask = ~((1ULL << 56) - 1); - // If Pointer Authentication feature is enabled then Linux exposes - // PAC data and code mask register. Try reading relevant register - // below and merge it with default address mask calculated above. + // 0 means there isn't a mask or it has not been read yet. + // We do not return the top byte mask unless thread_sp is valid. + // This prevents calls to this function before the thread is setup locking + // in the value to just the top byte mask, in cases where pointer + // authentication might also be active. + uint64_t address_mask = 0; lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); if (thread_sp) { + // Linux configures user-space virtual addresses with top byte ignored. + // We set default value of mask such that top byte is masked out. + address_mask = ~((1ULL << 56) - 1); + // If Pointer Authentication feature is enabled then Linux exposes + // PAC data and code mask register. Try reading relevant register + // below and merge it with default address mask calculated above. lldb::RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); if (reg_ctx_sp) { const RegisterInfo *reg_info = diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index fe22bcbd75a1..58b4fe3add1b 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" @@ -281,6 +282,9 @@ bool ProcessElfCore::IsAlive() { return true; } // Process Memory size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) { + if (lldb::ABISP abi_sp = GetABI()) + addr = abi_sp->FixAnyAddress(addr); + // Don't allow the caching that lldb_private::Process::ReadMemory does since // in core files we have it all cached our our core file anyway. return DoReadMemory(addr, buf, size, error); diff --git a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py index b9b5b54d4a30..d3de12d1b88a 100644 --- a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py +++ b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py @@ -163,6 +163,10 @@ class AArch64LinuxNonAddressBitMemoryAccessTestCase(TestBase): # Open log ignoring utf-8 decode errors with open(log_file, 'r', errors='ignore') as f: read_packet = "send packet: $x{:x}" + + # Since we allocated a 4k page that page will be aligned to 4k, which + # also fits the 512 byte line size of the memory cache. So we can expect + # to find a packet with its exact address. read_buf_packet = read_packet.format(buf) read_buf_with_non_address_packet = read_packet.format(buf_with_non_address) @@ -180,3 +184,51 @@ class AArch64LinuxNonAddressBitMemoryAccessTestCase(TestBase): if not found_read_buf: self.fail("Did not find any reads of buf.") + + @skipIfLLVMTargetMissing("AArch64") + def test_non_address_bit_memory_corefile(self): + self.runCmd("target create --core corefile") + + self.expect("thread list", substrs=['stopped', + 'stop reason = signal SIGSEGV']) + + # No caching (the program/corefile are the cache) and no writing + # to memory. So just check that tagged/untagged addresses read + # the same location. + + # These are known addresses in the corefile, since we won't have symbols. + buf = 0x0000ffffa75a5000 + buf_with_non_address = 0xff0bffffa75a5000 + + expected = ["4c 4c 44 42", "LLDB"] + self.expect("memory read 0x{:x}".format(buf), substrs=expected) + self.expect("memory read 0x{:x}".format(buf_with_non_address), substrs=expected) + + # This takes a more direct route to ReadMemory. As opposed to "memory read" + # above that might fix the addresses up front for display reasons. + self.expect("expression (char*)0x{:x}".format(buf), substrs=["LLDB"]) + self.expect("expression (char*)0x{:x}".format(buf_with_non_address), substrs=["LLDB"]) + + def check_reads(addrs, method, num_bytes, expected): + error = lldb.SBError() + for addr in addrs: + if num_bytes is None: + got = method(addr, error) + else: + got = method(addr, num_bytes, error) + + self.assertTrue(error.Success()) + self.assertEqual(expected, got) + + addr_buf = lldb.SBAddress() + addr_buf.SetLoadAddress(buf, self.target()) + addr_buf_with_non_address = lldb.SBAddress() + addr_buf_with_non_address.SetLoadAddress(buf_with_non_address, self.target()) + check_reads([addr_buf, addr_buf_with_non_address], self.target().ReadMemory, + 4, b'LLDB') + + addrs = [buf, buf_with_non_address] + check_reads(addrs, self.process().ReadMemory, 4, b'LLDB') + check_reads(addrs, self.process().ReadCStringFromMemory, 5, "LLDB") + check_reads(addrs, self.process().ReadUnsignedFromMemory, 4, 0x42444c4c) + check_reads(addrs, self.process().ReadPointerFromMemory, None, 0x0000000042444c4c) diff --git a/lldb/test/API/linux/aarch64/non_address_bit_memory_access/corefile b/lldb/test/API/linux/aarch64/non_address_bit_memory_access/corefile new file mode 100644 index 0000000000000000000000000000000000000000..ef02e54137f7e8233ff8bd958dd0948f8a0520a8 GIT binary patch literal 24576 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 + // Uncomment this line to crash and generate a corefile. + // Prints so we know what fixed address to look for in testing. + // printf("buf: %p\n", buf); + // printf("buf_with_non_address: %p\n", buf_with_non_address); + // *(char*)0 = 0; + return 0; // Set break point at this line. }