Add a new Row setting to mark all un-declared regs as Undefined
authorJason Molenda <jason@molenda.com>
Thu, 18 Feb 2021 07:44:03 +0000 (23:44 -0800)
committerJason Molenda <jason@molenda.com>
Thu, 18 Feb 2021 07:52:28 +0000 (23:52 -0800)
Add a new state for UnwindPlan::Row which indicates that any
register not listed is not defined, and should not be found in
stack frames newer than this one and passed up the stack.  Mostly
intended for use with architectural default unwind plans that are
used for jitted stack frames, where we have no unwind information
or start address.  lldb has no way to tell if registers were
spilled in the jitted frame & overwritten, so passing register
values up the stack is not safe to show the user.

Architectural default unwind plans are also used as a fast unwind
plan on x86_64 in particular, and are used as the fallback unwind
plans when lldb thinks it may be able to work around a problem
which causes the unwinder to stop walking the stack early.

For fast unwind plans, when we don't find a register location in
the arch default unwind plan, we fall back to computing & using
the full unwind plan. One small part of this patch is to know that
a register marked as Undefined in the fast unwind plan is a special
case, and we should continue on to the full unwind plan to find what
the real unwind rule is for this register.

Differential Revision: https://reviews.llvm.org/D96829
<rdar://problem/70398009>

16 files changed:
lldb/include/lldb/Symbol/UnwindPlan.h
lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp
lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp
lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp
lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp
lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp
lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp
lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp
lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp
lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
lldb/source/Symbol/UnwindPlan.cpp
lldb/source/Target/RegisterContextUnwind.cpp

index 40814da3de4aebecf784bdc0b54352a6b4a59134..06c76ca80796b7341f1b5731adbcc491c77fa7da 100644 (file)
@@ -360,6 +360,25 @@ public:
 
     bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
 
+    // When this UnspecifiedRegistersAreUndefined mode is
+    // set, any register that is not specified by this Row will
+    // be described as Undefined.
+    // This will prevent the unwinder from iterating down the
+    // stack looking for a spill location, or a live register value
+    // at frame 0.
+    // It would be used for an UnwindPlan row where we can't track
+    // spilled registers -- for instance a jitted stack frame where
+    // we have no unwind information or start address -- and registers
+    // MAY have been spilled and overwritten, so providing the
+    // spilled/live value from a newer frame may show an incorrect value.
+    void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
+      m_unspecified_registers_are_undefined = unspec_is_undef;
+    }
+
+    bool GetUnspecifiedRegistersAreUndefined() {
+      return m_unspecified_registers_are_undefined;
+    }
+
     void Clear();
 
     void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
@@ -372,6 +391,7 @@ public:
     FAValue m_cfa_value;
     FAValue m_afa_value;
     collection m_register_locations;
+    bool m_unspecified_registers_are_undefined;
   }; // class Row
 
   typedef std::shared_ptr<Row> RowSP;
index ea0c09a1596ab306f030eca8ada3b587caf32a0d..861310e3ea0c1bdcdfc6079645ad36c835a05d55 100644 (file)
@@ -384,6 +384,7 @@ bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 5918e2ccb5fa4592f67404434e9193819312f8ed..0f74c1f5c73b1751babc43abd4eefe2cd1c55d5a 100644 (file)
@@ -356,6 +356,7 @@ bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 06c4590b77409ce1f17b3d35df10f9c15fd6d275..e429f3ee0cc44981e25e25eb8766d4df170ca5a2 100644 (file)
@@ -1824,6 +1824,7 @@ bool ABIMacOSX_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 26b3152bed16463ea0e0061b06ab7bd76b9f162a..8a9be3fb67c7a14e4bbe21a315f96ad2d15dafd5 100644 (file)
@@ -1940,6 +1940,7 @@ bool ABISysV_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 47aaefd3b2281146a6abcd9e6420b0c6b197bd48..6794f7d072100925fc77511d32cc448660a62e34 100644 (file)
@@ -1225,6 +1225,7 @@ bool ABISysV_hexagon::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   UnwindPlan::RowSP row(new UnwindPlan::Row);
 
+  row->SetUnspecifiedRegistersAreUndefined(true);
   row->GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 8);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, -8, true);
index d66e0926ad99eaa90a5d24ac9c7b582dfd45bf41..538ec06c3b0dc1a590407f2c2e48b215c59bcd16 100644 (file)
@@ -985,6 +985,7 @@ bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   UnwindPlan::RowSP row(new UnwindPlan::Row);
 
+  row->SetUnspecifiedRegistersAreUndefined(true);
   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
 
   row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
