Fix PC adjustment in StackFrame::GetSymbolContext

Summary:
Update StackFrame::GetSymbolContext to mirror the logic in
RegisterContextLLDB::InitializeNonZerothFrame that knows not to do the
pc decrement when the given frame is a signal trap handler frame or the
parent of one, because the pc may not follow a call in these frames.
Accomplish this by adding a behaves_like_zeroth_frame field to
lldb_private::StackFrame, set to true for the zeroth frame, for
signal handler frames, and for parents of signal handler frames.

Also add logic to propagate the signal handler flag from UnwindPlan to
the FrameType on the RegisterContextLLDB it generates, and factor out a
helper to resolve symbol and address range for an Address now that we
need to invoke it in four places.

Reviewers: jasonmolenda, clayborg, jfb

Reviewed By: jasonmolenda

Subscribers: labath, dexonsmith, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D64993

llvm-svn: 367691
This commit is contained in:
Joseph Tremoulet 2019-08-02 16:53:42 +00:00
parent e93341f7c8
commit 31e6dbe1c6
16 changed files with 251 additions and 89 deletions

View File

@ -338,6 +338,23 @@ public:
bool ResolveAddressUsingFileSections(lldb::addr_t addr, bool ResolveAddressUsingFileSections(lldb::addr_t addr,
const SectionList *sections); const SectionList *sections);
/// Resolve this address to its containing function and optionally get
/// that function's address range.
///
/// \param[out] sym_ctx
/// The symbol context describing the function in which this address lies
///
/// \parm[out] addr_range_ptr
/// Pointer to the AddressRange to fill in with the function's address
/// range. Caller may pass null if they don't need the address range.
///
/// \return
/// Returns \b false if the function/symbol could not be resolved
/// or if the address range was requested and could not be resolved;
/// returns \b true otherwise.
bool ResolveFunctionScope(lldb_private::SymbolContext &sym_ctx,
lldb_private::AddressRange *addr_range_ptr = nullptr);
/// Set the address to represent \a load_addr. /// Set the address to represent \a load_addr.
/// ///
/// The address will attempt to find a loaded section within \a target that /// The address will attempt to find a loaded section within \a target that

View File

@ -108,17 +108,19 @@ public:
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa, lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa,
bool cfa_is_valid, lldb::addr_t pc, Kind frame_kind, bool cfa_is_valid, lldb::addr_t pc, Kind frame_kind,
bool behaves_like_zeroth_frame, const SymbolContext *sc_ptr);
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
lldb::user_id_t concrete_frame_idx,
const lldb::RegisterContextSP &reg_context_sp, lldb::addr_t cfa,
lldb::addr_t pc, bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr); const SymbolContext *sc_ptr);
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
lldb::user_id_t concrete_frame_idx, lldb::user_id_t concrete_frame_idx,
const lldb::RegisterContextSP &reg_context_sp, lldb::addr_t cfa, const lldb::RegisterContextSP &reg_context_sp, lldb::addr_t cfa,
lldb::addr_t pc, const SymbolContext *sc_ptr); const Address &pc, bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr);
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
lldb::user_id_t concrete_frame_idx,
const lldb::RegisterContextSP &reg_context_sp, lldb::addr_t cfa,
const Address &pc, const SymbolContext *sc_ptr);
~StackFrame() override; ~StackFrame() override;
@ -367,6 +369,12 @@ public:
/// may have limited support for inspecting variables. /// may have limited support for inspecting variables.
bool IsArtificial() const; bool IsArtificial() const;
/// Query whether this frame behaves like the zeroth frame, in the sense
/// that its pc value might not immediately follow a call (and thus might
/// be the first address of its function). True for actual frame zero as
/// well as any other frame with the same trait.
bool BehavesLikeZerothFrame() const;
/// Query this frame to find what frame it is in this Thread's /// Query this frame to find what frame it is in this Thread's
/// StackFrameList. /// StackFrameList.
/// ///
@ -511,6 +519,7 @@ private:
bool m_cfa_is_valid; // Does this frame have a CFA? Different from CFA == bool m_cfa_is_valid; // Does this frame have a CFA? Different from CFA ==
// LLDB_INVALID_ADDRESS // LLDB_INVALID_ADDRESS
Kind m_stack_frame_kind; Kind m_stack_frame_kind;
bool m_behaves_like_zeroth_frame;
lldb::VariableListSP m_variable_list_sp; lldb::VariableListSP m_variable_list_sp;
ValueObjectList m_variable_list_value_objects; // Value objects for each ValueObjectList m_variable_list_value_objects; // Value objects for each
// variable in // variable in

