Index: lldb/trunk/include/lldb/Core/Address.h =================================================================== --- lldb/trunk/include/lldb/Core/Address.h +++ lldb/trunk/include/lldb/Core/Address.h @@ -338,6 +338,23 @@ 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 Index: lldb/trunk/include/lldb/Target/StackFrame.h =================================================================== --- lldb/trunk/include/lldb/Target/StackFrame.h +++ lldb/trunk/include/lldb/Target/StackFrame.h @@ -108,17 +108,19 @@ 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, - const SymbolContext *sc_ptr); + 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); + 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, - 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 @@ /// 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 @@ 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 Index: lldb/trunk/include/lldb/Target/Unwind.h =================================================================== --- lldb/trunk/include/lldb/Target/Unwind.h +++ lldb/trunk/include/lldb/Target/Unwind.h @@ -37,9 +37,10 @@ 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 @@ } 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 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 @@ 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; Index: lldb/trunk/lit/Unwind/Inputs/trap_frame_sym_ctx.s =================================================================== --- lldb/trunk/lit/Unwind/Inputs/trap_frame_sym_ctx.s +++ lldb/trunk/lit/Unwind/Inputs/trap_frame_sym_ctx.s @@ -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 Index: lldb/trunk/lit/Unwind/trap_frame_sym_ctx.test =================================================================== --- lldb/trunk/lit/Unwind/trap_frame_sym_ctx.test +++ lldb/trunk/lit/Unwind/trap_frame_sym_ctx.test @@ -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 Index: lldb/trunk/source/Core/Address.cpp =================================================================== --- lldb/trunk/source/Core/Address.cpp +++ lldb/trunk/source/Core/Address.cpp @@ -261,6 +261,24 @@ 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()); Index: lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.h =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.h +++ lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.h @@ -29,7 +29,8 @@ 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: Index: lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ lldb/trunk/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -51,13 +51,15 @@ } 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 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; Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -120,6 +120,10 @@ 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, Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -150,15 +150,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; - - 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; - } + m_sym_ctx_valid = temporary_pc.ResolveFunctionScope(m_sym_ctx, &addr_range); + UnwindLogMsg("Symbol is now %s", GetSymbolOrFunctionName(m_sym_ctx).AsCString("")); } @@ -573,6 +532,7 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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) { Index: lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h +++ lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.h @@ -73,7 +73,8 @@ 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; Index: lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ lldb/trunk/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -390,7 +390,8 @@ 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 @@ 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; Index: lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h +++ lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h @@ -26,7 +26,8 @@ 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; Index: lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp +++ lldb/trunk/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp @@ -43,9 +43,8 @@ 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 @@ pc = m_cursors[idx].pc; cfa = m_cursors[idx].fp; + behaves_like_zeroth_frame = (idx == 0); return true; } Index: lldb/trunk/source/Target/StackFrame.cpp =================================================================== --- lldb/trunk/source/Target/StackFrame.cpp +++ lldb/trunk/source/Target/StackFrame.cpp @@ -51,14 +51,16 @@ 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, 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, 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 @@ 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 @@ // 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); Index: lldb/trunk/source/Target/StackFrameList.cpp =================================================================== --- lldb/trunk/source/Target/StackFrameList.cpp +++ lldb/trunk/source/Target/StackFrameList.cpp @@ -397,11 +397,13 @@ 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( 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 @@ 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 @@ 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 @@ unwind_frame_sp = std::make_shared( 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 @@ 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 @@ const bool cfa_is_valid = true; unwind_frame_sp = std::make_shared( 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 @@ 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 @@ 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( 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;