[Lldb-commits] [lldb] [lldb][NFC] Split RegisterContextUnwind::SavedLocationForRegister (PR #139817)
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Tue May 13 22:03:17 PDT 2025
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/139817
>From e63e53adc0909f481a165eca958a3ac2ca4374ee Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 13 May 2025 17:11:08 -0700
Subject: [PATCH 1/5] [lldb][NFC] Split
RegisterContextUnwind::SavedLocationForRegister
RegisterContextUnwind::SavedLocationForRegister is around 450 lines
that first find an abstract register location (e.g. "CFA-8") for a
register by looking in the UnwindPlans. Then it evaluates the
abstract register location to create a concrete register location
(e.g. "stored at address 0x...", "live in register at frame 0").
There are some complicated cases in the first half of the method
to handle return address register architectures correctly, in
particular.
Looking at the two halves, they're both exactly 226 lines long and
there's little involvement between them except for passing an
abstract register location along.
(there were some parts in the "abstract register location" code
that would set the concrete register location, unnecessarily)
It's also a complex enough method that there are some bits of code
that aren't actually doing anything at this point.
This patch adds a RegisterContextUnwind::GetAbstractRegisterLocation
method, which does the first half, and has a clearly defined return
values.
The code to convert an AbstractRegisterLocation into a
ConcreteRegisterLocation remains in SavedLocationForRegister.
It's a bit of a tricky patch to visually inspect, despite it not
changing functionality, the reorganizations and rewrites make the
diff unreadable. Nearly all the real changes are in the
"find the abstract register location" first half of the method.
I think reading the new code in its new form is the easiest way
to inspect this PR. With a defined interface between the two of
what is expected, it's pretty easy to look at the code and reason
about whether it is written correctly.
(whereas before, that was very difficult, for me at least.)
---
.../lldb/Target/RegisterContextUnwind.h | 3 +
lldb/source/Target/RegisterContextUnwind.cpp | 530 +++++++++---------
lldb/source/Target/RegisterNumber.cpp | 1 +
3 files changed, 259 insertions(+), 275 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterContextUnwind.h b/lldb/include/lldb/Target/RegisterContextUnwind.h
index 044a387fe5aa2..b10a364823b83 100644
--- a/lldb/include/lldb/Target/RegisterContextUnwind.h
+++ b/lldb/include/lldb/Target/RegisterContextUnwind.h
@@ -151,6 +151,9 @@ class RegisterContextUnwind : public lldb_private::RegisterContext {
uint32_t lldb_regnum,
lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc);
+ std::optional<UnwindPlan::Row::AbstractRegisterLocation>
+ GetAbstractRegisterLocation(uint32_t lldb_regnum, lldb::RegisterKind &kind);
+
bool ReadRegisterValueFromRegisterLocation(
lldb_private::UnwindLLDB::ConcreteRegisterLocation regloc,
const lldb_private::RegisterInfo *reg_info,
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index cf4b96c6eda9f..a3931abefb054 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1243,247 +1243,194 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol(
return false;
}
-// Answer the question: Where did THIS frame save the CALLER frame ("previous"
-// frame)'s register value?
-
-enum UnwindLLDB::RegisterSearchResult
-RegisterContextUnwind::SavedLocationForRegister(
- uint32_t lldb_regnum,
- lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) {
+// Search this stack frame's UnwindPlans for the AbstractRegisterLocation
+// for this register.
+//
+// When an AbstractRegisterLocation is found in an UnwindPlan, that is
+// returned, regardless of the ABI rules for volatile/non-volatile registers
+// in effect.
+//
+// If there is no unwind rule for a volatile (caller-preserved) register
+// the returned AbstractRegisterLocation will be IsUndefined,
+// indicating that we should stop searching.
+//
+// If there is no unwind rule for a non-volatile (callee-preserved)
+// register, the returned AbstractRegisterLocation will be IsSame.
+// In frame 0, IsSame means get the value from the live register context.
+// Else it means to continue descending down the stack to more-live frames
+// looking for a location/value.
+//
+// An empty optional indicates that there was an error in processing.
+std::optional<UnwindPlan::Row::AbstractRegisterLocation>
+RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
+ lldb::RegisterKind &kind) {
RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum);
Log *log = GetLog(LLDBLog::Unwind);
- // Have we already found this register location?
- if (!m_registers.empty()) {
- std::map<uint32_t,
- lldb_private::UnwindLLDB::ConcreteRegisterLocation>::const_iterator
- iterator;
- iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB));
- if (iterator != m_registers.end()) {
- regloc = iterator->second;
- UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- return UnwindLLDB::RegisterSearchResult::eRegisterFound;
- }
- }
-
- // Look through the available UnwindPlans for the register location.
-
UnwindPlan::Row::AbstractRegisterLocation unwindplan_regloc;
- bool have_unwindplan_regloc = false;
- RegisterKind unwindplan_registerkind = kNumRegisterKinds;
+ // First, try to find a register location via the FastUnwindPlan
if (m_fast_unwind_plan_sp) {
const UnwindPlan::Row *active_row =
m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
- unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind();
- if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
+ kind = m_fast_unwind_plan_sp->GetRegisterKind();
+ if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) {
UnwindLogMsg("could not convert lldb regnum %s (%d) into %d RegisterKind "
"reg numbering scheme",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
- (int)unwindplan_registerkind);
- return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ (int)kind);
+ return {};
}
// The architecture default unwind plan marks unknown registers as
// Undefined so that we don't forward them up the stack when a
// jitted stack frame may have overwritten them. But when the
// arch default unwind plan is used as the Fast Unwind Plan, we
// need to recognize this & switch over to the Full Unwind Plan
- // to see what unwind rule that (more knoweldgeable, probably)
- // UnwindPlan has. If the full UnwindPlan says the register
- // location is Undefined, then it really is.
- if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
+ // to see what unwind rule that (more knowledgeable, probably)
+ // UnwindPlan has.
+ if (active_row->GetRegisterInfo(regnum.GetAsKind(kind),
unwindplan_regloc) &&
!unwindplan_regloc.IsUndefined()) {
UnwindLogMsg(
"supplying caller's saved %s (%d)'s location using FastUnwindPlan",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- have_unwindplan_regloc = true;
+ return unwindplan_regloc;
}
}
- if (!have_unwindplan_regloc) {
- // m_full_unwind_plan_sp being NULL means that we haven't tried to find a
- // full UnwindPlan yet
- bool got_new_full_unwindplan = false;
- if (!m_full_unwind_plan_sp) {
- m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
- got_new_full_unwindplan = true;
- }
+ // Second, try to find a register location via the FullUnwindPlan.
+ bool got_new_full_unwindplan = false;
+ if (!m_full_unwind_plan_sp) {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame();
+ got_new_full_unwindplan = true;
+ }
+ if (m_full_unwind_plan_sp) {
+ RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
- if (m_full_unwind_plan_sp) {
- RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric,
- LLDB_REGNUM_GENERIC_PC);
+ const UnwindPlan::Row *active_row =
+ m_full_unwind_plan_sp->GetRowForFunctionOffset(
+ m_current_offset_backed_up_one);
+ kind = m_full_unwind_plan_sp->GetRegisterKind();
- const UnwindPlan::Row *active_row =
- m_full_unwind_plan_sp->GetRowForFunctionOffset(
- m_current_offset_backed_up_one);
- unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
+ if (got_new_full_unwindplan && active_row && log) {
+ StreamString active_row_strm;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread,
+ m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg("Using full unwind plan '%s'",
+ m_full_unwind_plan_sp->GetSourceName().AsCString());
+ UnwindLogMsg("active row: %s", active_row_strm.GetData());
+ }
- if (got_new_full_unwindplan && active_row && log) {
- StreamString active_row_strm;
- ExecutionContext exe_ctx(m_thread.shared_from_this());
- active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(),
- &m_thread,
- m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
- UnwindLogMsg("Using full unwind plan '%s'",
- m_full_unwind_plan_sp->GetSourceName().AsCString());
- UnwindLogMsg("active row: %s", active_row_strm.GetData());
+ if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) {
+ if (kind == eRegisterKindGeneric) {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into "
+ "eRegisterKindGeneric reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ } else {
+ UnwindLogMsg("could not convert lldb regnum %s (%d) into %d "
+ "RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ (int)kind);
}
+ return {};
+ }
+
+ if (regnum.IsValid() && active_row &&
+ active_row->GetRegisterInfo(regnum.GetAsKind(kind),
+ unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using %s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ return unwindplan_regloc;
+ }
+
+ // When asking for the caller's pc, check if we have a
+ // Return Address register on this target.
+ //
+ // On a Return Address Register architecture like arm/mips/riscv,
+ // the caller's pc is in the RA register, and will be spilled to
+ // stack before any other function can be called. We may have a
+ // register location saying
+ // pc=RAReg {caller's retrun addr is in RA register}
+ // ra=IsSame {caller's return addr is live in RA register}
+ // ra=StackAddr {caller's return addr spilled to stack}
+ // or none of the above, which means the caller's pc is live in the
+ // return address reg if this is frame 0, or the frame below is
+ // a trap/sigtramp/interrupt handler function. Any other mid-stack
+ // function must have an unwind rule for PC/RA giving a location/value.
+ //
+ // In the case of an interrupted function -- the function above sigtramp,
+ // or a function interrupted asynchronously, or that has faulted to
+ // a trap handler -- it is valid to ask both the "pc" value -- the
+ // instruction that was executing when the interrupt/fault happend --
+ // and the RA Register value. If a frameless function (which doesn't
+ // create a stack frame, doesn't save the RA reg to stack) is interrupted,
+ // the trap handler will have a rule to provide the pc (the instruction
+ // that was executing) AND a rule to provide the RA Register, which we
+ // need to use to find the caller function:
+ // pc=StackAddr1
+ // ra=StackAddr2
+ // and we don't want to rewrite a request of "pc" to "ra" here, because
+ // they mean different things.
+
+ if (pc_regnum.IsValid() && pc_regnum == regnum) {
RegisterNumber return_address_reg;
+ uint32_t return_address_regnum =
+ LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering
+
+ // Get the return address register number from the UnwindPlan
+ // or the arch register set.
+ if (m_full_unwind_plan_sp->GetReturnAddressRegister() !=
+ LLDB_INVALID_REGNUM) {
+ return_address_regnum =
+ m_full_unwind_plan_sp->GetReturnAddressRegister();
+ } else {
+ RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+ return_address_regnum = arch_default_ra_regnum.GetAsKind(kind);
+ }
- // If we're fetching the saved pc and this UnwindPlan defines a
- // ReturnAddress register (e.g. lr on arm), look for the return address
- // register number in the UnwindPlan's row.
- if (pc_regnum.IsValid() && pc_regnum == regnum &&
- m_full_unwind_plan_sp->GetReturnAddressRegister() !=
- LLDB_INVALID_REGNUM) {
- // If this is a trap handler frame, we should have access to
- // the complete register context when the interrupt/async
- // signal was received, we should fetch the actual saved $pc
- // value instead of the Return Address register.
- // If $pc is not available, fall back to the RA reg.
+ if (return_address_regnum != LLDB_INVALID_REGNUM) {
UnwindPlan::Row::AbstractRegisterLocation scratch;
+ // This is a sigtramp/interrupt handler - treat a
+ // request for "pc" and "ra" as distinct.
if (m_frame_type == eTrapHandlerFrame && active_row &&
- active_row->GetRegisterInfo(
- pc_regnum.GetAsKind(unwindplan_registerkind), scratch)) {
+ active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) {
UnwindLogMsg("Providing pc register instead of rewriting to "
"RA reg because this is a trap handler and there is "
"a location for the saved pc register value.");
} else {
- return_address_reg.init(
- m_thread, m_full_unwind_plan_sp->GetRegisterKind(),
- m_full_unwind_plan_sp->GetReturnAddressRegister());
+ // This is a normal function, there's no rule for
+ // finding the caller's pc value, look for the caller's
+ // return address register value.
+ return_address_reg.init(m_thread,
+ m_full_unwind_plan_sp->GetRegisterKind(),
+ return_address_regnum);
regnum = return_address_reg;
UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
"RA reg; getting %s (%d) instead",
return_address_reg.GetName(),
return_address_reg.GetAsKind(eRegisterKindLLDB));
- }
- } else {
- if (regnum.GetAsKind(unwindplan_registerkind) == LLDB_INVALID_REGNUM) {
- if (unwindplan_registerkind == eRegisterKindGeneric) {
- UnwindLogMsg("could not convert lldb regnum %s (%d) into "
- "eRegisterKindGeneric reg numbering scheme",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- } else {
- UnwindLogMsg("could not convert lldb regnum %s (%d) into %d "
- "RegisterKind reg numbering scheme",
+ if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind),
+ unwindplan_regloc)) {
+ UnwindLogMsg("supplying caller's saved %s (%d)'s location using "
+ "%s UnwindPlan",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
- (int)unwindplan_registerkind);
- }
- return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- }
- }
-
- // Check if the active_row has a register location listed.
- if (regnum.IsValid() && active_row &&
- active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
- unwindplan_regloc)) {
- have_unwindplan_regloc = true;
- UnwindLogMsg(
- "supplying caller's saved %s (%d)'s location using %s UnwindPlan",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
- m_full_unwind_plan_sp->GetSourceName().GetCString());
- }
-
- // This is frame 0 and we're retrieving the PC and it's saved in a Return
- // Address register and it hasn't been saved anywhere yet -- that is,
- // it's still live in the actual register. Handle this specially.
- if (!have_unwindplan_regloc && return_address_reg.IsValid() &&
- return_address_reg.GetAsKind(eRegisterKindLLDB) !=
- LLDB_INVALID_REGNUM) {
- if (IsFrameZero()) {
- lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc;
- new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::
- eRegisterInLiveRegisterContext;
- new_regloc.location.register_number =
- return_address_reg.GetAsKind(eRegisterKindLLDB);
- m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
- regloc = new_regloc;
- UnwindLogMsg("supplying caller's register %s (%d) from the live "
- "RegisterContext at frame 0, saved in %d",
- return_address_reg.GetName(),
- return_address_reg.GetAsKind(eRegisterKindLLDB),
- return_address_reg.GetAsKind(eRegisterKindLLDB));
- return UnwindLLDB::RegisterSearchResult::eRegisterFound;
- } else if (BehavesLikeZerothFrame()) {
- // This function was interrupted asynchronously -- it faulted,
- // an async interrupt, a timer fired, a debugger expression etc.
- // The caller's pc is in the Return Address register, but the
- // UnwindPlan for this function may have no location rule for
- // the RA reg.
- // This means that the caller's return address is in the RA reg
- // when the function was interrupted--descend down one stack frame
- // to retrieve it from the trap handler's saved context.
- unwindplan_regloc.SetSame();
- have_unwindplan_regloc = true;
- }
- }
-
- // If this architecture stores the return address in a register (it
- // defines a Return Address register) and we're on a non-zero stack frame
- // and the Full UnwindPlan says that the pc is stored in the
- // RA registers (e.g. lr on arm), then we know that the full unwindplan is
- // not trustworthy -- this
- // is an impossible situation and the instruction emulation code has
- // likely been misled. If this stack frame meets those criteria, we need
- // to throw away the Full UnwindPlan that the instruction emulation came
- // up with and fall back to the architecture's Default UnwindPlan so the
- // stack walk can get past this point.
-
- // Special note: If the Full UnwindPlan was generated from the compiler,
- // don't second-guess it when we're at a call site location.
-
- // arch_default_ra_regnum is the return address register # in the Full
- // UnwindPlan register numbering
- RegisterNumber arch_default_ra_regnum(m_thread, eRegisterKindGeneric,
- LLDB_REGNUM_GENERIC_RA);
-
- if (arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) !=
- LLDB_INVALID_REGNUM &&
- pc_regnum == regnum && unwindplan_regloc.IsInOtherRegister() &&
- unwindplan_regloc.GetRegisterNumber() ==
- arch_default_ra_regnum.GetAsKind(unwindplan_registerkind) &&
- m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes &&
- !m_all_registers_available) {
- UnwindLogMsg("%s UnwindPlan tried to restore the pc from the link "
- "register but this is a non-zero frame",
- m_full_unwind_plan_sp->GetSourceName().GetCString());
-
- // Throw away the full unwindplan; install the arch default unwindplan
- if (ForceSwitchToFallbackUnwindPlan()) {
- // Update for the possibly new unwind plan
- unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind();
- const UnwindPlan::Row *active_row =
- m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
-
- // Sanity check: Verify that we can fetch a pc value and CFA value
- // with this unwind plan
-
- RegisterNumber arch_default_pc_reg(m_thread, eRegisterKindGeneric,
- LLDB_REGNUM_GENERIC_PC);
- bool can_fetch_pc_value = false;
- bool can_fetch_cfa = false;
- addr_t cfa_value;
- if (active_row) {
- if (arch_default_pc_reg.GetAsKind(unwindplan_registerkind) !=
- LLDB_INVALID_REGNUM &&
- active_row->GetRegisterInfo(
- arch_default_pc_reg.GetAsKind(unwindplan_registerkind),
- unwindplan_regloc)) {
- can_fetch_pc_value = true;
- }
- if (ReadFrameAddress(unwindplan_registerkind,
- active_row->GetCFAValue(), cfa_value)) {
- can_fetch_cfa = true;
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ if (unwindplan_regloc.IsSame())
+ unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ return unwindplan_regloc;
+ } else {
+ // No unwind rule for the return address reg on frame
+ // 0 means that the caller's address is still in RA reg.
+ if (BehavesLikeZerothFrame()) {
+ unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ return unwindplan_regloc;
}
}
-
- have_unwindplan_regloc = can_fetch_pc_value && can_fetch_cfa;
- } else {
- // We were unable to fall back to another unwind plan
- have_unwindplan_regloc = false;
}
}
}
@@ -1491,55 +1438,84 @@ RegisterContextUnwind::SavedLocationForRegister(
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
- if (!have_unwindplan_regloc) {
- // If the UnwindPlan failed to give us an unwind location for this
- // register, we may be able to fall back to some ABI-defined default. For
- // example, some ABIs allow to determine the caller's SP via the CFA. Also,
- // the ABI may set volatile registers to the undefined state.
- ABI *abi = process ? process->GetABI().get() : nullptr;
- if (abi) {
- const RegisterInfo *reg_info =
- GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
- if (reg_info &&
- abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
- UnwindLogMsg(
- "supplying caller's saved %s (%d)'s location using ABI default",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- have_unwindplan_regloc = true;
- }
+
+ // Third, try finding a register location via the ABI
+ // FallbackRegisterLocation.
+ //
+ // If the UnwindPlan failed to give us an unwind location for this
+ // register, we may be able to fall back to some ABI-defined default. For
+ // example, some ABIs allow to determine the caller's SP via the CFA. Also,
+ // the ABI willset volatile registers to the undefined state.
+ ABI *abi = process ? process->GetABI().get() : nullptr;
+ if (abi) {
+ const RegisterInfo *reg_info =
+ GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
+ if (reg_info &&
+ abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using ABI default",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return unwindplan_regloc;
}
}
- if (!have_unwindplan_regloc) {
- if (IsFrameZero()) {
- // This is frame 0 - we should return the actual live register context
- // value
- lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc;
- new_regloc.type =
- UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext;
- new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
- m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
- regloc = new_regloc;
- UnwindLogMsg("supplying caller's register %s (%d) from the live "
- "RegisterContext at frame 0",
+ // We have no AbstractRegisterRule, and the ABI says this is a
+ // non-volatile / callee-preserved register.
+ std::string unwindplan_name;
+ if (m_full_unwind_plan_sp) {
+ unwindplan_name += "via '";
+ unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
+ unwindplan_name += "'";
+ }
+ UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(),
+ regnum.GetAsKind(eRegisterKindLLDB), unwindplan_name.c_str());
+
+ unwindplan_regloc.SetSame();
+ return unwindplan_regloc;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous"
+// frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextUnwind::SavedLocationForRegister(
+ uint32_t lldb_regnum,
+ lldb_private::UnwindLLDB::ConcreteRegisterLocation ®loc) {
+ RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum);
+ Log *log = GetLog(LLDBLog::Unwind);
+
+ // Have we already found this register location?
+ if (!m_registers.empty()) {
+ std::map<uint32_t,
+ lldb_private::UnwindLLDB::ConcreteRegisterLocation>::const_iterator
+ iterator;
+ iterator = m_registers.find(regnum.GetAsKind(eRegisterKindLLDB));
+ if (iterator != m_registers.end()) {
+ regloc = iterator->second;
+ UnwindLogMsg("supplying caller's saved %s (%d)'s location, cached",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
- } else {
- std::string unwindplan_name;
- if (m_full_unwind_plan_sp) {
- unwindplan_name += "via '";
- unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
- unwindplan_name += "'";
- }
- UnwindLogMsg("no save location for %s (%d) %s", regnum.GetName(),
- regnum.GetAsKind(eRegisterKindLLDB),
- unwindplan_name.c_str());
}
+ }
+
+ RegisterKind abs_regkind;
+ std::optional<UnwindPlan::Row::AbstractRegisterLocation> abs_regloc =
+ GetAbstractRegisterLocation(lldb_regnum, abs_regkind);
+
+ if (!abs_regloc)
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+ if (abs_regloc->IsUndefined()) {
+ UnwindLogMsg(
+ "did not supply reg location for %s (%d) because it is volatile",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
}
- // unwindplan_regloc has valid contents about where to retrieve the register
- if (unwindplan_regloc.IsUnspecified()) {
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // abs_regloc has valid contents about where to retrieve the register
+ if (abs_regloc->IsUnspecified()) {
lldb_private::UnwindLLDB::ConcreteRegisterLocation new_regloc = {};
new_regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterNotSaved;
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
@@ -1548,15 +1524,23 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
- if (unwindplan_regloc.IsUndefined()) {
- UnwindLogMsg(
- "did not supply reg location for %s (%d) because it is volatile",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
- }
-
- if (unwindplan_regloc.IsSame()) {
- if (!m_all_registers_available &&
+ if (abs_regloc->IsSame()) {
+ if (IsFrameZero()) {
+ regloc.type =
+ UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext;
+ regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) from the live "
+ "RegisterContext at frame 0",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ // PC/RA reg don't follow the usual "callee-saved aka non-volatile" versus
+ // "caller saved aka volatile" system. A stack frame can provide its caller
+ // return address, but if we don't find a rule for pc/RA mid-stack, we
+ // never want to iterate further down the stack looking for it.
+ // Defensively prevent iterating down the stack for these two.
+ if (!BehavesLikeZerothFrame() &&
(regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC ||
regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) {
UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or "
@@ -1564,20 +1548,19 @@ RegisterContextUnwind::SavedLocationForRegister(
"registers available -- treat as if we have no information",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- } else {
- regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister;
- regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
- m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
- UnwindLogMsg(
- "supplying caller's register %s (%d), saved in register %s (%d)",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
+
+ regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg(
+ "supplying caller's register %s (%d) value is unmodified in this frame",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsCFAPlusOffset()) {
- int offset = unwindplan_regloc.GetOffset();
+ if (abs_regloc->IsCFAPlusOffset()) {
+ int offset = abs_regloc->GetOffset();
regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred;
regloc.location.inferred_value = m_cfa + offset;
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
@@ -1588,8 +1571,8 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsAtCFAPlusOffset()) {
- int offset = unwindplan_regloc.GetOffset();
+ if (abs_regloc->IsAtCFAPlusOffset()) {
+ int offset = abs_regloc->GetOffset();
regloc.type =
UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation;
regloc.location.target_memory_location = m_cfa + offset;
@@ -1601,11 +1584,11 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsAFAPlusOffset()) {
+ if (abs_regloc->IsAFAPlusOffset()) {
if (m_afa == LLDB_INVALID_ADDRESS)
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- int offset = unwindplan_regloc.GetOffset();
+ int offset = abs_regloc->GetOffset();
regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred;
regloc.location.inferred_value = m_afa + offset;
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
@@ -1616,11 +1599,11 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsAtAFAPlusOffset()) {
+ if (abs_regloc->IsAtAFAPlusOffset()) {
if (m_afa == LLDB_INVALID_ADDRESS)
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
- int offset = unwindplan_regloc.GetOffset();
+ int offset = abs_regloc->GetOffset();
regloc.type =
UnwindLLDB::ConcreteRegisterLocation::eRegisterSavedAtMemoryLocation;
regloc.location.target_memory_location = m_afa + offset;
@@ -1632,10 +1615,9 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsInOtherRegister()) {
- uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
- RegisterNumber row_regnum(m_thread, unwindplan_registerkind,
- unwindplan_regnum);
+ if (abs_regloc->IsInOtherRegister()) {
+ RegisterNumber row_regnum(m_thread, abs_regkind,
+ abs_regloc->GetRegisterNumber());
if (row_regnum.GetAsKind(eRegisterKindLLDB) == LLDB_INVALID_REGNUM) {
UnwindLogMsg("could not supply caller's %s (%d) location - was saved in "
"another reg but couldn't convert that regnum",
@@ -1652,16 +1634,14 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
}
- if (unwindplan_regloc.IsDWARFExpression() ||
- unwindplan_regloc.IsAtDWARFExpression()) {
- DataExtractor dwarfdata(unwindplan_regloc.GetDWARFExpressionBytes(),
- unwindplan_regloc.GetDWARFExpressionLength(),
+ if (abs_regloc->IsDWARFExpression() || abs_regloc->IsAtDWARFExpression()) {
+ DataExtractor dwarfdata(abs_regloc->GetDWARFExpressionBytes(),
+ abs_regloc->GetDWARFExpressionLength(),
process->GetByteOrder(),
process->GetAddressByteSize());
ModuleSP opcode_ctx;
DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr);
- dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(
- unwindplan_registerkind);
+ dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(abs_regkind);
Value cfa_val = Scalar(m_cfa);
cfa_val.SetValueType(Value::ValueType::LoadAddress);
llvm::Expected<Value> result =
@@ -1672,7 +1652,7 @@ RegisterContextUnwind::SavedLocationForRegister(
} else {
addr_t val;
val = result->GetScalar().ULongLong();
- if (unwindplan_regloc.IsDWARFExpression()) {
+ if (abs_regloc->IsDWARFExpression()) {
regloc.type =
UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred;
regloc.location.inferred_value = val;
@@ -1698,9 +1678,9 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
- if (unwindplan_regloc.IsConstant()) {
+ if (abs_regloc->IsConstant()) {
regloc.type = UnwindLLDB::ConcreteRegisterLocation::eRegisterValueInferred;
- regloc.location.inferred_value = unwindplan_regloc.GetConstant();
+ regloc.location.inferred_value = abs_regloc->GetConstant();
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
UnwindLogMsg("supplying caller's register %s (%d) via constant value",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
diff --git a/lldb/source/Target/RegisterNumber.cpp b/lldb/source/Target/RegisterNumber.cpp
index e5610bf588543..56dda8d8be8b8 100644
--- a/lldb/source/Target/RegisterNumber.cpp
+++ b/lldb/source/Target/RegisterNumber.cpp
@@ -47,6 +47,7 @@ const RegisterNumber &RegisterNumber::operator=(const RegisterNumber &rhs) {
m_reg_ctx_sp = rhs.m_reg_ctx_sp;
m_regnum = rhs.m_regnum;
m_kind = rhs.m_kind;
+ m_kind_regnum_map.clear();
for (auto it : rhs.m_kind_regnum_map)
m_kind_regnum_map[it.first] = it.second;
m_name = rhs.m_name;
>From c1aad81d5c5c7d2e9fce64f83197c05b827c6f22 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 13 May 2025 17:37:42 -0700
Subject: [PATCH 2/5] Remove another bit of code in GetAbstractRegisterLocation
that wasn't doing anything.
---
lldb/source/Target/RegisterContextUnwind.cpp | 60 ++++++++------------
1 file changed, 25 insertions(+), 35 deletions(-)
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index a3931abefb054..aae5de97de242 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1256,7 +1256,7 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol(
//
// If there is no unwind rule for a non-volatile (callee-preserved)
// register, the returned AbstractRegisterLocation will be IsSame.
-// In frame 0, IsSame means get the value from the live register context.
+// In frame 0, IsSame means get the value from the live register context.
// Else it means to continue descending down the stack to more-live frames
// looking for a location/value.
//
@@ -1394,42 +1394,32 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
}
if (return_address_regnum != LLDB_INVALID_REGNUM) {
- UnwindPlan::Row::AbstractRegisterLocation scratch;
- // This is a sigtramp/interrupt handler - treat a
- // request for "pc" and "ra" as distinct.
- if (m_frame_type == eTrapHandlerFrame && active_row &&
- active_row->GetRegisterInfo(pc_regnum.GetAsKind(kind), scratch)) {
- UnwindLogMsg("Providing pc register instead of rewriting to "
- "RA reg because this is a trap handler and there is "
- "a location for the saved pc register value.");
+ // This is a normal function, there's no rule for
+ // finding the caller's pc value, look for the caller's
+ // return address register value.
+ return_address_reg.init(m_thread,
+ m_full_unwind_plan_sp->GetRegisterKind(),
+ return_address_regnum);
+ regnum = return_address_reg;
+ UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
+ "RA reg; getting %s (%d) instead",
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB));
+ if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind),
+ unwindplan_regloc)) {
+ UnwindLogMsg("supplying caller's saved %s (%d)'s location using "
+ "%s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ if (unwindplan_regloc.IsSame())
+ unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ return unwindplan_regloc;
} else {
- // This is a normal function, there's no rule for
- // finding the caller's pc value, look for the caller's
- // return address register value.
- return_address_reg.init(m_thread,
- m_full_unwind_plan_sp->GetRegisterKind(),
- return_address_regnum);
- regnum = return_address_reg;
- UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
- "RA reg; getting %s (%d) instead",
- return_address_reg.GetName(),
- return_address_reg.GetAsKind(eRegisterKindLLDB));
- if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind),
- unwindplan_regloc)) {
- UnwindLogMsg("supplying caller's saved %s (%d)'s location using "
- "%s UnwindPlan",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
- m_full_unwind_plan_sp->GetSourceName().GetCString());
- if (unwindplan_regloc.IsSame())
- unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ // No unwind rule for the return address reg on frame
+ // 0 means that the caller's address is still in RA reg.
+ if (BehavesLikeZerothFrame()) {
+ unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
return unwindplan_regloc;
- } else {
- // No unwind rule for the return address reg on frame
- // 0 means that the caller's address is still in RA reg.
- if (BehavesLikeZerothFrame()) {
- unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
- return unwindplan_regloc;
- }
}
}
}
>From fde91220492202f7a8b56312cac5b7316975d69a Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 13 May 2025 17:41:45 -0700
Subject: [PATCH 3/5] Don't log a message when the ABI says this is a volatile
register -- has an Undefined abstract register location.
---
lldb/source/Target/RegisterContextUnwind.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index aae5de97de242..cf23df21f5044 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1441,7 +1441,8 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
const RegisterInfo *reg_info =
GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
if (reg_info &&
- abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
+ abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) &&
+ !unwindplan_regloc.IsUndefined()) {
UnwindLogMsg(
"supplying caller's saved %s (%d)'s location using ABI default",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
>From 853da6655104080cb7022ca4e7f18ffae2e5df1b Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 13 May 2025 18:03:41 -0700
Subject: [PATCH 4/5] clarify comment.
---
lldb/source/Target/RegisterContextUnwind.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index cf23df21f5044..64cb906f4d6c3 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1450,8 +1450,9 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
}
}
- // We have no AbstractRegisterRule, and the ABI says this is a
- // non-volatile / callee-preserved register.
+ // We have no AbstractRegisterLocation, and the ABI says this is a
+ // non-volatile / callee-preserved register. Continue down the stack
+ // or to frame 0 & the live RegisterContext.
std::string unwindplan_name;
if (m_full_unwind_plan_sp) {
unwindplan_name += "via '";
>From 1f40042126fb4941f365c6b0bb3f83961248695e Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 13 May 2025 22:02:17 -0700
Subject: [PATCH 5/5] make another pass over all the comments and
rewrite/clarify a bunch of them. Tiny tweaks to the code to make it more
readable.
---
lldb/source/Target/RegisterContextUnwind.cpp | 143 ++++++++++---------
1 file changed, 78 insertions(+), 65 deletions(-)
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 64cb906f4d6c3..791671dc8e166 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1243,24 +1243,34 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol(
return false;
}
-// Search this stack frame's UnwindPlans for the AbstractRegisterLocation
-// for this register.
-//
-// When an AbstractRegisterLocation is found in an UnwindPlan, that is
-// returned, regardless of the ABI rules for volatile/non-volatile registers
-// in effect.
-//
-// If there is no unwind rule for a volatile (caller-preserved) register
-// the returned AbstractRegisterLocation will be IsUndefined,
-// indicating that we should stop searching.
-//
-// If there is no unwind rule for a non-volatile (callee-preserved)
-// register, the returned AbstractRegisterLocation will be IsSame.
-// In frame 0, IsSame means get the value from the live register context.
-// Else it means to continue descending down the stack to more-live frames
-// looking for a location/value.
-//
-// An empty optional indicates that there was an error in processing.
+/// Search this stack frame's UnwindPlans for the AbstractRegisterLocation
+/// for this register.
+///
+/// \param[out] kind
+/// Set to the RegisterKind of the UnwindPlan which is the basis for
+/// the returned AbstractRegisterLocation; if the location is in terms
+/// of another register number, this Kind is needed to interpret it
+/// correctly.
+///
+/// \return
+/// An empty optional indicaTes that there was an error in processing
+/// the request.
+///
+/// If there is no unwind rule for a volatile (caller-preserved) register,
+/// the returned AbstractRegisterLocation will be IsUndefined,
+/// indicating that we should stop searching.
+///
+/// If there is no unwind rule for a non-volatile (callee-preserved)
+/// register, the returned AbstractRegisterLocation will be IsSame.
+/// In frame 0, IsSame means get the value from the live register context.
+/// Else it means to continue descending down the stack to more-live frames
+/// looking for a location/value.
+///
+/// If an AbstractRegisterLocation is found in an UnwindPlan, that will
+/// be returned, with no consideration of the current ABI rules for
+/// registers. Functions using an alternate ABI calling convention
+/// will work as long as the UnwindPlans are exhaustive about what
+/// registers are volatile/non-volatile.
std::optional<UnwindPlan::Row::AbstractRegisterLocation>
RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
lldb::RegisterKind &kind) {
@@ -1324,16 +1334,15 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
}
if (regnum.GetAsKind(kind) == LLDB_INVALID_REGNUM) {
- if (kind == eRegisterKindGeneric) {
+ if (kind == eRegisterKindGeneric)
UnwindLogMsg("could not convert lldb regnum %s (%d) into "
"eRegisterKindGeneric reg numbering scheme",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
- } else {
+ else
UnwindLogMsg("could not convert lldb regnum %s (%d) into %d "
"RegisterKind reg numbering scheme",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
(int)kind);
- }
return {};
}
@@ -1347,42 +1356,37 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
return unwindplan_regloc;
}
- // When asking for the caller's pc, check if we have a
+ // When asking for the caller's pc, and did not find a register
+ // location for PC above in the UnwindPlan. Check if we have a
// Return Address register on this target.
//
// On a Return Address Register architecture like arm/mips/riscv,
// the caller's pc is in the RA register, and will be spilled to
- // stack before any other function can be called. We may have a
- // register location saying
- // pc=RAReg {caller's retrun addr is in RA register}
- // ra=IsSame {caller's return addr is live in RA register}
- // ra=StackAddr {caller's return addr spilled to stack}
- // or none of the above, which means the caller's pc is live in the
- // return address reg if this is frame 0, or the frame below is
- // a trap/sigtramp/interrupt handler function. Any other mid-stack
- // function must have an unwind rule for PC/RA giving a location/value.
+ // stack before any other function is called. If no function
+ // has been called yet, the return address may still be in the
+ // live RA reg.
//
- // In the case of an interrupted function -- the function above sigtramp,
- // or a function interrupted asynchronously, or that has faulted to
- // a trap handler -- it is valid to ask both the "pc" value -- the
- // instruction that was executing when the interrupt/fault happend --
- // and the RA Register value. If a frameless function (which doesn't
- // create a stack frame, doesn't save the RA reg to stack) is interrupted,
- // the trap handler will have a rule to provide the pc (the instruction
- // that was executing) AND a rule to provide the RA Register, which we
- // need to use to find the caller function:
- // pc=StackAddr1
- // ra=StackAddr2
- // and we don't want to rewrite a request of "pc" to "ra" here, because
- // they mean different things.
-
+ // There's a lot of variety of what we might see in an UnwindPlan.
+ // We may have
+ // ra=IsSame {unncessary}
+ // ra=StackAddr {caller's return addr spilled to stack}
+ // or no unwindrule for pc or ra at all, in a frameless function -
+ // the caller's return address is in live ra reg.
+ //
+ // If a function has been interrupted in a non-call way --
+ // async signal/sigtramp, or a hardware exception / interrupt / fault --
+ // then the "pc" and "ra" are two distinct values, and must be
+ // handled separately. The "pc" is the pc value at the point
+ // the function was interrupted. The "ra" is the return address
+ // register value at that point.
+ // The UnwindPlan for the sigtramp/trap handler will normally have
+ // register loations for both pc and lr, and so we'll have already
+ // fetched them above.
if (pc_regnum.IsValid() && pc_regnum == regnum) {
- RegisterNumber return_address_reg;
- uint32_t return_address_regnum =
- LLDB_INVALID_REGNUM; // in full UnwindPlan's numbering
+ uint32_t return_address_regnum = LLDB_INVALID_REGNUM;
// Get the return address register number from the UnwindPlan
- // or the arch register set.
+ // or the register set definition.
if (m_full_unwind_plan_sp->GetReturnAddressRegister() !=
LLDB_INVALID_REGNUM) {
return_address_regnum =
@@ -1393,32 +1397,38 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
return_address_regnum = arch_default_ra_regnum.GetAsKind(kind);
}
+ // This system is using a return address register.
if (return_address_regnum != LLDB_INVALID_REGNUM) {
- // This is a normal function, there's no rule for
- // finding the caller's pc value, look for the caller's
- // return address register value.
+ RegisterNumber return_address_reg;
return_address_reg.init(m_thread,
m_full_unwind_plan_sp->GetRegisterKind(),
return_address_regnum);
- regnum = return_address_reg;
UnwindLogMsg("requested caller's saved PC but this UnwindPlan uses a "
"RA reg; getting %s (%d) instead",
return_address_reg.GetName(),
return_address_reg.GetAsKind(eRegisterKindLLDB));
- if (active_row && active_row->GetRegisterInfo(regnum.GetAsKind(kind),
- unwindplan_regloc)) {
+
+ // Do we have a location for the ra register?
+ if (active_row &&
+ active_row->GetRegisterInfo(return_address_reg.GetAsKind(kind),
+ unwindplan_regloc)) {
UnwindLogMsg("supplying caller's saved %s (%d)'s location using "
"%s UnwindPlan",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB),
+ return_address_reg.GetName(),
+ return_address_reg.GetAsKind(eRegisterKindLLDB),
m_full_unwind_plan_sp->GetSourceName().GetCString());
+ // If we have "ra=IsSame", rewrite to "ra=InRegister(ra)" because the
+ // calling function thinks it is fetching "pc" and if we return an
+ // IsSame register location, it will try to read pc.
if (unwindplan_regloc.IsSame())
- unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind));
return unwindplan_regloc;
} else {
- // No unwind rule for the return address reg on frame
- // 0 means that the caller's address is still in RA reg.
+ // No unwind rule for the return address reg on frame 0, or an
+ // interrupted function, means that the caller's address is still in
+ // RA reg.
if (BehavesLikeZerothFrame()) {
- unwindplan_regloc.SetInRegister(regnum.GetAsKind(kind));
+ unwindplan_regloc.SetInRegister(return_address_reg.GetAsKind(kind));
return unwindplan_regloc;
}
}
@@ -1441,11 +1451,14 @@ RegisterContextUnwind::GetAbstractRegisterLocation(uint32_t lldb_regnum,
const RegisterInfo *reg_info =
GetRegisterInfoAtIndex(regnum.GetAsKind(eRegisterKindLLDB));
if (reg_info &&
- abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc) &&
- !unwindplan_regloc.IsUndefined()) {
- UnwindLogMsg(
- "supplying caller's saved %s (%d)'s location using ABI default",
- regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ abi->GetFallbackRegisterLocation(reg_info, unwindplan_regloc)) {
+ if (!unwindplan_regloc.IsUndefined())
+ UnwindLogMsg(
+ "supplying caller's saved %s (%d)'s location using ABI default",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ // ABI defined volatile registers with no register location
+ // will be returned as IsUndefined, stopping the search down
+ // the stack.
return unwindplan_regloc;
}
}
More information about the lldb-commits
mailing list