aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Target/RegisterContextUnwind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Target/RegisterContextUnwind.cpp')
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp192
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 &regloc) {
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,