View File

@ -37,9 +37,10 @@ public:
lldb::addr_t cfa; lldb::addr_t cfa;
lldb::addr_t pc; lldb::addr_t pc;
uint32_t idx; uint32_t idx;
bool behaves_like_zeroth_frame = (end_idx == 0);
for (idx = 0; idx < end_idx; idx++) { for (idx = 0; idx < end_idx; idx++) {
if (!DoGetFrameInfoAtIndex(idx, cfa, pc)) { if (!DoGetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame)) {
break; break;
} }
} }
@ -47,9 +48,9 @@ public:
} }
bool GetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, bool GetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc) { lldb::addr_t &pc, bool &behaves_like_zeroth_frame) {
std::lock_guard<std::recursive_mutex> guard(m_unwind_mutex); std::lock_guard<std::recursive_mutex> guard(m_unwind_mutex);
return DoGetFrameInfoAtIndex(frame_idx, cfa, pc); return DoGetFrameInfoAtIndex(frame_idx, cfa, pc, behaves_like_zeroth_frame);
} }
lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) { lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) {
@ -66,7 +67,8 @@ protected:
virtual uint32_t DoGetFrameCount() = 0; virtual uint32_t DoGetFrameCount() = 0;
virtual bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, virtual bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc) = 0; lldb::addr_t &pc,
bool &behaves_like_zeroth_frame) = 0;
virtual lldb::RegisterContextSP virtual lldb::RegisterContextSP
DoCreateRegisterContextForFrame(StackFrame *frame) = 0; DoCreateRegisterContextForFrame(StackFrame *frame) = 0;

View File

@ -0,0 +1,42 @@
.text
.globl bar
bar:
.cfi_startproc
leal (%edi, %edi), %eax
ret
.cfi_endproc
.globl asm_main
asm_main:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl $47, %edi
# install tramp as return address
# (similar to signal return trampolines on some platforms)
leaq tramp, %rax
pushq %rax
jmp bar # call, with return address pointing to tramp
popq %rbp
.cfi_def_cfa %rsp, 8
ret
.cfi_endproc
.globl tramp
tramp:
.cfi_startproc
.cfi_signal_frame
# Emit cfi to line up with the frame created by asm_main
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
.cfi_def_cfa_register %rbp
# copy asm_main's epilog to clean up the frame
popq %rbp
.cfi_def_cfa %rsp, 8
ret
.cfi_endproc

View File

@ -0,0 +1,21 @@
# Test that symbol contexts for trap handler frames are set correctly even when
# the pc is at the start of the function.
# UNSUPPORTED: system-windows
# REQUIRES: target-x86_64, native
# RUN: %clang %p/Inputs/call-asm.c %p/Inputs/trap_frame_sym_ctx.s -o %t
# RUN: %lldb %t -s %s -o exit | FileCheck %s
settings append target.trap-handler-names tramp
breakpoint set -n bar
# CHECK: Breakpoint 1: where = {{.*}}`bar
process launch
# CHECK: stop reason = breakpoint 1.1
thread backtrace
# CHECK: frame #0: {{.*}}`bar
# CHECK: frame #1: {{.*}}`tramp
# CHECK: frame #2: {{.*}}`main

View File

