diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
commit | 5e95aa85bb660d45e9905ef1d7180b2678280660 (patch) | |
tree | 3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source/Plugins/UnwindAssembly | |
parent | 12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff) |
Diffstat (limited to 'source/Plugins/UnwindAssembly')
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? |