================
@@ -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;
----------------
jasonmolenda wrote:

ugh, it's so poorly defined what is Correct here.  In most cases, the caller's 
"return pc" is the same as "lr value on function entry to this stack frame".  
There is a case where they diverge -- an exception/fault/interrupt/async signal 
-- where we may be able to retrieve both the pc (that was executing when it was 
interrupted) and the lr (possibly the caller of the function that was 
interrupted), they have separate values.

We may be working with an UnwindPlan that can provide a location for the 
caller's $lr, or it may provide a location of the caller's $pc.  UnwindPlans 
from the compiler or from assembly analysis typically track it in terms of $pc, 
but for instance `ABISysV_arm::CreateDefaultUnwindPlan` provide the caller's pc 
location and caller's fp location.  I wanted to interoperate with any of these 
plans, so I try both.

https://github.com/llvm/llvm-project/pull/153922
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to