@ -261,6 +261,24 @@ bool Address::ResolveAddressUsingFileSections(addr_t file_addr,
return false; // Failed to resolve this address to a section offset value return false; // Failed to resolve this address to a section offset value
} }
/// if "addr_range_ptr" is not NULL, then fill in with the address range of the function.
bool Address::ResolveFunctionScope(SymbolContext &sym_ctx,
AddressRange *addr_range_ptr) {
constexpr SymbolContextItem resolve_scope =
eSymbolContextFunction | eSymbolContextSymbol;
if (!(CalculateSymbolContext(&sym_ctx, resolve_scope) & resolve_scope)) {
if (addr_range_ptr)
addr_range_ptr->Clear();
return false;
}
if (!addr_range_ptr)
return true;
return sym_ctx.GetAddressRange(resolve_scope, 0, false, *addr_range_ptr);
}
ModuleSP Address::GetModule() const { ModuleSP Address::GetModule() const {
lldb::ModuleSP module_sp; lldb::ModuleSP module_sp;
SectionSP section_sp(GetSection()); SectionSP section_sp(GetSection());

View File

@ -51,13 +51,15 @@ HistoryUnwind::DoCreateRegisterContextForFrame(StackFrame *frame) {
} }
bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc) { lldb::addr_t &pc,
bool &behaves_like_zeroth_frame) {
// FIXME do not throw away the lock after we acquire it.. // FIXME do not throw away the lock after we acquire it..
std::unique_lock<std::recursive_mutex> guard(m_unwind_mutex); std::unique_lock<std::recursive_mutex> guard(m_unwind_mutex);
guard.unlock(); guard.unlock();
if (frame_idx < m_pcs.size()) { if (frame_idx < m_pcs.size()) {
cfa = frame_idx; cfa = frame_idx;
pc = m_pcs[frame_idx]; pc = m_pcs[frame_idx];
behaves_like_zeroth_frame = (frame_idx == 0);
return true; return true;
} }
return false; return false;

View File

@ -29,7 +29,8 @@ protected:
DoCreateRegisterContextForFrame(StackFrame *frame) override; DoCreateRegisterContextForFrame(StackFrame *frame) override;
bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc) override; lldb::addr_t &pc,
bool &behaves_like_zeroth_frame) override;
uint32_t DoGetFrameCount() override; uint32_t DoGetFrameCount() override;
private: private:

View File