index 5e72af076f66ba53aea6269d48693be0df47d71e..7220508c75ffe16a892d49312900ac71f9775d01 100644 (file)
@@ -1156,6 +1156,7 @@ bool ABISysV_mips64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   UnwindPlan::RowSP row(new UnwindPlan::Row);
 
+  row->SetUnspecifiedRegistersAreUndefined(true);
   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
 
   row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
index d5605642d6230b2187260c374da0a0748d06259c..cfecf35da1ed64ec269b88be611e95919351327a 100644 (file)
@@ -900,6 +900,7 @@ bool ABISysV_ppc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
   UnwindPlan::RowSP row(new UnwindPlan::Row);
 
   const int32_t ptr_size = 4;
+  row->SetUnspecifiedRegistersAreUndefined(true);
   row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);
 
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true);
index 603143190dc5d06b4216eeba3017870fc073b058..7cc9482e7c5d516803fb5e6f539d9d386149cefc 100644 (file)
@@ -1003,6 +1003,7 @@ bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   UnwindPlan::RowSP row(new UnwindPlan::Row);
   const int32_t ptr_size = 8;
+  row->SetUnspecifiedRegistersAreUndefined(true);
   row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num);
 
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true);
index 89112deb2c4a594648cfa2cace1344f269a1395c..461e4af599d371789a5322abfcbf5ee4076ce15b 100644 (file)
@@ -389,6 +389,7 @@ bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 38d7364aaa51a49dad2e0214e04ec85b02a29cdf..7d2f0a64d679aaa49c2069ba413ba618d6668247 100644 (file)
@@ -652,6 +652,7 @@ bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
 
   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index 8d5614756a6af44b7e7c32270a0d0acea488a6f5..196b45b3b6da4490cdf2cff467ec788ca719e9de 100644 (file)
@@ -887,6 +887,7 @@ bool ABISysV_x86_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
   const int32_t ptr_size = 8;
   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index da241458840f30fb4d49d855c6a1b2f3f646d819..6c473c652c5f855b630263f789ae411ad71004d9 100644 (file)
@@ -767,6 +767,7 @@ bool ABIWindows_x86_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
   const int32_t ptr_size = 8;
   row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size);
   row->SetOffset(0);
+  row->SetUnspecifiedRegistersAreUndefined(true);
 
   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
index d24cabed14ce956465cd53a657f41cf55adacb13..d74c78f084afa876f7d9efb6ff8cc7ad3afd2182 100644 (file)
@@ -217,6 +217,7 @@ void UnwindPlan::Row::Clear() {
   m_cfa_value.SetUnspecified();
   m_afa_value.SetUnspecified();
   m_offset = 0;
+  m_unspecified_registers_are_undefined = false;
   m_register_locations.clear();
 }
 
@@ -242,11 +243,11 @@ void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
     idx->second.Dump(s, unwind_plan, this, thread, verbose);
     s.PutChar(' ');
   }
-  s.EOL();
 }
 
 UnwindPlan::Row::Row()
-    : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations() {}
+    : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations(),
+      m_unspecified_registers_are_undefined(false) {}
 
 bool UnwindPlan::Row::GetRegisterInfo(
     uint32_t reg_num,
@@ -256,6 +257,10 @@ bool UnwindPlan::Row::GetRegisterInfo(
     register_location = pos->second;
     return true;
   }
+  if (m_unspecified_registers_are_undefined) {
+    register_location.SetUndefined();
+    return true;
+  }
   return false;
 }
 
@@ -348,10 +353,11 @@ bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
 }
 
 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
-  return m_offset == rhs.m_offset &&
-      m_cfa_value == rhs.m_cfa_value &&
-      m_afa_value == rhs.m_afa_value &&
-      m_register_locations == rhs.m_register_locations;
+  return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
+         m_afa_value == rhs.m_afa_value &&
+         m_unspecified_registers_are_undefined ==
+             rhs.m_unspecified_registers_are_undefined &&
+         m_register_locations == rhs.m_register_locations;
 }
 
 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
@@ -552,6 +558,7 @@ void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {
   for (pos = begin; pos != end; ++pos) {
     s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos));
     (*pos)->Dump(s, this, thread, base_addr);
+    s.Printf("\n");
   }
 }
 
index 991a3c821923624cc2b85ef6fe0d67e3d51a7ba5..a677121d8279f1039e1be18dad04585af0935aae 100644 (file)
@@ -542,6 +542,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 +558,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());
       }
     }
@@ -662,13 +666,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 {
@@ -1147,6 +1144,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 +1177,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 +1198,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 +1212,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