virtual bool isA(const void *ClassID) const { return ClassID == &ID; }
static char ID;
+ /// A language runtime may be able to provide a special UnwindPlan for
+ /// the frame represented by the register contents \a regctx when that
+ /// frame is not following the normal ABI conventions.
+ /// Instead of using the normal UnwindPlan for the function, we will use
+ /// this special UnwindPlan for this one backtrace.
+ /// One example of this would be a language that has asynchronous functions,
+ /// functions that may not be currently-executing, while waiting on other
+ /// asynchronous calls they made, but are part of a logical backtrace that
+ /// we want to show the developer because that's how they think of the
+ /// program flow.
+ static lldb::UnwindPlanSP
+ GetRuntimeUnwindPlan(lldb_private::Thread &thread,
+ lldb_private::RegisterContext *regctx);
+
protected:
+ // The static GetRuntimeUnwindPlan method above is only implemented in the
+ // base class; subclasses may override this protected member if they can
+ // provide one of these UnwindPlans.
+ virtual lldb::UnwindPlanSP
+ GetRuntimeUnwindPlan(lldb::ProcessSP process_sp,
+ lldb_private::RegisterContext *regctx) {
+ return lldb::UnwindPlanSP();
+ }
+
LanguageRuntime(Process *process);
};
#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"
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);
+ 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");
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();
}
}
- // 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.)