@ -150,15 +150,8 @@ void RegisterContextLLDB::InitializeZerothFrame() {
UnwindLogMsg("using architectural default unwind method"); UnwindLogMsg("using architectural default unwind method");
} }
// We require either a symbol or function in the symbols context to be AddressRange addr_range;
// successfully filled in or this context is of no use to us. m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
const SymbolContextItem resolve_scope =
eSymbolContextFunction | eSymbolContextSymbol;
if (pc_module_sp.get() && (pc_module_sp->ResolveSymbolContextForAddress(
m_current_pc, resolve_scope, m_sym_ctx) &
resolve_scope)) {
m_sym_ctx_valid = true;
}
if (m_sym_ctx.symbol) { if (m_sym_ctx.symbol) {
UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
@ -172,9 +165,6 @@ void RegisterContextLLDB::InitializeZerothFrame() {
current_pc); current_pc);
} }
AddressRange addr_range;
m_sym_ctx.GetAddressRange(resolve_scope, 0, false, addr_range);
if (IsTrapHandlerSymbol(process, m_sym_ctx)) { if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
m_frame_type = eTrapHandlerFrame; m_frame_type = eTrapHandlerFrame;
} else { } else {
@ -436,24 +426,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
return; return;
} }
bool resolve_tail_call_address = false; // m_current_pc can be one past the AddressRange addr_range;
// address range of the function... m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
// If the saved pc does not point to a function/symbol because it is beyond
// the bounds of the correct function and there's no symbol there, we do
// *not* want ResolveSymbolContextForAddress to back up the pc by 1, because
// then we might not find the correct unwind information later. Instead, let
// ResolveSymbolContextForAddress fail, and handle the case via
// decr_pc_and_recompute_addr_range below.
const SymbolContextItem resolve_scope =
eSymbolContextFunction | eSymbolContextSymbol;
uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress(
m_current_pc, resolve_scope, m_sym_ctx, resolve_tail_call_address);
// We require either a symbol or function in the symbols context to be
// successfully filled in or this context is of no use to us.
if (resolve_scope & resolved_scope) {
m_sym_ctx_valid = true;
}
if (m_sym_ctx.symbol) { if (m_sym_ctx.symbol) {
UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc, UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc,
@ -467,11 +441,6 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
pc); pc);
} }
AddressRange addr_range;
if (!m_sym_ctx.GetAddressRange(resolve_scope, 0, false, addr_range)) {
m_sym_ctx_valid = false;
}
bool decr_pc_and_recompute_addr_range; bool decr_pc_and_recompute_addr_range;
if (!m_sym_ctx_valid) { if (!m_sym_ctx_valid) {
@ -512,18 +481,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
Address temporary_pc; Address temporary_pc;
temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget()); temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget());
m_sym_ctx.Clear(false); m_sym_ctx.Clear(false);
m_sym_ctx_valid = false; m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
SymbolContextItem resolve_scope =
eSymbolContextFunction | eSymbolContextSymbol;
ModuleSP temporary_module_sp = temporary_pc.GetModule();
if (temporary_module_sp &&
temporary_module_sp->ResolveSymbolContextForAddress(
temporary_pc, resolve_scope, m_sym_ctx) &
resolve_scope) {
if (m_sym_ctx.GetAddressRange(resolve_scope, 0, false, addr_range))
m_sym_ctx_valid = true;
}
UnwindLogMsg("Symbol is now %s", UnwindLogMsg("Symbol is now %s",
GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
} }
@ -573,6 +532,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
active_row = active_row =
m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind(); row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind();
PropagateTrapHandlerFlagFromUnwindPlan(m_fast_unwind_plan_sp);
if (active_row.get() && log) { if (active_row.get() && log) {
StreamString active_row_strm; StreamString active_row_strm;
active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread,
@ -585,6 +545,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) {
active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset); active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset);
row_register_kind = m_full_unwind_plan_sp->GetRegisterKind(); row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
if (active_row.get() && log) { if (active_row.get() && log) {
StreamString active_row_strm; StreamString active_row_strm;
active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(),
@ -1708,6 +1669,7 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() {
// We've copied the fallback unwind plan into the full - now clear the // We've copied the fallback unwind plan into the full - now clear the
// fallback. // fallback.
m_fallback_unwind_plan_sp.reset(); m_fallback_unwind_plan_sp.reset();
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
} }
return true; return true;
@ -1751,6 +1713,8 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
m_cfa = new_cfa; m_cfa = new_cfa;
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
UnwindLogMsg("switched unconditionally to the fallback unwindplan %s", UnwindLogMsg("switched unconditionally to the fallback unwindplan %s",
m_full_unwind_plan_sp->GetSourceName().GetCString()); m_full_unwind_plan_sp->GetSourceName().GetCString());
return true; return true;
@ -1758,6 +1722,53 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
return false; return false;
} }
void RegisterContextLLDB::PropagateTrapHandlerFlagFromUnwindPlan(
lldb::UnwindPlanSP unwind_plan) {
if (unwind_plan->GetUnwindPlanForSignalTrap() != eLazyBoolYes) {
// Unwind plan does not indicate trap handler. Do nothing. We may
// already be flagged as trap handler flag due to the symbol being
// in the trap handler symbol list, and that should take precedence.
return;
} else if (m_frame_type != eNormalFrame) {
// If this is already a trap handler frame, nothing to do.
// If this is a skip or debug or invalid frame, don't override that.
return;
}
m_frame_type = eTrapHandlerFrame;
if (m_current_offset_backed_up_one != m_current_offset) {
// We backed up the pc by 1 to compute the symbol context, but
// now need to undo that because the pc of the trap handler
// frame may in fact be the first instruction of a signal return
// trampoline, rather than the instruction after a call. This
// happens on systems where the signal handler dispatch code, rather
// than calling the handler and being returned to, jumps to the
// handler after pushing the address of a return trampoline on the
// stack -- on these systems, when the handler returns, control will
// be transferred to the return trampoline, so that's the best
// symbol we can present in the callstack.
UnwindLogMsg("Resetting current offset and re-doing symbol lookup; "
"old symbol was %s",
GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
m_current_offset_backed_up_one = m_current_offset;
AddressRange addr_range;
m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
UnwindLogMsg("Symbol is now %s",
GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
ExecutionContext exe_ctx(m_thread.shared_from_this());
Process *process = exe_ctx.GetProcessPtr();
Target *target = &process->GetTarget();
m_start_pc = addr_range.GetBaseAddress();
m_current_offset =
m_current_pc.GetLoadAddress(target) - m_start_pc.GetLoadAddress(target);
}
}
bool RegisterContextLLDB::ReadFrameAddress( bool RegisterContextLLDB::ReadFrameAddress(
lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa, lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa,
addr_t &address) { addr_t &address) {

View File

@ -120,6 +120,10 @@ private:
bool IsTrapHandlerSymbol(lldb_private::Process *process, bool IsTrapHandlerSymbol(lldb_private::Process *process,
const lldb_private::SymbolContext &m_sym_ctx) const; const lldb_private::SymbolContext &m_sym_ctx) const;
/// Check if the given unwind plan indicates a signal trap handler, and
/// update frame type and symbol context if so.
void PropagateTrapHandlerFlagFromUnwindPlan(lldb::UnwindPlanSP unwind_plan);
// Provide a location for where THIS function saved the CALLER's register // Provide a location for where THIS function saved the CALLER's register
// value // value
// Or a frame "below" this one saved it, i.e. a function called by this one, // Or a frame "below" this one saved it, i.e. a function called by this one,

View File

@ -390,7 +390,8 @@ bool UnwindLLDB::AddOneMoreFrame(ABI *abi) {
return true; return true;
} }
bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc) { bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc,
bool &behaves_like_zeroth_frame) {
if (m_frames.size() == 0) { if (m_frames.size() == 0) {
if (!AddFirstFrame()) if (!AddFirstFrame())
return false; return false;
@ -405,6 +406,24 @@ bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc) {
if (idx < m_frames.size()) { if (idx < m_frames.size()) {
cfa = m_frames[idx]->cfa; cfa = m_frames[idx]->cfa;
pc = m_frames[idx]->start_pc; pc = m_frames[idx]->start_pc;
if (idx == 0) {
// Frame zero always behaves like it.
behaves_like_zeroth_frame = true;
} else if (m_frames[idx - 1]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) {
// This could be an asynchronous signal, thus the
// pc might point to the interrupted instruction rather
// than a post-call instruction
behaves_like_zeroth_frame = true;
} else if (m_frames[idx]->reg_ctx_lldb_sp->IsTrapHandlerFrame()) {
// This frame may result from signal processing installing
// a pointer to the first byte of a signal-return trampoline
// in the return address slot of the frame below, so this
// too behaves like the zeroth frame (i.e. the pc might not
// be pointing just past a call in it)
behaves_like_zeroth_frame = true;
} else {
behaves_like_zeroth_frame = false;
}
return true; return true;
} }
return false; return false;

View File

@ -73,7 +73,8 @@ protected:
uint32_t DoGetFrameCount() override; uint32_t DoGetFrameCount() override;
bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &start_pc) override; lldb::addr_t &start_pc,
bool &behaves_like_zeroth_frame) override;
lldb::RegisterContextSP lldb::RegisterContextSP
DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;

View File

@ -43,9 +43,8 @@ uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
return m_cursors.size(); return m_cursors.size();
} }
bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx, bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(
addr_t &cfa, uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) {
addr_t &pc) {
const uint32_t frame_count = GetFrameCount(); const uint32_t frame_count = GetFrameCount();
if (idx < frame_count) { if (idx < frame_count) {
if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS) if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
@ -55,6 +54,7 @@ bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx,
pc = m_cursors[idx].pc; pc = m_cursors[idx].pc;
cfa = m_cursors[idx].fp; cfa = m_cursors[idx].fp;
behaves_like_zeroth_frame = (idx == 0);
return true; return true;
} }

View File

@ -26,7 +26,8 @@ protected:
uint32_t DoGetFrameCount() override; uint32_t DoGetFrameCount() override;
bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
lldb::addr_t &pc) override; lldb::addr_t &pc,
bool &behaves_like_zeroth_frame) override;
lldb::RegisterContextSP lldb::RegisterContextSP
DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;

