[Lldb-commits] [lldb] [lldb] Unwind through ARM Cortex-M exceptions automatically (PR #153922)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Thu Aug 28 19:10:42 PDT 2025
================
@@ -150,3 +158,161 @@ addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr,
}
return opcode_addr & ~(1ull);
}
+
+// The ARM M-Profile Armv7-M Architecture Reference Manual
+// "Exception return behavior" describes how the processor
+// saves registers to the stack, decrements the stack pointer,
+// puts a special value in $lr, and then calls a registered
+// exception handler routine.
+//
+// Detect that special value in $lr, and if present, add
+// unwind rules for the registers that were saved above this
+// stack frame's CFA. Overwrite any register locations that
+// the current_unwindplan has for these registers; they are
+// not correct when we're invoked this way.
+UnwindPlanSP ArchitectureArm::GetArchitectureUnwindPlan(
+ Thread &thread, RegisterContextUnwind *regctx,
+ std::shared_ptr<const UnwindPlan> current_unwindplan) {
+
+ ProcessSP process_sp = thread.GetProcess();
+ if (!process_sp)
+ return {};
+
+ const ArchSpec arch = process_sp->GetTarget().GetArchitecture();
+ if (!arch.GetTriple().isArmMClass() || arch.GetAddressByteSize() != 4)
+ return {};
+
+ // Get the caller's LR value from regctx (the LR value
+ // at function entry to this function).
+ RegisterNumber ra_regnum(thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+ uint32_t ra_regnum_lldb = ra_regnum.GetAsKind(eRegisterKindLLDB);
+
+ if (ra_regnum_lldb == LLDB_INVALID_REGNUM)
+ return {};
+
+ UnwindLLDB::ConcreteRegisterLocation regloc = {};
+ bool got_concrete_location = false;
+ if (regctx->SavedLocationForRegister(ra_regnum_lldb, regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound) {
+ got_concrete_location = true;
+ } else {
+ RegisterNumber pc_regnum(thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ uint32_t pc_regnum_lldb = pc_regnum.GetAsKind(eRegisterKindLLDB);
+ if (regctx->SavedLocationForRegister(pc_regnum_lldb, regloc) ==
+ UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ got_concrete_location = true;
+ }
+
+ addr_t callers_return_address = LLDB_INVALID_ADDRESS;
+ if (got_concrete_location) {
+ const RegisterInfo *reg_info =
+ regctx->GetRegisterInfoAtIndex(ra_regnum_lldb);
+ if (reg_info) {
+ RegisterValue reg_value;
+ if (regctx->ReadRegisterValueFromRegisterLocation(regloc, reg_info,
+ reg_value)) {
+ callers_return_address = reg_value.GetAsUInt32();
+ }
+ }
+ }
+
+ if (callers_return_address == LLDB_INVALID_ADDRESS)
+ return {};
+
+ if (callers_return_address != 0xFFFFFFF1 &&
+ callers_return_address != 0xFFFFFFF9 &&
+ callers_return_address != 0xFFFFFFFD &&
+ callers_return_address != 0xFFFFFFE1 &&
+ callers_return_address != 0xFFFFFFE9 &&
+ callers_return_address != 0xFFFFFFED)
----------------
jasonmolenda wrote:
Yeah this list of magic values that are in $lr after an exception fault has occurred are a little clearer if you happen to have the Armv7-M ARM open in the next window. :)
> Bits[31:28] 0xF. This value identifies the value in a PC load as an EXC_RETURN value.
> Bits[27:5] Reserved, SBOP. The effect of writing a value other than 1 to any bit in this field is UNPREDICTABLE.
> Bit[4], if the processor does not implement the FP extension
> Reserved, SBOP. The effect of writing a value other than 1 to any bit in this field is UNPREDICTABLE.
> Bit[4], if the processor implements the FP extension
> Bits[3:0] Define the required exception return behavior, as shown in:
> Table B1-8, for an implementation without the FP extension.
> Table B1-9 on page B1-540, for an implementation with the FP extension.
where Bits[3:0] only have values 0x1, 0x9, and 0xd defined. And Bits[4] may be 1 or 0, depending on whether the stack pointer was aligned before the saved registers was written to stack.
I don't know if it's clearer to check the bits directly over these magic values, purely a judgement call and given that I was immersed in the ARMv7M ARM your take is probably the better one, and maybe I should just check the bits directly.
https://github.com/llvm/llvm-project/pull/153922
More information about the lldb-commits
mailing list