diff options
Diffstat (limited to 'lldb/source/Target/RegisterContextUnwind.cpp')
| -rw-r--r-- | lldb/source/Target/RegisterContextUnwind.cpp | 192 |
1 files changed, 168 insertions, 24 deletions
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp index f33f4180be23..1ce21e6306e0 100644 --- a/lldb/source/Target/RegisterContextUnwind.cpp +++ b/lldb/source/Target/RegisterContextUnwind.cpp @@ -24,6 +24,7 @@ #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" @@ -57,10 +58,11 @@ RegisterContextUnwind::RegisterContextUnwind(Thread &thread, m_fast_unwind_plan_sp(), m_full_unwind_plan_sp(), m_fallback_unwind_plan_sp(), m_all_registers_available(false), m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS), - m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), - m_current_pc(), m_current_offset(0), m_current_offset_backed_up_one(0), - m_sym_ctx(sym_ctx), m_sym_ctx_valid(false), m_frame_number(frame_number), - m_registers(), m_parent_unwind(unwind_lldb) { + m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), m_current_pc(), + m_current_offset(0), m_current_offset_backed_up_one(0), + m_behaves_like_zeroth_frame(false), m_sym_ctx(sym_ctx), + m_sym_ctx_valid(false), m_frame_number(frame_number), m_registers(), + m_parent_unwind(unwind_lldb) { m_sym_ctx.Clear(false); m_sym_ctx_valid = false; @@ -139,6 +141,12 @@ void RegisterContextUnwind::InitializeZerothFrame() { if (abi) current_pc = abi->FixCodeAddress(current_pc); + UnwindPlanSP lang_runtime_plan_sp = LanguageRuntime::GetRuntimeUnwindPlan( + m_thread, this, m_behaves_like_zeroth_frame); + if (lang_runtime_plan_sp.get()) { + UnwindLogMsg("This is an async frame"); + } + // Initialize m_current_pc, an Address object, based on current_pc, an // addr_t. m_current_pc.SetLoadAddress(current_pc, &process->GetTarget()); @@ -202,6 +210,38 @@ void RegisterContextUnwind::InitializeZerothFrame() { UnwindPlan::RowSP active_row; lldb::RegisterKind row_register_kind = eRegisterKindGeneric; + + // If we have LanguageRuntime UnwindPlan for this unwind, use those + // rules to find the caller frame instead of the function's normal + // UnwindPlans. The full unwind plan for this frame will be + // the LanguageRuntime-provided unwind plan, and there will not be a + // fast unwind plan. + if (lang_runtime_plan_sp.get()) { + active_row = + lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); + row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); + if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), + m_cfa)) { + UnwindLogMsg("Cannot set cfa"); + } else { + m_full_unwind_plan_sp = lang_runtime_plan_sp; + if (log) { + StreamString active_row_strm; + active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("async active row: %s", active_row_strm.GetData()); + } + UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa); + UnwindLogMsg( + "initialized async frame current pc is 0x%" PRIx64 + " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, + (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), + (uint64_t)m_cfa, (uint64_t)m_afa); + + return; + } + } + if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { active_row = @@ -283,6 +323,22 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { return; } + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + + // Some languages may have a logical parent stack frame which is + // not a real stack frame, but the programmer would consider it to + // be the caller of the frame, e.g. Swift asynchronous frames. + // + // A LanguageRuntime may provide an UnwindPlan that is used in this + // stack trace base on the RegisterContext contents, intsead + // of the normal UnwindPlans we would use for the return-pc. + UnwindPlanSP lang_runtime_plan_sp = LanguageRuntime::GetRuntimeUnwindPlan( + m_thread, this, m_behaves_like_zeroth_frame); + if (lang_runtime_plan_sp.get()) { + UnwindLogMsg("This is an async frame"); + } + addr_t pc; if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { UnwindLogMsg("could not get pc value"); @@ -290,8 +346,6 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { return; } - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs // this will strip bit zero in case we read a PC from memory or from the LR. ABI *abi = process->GetABI().get(); @@ -468,6 +522,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { // so do not decrement and recompute if the symbol we already found is a trap // handler. decr_pc_and_recompute_addr_range = false; + } else if (m_behaves_like_zeroth_frame) { + decr_pc_and_recompute_addr_range = false; } else { // Decrement to find the function containing the call. decr_pc_and_recompute_addr_range = true; @@ -522,12 +578,43 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { } } - // We've set m_frame_type and m_sym_ctx before this call. - m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); - UnwindPlan::RowSP active_row; RegisterKind row_register_kind = eRegisterKindGeneric; + // If we have LanguageRuntime UnwindPlan for this unwind, use those + // rules to find the caller frame instead of the function's normal + // UnwindPlans. The full unwind plan for this frame will be + // the LanguageRuntime-provided unwind plan, and there will not be a + // fast unwind plan. + if (lang_runtime_plan_sp.get()) { + active_row = + lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); + row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); + if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), + m_cfa)) { + UnwindLogMsg("Cannot set cfa"); + } else { + m_full_unwind_plan_sp = lang_runtime_plan_sp; + if (log) { + StreamString active_row_strm; + active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("async active row: %s", active_row_strm.GetData()); + } + UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa); + UnwindLogMsg( + "initialized async frame current pc is 0x%" PRIx64 + " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, + (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), + (uint64_t)m_cfa, (uint64_t)m_afa); + + return; + } + } + + // We've set m_frame_type and m_sym_ctx before this call. + m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); + // Try to get by with just the fast UnwindPlan if possible - the full // UnwindPlan may be expensive to get (e.g. if we have to parse the entire // eh_frame section of an ObjectFile for the first time.) @@ -542,6 +629,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { StreamString active_row_strm; active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using fast unwind plan '%s'", + m_fast_unwind_plan_sp->GetSourceName().AsCString()); UnwindLogMsg("active row: %s", active_row_strm.GetData()); } } else { @@ -556,6 +645,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { 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()); } } @@ -625,6 +716,14 @@ bool RegisterContextUnwind::CheckIfLoopingStack() { bool RegisterContextUnwind::IsFrameZero() const { return m_frame_number == 0; } +bool RegisterContextUnwind::BehavesLikeZerothFrame() const { + if (m_frame_number == 0) + return true; + if (m_behaves_like_zeroth_frame) + return true; + return false; +} + // Find a fast unwind plan for this frame, if possible. // // On entry to this method, @@ -662,13 +761,6 @@ UnwindPlanSP RegisterContextUnwind::GetFastUnwindPlanForFrame() { *m_thread.CalculateTarget(), m_thread); if (unwind_plan_sp) { if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log && log->GetVerbose()) { - if (m_fast_unwind_plan_sp) - UnwindLogMsgVerbose("frame, and has a fast UnwindPlan"); - else - UnwindLogMsgVerbose("frame"); - } m_frame_type = eNormalFrame; return unwind_plan_sp; } else { @@ -702,10 +794,9 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { "unable to get architectural default UnwindPlan from ABI plugin"); } - bool behaves_like_zeroth_frame = false; if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { - behaves_like_zeroth_frame = true; + m_behaves_like_zeroth_frame = true; // If this frame behaves like a 0th frame (currently executing or // interrupted asynchronously), all registers can be retrieved. m_all_registers_available = true; @@ -721,7 +812,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { if ((!m_sym_ctx_valid || (m_sym_ctx.function == nullptr && m_sym_ctx.symbol == nullptr)) && - behaves_like_zeroth_frame && m_current_pc.IsValid()) { + m_behaves_like_zeroth_frame && m_current_pc.IsValid()) { uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()); @@ -849,7 +940,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { // Typically the NonCallSite UnwindPlan is the unwind created by inspecting // the assembly language instructions - if (behaves_like_zeroth_frame && process) { + if (m_behaves_like_zeroth_frame && process) { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite( process->GetTarget(), m_thread); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { @@ -1147,6 +1238,7 @@ enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); // Have we already found this register location? if (!m_registers.empty()) { @@ -1179,8 +1271,17 @@ RegisterContextUnwind::SavedLocationForRegister( (int)unwindplan_registerkind); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } + // 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), - unwindplan_regloc)) { + unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); @@ -1191,8 +1292,11 @@ RegisterContextUnwind::SavedLocationForRegister( if (!have_unwindplan_regloc) { // m_full_unwind_plan_sp being NULL means that we haven't tried to find a // full UnwindPlan yet - if (!m_full_unwind_plan_sp) + 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, @@ -1202,6 +1306,16 @@ RegisterContextUnwind::SavedLocationForRegister( m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row.get() && 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()); + } RegisterNumber return_address_reg; // If we're fetching the saved pc and this UnwindPlan defines a @@ -1521,7 +1635,7 @@ RegisterContextUnwind::SavedLocationForRegister( DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); dwarfexpr.SetRegisterKind(unwindplan_registerkind); Value cfa_val = Scalar(m_cfa); - cfa_val.SetValueType(Value::eValueTypeLoadAddress); + cfa_val.SetValueType(Value::ValueType::LoadAddress); Value result; Status error; if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, result, @@ -1616,6 +1730,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { RegisterValue reg_value; if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { old_caller_pc_value = reg_value.GetAsUInt64(); + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + old_caller_pc_value = abi->FixCodeAddress(old_caller_pc_value); + } } } } @@ -1671,6 +1789,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { new_caller_pc_value = reg_value.GetAsUInt64(); + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + new_caller_pc_value = abi->FixCodeAddress(new_caller_pc_value); + } } } } @@ -1824,6 +1946,8 @@ bool RegisterContextUnwind::ReadFrameAddress( reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); if (error.Success()) { address = reg_value.GetAsUInt64(); + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + address = abi_sp->FixCodeAddress(address); UnwindLogMsg( "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, @@ -1878,6 +2002,8 @@ bool RegisterContextUnwind::ReadFrameAddress( if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, &error)) { address = result.GetScalar().ULongLong(); + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + address = abi_sp->FixCodeAddress(address); UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64, address); @@ -2007,6 +2133,12 @@ bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind, } if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { value = reg_value.GetAsUInt64(); + if (pc_register) { + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + value = abi->FixCodeAddress(value); + } + } return true; } return false; @@ -2048,7 +2180,19 @@ bool RegisterContextUnwind::ReadRegister(const RegisterInfo *reg_info, lldb_regnum, regloc, m_frame_number - 1, is_pc_regnum)) return false; - return ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); + bool result = ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); + if (result) { + if (is_pc_regnum && value.GetType() == RegisterValue::eTypeUInt64) { + addr_t reg_value = value.GetAsUInt64(LLDB_INVALID_ADDRESS); + if (reg_value != LLDB_INVALID_ADDRESS) { + if(ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + value = abi->FixCodeAddress(reg_value); + } + } + } + } + return result; } bool RegisterContextUnwind::WriteRegister(const RegisterInfo *reg_info, |