View File

@ -51,14 +51,16 @@ using namespace lldb_private;
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
user_id_t unwind_frame_index, addr_t cfa, user_id_t unwind_frame_index, addr_t cfa,
bool cfa_is_valid, addr_t pc, StackFrame::Kind kind, bool cfa_is_valid, addr_t pc, StackFrame::Kind kind,
bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr) const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx), : m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(), m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(),
m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(), m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(),
m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
m_stack_frame_kind(kind), m_variable_list_sp(), m_stack_frame_kind(kind),
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_mutex() { m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
// If we don't have a CFA value, use the frame index for our StackID so that // If we don't have a CFA value, use the frame index for our StackID so that
// recursive functions properly aren't confused with one another on a history // recursive functions properly aren't confused with one another on a history
// stack. // stack.
@ -75,15 +77,17 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
user_id_t unwind_frame_index, user_id_t unwind_frame_index,
const RegisterContextSP &reg_context_sp, addr_t cfa, const RegisterContextSP &reg_context_sp, addr_t cfa,
addr_t pc, const SymbolContext *sc_ptr) addr_t pc, bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx), : m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index), m_concrete_frame_index(unwind_frame_index),
m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr), m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr),
m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true), m_frame_base_error(), m_cfa_is_valid(true),
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(), m_stack_frame_kind(StackFrame::Kind::Regular),
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_mutex() { m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
if (sc_ptr != nullptr) { if (sc_ptr != nullptr) {
m_sc = *sc_ptr; m_sc = *sc_ptr;
m_flags.Set(m_sc.GetResolvedMask()); m_flags.Set(m_sc.GetResolvedMask());
@ -99,7 +103,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
user_id_t unwind_frame_index, user_id_t unwind_frame_index,
const RegisterContextSP &reg_context_sp, addr_t cfa, const RegisterContextSP &reg_context_sp, addr_t cfa,
const Address &pc_addr, const SymbolContext *sc_ptr) const Address &pc_addr, bool behaves_like_zeroth_frame,
const SymbolContext *sc_ptr)
: m_thread_wp(thread_sp), m_frame_index(frame_idx), : m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index), m_concrete_frame_index(unwind_frame_index),
m_reg_context_sp(reg_context_sp), m_reg_context_sp(reg_context_sp),
@ -107,9 +112,10 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
nullptr), nullptr),
m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
m_frame_base_error(), m_cfa_is_valid(true), m_frame_base_error(), m_cfa_is_valid(true),
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(), m_stack_frame_kind(StackFrame::Kind::Regular),
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
m_mutex() { m_variable_list_sp(), m_variable_list_value_objects(),
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
if (sc_ptr != nullptr) { if (sc_ptr != nullptr) {
m_sc = *sc_ptr; m_sc = *sc_ptr;
m_flags.Set(m_sc.GetResolvedMask()); m_flags.Set(m_sc.GetResolvedMask());
@ -289,7 +295,7 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) {
// following the function call instruction... // following the function call instruction...
Address lookup_addr(GetFrameCodeAddress()); Address lookup_addr(GetFrameCodeAddress());
if (m_frame_index > 0 && lookup_addr.IsValid()) { if (!m_behaves_like_zeroth_frame && lookup_addr.IsValid()) {
addr_t offset = lookup_addr.GetOffset(); addr_t offset = lookup_addr.GetOffset();
if (offset > 0) { if (offset > 0) {
lookup_addr.SetOffset(offset - 1); lookup_addr.SetOffset(offset - 1);

View File

@ -397,11 +397,13 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
bool cfa_is_valid = false; bool cfa_is_valid = false;
addr_t pc = addr_t pc =
callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target); callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target);
constexpr bool behaves_like_zeroth_frame = false;
SymbolContext sc; SymbolContext sc;
callee->CalculateSymbolContext(&sc); callee->CalculateSymbolContext(&sc);
auto synth_frame = std::make_shared<StackFrame>( auto synth_frame = std::make_shared<StackFrame>(
m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa, m_thread.shared_from_this(), frame_idx, concrete_frame_idx, cfa,
cfa_is_valid, pc, StackFrame::Kind::Artificial, &sc); cfa_is_valid, pc, StackFrame::Kind::Artificial,
behaves_like_zeroth_frame, &sc);
m_frames.push_back(synth_frame); m_frames.push_back(synth_frame);
LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName()); LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName());
} }
@ -451,6 +453,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
uint32_t idx = m_concrete_frames_fetched++; uint32_t idx = m_concrete_frames_fetched++;
lldb::addr_t pc = LLDB_INVALID_ADDRESS; lldb::addr_t pc = LLDB_INVALID_ADDRESS;
lldb::addr_t cfa = LLDB_INVALID_ADDRESS; lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
bool behaves_like_zeroth_frame = (idx == 0);
if (idx == 0) { if (idx == 0) {
// We might have already created frame zero, only create it if we need // We might have already created frame zero, only create it if we need
// to. // to.
@ -458,8 +461,9 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext()); RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
if (reg_ctx_sp) { if (reg_ctx_sp) {
const bool success = const bool success = unwinder &&
unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); unwinder->GetFrameInfoAtIndex(
idx, cfa, pc, behaves_like_zeroth_frame);
// There shouldn't be any way not to get the frame info for frame // There shouldn't be any way not to get the frame info for frame
// 0. But if the unwinder can't make one, lets make one by hand // 0. But if the unwinder can't make one, lets make one by hand
// with the SP as the CFA and see if that gets any further. // with the SP as the CFA and see if that gets any further.
@ -470,7 +474,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
unwind_frame_sp = std::make_shared<StackFrame>( unwind_frame_sp = std::make_shared<StackFrame>(
m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp, m_thread.shared_from_this(), m_frames.size(), idx, reg_ctx_sp,
cfa, pc, nullptr); cfa, pc, behaves_like_zeroth_frame, nullptr);
m_frames.push_back(unwind_frame_sp); m_frames.push_back(unwind_frame_sp);
} }
} else { } else {
@ -478,8 +482,9 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
} }
} else { } else {
const bool success = const bool success = unwinder &&
unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); unwinder->GetFrameInfoAtIndex(
idx, cfa, pc, behaves_like_zeroth_frame);
if (!success) { if (!success) {
// We've gotten to the end of the stack. // We've gotten to the end of the stack.
SetAllFramesFetched(); SetAllFramesFetched();
@ -488,7 +493,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
const bool cfa_is_valid = true; const bool cfa_is_valid = true;
unwind_frame_sp = std::make_shared<StackFrame>( unwind_frame_sp = std::make_shared<StackFrame>(
m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid, m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid,
pc, StackFrame::Kind::Regular, nullptr); pc, StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
// Create synthetic tail call frames between the previous frame and the // Create synthetic tail call frames between the previous frame and the
// newly-found frame. The new frame's index may change after this call, // newly-found frame. The new frame's index may change after this call,
@ -530,10 +535,11 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
while (unwind_sc.GetParentOfInlinedScope( while (unwind_sc.GetParentOfInlinedScope(
curr_frame_address, next_frame_sc, next_frame_address)) { curr_frame_address, next_frame_sc, next_frame_address)) {
next_frame_sc.line_entry.ApplyFileMappings(target_sp); next_frame_sc.line_entry.ApplyFileMappings(target_sp);
StackFrameSP frame_sp( behaves_like_zeroth_frame = false;
new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx, StackFrameSP frame_sp(new StackFrame(
unwind_frame_sp->GetRegisterContextSP(), cfa, m_thread.shared_from_this(), m_frames.size(), idx,
next_frame_address, &next_frame_sc)); unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
behaves_like_zeroth_frame, &next_frame_sc));
m_frames.push_back(frame_sp); m_frames.push_back(frame_sp);
unwind_sc = next_frame_sc; unwind_sc = next_frame_sc;
@ -664,11 +670,13 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
Unwind *unwinder = m_thread.GetUnwinder(); Unwind *unwinder = m_thread.GetUnwinder();
if (unwinder) { if (unwinder) {
addr_t pc, cfa; addr_t pc, cfa;
if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) { bool behaves_like_zeroth_frame = (idx == 0);
if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc,
behaves_like_zeroth_frame)) {
const bool cfa_is_valid = true; const bool cfa_is_valid = true;
frame_sp = std::make_shared<StackFrame>( frame_sp = std::make_shared<StackFrame>(
m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
StackFrame::Kind::Regular, nullptr); StackFrame::Kind::Regular, behaves_like_zeroth_frame, nullptr);
Function *function = Function *function =
frame_sp->GetSymbolContext(eSymbolContextFunction).function; frame_sp->GetSymbolContext(eSymbolContextFunction).function;