https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/147011
>From bf1838f4676bab0f7c998d3dbb03b6b593103335 Mon Sep 17 00:00:00 2001 From: Jason Molenda <jmole...@apple.com> Date: Fri, 4 Jul 2025 00:11:30 -0700 Subject: [PATCH 1/2] [lldb] Pass address expression command args through FixAnyAddress Commands that take an address expression/address through the OptionArgParser::ToAddress method, which has filtered this user-specified address through one of the Process Fix methods to clear non-addressable bits (MTE, PAC, top byte ignore, etc). We don't know what class of address this is, IMEM or DMEM, but this method is passing the addresses through Process::FixCodeAddress, and on at least one target, FixCodeAddress clears low bits which are invalid for instructions. Correct this to use FixAnyAddress, which doesn't make alignment assumptions. The actual issue found was by people debugging on a 32-bit ARM Cortex-M part, who tried to do a memory read from an odd address, and lldb returned results starting at the next lower even address. rdar://154885727 --- lldb/source/Interpreter/OptionArgParser.cpp | 3 +- .../TestArmMachoCorefileRegctx.py | 3 +- .../create-arm-corefiles.cpp | 63 ++++++++++++++++--- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/lldb/source/Interpreter/OptionArgParser.cpp b/lldb/source/Interpreter/OptionArgParser.cpp index 2d393a57452ee..616f6e3dc8820 100644 --- a/lldb/source/Interpreter/OptionArgParser.cpp +++ b/lldb/source/Interpreter/OptionArgParser.cpp @@ -175,8 +175,7 @@ lldb::addr_t OptionArgParser::ToAddress(const ExecutionContext *exe_ctx, lldb::addr_t addr = *maybe_addr; if (Process *process = exe_ctx->GetProcessPtr()) - if (ABISP abi_sp = process->GetABI()) - addr = abi_sp->FixCodeAddress(addr); + addr = process->FixAnyAddress(addr); return addr; } diff --git a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py index 4190ea3ac3318..8e34a292e4d5e 100644 --- a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py +++ b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py @@ -1,6 +1,5 @@ """Test that Mach-O armv7/arm64 corefile register contexts are read by lldb.""" - import os import re import subprocess @@ -44,6 +43,8 @@ def test_armv7_corefile(self): self.assertTrue(exception.IsValid()) self.assertEqual(exception.GetValueAsUnsigned(), 0x00003F5C) + self.expect("x/4bx $sp-1", substrs=["0x000dffff", "0xff 0x00 0x01 0x02"]) + def test_arm64_corefile(self): ### Create corefile retcode = call(self.create_corefile + " arm64 " + self.corefile, shell=True) diff --git a/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp b/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp index 5517a2397ae52..2bcc48497bdc4 100644 --- a/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp +++ b/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp @@ -10,15 +10,30 @@ // only defines the ARM register context constants when building on // an arm system. We're creating fake corefiles, and might be // creating them on an intel system. +#ifndef ARM_THREAD_STATE #define ARM_THREAD_STATE 1 +#endif +#ifndef ARM_THREAD_STATE_COUNT #define ARM_THREAD_STATE_COUNT 17 +#endif +#ifndef ARM_EXCEPTION_STATE #define ARM_EXCEPTION_STATE 3 +#endif +#ifndef ARM_EXCEPTION_STATE_COUNT #define ARM_EXCEPTION_STATE_COUNT 3 +#endif +#ifndef ARM_THREAD_STATE64 #define ARM_THREAD_STATE64 6 +#endif +#ifndef ARM_THREAD_STATE64_COUNT #define ARM_THREAD_STATE64_COUNT 68 +#endif +#ifndef ARM_EXCEPTION_STATE64 #define ARM_EXCEPTION_STATE64 7 +#endif +#ifndef ARM_EXCEPTION_STATE64_COUNT #define ARM_EXCEPTION_STATE64_COUNT 4 - +#endif union uint32_buf { uint8_t bytebuf[4]; @@ -129,6 +144,24 @@ std::vector<uint8_t> arm64_lc_thread_load_command() { return data; } +std::vector<uint8_t> lc_segment(uint32_t fileoff) { + std::vector<uint8_t> data; + add_uint32(data, LC_SEGMENT); // segment_command.cmd + add_uint32(data, sizeof(struct segment_command)); // segment_command.cmdsize + for (int i = 0; i < 16; i++) + data.push_back(0); // segment_command.segname[16] + add_uint32(data, 0x000e0000 - 512); // segment_command.vmaddr + add_uint32(data, 1024); // segment_command.vmsize + add_uint32(data, fileoff); // segment_command.fileoff + add_uint32(data, 1024); // segment_command.filesize + add_uint32(data, 3); // segment_command.maxprot + add_uint32(data, 3); // segment_command.initprot + add_uint32(data, 0); // segment_command.nsects + add_uint32(data, 0); // segment_command.flags + + return data; +} + enum arch { unspecified, armv7, arm64 }; int main(int argc, char **argv) { @@ -157,10 +190,12 @@ int main(int argc, char **argv) { // First add all the load commands / payload so we can figure out how large // the load commands will actually be. - if (arch == armv7) + if (arch == armv7) { load_commands.push_back(armv7_lc_thread_load_command()); - else if (arch == arm64) + load_commands.push_back(lc_segment(0)); + } else if (arch == arm64) { load_commands.push_back(arm64_lc_thread_load_command()); + } int size_of_load_commands = 0; for (const auto &lc : load_commands) @@ -174,19 +209,31 @@ int main(int argc, char **argv) { load_commands.clear(); payload.clear(); - if (arch == armv7) + int payload_fileoff = (header_and_load_cmd_room + 4096 - 1) & ~(4096 - 1); + + if (arch == armv7) { load_commands.push_back(armv7_lc_thread_load_command()); - else if (arch == arm64) + load_commands.push_back(lc_segment(payload_fileoff)); + } else if (arch == arm64) { load_commands.push_back(arm64_lc_thread_load_command()); + } + + if (arch == armv7) + for (int i = 0; i < 1024; i++) // from segment_command.filesize + payload.push_back(i); struct mach_header_64 mh; - mh.magic = MH_MAGIC_64; + int header_size; if (arch == armv7) { + mh.magic = MH_MAGIC; mh.cputype = CPU_TYPE_ARM; mh.cpusubtype = CPU_SUBTYPE_ARM_V7M; + header_size = sizeof(struct mach_header); } else if (arch == arm64) { + mh.magic = MH_MAGIC_64; mh.cputype = CPU_TYPE_ARM64; mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL; + header_size = sizeof(struct mach_header_64); } mh.filetype = MH_CORE; mh.ncmds = load_commands.size(); @@ -201,12 +248,12 @@ int main(int argc, char **argv) { exit(1); } - fwrite(&mh, sizeof(struct mach_header_64), 1, f); + fwrite(&mh, header_size, 1, f); for (const auto &lc : load_commands) fwrite(lc.data(), lc.size(), 1, f); - fseek(f, header_and_load_cmd_room, SEEK_SET); + fseek(f, payload_fileoff, SEEK_SET); fwrite(payload.data(), payload.size(), 1, f); >From 33e24cafab820131d92f9f879568896599aaacc0 Mon Sep 17 00:00:00 2001 From: Jason Molenda <jmole...@apple.com> Date: Sat, 5 Jul 2025 23:29:42 -0700 Subject: [PATCH 2/2] Add a comment explaining what the memory read alias is doing. Tighten up how much data is being stored in the corefile. --- .../TestArmMachoCorefileRegctx.py | 5 +++- .../create-arm-corefiles.cpp | 30 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py index 8e34a292e4d5e..6754288a65e1a 100644 --- a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py +++ b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py @@ -43,7 +43,10 @@ def test_armv7_corefile(self): self.assertTrue(exception.IsValid()) self.assertEqual(exception.GetValueAsUnsigned(), 0x00003F5C) - self.expect("x/4bx $sp-1", substrs=["0x000dffff", "0xff 0x00 0x01 0x02"]) + # read 4 bytes starting at $sp-1 (an odd/unaligned address on this arch), + # formatted hex. + # aka `mem read -f x -s 1 -c 4 $sp-1` + self.expect("x/4bx $sp-1", substrs=["0x000dffff", "0x1f 0x20 0x21 0x22"]) def test_arm64_corefile(self): ### Create corefile diff --git a/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp b/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp index 2bcc48497bdc4..f2a95a9aaecaa 100644 --- a/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp +++ b/lldb/test/API/macosx/arm-corefile-regctx/create-arm-corefiles.cpp @@ -144,20 +144,22 @@ std::vector<uint8_t> arm64_lc_thread_load_command() { return data; } -std::vector<uint8_t> lc_segment(uint32_t fileoff) { +std::vector<uint8_t> lc_segment(uint32_t fileoff, + uint32_t lc_segment_data_size) { std::vector<uint8_t> data; + uint32_t start_vmaddr = 0x000e0000 - (lc_segment_data_size / 2); add_uint32(data, LC_SEGMENT); // segment_command.cmd add_uint32(data, sizeof(struct segment_command)); // segment_command.cmdsize for (int i = 0; i < 16; i++) - data.push_back(0); // segment_command.segname[16] - add_uint32(data, 0x000e0000 - 512); // segment_command.vmaddr - add_uint32(data, 1024); // segment_command.vmsize - add_uint32(data, fileoff); // segment_command.fileoff - add_uint32(data, 1024); // segment_command.filesize - add_uint32(data, 3); // segment_command.maxprot - add_uint32(data, 3); // segment_command.initprot - add_uint32(data, 0); // segment_command.nsects - add_uint32(data, 0); // segment_command.flags + data.push_back(0); // segment_command.segname[16] + add_uint32(data, start_vmaddr); // segment_command.vmaddr + add_uint32(data, lc_segment_data_size); // segment_command.vmsize + add_uint32(data, fileoff); // segment_command.fileoff + add_uint32(data, lc_segment_data_size); // segment_command.filesize + add_uint32(data, 3); // segment_command.maxprot + add_uint32(data, 3); // segment_command.initprot + add_uint32(data, 0); // segment_command.nsects + add_uint32(data, 0); // segment_command.flags return data; } @@ -192,7 +194,7 @@ int main(int argc, char **argv) { // the load commands will actually be. if (arch == armv7) { load_commands.push_back(armv7_lc_thread_load_command()); - load_commands.push_back(lc_segment(0)); + load_commands.push_back(lc_segment(0, 0)); } else if (arch == arm64) { load_commands.push_back(arm64_lc_thread_load_command()); } @@ -211,15 +213,17 @@ int main(int argc, char **argv) { int payload_fileoff = (header_and_load_cmd_room + 4096 - 1) & ~(4096 - 1); + const int lc_segment_data_size = 64; if (arch == armv7) { load_commands.push_back(armv7_lc_thread_load_command()); - load_commands.push_back(lc_segment(payload_fileoff)); + load_commands.push_back(lc_segment(payload_fileoff, lc_segment_data_size)); } else if (arch == arm64) { load_commands.push_back(arm64_lc_thread_load_command()); } if (arch == armv7) - for (int i = 0; i < 1024; i++) // from segment_command.filesize + for (int i = 0; i < lc_segment_data_size; + i++) // from segment_command.filesize payload.push_back(i); struct mach_header_64 mh; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits