This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd82ecb0ac722: LanguageRuntime can provide an UnwindPlan for 
special occasions (authored by jasonmolenda).

Changed prior to commit:
  https://reviews.llvm.org/D96839?vs=324191&id=324894#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D96839/new/

https://reviews.llvm.org/D96839

Files:
  lldb/include/lldb/Target/LanguageRuntime.h
  lldb/source/Target/LanguageRuntime.cpp
  lldb/source/Target/RegisterContextUnwind.cpp

Index: lldb/source/Target/RegisterContextUnwind.cpp
===================================================================
--- lldb/source/Target/RegisterContextUnwind.cpp
+++ 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"
@@ -283,6 +284,22 @@
     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");
@@ -290,8 +307,6 @@
     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();
@@ -522,12 +537,43 @@
     }
   }
 
-  // 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.)
Index: lldb/source/Target/LanguageRuntime.cpp
===================================================================
--- lldb/source/Target/LanguageRuntime.cpp
+++ lldb/source/Target/LanguageRuntime.cpp
@@ -259,6 +259,21 @@
   return exc_breakpt_sp;
 }
 
+UnwindPlanSP LanguageRuntime::GetRuntimeUnwindPlan(Thread &thread,
+                                                   RegisterContext *regctx) {
+  ProcessSP process_sp = thread.GetProcess();
+  if (!process_sp.get())
+    return UnwindPlanSP();
+  for (const lldb::LanguageType lang_type : Language::GetSupportedLanguages()) {
+    if (LanguageRuntime *runtime = process_sp->GetLanguageRuntime(lang_type)) {
+      UnwindPlanSP plan_sp = runtime->GetRuntimeUnwindPlan(process_sp, regctx);
+      if (plan_sp.get())
+        return plan_sp;
+    }
+  }
+  return UnwindPlanSP();
+}
+
 void LanguageRuntime::InitializeCommands(CommandObject *parent) {
   if (!parent)
     return;
Index: lldb/include/lldb/Target/LanguageRuntime.h
===================================================================
--- lldb/include/lldb/Target/LanguageRuntime.h
+++ lldb/include/lldb/Target/LanguageRuntime.h
@@ -173,7 +173,30 @@
   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);
 };
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to