15ffd83dbSDimitry Andric //===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "UnwindAssemblyInstEmulation.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "lldb/Core/Address.h" 120b57cec5SDimitry Andric #include "lldb/Core/Disassembler.h" 130b57cec5SDimitry Andric #include "lldb/Core/DumpDataExtractor.h" 140b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h" 150b57cec5SDimitry Andric #include "lldb/Core/FormatEntity.h" 160b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 170b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 180b57cec5SDimitry Andric #include "lldb/Target/Process.h" 190b57cec5SDimitry Andric #include "lldb/Target/Target.h" 200b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 210b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h" 220b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 230b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h" 2481ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 250b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 260b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 270b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace lldb; 300b57cec5SDimitry Andric using namespace lldb_private; 310b57cec5SDimitry Andric 325ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation) 335ffd83dbSDimitry Andric 340b57cec5SDimitry Andric // UnwindAssemblyInstEmulation method definitions 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( 370b57cec5SDimitry Andric AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) { 380b57cec5SDimitry Andric std::vector<uint8_t> function_text(range.GetByteSize()); 390b57cec5SDimitry Andric ProcessSP process_sp(thread.GetProcess()); 400b57cec5SDimitry Andric if (process_sp) { 410b57cec5SDimitry Andric Status error; 42fe6060f1SDimitry Andric const bool force_live_memory = true; 430b57cec5SDimitry Andric if (process_sp->GetTarget().ReadMemory( 44fe6060f1SDimitry Andric range.GetBaseAddress(), function_text.data(), range.GetByteSize(), 45fe6060f1SDimitry Andric error, force_live_memory) != range.GetByteSize()) { 460b57cec5SDimitry Andric return false; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric return GetNonCallSiteUnwindPlanFromAssembly( 500b57cec5SDimitry Andric range, function_text.data(), function_text.size(), unwind_plan); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( 540b57cec5SDimitry Andric AddressRange &range, uint8_t *opcode_data, size_t opcode_size, 550b57cec5SDimitry Andric UnwindPlan &unwind_plan) { 560b57cec5SDimitry Andric if (opcode_data == nullptr || opcode_size == 0) 570b57cec5SDimitry Andric return false; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() && 600b57cec5SDimitry Andric m_inst_emulator_up.get()) { 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // The instruction emulation subclass setup the unwind plan for the first 630b57cec5SDimitry Andric // instruction. 640b57cec5SDimitry Andric m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric // CreateFunctionEntryUnwind should have created the first row. If it 670b57cec5SDimitry Andric // doesn't, then we are done. 680b57cec5SDimitry Andric if (unwind_plan.GetRowCount() == 0) 690b57cec5SDimitry Andric return false; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric const bool prefer_file_cache = true; 720b57cec5SDimitry Andric DisassemblerSP disasm_sp(Disassembler::DisassembleBytes( 730b57cec5SDimitry Andric m_arch, nullptr, nullptr, range.GetBaseAddress(), opcode_data, 740b57cec5SDimitry Andric opcode_size, 99999, prefer_file_cache)); 750b57cec5SDimitry Andric 7681ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric if (disasm_sp) { 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric m_range_ptr = ⦥ 810b57cec5SDimitry Andric m_unwind_plan_ptr = &unwind_plan; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric const uint32_t addr_byte_size = m_arch.GetAddressByteSize(); 840b57cec5SDimitry Andric const bool show_address = true; 850b57cec5SDimitry Andric const bool show_bytes = true; 86*0fca6ea1SDimitry Andric const bool show_control_flow_kind = false; 87bdd1243dSDimitry Andric m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo( 88bdd1243dSDimitry Andric unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister()); 890b57cec5SDimitry Andric m_fp_is_cfa = false; 900b57cec5SDimitry Andric m_register_values.clear(); 910b57cec5SDimitry Andric m_pushed_regs.clear(); 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Initialize the CFA with a known value. In the 32 bit case it will be 940b57cec5SDimitry Andric // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the 950b57cec5SDimitry Andric // address byte size to be safe for any future address sizes 960b57cec5SDimitry Andric m_initial_sp = (1ull << ((addr_byte_size * 8) - 1)); 970b57cec5SDimitry Andric RegisterValue cfa_reg_value; 980b57cec5SDimitry Andric cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size); 990b57cec5SDimitry Andric SetRegisterValue(m_cfa_reg_info, cfa_reg_value); 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric const InstructionList &inst_list = disasm_sp->GetInstructionList(); 1020b57cec5SDimitry Andric const size_t num_instructions = inst_list.GetSize(); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric if (num_instructions > 0) { 1050b57cec5SDimitry Andric Instruction *inst = inst_list.GetInstructionAtIndex(0).get(); 1060b57cec5SDimitry Andric const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress(); 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // Map for storing the unwind plan row and the value of the registers 1090b57cec5SDimitry Andric // at a given offset. When we see a forward branch we add a new entry 1100b57cec5SDimitry Andric // to this map with the actual unwind plan row and register context for 1110b57cec5SDimitry Andric // the target address of the branch as the current data have to be 1120b57cec5SDimitry Andric // valid for the target address of the branch too if we are in the same 1130b57cec5SDimitry Andric // function. 1140b57cec5SDimitry Andric std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> 1150b57cec5SDimitry Andric saved_unwind_states; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // Make a copy of the current instruction Row and save it in m_curr_row 1180b57cec5SDimitry Andric // so we can add updates as we process the instructions. 1190b57cec5SDimitry Andric UnwindPlan::RowSP last_row = unwind_plan.GetLastRow(); 1200b57cec5SDimitry Andric UnwindPlan::Row *newrow = new UnwindPlan::Row; 1210b57cec5SDimitry Andric if (last_row.get()) 1220b57cec5SDimitry Andric *newrow = *last_row.get(); 1230b57cec5SDimitry Andric m_curr_row.reset(newrow); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // Add the initial state to the save list with offset 0. 1260b57cec5SDimitry Andric saved_unwind_states.insert({0, {last_row, m_register_values}}); 1270b57cec5SDimitry Andric 1285ffd83dbSDimitry Andric // cache the stack pointer register number (in whatever register 1290b57cec5SDimitry Andric // numbering this UnwindPlan uses) for quick reference during 1300b57cec5SDimitry Andric // instruction parsing. 131bdd1243dSDimitry Andric RegisterInfo sp_reg_info = *m_inst_emulator_up->GetRegisterInfo( 132bdd1243dSDimitry Andric eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric // The architecture dependent condition code of the last processed 1350b57cec5SDimitry Andric // instruction. 1360b57cec5SDimitry Andric EmulateInstruction::InstructionCondition last_condition = 1370b57cec5SDimitry Andric EmulateInstruction::UnconditionalCondition; 1380b57cec5SDimitry Andric lldb::addr_t condition_block_start_offset = 0; 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric for (size_t idx = 0; idx < num_instructions; ++idx) { 1410b57cec5SDimitry Andric m_curr_row_modified = false; 1420b57cec5SDimitry Andric m_forward_branch_offset = 0; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric inst = inst_list.GetInstructionAtIndex(idx).get(); 1450b57cec5SDimitry Andric if (inst) { 1460b57cec5SDimitry Andric lldb::addr_t current_offset = 1470b57cec5SDimitry Andric inst->GetAddress().GetFileAddress() - base_addr; 1480b57cec5SDimitry Andric auto it = saved_unwind_states.upper_bound(current_offset); 1490b57cec5SDimitry Andric assert(it != saved_unwind_states.begin() && 1500b57cec5SDimitry Andric "Unwind row for the function entry missing"); 1510b57cec5SDimitry Andric --it; // Move it to the row corresponding to the current offset 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // If the offset of m_curr_row don't match with the offset we see 1540b57cec5SDimitry Andric // in saved_unwind_states then we have to update m_curr_row and 1550b57cec5SDimitry Andric // m_register_values based on the saved values. It is happening 1560b57cec5SDimitry Andric // after we processed an epilogue and a return to caller 1570b57cec5SDimitry Andric // instruction. 1580b57cec5SDimitry Andric if (it->second.first->GetOffset() != m_curr_row->GetOffset()) { 1590b57cec5SDimitry Andric UnwindPlan::Row *newrow = new UnwindPlan::Row; 1600b57cec5SDimitry Andric *newrow = *it->second.first; 1610b57cec5SDimitry Andric m_curr_row.reset(newrow); 1620b57cec5SDimitry Andric m_register_values = it->second.second; 1635ffd83dbSDimitry Andric // re-set the CFA register ivars to match the 1645ffd83dbSDimitry Andric // new m_curr_row. 1655ffd83dbSDimitry Andric if (sp_reg_info.name && 1665ffd83dbSDimitry Andric m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { 1675ffd83dbSDimitry Andric uint32_t row_cfa_regnum = 1685ffd83dbSDimitry Andric m_curr_row->GetCFAValue().GetRegisterNumber(); 1695ffd83dbSDimitry Andric lldb::RegisterKind row_kind = 1705ffd83dbSDimitry Andric m_unwind_plan_ptr->GetRegisterKind(); 1715ffd83dbSDimitry Andric // set m_cfa_reg_info to the row's CFA reg. 172bdd1243dSDimitry Andric m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo( 173bdd1243dSDimitry Andric row_kind, row_cfa_regnum); 1745ffd83dbSDimitry Andric // set m_fp_is_cfa. 1755ffd83dbSDimitry Andric if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) 1765ffd83dbSDimitry Andric m_fp_is_cfa = false; 1775ffd83dbSDimitry Andric else 1785ffd83dbSDimitry Andric m_fp_is_cfa = true; 1795ffd83dbSDimitry Andric } 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric m_inst_emulator_up->SetInstruction(inst->GetOpcode(), 1830b57cec5SDimitry Andric inst->GetAddress(), nullptr); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric if (last_condition != 1860b57cec5SDimitry Andric m_inst_emulator_up->GetInstructionCondition()) { 1870b57cec5SDimitry Andric if (m_inst_emulator_up->GetInstructionCondition() != 1880b57cec5SDimitry Andric EmulateInstruction::UnconditionalCondition && 1890b57cec5SDimitry Andric saved_unwind_states.count(current_offset) == 0) { 1900b57cec5SDimitry Andric // If we don't have a saved row for the current offset then 1910b57cec5SDimitry Andric // save our current state because we will have to restore it 1920b57cec5SDimitry Andric // after the conditional block. 1930b57cec5SDimitry Andric auto new_row = 1940b57cec5SDimitry Andric std::make_shared<UnwindPlan::Row>(*m_curr_row.get()); 1950b57cec5SDimitry Andric saved_unwind_states.insert( 1960b57cec5SDimitry Andric {current_offset, {new_row, m_register_values}}); 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric // If the last instruction was conditional with a different 2000b57cec5SDimitry Andric // condition then the then current condition then restore the 2010b57cec5SDimitry Andric // condition. 2020b57cec5SDimitry Andric if (last_condition != 2030b57cec5SDimitry Andric EmulateInstruction::UnconditionalCondition) { 2040b57cec5SDimitry Andric const auto &saved_state = 2050b57cec5SDimitry Andric saved_unwind_states.at(condition_block_start_offset); 2060b57cec5SDimitry Andric m_curr_row = 2070b57cec5SDimitry Andric std::make_shared<UnwindPlan::Row>(*saved_state.first); 2080b57cec5SDimitry Andric m_curr_row->SetOffset(current_offset); 2090b57cec5SDimitry Andric m_register_values = saved_state.second; 2105ffd83dbSDimitry Andric // re-set the CFA register ivars to match the 2115ffd83dbSDimitry Andric // new m_curr_row. 2125ffd83dbSDimitry Andric if (sp_reg_info.name && 2135ffd83dbSDimitry Andric m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { 2145ffd83dbSDimitry Andric uint32_t row_cfa_regnum = 2155ffd83dbSDimitry Andric m_curr_row->GetCFAValue().GetRegisterNumber(); 2165ffd83dbSDimitry Andric lldb::RegisterKind row_kind = 2175ffd83dbSDimitry Andric m_unwind_plan_ptr->GetRegisterKind(); 2185ffd83dbSDimitry Andric // set m_cfa_reg_info to the row's CFA reg. 219bdd1243dSDimitry Andric m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo( 220bdd1243dSDimitry Andric row_kind, row_cfa_regnum); 2215ffd83dbSDimitry Andric // set m_fp_is_cfa. 2225ffd83dbSDimitry Andric if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) 2235ffd83dbSDimitry Andric m_fp_is_cfa = false; 2245ffd83dbSDimitry Andric else 2255ffd83dbSDimitry Andric m_fp_is_cfa = true; 2265ffd83dbSDimitry Andric } 2270b57cec5SDimitry Andric bool replace_existing = 2280b57cec5SDimitry Andric true; // The last instruction might already 2290b57cec5SDimitry Andric // created a row for this offset and 2300b57cec5SDimitry Andric // we want to overwrite it. 2310b57cec5SDimitry Andric unwind_plan.InsertRow( 2320b57cec5SDimitry Andric std::make_shared<UnwindPlan::Row>(*m_curr_row), 2330b57cec5SDimitry Andric replace_existing); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // We are starting a new conditional block at the actual offset 2370b57cec5SDimitry Andric condition_block_start_offset = current_offset; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric if (log && log->GetVerbose()) { 2410b57cec5SDimitry Andric StreamString strm; 2420b57cec5SDimitry Andric lldb_private::FormatEntity::Entry format; 2430b57cec5SDimitry Andric FormatEntity::Parse("${frame.pc}: ", format); 2440b57cec5SDimitry Andric inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address, 245753f127fSDimitry Andric show_bytes, show_control_flow_kind, nullptr, nullptr, 246753f127fSDimitry Andric nullptr, &format, 0); 2470b57cec5SDimitry Andric log->PutString(strm.GetString()); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric last_condition = m_inst_emulator_up->GetInstructionCondition(); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric m_inst_emulator_up->EvaluateInstruction( 2530b57cec5SDimitry Andric eEmulateInstructionOptionIgnoreConditions); 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric // If the current instruction is a branch forward then save the 2560b57cec5SDimitry Andric // current CFI information for the offset where we are branching. 2570b57cec5SDimitry Andric if (m_forward_branch_offset != 0 && 2580b57cec5SDimitry Andric range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + 2590b57cec5SDimitry Andric m_forward_branch_offset)) { 2600b57cec5SDimitry Andric auto newrow = 2610b57cec5SDimitry Andric std::make_shared<UnwindPlan::Row>(*m_curr_row.get()); 2620b57cec5SDimitry Andric newrow->SetOffset(current_offset + m_forward_branch_offset); 2630b57cec5SDimitry Andric saved_unwind_states.insert( 2640b57cec5SDimitry Andric {current_offset + m_forward_branch_offset, 2650b57cec5SDimitry Andric {newrow, m_register_values}}); 2660b57cec5SDimitry Andric unwind_plan.InsertRow(newrow); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric // Were there any changes to the CFI while evaluating this 2700b57cec5SDimitry Andric // instruction? 2710b57cec5SDimitry Andric if (m_curr_row_modified) { 2720b57cec5SDimitry Andric // Save the modified row if we don't already have a CFI row in 2730b57cec5SDimitry Andric // the current address 2740b57cec5SDimitry Andric if (saved_unwind_states.count( 2750b57cec5SDimitry Andric current_offset + inst->GetOpcode().GetByteSize()) == 0) { 2760b57cec5SDimitry Andric m_curr_row->SetOffset(current_offset + 2770b57cec5SDimitry Andric inst->GetOpcode().GetByteSize()); 2780b57cec5SDimitry Andric unwind_plan.InsertRow(m_curr_row); 2790b57cec5SDimitry Andric saved_unwind_states.insert( 2800b57cec5SDimitry Andric {current_offset + inst->GetOpcode().GetByteSize(), 2810b57cec5SDimitry Andric {m_curr_row, m_register_values}}); 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric // Allocate a new Row for m_curr_row, copy the current state 2840b57cec5SDimitry Andric // into it 2850b57cec5SDimitry Andric UnwindPlan::Row *newrow = new UnwindPlan::Row; 2860b57cec5SDimitry Andric *newrow = *m_curr_row.get(); 2870b57cec5SDimitry Andric m_curr_row.reset(newrow); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric if (log && log->GetVerbose()) { 2960b57cec5SDimitry Andric StreamString strm; 2970b57cec5SDimitry Andric lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress(); 2980b57cec5SDimitry Andric strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", 2990b57cec5SDimitry Andric base_addr, base_addr + range.GetByteSize()); 3000b57cec5SDimitry Andric unwind_plan.Dump(strm, nullptr, base_addr); 3010b57cec5SDimitry Andric log->PutString(strm.GetString()); 3020b57cec5SDimitry Andric } 3030b57cec5SDimitry Andric return unwind_plan.GetRowCount() > 0; 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric return false; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite( 3090b57cec5SDimitry Andric AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) { 3100b57cec5SDimitry Andric return false; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func, 3140b57cec5SDimitry Andric Thread &thread, 3150b57cec5SDimitry Andric UnwindPlan &unwind_plan) { 3160b57cec5SDimitry Andric return false; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn( 3200b57cec5SDimitry Andric AddressRange &func, const ExecutionContext &exe_ctx, 3210b57cec5SDimitry Andric Address &first_non_prologue_insn) { 3220b57cec5SDimitry Andric return false; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric UnwindAssembly * 3260b57cec5SDimitry Andric UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) { 3270b57cec5SDimitry Andric std::unique_ptr<EmulateInstruction> inst_emulator_up( 3280b57cec5SDimitry Andric EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue, 3290b57cec5SDimitry Andric nullptr)); 3300b57cec5SDimitry Andric // Make sure that all prologue instructions are handled 3310b57cec5SDimitry Andric if (inst_emulator_up) 3320b57cec5SDimitry Andric return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release()); 3330b57cec5SDimitry Andric return nullptr; 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric void UnwindAssemblyInstEmulation::Initialize() { 3370b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 3380b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric void UnwindAssemblyInstEmulation::Terminate() { 3420b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric 345349cc55cSDimitry Andric llvm::StringRef UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() { 3460b57cec5SDimitry Andric return "Instruction emulation based unwind information."; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair( 3500b57cec5SDimitry Andric const RegisterInfo ®_info) { 3510b57cec5SDimitry Andric lldb::RegisterKind reg_kind; 3520b57cec5SDimitry Andric uint32_t reg_num; 3530b57cec5SDimitry Andric if (EmulateInstruction::GetBestRegisterKindAndNumber(®_info, reg_kind, 3540b57cec5SDimitry Andric reg_num)) 3550b57cec5SDimitry Andric return (uint64_t)reg_kind << 24 | reg_num; 3560b57cec5SDimitry Andric return 0ull; 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric void UnwindAssemblyInstEmulation::SetRegisterValue( 3600b57cec5SDimitry Andric const RegisterInfo ®_info, const RegisterValue ®_value) { 3610b57cec5SDimitry Andric m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value; 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo ®_info, 3650b57cec5SDimitry Andric RegisterValue ®_value) { 3660b57cec5SDimitry Andric const uint64_t reg_id = MakeRegisterKindValuePair(reg_info); 3670b57cec5SDimitry Andric RegisterValueMap::const_iterator pos = m_register_values.find(reg_id); 3680b57cec5SDimitry Andric if (pos != m_register_values.end()) { 3690b57cec5SDimitry Andric reg_value = pos->second; 3700b57cec5SDimitry Andric return true; // We had a real value that comes from an opcode that wrote 3710b57cec5SDimitry Andric // to it... 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric // We are making up a value that is recognizable... 3740b57cec5SDimitry Andric reg_value.SetUInt(reg_id, reg_info.byte_size); 3750b57cec5SDimitry Andric return false; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric size_t UnwindAssemblyInstEmulation::ReadMemory( 3790b57cec5SDimitry Andric EmulateInstruction *instruction, void *baton, 3800b57cec5SDimitry Andric const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, 3810b57cec5SDimitry Andric size_t dst_len) { 38281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric if (log && log->GetVerbose()) { 3850b57cec5SDimitry Andric StreamString strm; 3860b57cec5SDimitry Andric strm.Printf( 3870b57cec5SDimitry Andric "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64 3880b57cec5SDimitry Andric ", dst = %p, dst_len = %" PRIu64 ", context = ", 3890b57cec5SDimitry Andric addr, dst, (uint64_t)dst_len); 3900b57cec5SDimitry Andric context.Dump(strm, instruction); 3910b57cec5SDimitry Andric log->PutString(strm.GetString()); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric memset(dst, 0, dst_len); 3940b57cec5SDimitry Andric return dst_len; 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric size_t UnwindAssemblyInstEmulation::WriteMemory( 3980b57cec5SDimitry Andric EmulateInstruction *instruction, void *baton, 3990b57cec5SDimitry Andric const EmulateInstruction::Context &context, lldb::addr_t addr, 4000b57cec5SDimitry Andric const void *dst, size_t dst_len) { 4010b57cec5SDimitry Andric if (baton && dst && dst_len) 4020b57cec5SDimitry Andric return ((UnwindAssemblyInstEmulation *)baton) 4030b57cec5SDimitry Andric ->WriteMemory(instruction, context, addr, dst, dst_len); 4040b57cec5SDimitry Andric return 0; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric size_t UnwindAssemblyInstEmulation::WriteMemory( 4080b57cec5SDimitry Andric EmulateInstruction *instruction, const EmulateInstruction::Context &context, 4090b57cec5SDimitry Andric lldb::addr_t addr, const void *dst, size_t dst_len) { 4100b57cec5SDimitry Andric DataExtractor data(dst, dst_len, 4110b57cec5SDimitry Andric instruction->GetArchitecture().GetByteOrder(), 4120b57cec5SDimitry Andric instruction->GetArchitecture().GetAddressByteSize()); 4130b57cec5SDimitry Andric 41481ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric if (log && log->GetVerbose()) { 4170b57cec5SDimitry Andric StreamString strm; 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory ("); 4200b57cec5SDimitry Andric DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, 4210b57cec5SDimitry Andric addr, 0, 0); 4220b57cec5SDimitry Andric strm.PutCString(", context = "); 4230b57cec5SDimitry Andric context.Dump(strm, instruction); 4240b57cec5SDimitry Andric log->PutString(strm.GetString()); 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric switch (context.type) { 4280b57cec5SDimitry Andric default: 4290b57cec5SDimitry Andric case EmulateInstruction::eContextInvalid: 4300b57cec5SDimitry Andric case EmulateInstruction::eContextReadOpcode: 4310b57cec5SDimitry Andric case EmulateInstruction::eContextImmediate: 4320b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustBaseRegister: 4330b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterPlusOffset: 4340b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustPC: 4350b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterStore: 4360b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterLoad: 4370b57cec5SDimitry Andric case EmulateInstruction::eContextRelativeBranchImmediate: 4380b57cec5SDimitry Andric case EmulateInstruction::eContextAbsoluteBranchRegister: 4390b57cec5SDimitry Andric case EmulateInstruction::eContextSupervisorCall: 4400b57cec5SDimitry Andric case EmulateInstruction::eContextTableBranchReadMemory: 4410b57cec5SDimitry Andric case EmulateInstruction::eContextWriteRegisterRandomBits: 4420b57cec5SDimitry Andric case EmulateInstruction::eContextWriteMemoryRandomBits: 4430b57cec5SDimitry Andric case EmulateInstruction::eContextArithmetic: 4440b57cec5SDimitry Andric case EmulateInstruction::eContextAdvancePC: 4450b57cec5SDimitry Andric case EmulateInstruction::eContextReturnFromException: 4460b57cec5SDimitry Andric case EmulateInstruction::eContextPopRegisterOffStack: 4470b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustStackPointer: 4480b57cec5SDimitry Andric break; 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric case EmulateInstruction::eContextPushRegisterOnStack: { 4510b57cec5SDimitry Andric uint32_t reg_num = LLDB_INVALID_REGNUM; 4520b57cec5SDimitry Andric uint32_t generic_regnum = LLDB_INVALID_REGNUM; 453bdd1243dSDimitry Andric assert(context.GetInfoType() == 4540b57cec5SDimitry Andric EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset && 4550b57cec5SDimitry Andric "unhandled case, add code to handle this!"); 4560b57cec5SDimitry Andric const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind(); 4570b57cec5SDimitry Andric reg_num = context.info.RegisterToRegisterPlusOffset.data_reg 4580b57cec5SDimitry Andric .kinds[unwind_reg_kind]; 4590b57cec5SDimitry Andric generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg 4600b57cec5SDimitry Andric .kinds[eRegisterKindGeneric]; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric if (reg_num != LLDB_INVALID_REGNUM && 4630b57cec5SDimitry Andric generic_regnum != LLDB_REGNUM_GENERIC_SP) { 4640b57cec5SDimitry Andric if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) { 4650b57cec5SDimitry Andric m_pushed_regs[reg_num] = addr; 4660b57cec5SDimitry Andric const int32_t offset = addr - m_initial_sp; 4670b57cec5SDimitry Andric m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset, 468*0fca6ea1SDimitry Andric /*can_replace=*/true); 4690b57cec5SDimitry Andric m_curr_row_modified = true; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric } break; 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric return dst_len; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction, 4790b57cec5SDimitry Andric void *baton, 4800b57cec5SDimitry Andric const RegisterInfo *reg_info, 4810b57cec5SDimitry Andric RegisterValue ®_value) { 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric if (baton && reg_info) 4840b57cec5SDimitry Andric return ((UnwindAssemblyInstEmulation *)baton) 4850b57cec5SDimitry Andric ->ReadRegister(instruction, reg_info, reg_value); 4860b57cec5SDimitry Andric return false; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction, 4890b57cec5SDimitry Andric const RegisterInfo *reg_info, 4900b57cec5SDimitry Andric RegisterValue ®_value) { 4910b57cec5SDimitry Andric bool synthetic = GetRegisterValue(*reg_info, reg_value); 4920b57cec5SDimitry Andric 49381ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric if (log && log->GetVerbose()) { 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric StreamString strm; 4980b57cec5SDimitry Andric strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => " 4990b57cec5SDimitry Andric "synthetic_value = %i, value = ", 5000b57cec5SDimitry Andric reg_info->name, synthetic); 50106c3fb27SDimitry Andric DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault); 5020b57cec5SDimitry Andric log->PutString(strm.GetString()); 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric return true; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::WriteRegister( 5080b57cec5SDimitry Andric EmulateInstruction *instruction, void *baton, 5090b57cec5SDimitry Andric const EmulateInstruction::Context &context, const RegisterInfo *reg_info, 5100b57cec5SDimitry Andric const RegisterValue ®_value) { 5110b57cec5SDimitry Andric if (baton && reg_info) 5120b57cec5SDimitry Andric return ((UnwindAssemblyInstEmulation *)baton) 5130b57cec5SDimitry Andric ->WriteRegister(instruction, context, reg_info, reg_value); 5140b57cec5SDimitry Andric return false; 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric bool UnwindAssemblyInstEmulation::WriteRegister( 5170b57cec5SDimitry Andric EmulateInstruction *instruction, const EmulateInstruction::Context &context, 5180b57cec5SDimitry Andric const RegisterInfo *reg_info, const RegisterValue ®_value) { 51981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Unwind); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric if (log && log->GetVerbose()) { 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric StreamString strm; 5240b57cec5SDimitry Andric strm.Printf( 5250b57cec5SDimitry Andric "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", 5260b57cec5SDimitry Andric reg_info->name); 52706c3fb27SDimitry Andric DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault); 5280b57cec5SDimitry Andric strm.PutCString(", context = "); 5290b57cec5SDimitry Andric context.Dump(strm, instruction); 5300b57cec5SDimitry Andric log->PutString(strm.GetString()); 5310b57cec5SDimitry Andric } 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric SetRegisterValue(*reg_info, reg_value); 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric switch (context.type) { 5360b57cec5SDimitry Andric case EmulateInstruction::eContextInvalid: 5370b57cec5SDimitry Andric case EmulateInstruction::eContextReadOpcode: 5380b57cec5SDimitry Andric case EmulateInstruction::eContextImmediate: 5390b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustBaseRegister: 5400b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterPlusOffset: 5410b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustPC: 5420b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterStore: 5430b57cec5SDimitry Andric case EmulateInstruction::eContextSupervisorCall: 5440b57cec5SDimitry Andric case EmulateInstruction::eContextTableBranchReadMemory: 5450b57cec5SDimitry Andric case EmulateInstruction::eContextWriteRegisterRandomBits: 5460b57cec5SDimitry Andric case EmulateInstruction::eContextWriteMemoryRandomBits: 5470b57cec5SDimitry Andric case EmulateInstruction::eContextAdvancePC: 5480b57cec5SDimitry Andric case EmulateInstruction::eContextReturnFromException: 5490b57cec5SDimitry Andric case EmulateInstruction::eContextPushRegisterOnStack: 5500b57cec5SDimitry Andric case EmulateInstruction::eContextRegisterLoad: 5510b57cec5SDimitry Andric // { 5520b57cec5SDimitry Andric // const uint32_t reg_num = 5530b57cec5SDimitry Andric // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 5540b57cec5SDimitry Andric // if (reg_num != LLDB_INVALID_REGNUM) 5550b57cec5SDimitry Andric // { 5560b57cec5SDimitry Andric // const bool can_replace_only_if_unspecified = true; 5570b57cec5SDimitry Andric // 5580b57cec5SDimitry Andric // m_curr_row.SetRegisterLocationToUndefined (reg_num, 5590b57cec5SDimitry Andric // can_replace_only_if_unspecified, 5600b57cec5SDimitry Andric // can_replace_only_if_unspecified); 5610b57cec5SDimitry Andric // m_curr_row_modified = true; 5620b57cec5SDimitry Andric // } 5630b57cec5SDimitry Andric // } 5640b57cec5SDimitry Andric break; 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric case EmulateInstruction::eContextArithmetic: { 5670b57cec5SDimitry Andric // If we adjusted the current frame pointer by a constant then adjust the 5680b57cec5SDimitry Andric // CFA offset 5690b57cec5SDimitry Andric // with the same amount. 5700b57cec5SDimitry Andric lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind(); 5710b57cec5SDimitry Andric if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] && 572bdd1243dSDimitry Andric context.GetInfoType() == 573bdd1243dSDimitry Andric EmulateInstruction::eInfoTypeRegisterPlusOffset && 5740b57cec5SDimitry Andric context.info.RegisterPlusOffset.reg.kinds[kind] == 5750b57cec5SDimitry Andric m_cfa_reg_info.kinds[kind]) { 5760b57cec5SDimitry Andric const int64_t offset = context.info.RegisterPlusOffset.signed_offset; 5770b57cec5SDimitry Andric m_curr_row->GetCFAValue().IncOffset(-1 * offset); 5780b57cec5SDimitry Andric m_curr_row_modified = true; 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric } break; 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric case EmulateInstruction::eContextAbsoluteBranchRegister: 5830b57cec5SDimitry Andric case EmulateInstruction::eContextRelativeBranchImmediate: { 584bdd1243dSDimitry Andric if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate && 5850b57cec5SDimitry Andric context.info.ISAAndImmediate.unsigned_data32 > 0) { 5860b57cec5SDimitry Andric m_forward_branch_offset = 5870b57cec5SDimitry Andric context.info.ISAAndImmediateSigned.signed_data32; 588bdd1243dSDimitry Andric } else if (context.GetInfoType() == 5890b57cec5SDimitry Andric EmulateInstruction::eInfoTypeISAAndImmediateSigned && 5900b57cec5SDimitry Andric context.info.ISAAndImmediateSigned.signed_data32 > 0) { 5910b57cec5SDimitry Andric m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32; 592bdd1243dSDimitry Andric } else if (context.GetInfoType() == 593bdd1243dSDimitry Andric EmulateInstruction::eInfoTypeImmediate && 5940b57cec5SDimitry Andric context.info.unsigned_immediate > 0) { 5950b57cec5SDimitry Andric m_forward_branch_offset = context.info.unsigned_immediate; 596bdd1243dSDimitry Andric } else if (context.GetInfoType() == 5970b57cec5SDimitry Andric EmulateInstruction::eInfoTypeImmediateSigned && 5980b57cec5SDimitry Andric context.info.signed_immediate > 0) { 5990b57cec5SDimitry Andric m_forward_branch_offset = context.info.signed_immediate; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric } break; 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric case EmulateInstruction::eContextPopRegisterOffStack: { 6040b57cec5SDimitry Andric const uint32_t reg_num = 6050b57cec5SDimitry Andric reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 6060b57cec5SDimitry Andric const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric]; 6070b57cec5SDimitry Andric if (reg_num != LLDB_INVALID_REGNUM && 6080b57cec5SDimitry Andric generic_regnum != LLDB_REGNUM_GENERIC_SP) { 609bdd1243dSDimitry Andric switch (context.GetInfoType()) { 6100b57cec5SDimitry Andric case EmulateInstruction::eInfoTypeAddress: 6110b57cec5SDimitry Andric if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() && 6120b57cec5SDimitry Andric context.info.address == m_pushed_regs[reg_num]) { 6130b57cec5SDimitry Andric m_curr_row->SetRegisterLocationToSame(reg_num, 6140b57cec5SDimitry Andric false /*must_replace*/); 6150b57cec5SDimitry Andric m_curr_row_modified = true; 61681ad6265SDimitry Andric 61781ad6265SDimitry Andric // FP has been restored to its original value, we are back 61881ad6265SDimitry Andric // to using SP to calculate the CFA. 61981ad6265SDimitry Andric if (m_fp_is_cfa) { 62081ad6265SDimitry Andric m_fp_is_cfa = false; 62181ad6265SDimitry Andric lldb::RegisterKind sp_reg_kind = eRegisterKindGeneric; 62281ad6265SDimitry Andric uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP; 623bdd1243dSDimitry Andric RegisterInfo sp_reg_info = 624bdd1243dSDimitry Andric *m_inst_emulator_up->GetRegisterInfo(sp_reg_kind, sp_reg_num); 62581ad6265SDimitry Andric RegisterValue sp_reg_val; 62681ad6265SDimitry Andric if (GetRegisterValue(sp_reg_info, sp_reg_val)) { 62781ad6265SDimitry Andric m_cfa_reg_info = sp_reg_info; 62881ad6265SDimitry Andric const uint32_t cfa_reg_num = 62981ad6265SDimitry Andric sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()]; 63081ad6265SDimitry Andric assert(cfa_reg_num != LLDB_INVALID_REGNUM); 63181ad6265SDimitry Andric m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 63281ad6265SDimitry Andric cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64()); 63381ad6265SDimitry Andric } 63481ad6265SDimitry Andric } 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric break; 6370b57cec5SDimitry Andric case EmulateInstruction::eInfoTypeISA: 6380b57cec5SDimitry Andric assert( 6390b57cec5SDimitry Andric (generic_regnum == LLDB_REGNUM_GENERIC_PC || 6400b57cec5SDimitry Andric generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) && 6410b57cec5SDimitry Andric "eInfoTypeISA used for popping a register other the PC/FLAGS"); 6420b57cec5SDimitry Andric if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) { 6430b57cec5SDimitry Andric m_curr_row->SetRegisterLocationToSame(reg_num, 6440b57cec5SDimitry Andric false /*must_replace*/); 6450b57cec5SDimitry Andric m_curr_row_modified = true; 6460b57cec5SDimitry Andric } 6470b57cec5SDimitry Andric break; 6480b57cec5SDimitry Andric default: 6490b57cec5SDimitry Andric assert(false && "unhandled case, add code to handle this!"); 6500b57cec5SDimitry Andric break; 6510b57cec5SDimitry Andric } 6520b57cec5SDimitry Andric } 6530b57cec5SDimitry Andric } break; 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric case EmulateInstruction::eContextSetFramePointer: 6560b57cec5SDimitry Andric if (!m_fp_is_cfa) { 6570b57cec5SDimitry Andric m_fp_is_cfa = true; 6580b57cec5SDimitry Andric m_cfa_reg_info = *reg_info; 6590b57cec5SDimitry Andric const uint32_t cfa_reg_num = 6600b57cec5SDimitry Andric reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 6610b57cec5SDimitry Andric assert(cfa_reg_num != LLDB_INVALID_REGNUM); 6620b57cec5SDimitry Andric m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 6630b57cec5SDimitry Andric cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); 6640b57cec5SDimitry Andric m_curr_row_modified = true; 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric break; 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric case EmulateInstruction::eContextRestoreStackPointer: 6690b57cec5SDimitry Andric if (m_fp_is_cfa) { 6700b57cec5SDimitry Andric m_fp_is_cfa = false; 6710b57cec5SDimitry Andric m_cfa_reg_info = *reg_info; 6720b57cec5SDimitry Andric const uint32_t cfa_reg_num = 6730b57cec5SDimitry Andric reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()]; 6740b57cec5SDimitry Andric assert(cfa_reg_num != LLDB_INVALID_REGNUM); 6750b57cec5SDimitry Andric m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 6760b57cec5SDimitry Andric cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64()); 6770b57cec5SDimitry Andric m_curr_row_modified = true; 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric break; 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric case EmulateInstruction::eContextAdjustStackPointer: 6820b57cec5SDimitry Andric // If we have created a frame using the frame pointer, don't follow 6830b57cec5SDimitry Andric // subsequent adjustments to the stack pointer. 6840b57cec5SDimitry Andric if (!m_fp_is_cfa) { 6850b57cec5SDimitry Andric m_curr_row->GetCFAValue().SetIsRegisterPlusOffset( 6860b57cec5SDimitry Andric m_curr_row->GetCFAValue().GetRegisterNumber(), 6870b57cec5SDimitry Andric m_initial_sp - reg_value.GetAsUInt64()); 6880b57cec5SDimitry Andric m_curr_row_modified = true; 6890b57cec5SDimitry Andric } 6900b57cec5SDimitry Andric break; 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric return true; 6930b57cec5SDimitry Andric } 694