[Lldb-commits] [lldb] r160337 - in /lldb/trunk: include/lldb/Symbol/UnwindPlan.h source/API/SBCommandInterpreter.cpp source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h source/Symbol/UnwindPlan.cpp
Jason Molenda
jmolenda at apple.com
Mon Jul 16 18:57:24 PDT 2012
Author: jmolenda
Date: Mon Jul 16 20:57:24 2012
New Revision: 160337
URL: http://llvm.org/viewvc/llvm-project?rev=160337&view=rev
Log:
Change UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly so it records
the state of the unwind instructions once the prologue has finished. If it hits an
early return epilogue in the middle of the function, re-instate the prologue after that
epilogue has completed so that we can still unwind for cases where the flow of control
goes past that early-return. <rdar://problem/11775059>
Move the UnwindPlan operator== definition into the .cpp file, expand the definition a bit.
Add some casts to a SBCommandInterpreter::HandleCompletion() log statement so it builds without
warning on 64- and 32-bit systems.
Modified:
lldb/trunk/include/lldb/Symbol/UnwindPlan.h
lldb/trunk/source/API/SBCommandInterpreter.cpp
lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
lldb/trunk/source/Symbol/UnwindPlan.cpp
Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Mon Jul 16 20:57:24 2012
@@ -250,6 +250,9 @@
}
bool
+ operator == (const Row &rhs) const;
+
+ bool
GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
void
@@ -337,34 +340,12 @@
void
Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
- bool
- operator == (const Row &rhs) const
- {
- if (m_offset == rhs.m_offset &&
- m_cfa_reg_num != rhs.m_cfa_reg_num &&
- m_cfa_offset != rhs.m_cfa_offset)
- return m_register_locations == rhs.m_register_locations;
- return false;
- }
-
- bool
- operator != (const Row &rhs) const
- {
- if (m_offset != rhs.m_offset ||
- m_cfa_reg_num != rhs.m_cfa_reg_num ||
- m_cfa_offset != rhs.m_cfa_offset)
- return true;
-
- return m_register_locations != rhs.m_register_locations;
- }
-
protected:
typedef std::map<uint32_t, RegisterLocation> collection;
lldb::addr_t m_offset; // Offset into the function for this row
uint32_t m_cfa_reg_num; // The Call Frame Address register number
int32_t m_cfa_offset; // The offset from the CFA for this row
collection m_register_locations;
-
}; // class Row
public:
Modified: lldb/trunk/source/API/SBCommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBCommandInterpreter.cpp?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/API/SBCommandInterpreter.cpp (original)
+++ lldb/trunk/source/API/SBCommandInterpreter.cpp Mon Jul 16 20:57:24 2012
@@ -139,8 +139,8 @@
return 0;
if (log)
- log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %ld, last char at: %ld, match_start_point: %d, max_return_elements: %d)",
- m_opaque_ptr, current_line, cursor - current_line, last_char - current_line, match_start_point, max_return_elements);
+ log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %lld, last char at: %lld, match_start_point: %d, max_return_elements: %d)",
+ m_opaque_ptr, current_line, (uint64_t) (cursor - current_line), (uint64_t) (last_char - current_line), match_start_point, max_return_elements);
if (m_opaque_ptr)
{
Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp Mon Jul 16 20:57:24 2012
@@ -90,22 +90,38 @@
const InstructionList &inst_list = disasm_sp->GetInstructionList ();
const size_t num_instructions = inst_list.GetSize();
- UnwindPlan::RowSP prologue_completed_row;
-
if (num_instructions > 0)
{
Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
const addr_t base_addr = inst->GetAddress().GetFileAddress();
- // Initialize the current row with the one row that was created
- // from the CreateFunctionEntryUnwind call above...
+
+ // Make a copy of the current instruction Row and save it in m_curr_row
+ // so we can add updates as we process the instructions.
UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
UnwindPlan::Row *newrow = new UnwindPlan::Row;
if (last_row.get())
*newrow = *last_row.get();
m_curr_row.reset(newrow);
+ // Once we've seen the initial prologue instructions complete, save a
+ // copy of the CFI at that point into prologue_completed_row for possible
+ // use later.
+ int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update
+ bool prologue_complete = false; // true if we have finished prologue setup
+ bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
+ UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+
+ // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
+ // quick reference during instruction parsing.
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+ RegisterInfo pc_reg_info;
+ if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
+ pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
+
+
for (size_t idx=0; idx<num_instructions; ++idx)
{
+ m_curr_row_modified = false;
inst = inst_list.GetInstructionAtIndex (idx).get();
if (inst)
{
@@ -121,18 +137,70 @@
exe_ctx.GetTargetPtr());
m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
-
- if (unwind_plan.GetLastRow() != m_curr_row)
+
+ // Were there any changes to the CFI while evaluating this instruction?
+ if (m_curr_row_modified)
{
- // Be sure to not edit the offset unless our row has changed
- // so that the "!=" call above doesn't trigger every time
+ reinstate_prologue_next_instruction = false;
m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
// Append the new row
unwind_plan.AppendRow (m_curr_row);
+ // Allocate a new Row for m_curr_row, copy the current state into it
UnwindPlan::Row *newrow = new UnwindPlan::Row;
*newrow = *m_curr_row.get();
m_curr_row.reset(newrow);
+
+ instructions_since_last_prologue_insn = 0;
+
+ // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
+ // after this instruction completes executing.
+ // If there are any instructions past this, there must have been flow control over this
+ // epilogue so we'll reinstate the original prologue setup instructions.
+ UnwindPlan::Row::RegisterLocation pc_regloc;
+ if (prologue_complete
+ && pc_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
+ && pc_regloc.IsSame())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
+ reinstate_prologue_next_instruction = true;
+ }
+ }
+ else
+ {
+ // If the previous instruction was a return-to-caller (epilogue), and we're still executing
+ // instructions in this function, there must be a code path that jumps over that epilogue.
+ // Reinstate the frame setup from the prologue.
+ if (reinstate_prologue_next_instruction)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *prologue_completed_row.get();
+ m_curr_row.reset(newrow);
+ m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+ unwind_plan.AppendRow(m_curr_row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ m_curr_row.reset(newrow);
+
+ reinstate_prologue_next_instruction = false;
+ }
+
+ // If we haven't seen any prologue instructions for a while (4 instructions in a row),
+ // the function prologue has probably completed. Save a copy of that Row.
+ if (prologue_complete == false && instructions_since_last_prologue_insn++ > 3)
+ {
+ prologue_complete = true;
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ prologue_completed_row.reset(newrow);
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- prologue has been set up, saving a copy.");
+ }
}
}
}
@@ -373,6 +441,7 @@
m_pushed_regs[reg_num] = addr;
const int32_t offset = addr - m_initial_sp;
m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
+ m_curr_row_modified = true;
if (is_return_address_reg)
{
// This push was pushing the return address register,
@@ -382,7 +451,10 @@
{
uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
if (pc_reg_num != LLDB_INVALID_REGNUM)
+ {
m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
+ m_curr_row_modified = true;
+ }
}
}
}
@@ -489,6 +561,7 @@
// m_curr_row.SetRegisterLocationToUndefined (reg_num,
// can_replace_only_if_unspecified,
// can_replace_only_if_unspecified);
+// m_curr_row_modified = true;
// }
// }
break;
@@ -499,6 +572,7 @@
if (reg_num != LLDB_INVALID_REGNUM)
{
m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+ m_curr_row_modified = true;
}
}
break;
@@ -512,6 +586,7 @@
assert (cfa_reg_num != LLDB_INVALID_REGNUM);
m_curr_row->SetCFARegister(cfa_reg_num);
m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
}
break;
@@ -521,6 +596,7 @@
if (!m_fp_is_cfa)
{
m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
}
break;
}
Modified: lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h Mon Jul 16 20:57:24 2012
@@ -134,6 +134,7 @@
m_thread_ptr (NULL),
m_unwind_plan_ptr (NULL),
m_curr_row (),
+ m_curr_row_modified (false),
m_cfa_reg_info (),
m_fp_is_cfa (false),
m_register_values (),
@@ -162,6 +163,7 @@
lldb_private::Thread* m_thread_ptr;
lldb_private::UnwindPlan* m_unwind_plan_ptr;
lldb_private::UnwindPlan::RowSP m_curr_row;
+ bool m_curr_row_modified;
typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
uint64_t m_initial_sp;
lldb_private::RegisterInfo m_cfa_reg_info;
Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=160337&r1=160336&r2=160337&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Mon Jul 16 20:57:24 2012
@@ -295,6 +295,23 @@
m_cfa_reg_num = reg_num;
}
+bool
+UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
+{
+ if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
+ return false;
+ if (m_register_locations.size() != rhs.m_register_locations.size())
+ return false;
+ for (collection::const_iterator idx = m_register_locations.begin(); idx != m_register_locations.end(); ++idx)
+ {
+ collection::const_iterator lhs_pos = m_register_locations.find(idx->first);
+ collection::const_iterator rhs_pos = rhs.m_register_locations.find(idx->first);
+ if (lhs_pos->second != rhs_pos->second)
+ return false;
+ }
+ return true;
+}
+
void
UnwindPlan::AppendRow (UnwindPlan::RowSP row)
{
More information about the lldb-commits
mailing list