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>
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,
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;
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);
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);
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);
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);
UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetUnspecifiedRegistersAreUndefined(true);
row->GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 8);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, -8, true);
UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetUnspecifiedRegistersAreUndefined(true);
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetUnspecifiedRegistersAreUndefined(true);
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
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);
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);
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);
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);
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);
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);
m_cfa_value.SetUnspecified();
m_afa_value.SetUnspecified();
m_offset = 0;
+ m_unspecified_registers_are_undefined = false;
m_register_locations.clear();
}
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,
register_location = pos->second;
return true;
}
+ if (m_unspecified_registers_are_undefined) {
+ register_location.SetUndefined();
+ return true;
+ }
return false;
}
}
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) {
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");
}
}
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 {
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());
}
}
*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 {
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()) {
(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));
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,
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