summaryrefslogtreecommitdiff
path: root/lldb/test/API/functionalities/unwind/cortex-m-exception/binary.json
AgeCommit message (Collapse)Author
2025-10-09[lldb] Cortex-M exception unwind API test cleanupJason Molenda
This test, with a corefile created via yaml2macho-core plus an ObjectFileJSON binary with symbol addresses and ranges, was failing on some machines/CI because the wrong ABI was being picked. The bytes of the functions were not included in the yaml or .json binary. The unwind falls back to using the ABI plugin default unwind plans. We have two armv7 ABIs - the Darwin ABI that always uses r7 as the frame pointer, and the AAPCS ABI which uses r11 code. In reality, armv7 code uses r11 in arm mode, r7 in thumb code. But the ABI ArchDefaultUnwindPlan doesn't have any access to the Target's ArchSpec or Process register state, to determine the correct processor state (arm or thumb). And in fact, on Cortex-M targets, the instructions are always thumb, so the arch default unwind plan (hardcoded r11) is always wrong. The corefile doesn't specify a vendor/os, only a cpu. The object file json specifies the armv7m-apple-* triple, which will select the correct ABI plugin, and the test runs. In some cases, it looks like the Process ABI was fetched after opening the corefile, but before the binary.json was loaded and corrected the Target's ArchSpec. And we never re-evaluate the ABI once it is set, in a Process. When we picked the AAPCS armv7 ABI, we would try to use r11 as frame pointer, and the unwind would stop after one stack frame. I'm stepping around this problem by (1) adding the register bytes of the prologues of every test function in the backtrace, and (2) shortening the function ranges (in binary.json) to specify that the functions are all just long enough for the prologue where execution is stopped. The instruction emulation plugin will fail if it can't get all of the bytes from the function instructions, so I hacked the function sizes in the .json to cover the prologue plus one and changed the addresses in the backtrace to fit within those ranges. [ updated this commit to keep the @skipIfRemote on the API test because two remote CI bots are failing for reasons I don't quite see. ]
2025-10-08Revert "[lldb] Cortex-M exception unwind API test cleanup" (#162520)Vladislav Dzhidzhoev
This reverts commit 01a8f9b81870ac9bfe26d80fa3313d56cb8cbe13. The reason is "lldb-remote-linux-win" buildbot breakage (https://lab.llvm.org/buildbot/#/builders/197/builds/9625).
2025-10-07[lldb] Cortex-M exception unwind API test cleanupJason Molenda
This test, with a corefile created via yaml2macho-core plus an ObjectFileJSON binary with symbol addresses and ranges, was failing on some machines/CI because the wrong ABI was being picked. The bytes of the functions were not included in the yaml or .json binary. The unwind falls back to using the ABI plugin default unwind plans. We have two armv7 ABIs - the Darwin ABI that always uses r7 as the frame pointer, and the AAPCS ABI which uses r11 code. In reality, armv7 code uses r11 in arm mode, r7 in thumb code. But the ABI ArchDefaultUnwindPlan doesn't have any access to the Target's ArchSpec or Process register state, to determine the correct processor state (arm or thumb). And in fact, on Cortex-M targets, the instructions are always thumb, so the arch default unwind plan (hardcoded r11) is always wrong. The corefile doesn't specify a vendor/os, only a cpu. The object file json specifies the armv7m-apple-* triple, which will select the correct ABI plugin, and the test runs. In some cases, it looks like the Process ABI was fetched after opening the corefile, but before the binary.json was loaded and corrected the Target's ArchSpec. And we never re-evaluate the ABI once it is set, in a Process. When we picked the AAPCS armv7 ABI, we would try to use r11 as frame pointer, and the unwind would stop after one stack frame. I'm stepping around this problem by (1) adding the register bytes of the prologues of every test function in the backtrace, and (2) shortening the function ranges (in binary.json) to specify that the functions are all just long enough for the prologue where execution is stopped. The instruction emulation plugin will fail if it can't get all of the bytes from the function instructions, so I hacked the function sizes in the .json to cover the prologue plus one and changed the addresses in the backtrace to fit within those ranges.
2025-09-09[lldb] Unwind through ARM Cortex-M exceptions automatically (#153922)Jason Molenda
When a processor faults/is interrupted/gets an exception, it will stop running code and jump to an exception catcher routine. Most processors will store the pc that was executing in a system register, and the catcher functions have special instructions to retrieve that & possibly other registers. It may then save those values to stack, and the author can add .cfi directives to tell lldb's unwinder where to find those saved values. ARM Cortex-M (microcontroller) processors have a simpler mechanism where a fixed set of registers are saved to the stack on an exception, and a unique value is put in the link register to indicate to the caller that this has taken place. No special handling needs to be written into the exception catcher, unless it wants to inspect these preserved values. And it is possible for a general stack walker to walk the stack with no special knowledge about what the catch function does. This patch adds an Architecture plugin method to allow an Architecture to override/augment the UnwindPlan that lldb would use for a stack frame, given the contents of the return address register. It resembles a feature where the LanguageRuntime can replace/augment the unwind plan for a function, but it is doing it at offset by one level. The LanguageRuntime is looking at the local register context and/or symbol name to decide if it will override the unwind rules. For the Cortex-M exception unwinds, we need to modify THIS frame's unwind plan if the CALLER's LR had a specific value. RegisterContextUnwind has to retrieve the caller's LR value before it has completely decided on the UnwindPlan it will use for THIS stack frame. This does mean that we will need one additional read of stack memory than we currently do when unwinding, on Armv7 Cortex-M targets. The unwinder walks the stack lazily, as stack frames are requested, and so now if you ask for 2 stack frames, we will read enough stack to walk 2 frames, plus we will read one extra word of memory, the spilled LR value from the stack. In practice, with 512-byte memory cache reads, this is unlikely to be a real performance hit. This PR includes a test with a yaml corefile description and a JSON ObjectFile, incorporating all of the necessary stack memory and symbol names from a real debug session I worked on. The architectural default unwind plans are used for all stack frames except the 0th because there's no instructions for the functions, and no unwind info. I may need to add an encoding of unwind fules to ObjectFileJSON in the future as we create more test cases like this. This PR depends on the yaml2macho-core utility from https://github.com/llvm/llvm-project/pull/153911 to run its API test. rdar://110663219