summaryrefslogtreecommitdiff
path: root/source/Plugins/UnwindAssembly
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2015-07-03 16:57:06 +0000
committerEd Maste <emaste@FreeBSD.org>2015-07-03 16:57:06 +0000
commit5e95aa85bb660d45e9905ef1d7180b2678280660 (patch)
tree3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source/Plugins/UnwindAssembly
parent12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff)
Diffstat (limited to 'source/Plugins/UnwindAssembly')
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp226
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h11
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp143
3 files changed, 183 insertions, 197 deletions
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index 0eb0f83d5f35..8f5d92697501 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -96,7 +96,13 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
if (num_instructions > 0)
{
Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
- const addr_t base_addr = inst->GetAddress().GetFileAddress();
+ const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
+
+ // Map for storing the unwind plan row and the value of the registers at a given offset.
+ // When we see a forward branch we add a new entry to this map with the actual unwind plan
+ // row and register context for the target address of the branch as the current data have
+ // to be valid for the target address of the branch too if we are in the same function.
+ std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> saved_unwind_states;
// 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.
@@ -106,18 +112,8 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
*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 reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
-
- bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate
-
- bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
-
- UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+ // Add the initial state to the save list with offset 0.
+ saved_unwind_states.insert({0, {last_row, m_register_values}});
// cache the pc register number (in whatever register numbering this UnwindPlan uses) for
// quick reference during instruction parsing.
@@ -140,16 +136,33 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
for (size_t idx=0; idx<num_instructions; ++idx)
{
m_curr_row_modified = false;
- m_curr_insn_restored_a_register = false;
+ m_forward_branch_offset = 0;
+
inst = inst_list.GetInstructionAtIndex (idx).get();
if (inst)
{
+ lldb::addr_t current_offset = inst->GetAddress().GetFileAddress() - base_addr;
+ auto it = saved_unwind_states.upper_bound(current_offset);
+ assert(it != saved_unwind_states.begin() && "Unwind row for the function entry missing");
+ --it; // Move it to the row corresponding to the current offset
+
+ // If the offset of m_curr_row don't match with the offset we see in saved_unwind_states
+ // then we have to update m_curr_row and m_register_values based on the saved values. It
+ // is happenning after we processed an epilogue and a return to caller instruction.
+ if (it->second.first->GetOffset() != m_curr_row->GetOffset())
+ {
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *it->second.first;
+ m_curr_row.reset(newrow);
+ m_register_values = it->second.second;;
+ }
+
if (log && log->GetVerbose ())
{
StreamString strm;
lldb_private::FormatEntity::Entry format;
FormatEntity::Parse("${frame.pc}: ", format);
- inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, &format);
+ inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL, NULL, NULL, &format, 0);
log->PutCString (strm.GetData());
}
@@ -159,111 +172,30 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
+ // If the current instruction is a branch forward then save the current CFI information
+ // for the offset where we are branching.
+ if (m_forward_branch_offset != 0 && range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + m_forward_branch_offset))
+ {
+ auto newrow = std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
+ newrow->SetOffset(current_offset + m_forward_branch_offset);
+ saved_unwind_states.insert({current_offset + m_forward_branch_offset, {newrow, m_register_values}});
+ unwind_plan.InsertRow(newrow);
+ }
+
// Were there any changes to the CFI while evaluating this instruction?
if (m_curr_row_modified)
{
- 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);
-
- // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
- // Set instructions_since_last_prologue_insn to a very high number so we don't append
- // any of these epilogue instructions to our prologue_complete row.
- if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
- instructions_since_last_prologue_insn = 0;
- else
- instructions_since_last_prologue_insn = 99;
-
- UnwindPlan::Row::RegisterLocation pc_regloc;
- UnwindPlan::Row::RegisterLocation ra_regloc;
-
- // While parsing the instructions of this function, if we've ever
- // seen the return address register (aka lr on arm) in a non-IsSame() state,
- // it has been saved on the stack. If it's ever back to IsSame(), we've
- // executed an epilogue.
- if (ra_reg_num != LLDB_INVALID_REGNUM
- && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
- && !ra_regloc.IsSame())
+ // Save the modified row if we don't already have a CFI row in the currennt address
+ if (saved_unwind_states.count(current_offset + inst->GetOpcode().GetByteSize()) == 0)
{
- return_address_register_has_been_saved = true;
- }
+ m_curr_row->SetOffset (current_offset + inst->GetOpcode().GetByteSize());
+ unwind_plan.InsertRow (m_curr_row);
+ saved_unwind_states.insert({current_offset + inst->GetOpcode().GetByteSize(), {m_curr_row, m_register_values}});
- // 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.
- if (prologue_completed_row.get()
- && 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 (prologue_completed_row.get()
- && return_address_register_has_been_saved
- && ra_reg_num != LLDB_INVALID_REGNUM
- && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
- && ra_regloc.IsSame())
- {
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
- last_instruction_restored_return_addr_reg = 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.
- // Also detect the case where we epilogue & branch imm to another function (tail-call opt)
- // instead of a normal pop lr-into-pc exit.
- // Reinstate the frame setup from the prologue.
- if (reinstate_prologue_next_instruction
- || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
- {
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+ // Allocate a new Row for m_curr_row, copy the current state into it
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;
- last_instruction_restored_return_addr_reg = false;
- m_curr_insn_is_branch_immediate = false;
- }
-
- // clear both of these if either one wasn't set
- if (last_instruction_restored_return_addr_reg)
- {
- last_instruction_restored_return_addr_reg = false;
- }
- if (m_curr_insn_is_branch_immediate)
- {
- m_curr_insn_is_branch_immediate = false;
- }
-
- // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
- // in a row.
- if (instructions_since_last_prologue_insn++ < 8)
- {
- UnwindPlan::Row *newrow = new UnwindPlan::Row;
- *newrow = *m_curr_row.get();
- prologue_completed_row.reset(newrow);
- if (log && log->GetVerbose())
- log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
}
}
}
@@ -460,8 +392,7 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
context.Dump(strm, instruction);
log->PutCString (strm.GetData());
}
-
- const bool can_replace = true;
+
const bool cant_replace = false;
switch (context.type)
@@ -491,20 +422,17 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
case EmulateInstruction::eContextPushRegisterOnStack:
{
uint32_t reg_num = LLDB_INVALID_REGNUM;
- bool is_return_address_reg = false;
- const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
+ uint32_t generic_regnum = LLDB_INVALID_REGNUM;
if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
{
+ const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
- if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
- is_return_address_reg = true;
+ generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric];
}
else
- {
assert (!"unhandled case, add code to handle this!");
- }
-
- if (reg_num != LLDB_INVALID_REGNUM)
+
+ if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
{
if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
{
@@ -512,21 +440,6 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
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,
- // so this is also how we will unwind the PC...
- RegisterInfo pc_reg_info;
- if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
- {
- 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;
- }
- }
- }
}
}
}
@@ -598,7 +511,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
log->PutCString(strm.GetData());
}
- const bool must_replace = true;
SetRegisterValue (*reg_info, reg_value);
switch (context.type)
@@ -610,8 +522,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextRegisterPlusOffset:
case EmulateInstruction::eContextAdjustPC:
case EmulateInstruction::eContextRegisterStore:
- case EmulateInstruction::eContextRegisterLoad:
- case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextSupervisorCall:
case EmulateInstruction::eContextTableBranchReadMemory:
case EmulateInstruction::eContextWriteRegisterRandomBits:
@@ -620,6 +530,7 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextAdvancePC:
case EmulateInstruction::eContextReturnFromException:
case EmulateInstruction::eContextPushRegisterOnStack:
+ case EmulateInstruction::eContextRegisterLoad:
// {
// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
// if (reg_num != LLDB_INVALID_REGNUM)
@@ -634,11 +545,28 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
// }
break;
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
case EmulateInstruction::eContextRelativeBranchImmediate:
{
-
+ if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
+ context.info.ISAAndImmediate.unsigned_data32 > 0)
+ {
+ m_forward_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
+ context.info.ISAAndImmediateSigned.signed_data32 > 0)
+ {
+ m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeImmediate &&
+ context.info.unsigned_immediate > 0)
+ {
+ m_forward_branch_offset = context.info.unsigned_immediate;
+ }
+ else if (context.info_type == EmulateInstruction::eInfoTypeImmediateSigned &&
+ context.info.signed_immediate > 0)
{
- m_curr_insn_is_branch_immediate = true;
+ m_forward_branch_offset = context.info.signed_immediate;
}
}
break;
@@ -646,11 +574,11 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
case EmulateInstruction::eContextPopRegisterOffStack:
{
const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
- if (reg_num != LLDB_INVALID_REGNUM)
+ const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_num != LLDB_INVALID_REGNUM && generic_regnum != LLDB_REGNUM_GENERIC_SP)
{
- m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+ m_curr_row->SetRegisterLocationToSame (reg_num, /*must_replace*/ false);
m_curr_row_modified = true;
- m_curr_insn_restored_a_register = true;
}
}
break;
@@ -662,8 +590,8 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
m_cfa_reg_info = *reg_info;
const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
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->GetCFAValue().SetIsRegisterPlusOffset(cfa_reg_num, m_initial_sp -
+ reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
@@ -673,7 +601,9 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
// subsequent adjustments to the stack pointer.
if (!m_fp_is_cfa)
{
- m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
+ m_curr_row->GetCFAValue().GetRegisterNumber(),
+ m_initial_sp - reg_value.GetAsUInt64());
m_curr_row_modified = true;
}
break;
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
index 758c3ce2e28b..bf6d017370cc 100644
--- a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -141,8 +141,7 @@ private:
m_register_values (),
m_pushed_regs(),
m_curr_row_modified (false),
- m_curr_insn_is_branch_immediate (false),
- m_curr_insn_restored_a_register (false)
+ m_forward_branch_offset (0)
{
if (m_inst_emulator_ap.get())
{
@@ -178,13 +177,11 @@ private:
// While processing the instruction stream, we need to communicate some state change
// information up to the higher level loop that makes decisions about how to push
// the unwind instructions for the UnwindPlan we're constructing.
-
+
// The instruction we're processing updated the UnwindPlan::Row contents
bool m_curr_row_modified;
- // The instruction we're examining is a branch immediate instruction
- bool m_curr_insn_is_branch_immediate;
- // The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
- bool m_curr_insn_restored_a_register;
+ // The instruction is branching forward with the given offset. 0 value means no branching.
+ uint32_t m_forward_branch_offset;
};
#endif // liblldb_UnwindAssemblyInstEmulation_h_
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index dbf37d8a4de0..7e4c696a36d4 100644
--- a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -10,6 +10,7 @@
#include "UnwindAssembly-x86.h"
#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/TargetSelect.h"
#include "lldb/Core/Address.h"
@@ -17,6 +18,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -146,6 +148,7 @@ private:
bool mov_rsp_rbp_pattern_p ();
bool sub_rsp_pattern_p (int& amount);
bool add_rsp_pattern_p (int& amount);
+ bool lea_rsp_pattern_p (int& amount);
bool push_reg_p (int& regno);
bool pop_reg_p (int& regno);
bool push_imm_pattern_p ();
@@ -408,6 +411,36 @@ AssemblyParse_x86::add_rsp_pattern_p (int& amount)
return false;
}
+// lea esp, [esp - 0x28]
+// lea esp, [esp + 0x28]
+bool
+AssemblyParse_x86::lea_rsp_pattern_p (int& amount)
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+
+ // Check opcode
+ if (*p != 0x8d)
+ return false;
+
+ // 8 bit displacement
+ if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24)
+ {
+ amount = (int8_t) *(p + 3);
+ return true;
+ }
+
+ // 32 bit displacement
+ if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24)
+ {
+ amount = (int32_t) extract_4 (p + 3);
+ return true;
+ }
+
+ return false;
+}
+
// pushq %rbx
// pushl %ebx
bool
@@ -615,7 +648,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
m_cur_insn = m_func_bounds.GetBaseAddress ();
- int current_func_text_offset = 0;
+ addr_t current_func_text_offset = 0;
int current_sp_bytes_offset_from_cfa = 0;
UnwindPlan::Row::RegisterLocation initial_regloc;
Error error;
@@ -630,8 +663,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// At the start of the function, find the CFA by adding wordsize to the SP register
row->SetOffset (current_func_text_offset);
- row->SetCFARegister (m_lldb_sp_regnum);
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);
// caller's stack pointer value before the call insn is the CFA address
initial_regloc.SetIsCFAPlusOffset (0);
@@ -691,9 +723,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
if (push_rbp_pattern_p ())
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
UnwindPlan::Row::RegisterLocation regloc;
- regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+ regloc.SetAtCFAPlusOffset (-row->GetCFAValue().GetOffset());
row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
saved_registers[m_machine_fp_regnum] = true;
row_updated = true;
@@ -701,7 +733,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (mov_rsp_rbp_pattern_p ())
{
- row->SetCFARegister (m_lldb_fp_regnum);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_fp_regnum, row->GetCFAValue().GetOffset());
row_updated = true;
}
@@ -717,9 +749,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
current_sp_bytes_offset_from_cfa += m_wordsize;
// the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
// we need to add a new row of instructions.
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
// record where non-volatile (callee-saved, spilled) registers are saved on the stack
@@ -746,9 +778,10 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
saved_registers[machine_regno] = false;
row->RemoveRegisterInfo (lldb_regno);
- if (machine_regno == m_machine_fp_regnum)
+ if (machine_regno == (int)m_machine_fp_regnum)
{
- row->SetCFARegister (m_lldb_sp_regnum);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum,
+ row->GetCFAValue().GetOffset());
}
in_epilogue = true;
@@ -757,9 +790,10 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
// we need to add a new row of instructions.
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum,
+ current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -777,7 +811,7 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
// In the Row, we want to express this as the offset from the CFA. If the frame base
// is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
// want to say that the value is stored at the CFA address - 96.
- regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
+ regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAValue().GetOffset()));
row->SetRegisterInfo (lldb_regno, regloc);
@@ -787,9 +821,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (sub_rsp_pattern_p (stack_offset))
{
current_sp_bytes_offset_from_cfa += stack_offset;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -797,14 +831,26 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (add_rsp_pattern_p (stack_offset))
{
current_sp_bytes_offset_from_cfa -= stack_offset;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
in_epilogue = true;
}
+ else if (lea_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa -= stack_offset;
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
+ {
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ if (stack_offset > 0)
+ in_epilogue = true;
+ }
+
else if (ret_pattern_p () && prologue_completed_row.get())
{
// Reinstate the saved prologue setup for any instructions
@@ -833,9 +879,9 @@ AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
else if (call_next_insn_pattern_p ())
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- if (row->GetCFARegister() == m_lldb_sp_regnum)
+ if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum)
{
- row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row->GetCFAValue().SetOffset (current_sp_bytes_offset_from_cfa);
row_updated = true;
}
}
@@ -904,8 +950,8 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
return false;
uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
- first_row->GetCFARegister());
- if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
+ first_row->GetCFAValue().GetRegisterNumber());
+ if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAValue().GetOffset() != m_wordsize)
return false;
UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset (-1);
@@ -985,7 +1031,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// Inspect the instruction to check if we need a new row for it.
cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
- row->GetCFARegister());
+ row->GetCFAValue().GetRegisterNumber());
if (cfa_reg == m_lldb_sp_regnum)
{
// CFA register is sp.
@@ -996,7 +1042,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (call_next_insn_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1009,7 +1055,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (push_reg_p (regno))
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1024,7 +1070,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
// So we ignore this case.
row->SetOffset (offset);
- row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (-m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1036,7 +1082,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (push_imm_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
@@ -1048,7 +1094,7 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (add_rsp_pattern_p (amount))
{
row->SetOffset (offset);
- row->SetCFAOffset (-amount + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (-amount);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1058,13 +1104,26 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
if (sub_rsp_pattern_p (amount))
{
row->SetOffset (offset);
- row->SetCFAOffset (amount + row->GetCFAOffset());
+ row->GetCFAValue().IncOffset (amount);
+
+ UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+ unwind_plan.InsertRow (new_row);
+ unwind_plan_updated = true;
+ continue;
+ }
+
+ // lea %rsp, [%rsp + $offset]
+ if (lea_rsp_pattern_p (amount))
+ {
+ row->SetOffset (offset);
+ row->GetCFAValue().IncOffset (-amount);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
unwind_plan_updated = true;
continue;
}
+
if (ret_pattern_p ())
{
reinstate_unwind_state = true;
@@ -1085,8 +1144,8 @@ AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, Unwin
&& ret_pattern_p ())
{
row->SetOffset (offset);
- row->SetCFARegister (first_row->GetCFARegister());
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (
+ first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
unwind_plan.InsertRow (new_row);
@@ -1169,8 +1228,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
// Zero instructions into the function
- row->SetCFARegister (m_lldb_sp_regnum);
- row->SetCFAOffset (m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_sp_regnum, m_wordsize);
row->SetOffset (0);
unwind_plan.AppendRow (row);
UnwindPlan::Row *newrow = new UnwindPlan::Row;
@@ -1178,7 +1236,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row.reset(newrow);
// push %rbp has executed - stack moved, rbp now saved
- row->SetCFAOffset (2 * m_wordsize);
+ row->GetCFAValue().IncOffset (m_wordsize);
fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
row->SetOffset (1);
@@ -1189,8 +1247,7 @@ AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_
row.reset(newrow);
// mov %rsp, %rbp has executed
- row->SetCFARegister (m_lldb_fp_regnum);
- row->SetCFAOffset (2 * m_wordsize);
+ row->GetCFAValue().SetIsRegisterPlusOffset (m_lldb_fp_regnum, 2 * m_wordsize);
row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
unwind_plan.AppendRow (row);
@@ -1233,7 +1290,8 @@ AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
}
if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
- || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
+ || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset)
+ || (lea_rsp_pattern_p (offset) && offset < 0))
{
m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
continue;
@@ -1300,9 +1358,10 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// If there is no description of the prologue, don't try to augment this eh_frame
// unwinder code, fall back to assembly parsing instead.
- if (first_row->GetCFAType() != UnwindPlan::Row::CFAType::CFAIsRegisterPlusOffset
- || RegisterNumber (thread, unwind_plan.GetRegisterKind(), first_row->GetCFARegister()) != sp_regnum
- || first_row->GetCFAOffset() != wordsize)
+ if (first_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::isRegisterPlusOffset
+ || RegisterNumber (thread, unwind_plan.GetRegisterKind(),
+ first_row->GetCFAValue().GetRegisterNumber()) != sp_regnum
+ || first_row->GetCFAValue().GetOffset() != wordsize)
{
return false;
}
@@ -1326,9 +1385,9 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
// We're checking that both of them have an unwind rule like "CFA=esp+4" or CFA+rsp+8".
- if (first_row->GetCFAType() == last_row->GetCFAType()
- && first_row->GetCFARegister() == last_row->GetCFARegister()
- && first_row->GetCFAOffset() == last_row->GetCFAOffset())
+ if (first_row->GetCFAValue().GetValueType() == last_row->GetCFAValue().GetValueType()
+ && first_row->GetCFAValue().GetRegisterNumber() == last_row->GetCFAValue().GetRegisterNumber()
+ && first_row->GetCFAValue().GetOffset() == last_row->GetCFAValue().GetOffset())
{
// Get the register locations for eip/rip from the first & last rows.
// Are they both CFA plus an offset? Is it the same offset?