forked from OSchip/llvm-project
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:
parent
e93341f7c8
commit
31e6dbe1c6
|
@ -338,6 +338,23 @@ public:
|
|||
bool ResolveAddressUsingFileSections(lldb::addr_t addr,
|
||||
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.
|
||||
///
|
||||
/// The address will attempt to find a loaded section within \a target that
|
||||
|
|
|
@ -108,17 +108,19 @@ public:
|
|||
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx,
|
||||
lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa,
|
||||
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 ®_context_sp, lldb::addr_t cfa,
|
||||
lldb::addr_t 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 ®_context_sp, lldb::addr_t cfa,
|
||||
lldb::addr_t pc, 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 ®_context_sp, lldb::addr_t cfa,
|
||||
const Address &pc, const SymbolContext *sc_ptr);
|
||||
const Address &pc, bool behaves_like_zeroth_frame,
|
||||
const SymbolContext *sc_ptr);
|
||||
|
||||
~StackFrame() override;
|
||||
|
||||
|
@ -367,6 +369,12 @@ public:
|
|||
/// may have limited support for inspecting variables.
|
||||
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
|
||||
/// StackFrameList.
|
||||
///
|
||||
|
@ -511,6 +519,7 @@ private:
|
|||
bool m_cfa_is_valid; // Does this frame have a CFA? Different from CFA ==
|
||||
// LLDB_INVALID_ADDRESS
|
||||
Kind m_stack_frame_kind;
|
||||
bool m_behaves_like_zeroth_frame;
|
||||
lldb::VariableListSP m_variable_list_sp;
|
||||
ValueObjectList m_variable_list_value_objects; // Value objects for each
|
||||
// variable in
|
||||
|
|
|
@ -37,9 +37,10 @@ public:
|
|||
lldb::addr_t cfa;
|
||||
lldb::addr_t pc;
|
||||
uint32_t idx;
|
||||
bool behaves_like_zeroth_frame = (end_idx == 0);
|
||||
|
||||
for (idx = 0; idx < end_idx; idx++) {
|
||||
if (!DoGetFrameInfoAtIndex(idx, cfa, pc)) {
|
||||
if (!DoGetFrameInfoAtIndex(idx, cfa, pc, behaves_like_zeroth_frame)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -47,9 +48,9 @@ public:
|
|||
}
|
||||
|
||||
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);
|
||||
return DoGetFrameInfoAtIndex(frame_idx, cfa, pc);
|
||||
return DoGetFrameInfoAtIndex(frame_idx, cfa, pc, behaves_like_zeroth_frame);
|
||||
}
|
||||
|
||||
lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) {
|
||||
|
@ -66,7 +67,8 @@ protected:
|
|||
virtual uint32_t DoGetFrameCount() = 0;
|
||||
|
||||
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
|
||||
DoCreateRegisterContextForFrame(StackFrame *frame) = 0;
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -261,6 +261,24 @@ bool Address::ResolveAddressUsingFileSections(addr_t file_addr,
|
|||
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 {
|
||||
lldb::ModuleSP module_sp;
|
||||
SectionSP section_sp(GetSection());
|
||||
|
|
|
@ -51,13 +51,15 @@ HistoryUnwind::DoCreateRegisterContextForFrame(StackFrame *frame) {
|
|||
}
|
||||
|
||||
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..
|
||||
std::unique_lock<std::recursive_mutex> guard(m_unwind_mutex);
|
||||
guard.unlock();
|
||||
if (frame_idx < m_pcs.size()) {
|
||||
cfa = frame_idx;
|
||||
pc = m_pcs[frame_idx];
|
||||
behaves_like_zeroth_frame = (frame_idx == 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -29,7 +29,8 @@ protected:
|
|||
DoCreateRegisterContextForFrame(StackFrame *frame) override;
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -150,15 +150,8 @@ void RegisterContextLLDB::InitializeZerothFrame() {
|
|||
UnwindLogMsg("using architectural default unwind method");
|
||||
}
|
||||
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
AddressRange addr_range;
|
||||
m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
|
||||
|
||||
if (m_sym_ctx.symbol) {
|
||||
UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
|
||||
|
@ -172,9 +165,6 @@ void RegisterContextLLDB::InitializeZerothFrame() {
|
|||
current_pc);
|
||||
}
|
||||
|
||||
AddressRange addr_range;
|
||||
m_sym_ctx.GetAddressRange(resolve_scope, 0, false, addr_range);
|
||||
|
||||
if (IsTrapHandlerSymbol(process, m_sym_ctx)) {
|
||||
m_frame_type = eTrapHandlerFrame;
|
||||
} else {
|
||||
|
@ -436,24 +426,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
|
|||
return;
|
||||
}
|
||||
|
||||
bool resolve_tail_call_address = false; // m_current_pc can be one past the
|
||||
// address range of the function...
|
||||
// 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;
|
||||
}
|
||||
AddressRange addr_range;
|
||||
m_sym_ctx_valid = m_current_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
|
||||
|
||||
if (m_sym_ctx.symbol) {
|
||||
UnwindLogMsg("with pc value of 0x%" PRIx64 ", symbol name is '%s'", pc,
|
||||
|
@ -467,11 +441,6 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
|
|||
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;
|
||||
|
||||
if (!m_sym_ctx_valid) {
|
||||
|
@ -512,18 +481,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
|
|||
Address temporary_pc;
|
||||
temporary_pc.SetLoadAddress(pc - 1, &process->GetTarget());
|
||||
m_sym_ctx.Clear(false);
|
||||
m_sym_ctx_valid = false;
|
||||
SymbolContextItem resolve_scope =
|
||||
eSymbolContextFunction | eSymbolContextSymbol;
|
||||
m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range);
|
||||
|
||||
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",
|
||||
GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
|
||||
}
|
||||
|
@ -573,6 +532,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
|
|||
active_row =
|
||||
m_fast_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset);
|
||||
row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind();
|
||||
PropagateTrapHandlerFlagFromUnwindPlan(m_fast_unwind_plan_sp);
|
||||
if (active_row.get() && log) {
|
||||
StreamString active_row_strm;
|
||||
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)) {
|
||||
active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset(valid_offset);
|
||||
row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
|
||||
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
|
||||
if (active_row.get() && log) {
|
||||
StreamString active_row_strm;
|
||||
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
|
||||
// fallback.
|
||||
m_fallback_unwind_plan_sp.reset();
|
||||
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1751,6 +1713,8 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
|
|||
|
||||
m_cfa = new_cfa;
|
||||
|
||||
PropagateTrapHandlerFlagFromUnwindPlan(m_full_unwind_plan_sp);
|
||||
|
||||
UnwindLogMsg("switched unconditionally to the fallback unwindplan %s",
|
||||
m_full_unwind_plan_sp->GetSourceName().GetCString());
|
||||
return true;
|
||||
|
@ -1758,6 +1722,53 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
|
|||
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(
|
||||
lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa,
|
||||
addr_t &address) {
|
||||
|
|
|
@ -120,6 +120,10 @@ private:
|
|||
bool IsTrapHandlerSymbol(lldb_private::Process *process,
|
||||
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
|
||||
// value
|
||||
// Or a frame "below" this one saved it, i.e. a function called by this one,
|
||||
|
|
|
@ -390,7 +390,8 @@ bool UnwindLLDB::AddOneMoreFrame(ABI *abi) {
|
|||
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 (!AddFirstFrame())
|
||||
return false;
|
||||
|
@ -405,6 +406,24 @@ bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc) {
|
|||
if (idx < m_frames.size()) {
|
||||
cfa = m_frames[idx]->cfa;
|
||||
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 false;
|
||||
|
|
|
@ -73,7 +73,8 @@ protected:
|
|||
uint32_t DoGetFrameCount() override;
|
||||
|
||||
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
|
||||
DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
|
||||
|
|
|
@ -43,9 +43,8 @@ uint32_t UnwindMacOSXFrameBackchain::DoGetFrameCount() {
|
|||
return m_cursors.size();
|
||||
}
|
||||
|
||||
bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx,
|
||||
addr_t &cfa,
|
||||
addr_t &pc) {
|
||||
bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(
|
||||
uint32_t idx, addr_t &cfa, addr_t &pc, bool &behaves_like_zeroth_frame) {
|
||||
const uint32_t frame_count = GetFrameCount();
|
||||
if (idx < frame_count) {
|
||||
if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
|
||||
|
@ -55,6 +54,7 @@ bool UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex(uint32_t idx,
|
|||
|
||||
pc = m_cursors[idx].pc;
|
||||
cfa = m_cursors[idx].fp;
|
||||
behaves_like_zeroth_frame = (idx == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ protected:
|
|||
uint32_t DoGetFrameCount() override;
|
||||
|
||||
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
|
||||
DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
|
||||
|
|
|
@ -51,14 +51,16 @@ using namespace lldb_private;
|
|||
StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
|
||||
user_id_t unwind_frame_index, addr_t cfa,
|
||||
bool cfa_is_valid, addr_t pc, StackFrame::Kind kind,
|
||||
bool behaves_like_zeroth_frame,
|
||||
const SymbolContext *sc_ptr)
|
||||
: m_thread_wp(thread_sp), m_frame_index(frame_idx),
|
||||
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_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
|
||||
m_stack_frame_kind(kind), m_variable_list_sp(),
|
||||
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
|
||||
m_mutex() {
|
||||
m_stack_frame_kind(kind),
|
||||
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
|
||||
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
|
||||
// recursive functions properly aren't confused with one another on a history
|
||||
// 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,
|
||||
user_id_t unwind_frame_index,
|
||||
const RegisterContextSP ®_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_concrete_frame_index(unwind_frame_index),
|
||||
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_base_error(), m_cfa_is_valid(true),
|
||||
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
|
||||
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
|
||||
m_mutex() {
|
||||
m_stack_frame_kind(StackFrame::Kind::Regular),
|
||||
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
|
||||
m_variable_list_sp(), m_variable_list_value_objects(),
|
||||
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
|
||||
if (sc_ptr != nullptr) {
|
||||
m_sc = *sc_ptr;
|
||||
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,
|
||||
user_id_t unwind_frame_index,
|
||||
const RegisterContextSP ®_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_concrete_frame_index(unwind_frame_index),
|
||||
m_reg_context_sp(reg_context_sp),
|
||||
|
@ -107,9 +112,10 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
|
|||
nullptr),
|
||||
m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
|
||||
m_frame_base_error(), m_cfa_is_valid(true),
|
||||
m_stack_frame_kind(StackFrame::Kind::Regular), m_variable_list_sp(),
|
||||
m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(),
|
||||
m_mutex() {
|
||||
m_stack_frame_kind(StackFrame::Kind::Regular),
|
||||
m_behaves_like_zeroth_frame(behaves_like_zeroth_frame),
|
||||
m_variable_list_sp(), m_variable_list_value_objects(),
|
||||
m_recognized_frame_sp(), m_disassembly(), m_mutex() {
|
||||
if (sc_ptr != nullptr) {
|
||||
m_sc = *sc_ptr;
|
||||
m_flags.Set(m_sc.GetResolvedMask());
|
||||
|
@ -289,7 +295,7 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) {
|
|||
// following the function call instruction...
|
||||
|
||||
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();
|
||||
if (offset > 0) {
|
||||
lookup_addr.SetOffset(offset - 1);
|
||||
|
|
|
@ -397,11 +397,13 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) {
|
|||
bool cfa_is_valid = false;
|
||||
addr_t pc =
|
||||
callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target);
|
||||
constexpr bool behaves_like_zeroth_frame = false;
|
||||
SymbolContext sc;
|
||||
callee->CalculateSymbolContext(&sc);
|
||||
auto synth_frame = std::make_shared<StackFrame>(
|
||||
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);
|
||||
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++;
|
||||
lldb::addr_t pc = LLDB_INVALID_ADDRESS;
|
||||
lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
|
||||
bool behaves_like_zeroth_frame = (idx == 0);
|
||||
if (idx == 0) {
|
||||
// We might have already created frame zero, only create it if we need
|
||||
// to.
|
||||
|
@ -458,8 +461,9 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
|
|||
RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
|
||||
|
||||
if (reg_ctx_sp) {
|
||||
const bool success =
|
||||
unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
|
||||
const bool success = unwinder &&
|
||||
unwinder->GetFrameInfoAtIndex(
|
||||
idx, cfa, pc, behaves_like_zeroth_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
|
||||
// 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>(
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
|
@ -478,8 +482,9 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
|
|||
cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
|
||||
}
|
||||
} else {
|
||||
const bool success =
|
||||
unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
|
||||
const bool success = unwinder &&
|
||||
unwinder->GetFrameInfoAtIndex(
|
||||
idx, cfa, pc, behaves_like_zeroth_frame);
|
||||
if (!success) {
|
||||
// We've gotten to the end of the stack.
|
||||
SetAllFramesFetched();
|
||||
|
@ -488,7 +493,7 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
|
|||
const bool cfa_is_valid = true;
|
||||
unwind_frame_sp = std::make_shared<StackFrame>(
|
||||
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
|
||||
// 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(
|
||||
curr_frame_address, next_frame_sc, next_frame_address)) {
|
||||
next_frame_sc.line_entry.ApplyFileMappings(target_sp);
|
||||
StackFrameSP frame_sp(
|
||||
new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx,
|
||||
unwind_frame_sp->GetRegisterContextSP(), cfa,
|
||||
next_frame_address, &next_frame_sc));
|
||||
behaves_like_zeroth_frame = false;
|
||||
StackFrameSP frame_sp(new StackFrame(
|
||||
m_thread.shared_from_this(), m_frames.size(), idx,
|
||||
unwind_frame_sp->GetRegisterContextSP(), cfa, next_frame_address,
|
||||
behaves_like_zeroth_frame, &next_frame_sc));
|
||||
|
||||
m_frames.push_back(frame_sp);
|
||||
unwind_sc = next_frame_sc;
|
||||
|
@ -664,11 +670,13 @@ StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
|
|||
Unwind *unwinder = m_thread.GetUnwinder();
|
||||
if (unwinder) {
|
||||
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;
|
||||
frame_sp = std::make_shared<StackFrame>(
|
||||
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 =
|
||||
frame_sp->GetSymbolContext(eSymbolContextFunction).function;
|
||||
|
|
Loading…
Reference in New Issue