Path: blob/main/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
39644 views
//===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "UnwindAssemblyInstEmulation.h"910#include "lldb/Core/Address.h"11#include "lldb/Core/Disassembler.h"12#include "lldb/Core/DumpDataExtractor.h"13#include "lldb/Core/DumpRegisterValue.h"14#include "lldb/Core/FormatEntity.h"15#include "lldb/Core/PluginManager.h"16#include "lldb/Target/ExecutionContext.h"17#include "lldb/Target/Process.h"18#include "lldb/Target/Target.h"19#include "lldb/Target/Thread.h"20#include "lldb/Utility/ArchSpec.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/DataExtractor.h"23#include "lldb/Utility/LLDBLog.h"24#include "lldb/Utility/Log.h"25#include "lldb/Utility/Status.h"26#include "lldb/Utility/StreamString.h"2728using namespace lldb;29using namespace lldb_private;3031LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation)3233// UnwindAssemblyInstEmulation method definitions3435bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(36AddressRange &range, Thread &thread, UnwindPlan &unwind_plan) {37std::vector<uint8_t> function_text(range.GetByteSize());38ProcessSP process_sp(thread.GetProcess());39if (process_sp) {40Status error;41const bool force_live_memory = true;42if (process_sp->GetTarget().ReadMemory(43range.GetBaseAddress(), function_text.data(), range.GetByteSize(),44error, force_live_memory) != range.GetByteSize()) {45return false;46}47}48return GetNonCallSiteUnwindPlanFromAssembly(49range, function_text.data(), function_text.size(), unwind_plan);50}5152bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(53AddressRange &range, uint8_t *opcode_data, size_t opcode_size,54UnwindPlan &unwind_plan) {55if (opcode_data == nullptr || opcode_size == 0)56return false;5758if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&59m_inst_emulator_up.get()) {6061// The instruction emulation subclass setup the unwind plan for the first62// instruction.63m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan);6465// CreateFunctionEntryUnwind should have created the first row. If it66// doesn't, then we are done.67if (unwind_plan.GetRowCount() == 0)68return false;6970const bool prefer_file_cache = true;71DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(72m_arch, nullptr, nullptr, range.GetBaseAddress(), opcode_data,73opcode_size, 99999, prefer_file_cache));7475Log *log = GetLog(LLDBLog::Unwind);7677if (disasm_sp) {7879m_range_ptr = ⦥80m_unwind_plan_ptr = &unwind_plan;8182const uint32_t addr_byte_size = m_arch.GetAddressByteSize();83const bool show_address = true;84const bool show_bytes = true;85const bool show_control_flow_kind = false;86m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(87unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister());88m_fp_is_cfa = false;89m_register_values.clear();90m_pushed_regs.clear();9192// Initialize the CFA with a known value. In the 32 bit case it will be93// 0x80000000, and in the 64 bit case 0x8000000000000000. We use the94// address byte size to be safe for any future address sizes95m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));96RegisterValue cfa_reg_value;97cfa_reg_value.SetUInt(m_initial_sp, m_cfa_reg_info.byte_size);98SetRegisterValue(m_cfa_reg_info, cfa_reg_value);99100const InstructionList &inst_list = disasm_sp->GetInstructionList();101const size_t num_instructions = inst_list.GetSize();102103if (num_instructions > 0) {104Instruction *inst = inst_list.GetInstructionAtIndex(0).get();105const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();106107// Map for storing the unwind plan row and the value of the registers108// at a given offset. When we see a forward branch we add a new entry109// to this map with the actual unwind plan row and register context for110// the target address of the branch as the current data have to be111// valid for the target address of the branch too if we are in the same112// function.113std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>114saved_unwind_states;115116// Make a copy of the current instruction Row and save it in m_curr_row117// so we can add updates as we process the instructions.118UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();119UnwindPlan::Row *newrow = new UnwindPlan::Row;120if (last_row.get())121*newrow = *last_row.get();122m_curr_row.reset(newrow);123124// Add the initial state to the save list with offset 0.125saved_unwind_states.insert({0, {last_row, m_register_values}});126127// cache the stack pointer register number (in whatever register128// numbering this UnwindPlan uses) for quick reference during129// instruction parsing.130RegisterInfo sp_reg_info = *m_inst_emulator_up->GetRegisterInfo(131eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);132133// The architecture dependent condition code of the last processed134// instruction.135EmulateInstruction::InstructionCondition last_condition =136EmulateInstruction::UnconditionalCondition;137lldb::addr_t condition_block_start_offset = 0;138139for (size_t idx = 0; idx < num_instructions; ++idx) {140m_curr_row_modified = false;141m_forward_branch_offset = 0;142143inst = inst_list.GetInstructionAtIndex(idx).get();144if (inst) {145lldb::addr_t current_offset =146inst->GetAddress().GetFileAddress() - base_addr;147auto it = saved_unwind_states.upper_bound(current_offset);148assert(it != saved_unwind_states.begin() &&149"Unwind row for the function entry missing");150--it; // Move it to the row corresponding to the current offset151152// If the offset of m_curr_row don't match with the offset we see153// in saved_unwind_states then we have to update m_curr_row and154// m_register_values based on the saved values. It is happening155// after we processed an epilogue and a return to caller156// instruction.157if (it->second.first->GetOffset() != m_curr_row->GetOffset()) {158UnwindPlan::Row *newrow = new UnwindPlan::Row;159*newrow = *it->second.first;160m_curr_row.reset(newrow);161m_register_values = it->second.second;162// re-set the CFA register ivars to match the163// new m_curr_row.164if (sp_reg_info.name &&165m_curr_row->GetCFAValue().IsRegisterPlusOffset()) {166uint32_t row_cfa_regnum =167m_curr_row->GetCFAValue().GetRegisterNumber();168lldb::RegisterKind row_kind =169m_unwind_plan_ptr->GetRegisterKind();170// set m_cfa_reg_info to the row's CFA reg.171m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(172row_kind, row_cfa_regnum);173// set m_fp_is_cfa.174if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)175m_fp_is_cfa = false;176else177m_fp_is_cfa = true;178}179}180181m_inst_emulator_up->SetInstruction(inst->GetOpcode(),182inst->GetAddress(), nullptr);183184if (last_condition !=185m_inst_emulator_up->GetInstructionCondition()) {186if (m_inst_emulator_up->GetInstructionCondition() !=187EmulateInstruction::UnconditionalCondition &&188saved_unwind_states.count(current_offset) == 0) {189// If we don't have a saved row for the current offset then190// save our current state because we will have to restore it191// after the conditional block.192auto new_row =193std::make_shared<UnwindPlan::Row>(*m_curr_row.get());194saved_unwind_states.insert(195{current_offset, {new_row, m_register_values}});196}197198// If the last instruction was conditional with a different199// condition then the then current condition then restore the200// condition.201if (last_condition !=202EmulateInstruction::UnconditionalCondition) {203const auto &saved_state =204saved_unwind_states.at(condition_block_start_offset);205m_curr_row =206std::make_shared<UnwindPlan::Row>(*saved_state.first);207m_curr_row->SetOffset(current_offset);208m_register_values = saved_state.second;209// re-set the CFA register ivars to match the210// new m_curr_row.211if (sp_reg_info.name &&212m_curr_row->GetCFAValue().IsRegisterPlusOffset()) {213uint32_t row_cfa_regnum =214m_curr_row->GetCFAValue().GetRegisterNumber();215lldb::RegisterKind row_kind =216m_unwind_plan_ptr->GetRegisterKind();217// set m_cfa_reg_info to the row's CFA reg.218m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo(219row_kind, row_cfa_regnum);220// set m_fp_is_cfa.221if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)222m_fp_is_cfa = false;223else224m_fp_is_cfa = true;225}226bool replace_existing =227true; // The last instruction might already228// created a row for this offset and229// we want to overwrite it.230unwind_plan.InsertRow(231std::make_shared<UnwindPlan::Row>(*m_curr_row),232replace_existing);233}234235// We are starting a new conditional block at the actual offset236condition_block_start_offset = current_offset;237}238239if (log && log->GetVerbose()) {240StreamString strm;241lldb_private::FormatEntity::Entry format;242FormatEntity::Parse("${frame.pc}: ", format);243inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,244show_bytes, show_control_flow_kind, nullptr, nullptr,245nullptr, &format, 0);246log->PutString(strm.GetString());247}248249last_condition = m_inst_emulator_up->GetInstructionCondition();250251m_inst_emulator_up->EvaluateInstruction(252eEmulateInstructionOptionIgnoreConditions);253254// If the current instruction is a branch forward then save the255// current CFI information for the offset where we are branching.256if (m_forward_branch_offset != 0 &&257range.ContainsFileAddress(inst->GetAddress().GetFileAddress() +258m_forward_branch_offset)) {259auto newrow =260std::make_shared<UnwindPlan::Row>(*m_curr_row.get());261newrow->SetOffset(current_offset + m_forward_branch_offset);262saved_unwind_states.insert(263{current_offset + m_forward_branch_offset,264{newrow, m_register_values}});265unwind_plan.InsertRow(newrow);266}267268// Were there any changes to the CFI while evaluating this269// instruction?270if (m_curr_row_modified) {271// Save the modified row if we don't already have a CFI row in272// the current address273if (saved_unwind_states.count(274current_offset + inst->GetOpcode().GetByteSize()) == 0) {275m_curr_row->SetOffset(current_offset +276inst->GetOpcode().GetByteSize());277unwind_plan.InsertRow(m_curr_row);278saved_unwind_states.insert(279{current_offset + inst->GetOpcode().GetByteSize(),280{m_curr_row, m_register_values}});281282// Allocate a new Row for m_curr_row, copy the current state283// into it284UnwindPlan::Row *newrow = new UnwindPlan::Row;285*newrow = *m_curr_row.get();286m_curr_row.reset(newrow);287}288}289}290}291}292}293294if (log && log->GetVerbose()) {295StreamString strm;296lldb::addr_t base_addr = range.GetBaseAddress().GetFileAddress();297strm.Printf("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):",298base_addr, base_addr + range.GetByteSize());299unwind_plan.Dump(strm, nullptr, base_addr);300log->PutString(strm.GetString());301}302return unwind_plan.GetRowCount() > 0;303}304return false;305}306307bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(308AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {309return false;310}311312bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func,313Thread &thread,314UnwindPlan &unwind_plan) {315return false;316}317318bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(319AddressRange &func, const ExecutionContext &exe_ctx,320Address &first_non_prologue_insn) {321return false;322}323324UnwindAssembly *325UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) {326std::unique_ptr<EmulateInstruction> inst_emulator_up(327EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue,328nullptr));329// Make sure that all prologue instructions are handled330if (inst_emulator_up)331return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release());332return nullptr;333}334335void UnwindAssemblyInstEmulation::Initialize() {336PluginManager::RegisterPlugin(GetPluginNameStatic(),337GetPluginDescriptionStatic(), CreateInstance);338}339340void UnwindAssemblyInstEmulation::Terminate() {341PluginManager::UnregisterPlugin(CreateInstance);342}343344llvm::StringRef UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {345return "Instruction emulation based unwind information.";346}347348uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(349const RegisterInfo ®_info) {350lldb::RegisterKind reg_kind;351uint32_t reg_num;352if (EmulateInstruction::GetBestRegisterKindAndNumber(®_info, reg_kind,353reg_num))354return (uint64_t)reg_kind << 24 | reg_num;355return 0ull;356}357358void UnwindAssemblyInstEmulation::SetRegisterValue(359const RegisterInfo ®_info, const RegisterValue ®_value) {360m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;361}362363bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo ®_info,364RegisterValue ®_value) {365const uint64_t reg_id = MakeRegisterKindValuePair(reg_info);366RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);367if (pos != m_register_values.end()) {368reg_value = pos->second;369return true; // We had a real value that comes from an opcode that wrote370// to it...371}372// We are making up a value that is recognizable...373reg_value.SetUInt(reg_id, reg_info.byte_size);374return false;375}376377size_t UnwindAssemblyInstEmulation::ReadMemory(378EmulateInstruction *instruction, void *baton,379const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,380size_t dst_len) {381Log *log = GetLog(LLDBLog::Unwind);382383if (log && log->GetVerbose()) {384StreamString strm;385strm.Printf(386"UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64387", dst = %p, dst_len = %" PRIu64 ", context = ",388addr, dst, (uint64_t)dst_len);389context.Dump(strm, instruction);390log->PutString(strm.GetString());391}392memset(dst, 0, dst_len);393return dst_len;394}395396size_t UnwindAssemblyInstEmulation::WriteMemory(397EmulateInstruction *instruction, void *baton,398const EmulateInstruction::Context &context, lldb::addr_t addr,399const void *dst, size_t dst_len) {400if (baton && dst && dst_len)401return ((UnwindAssemblyInstEmulation *)baton)402->WriteMemory(instruction, context, addr, dst, dst_len);403return 0;404}405406size_t UnwindAssemblyInstEmulation::WriteMemory(407EmulateInstruction *instruction, const EmulateInstruction::Context &context,408lldb::addr_t addr, const void *dst, size_t dst_len) {409DataExtractor data(dst, dst_len,410instruction->GetArchitecture().GetByteOrder(),411instruction->GetArchitecture().GetAddressByteSize());412413Log *log = GetLog(LLDBLog::Unwind);414415if (log && log->GetVerbose()) {416StreamString strm;417418strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");419DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,420addr, 0, 0);421strm.PutCString(", context = ");422context.Dump(strm, instruction);423log->PutString(strm.GetString());424}425426switch (context.type) {427default:428case EmulateInstruction::eContextInvalid:429case EmulateInstruction::eContextReadOpcode:430case EmulateInstruction::eContextImmediate:431case EmulateInstruction::eContextAdjustBaseRegister:432case EmulateInstruction::eContextRegisterPlusOffset:433case EmulateInstruction::eContextAdjustPC:434case EmulateInstruction::eContextRegisterStore:435case EmulateInstruction::eContextRegisterLoad:436case EmulateInstruction::eContextRelativeBranchImmediate:437case EmulateInstruction::eContextAbsoluteBranchRegister:438case EmulateInstruction::eContextSupervisorCall:439case EmulateInstruction::eContextTableBranchReadMemory:440case EmulateInstruction::eContextWriteRegisterRandomBits:441case EmulateInstruction::eContextWriteMemoryRandomBits:442case EmulateInstruction::eContextArithmetic:443case EmulateInstruction::eContextAdvancePC:444case EmulateInstruction::eContextReturnFromException:445case EmulateInstruction::eContextPopRegisterOffStack:446case EmulateInstruction::eContextAdjustStackPointer:447break;448449case EmulateInstruction::eContextPushRegisterOnStack: {450uint32_t reg_num = LLDB_INVALID_REGNUM;451uint32_t generic_regnum = LLDB_INVALID_REGNUM;452assert(context.GetInfoType() ==453EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset &&454"unhandled case, add code to handle this!");455const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();456reg_num = context.info.RegisterToRegisterPlusOffset.data_reg457.kinds[unwind_reg_kind];458generic_regnum = context.info.RegisterToRegisterPlusOffset.data_reg459.kinds[eRegisterKindGeneric];460461if (reg_num != LLDB_INVALID_REGNUM &&462generic_regnum != LLDB_REGNUM_GENERIC_SP) {463if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) {464m_pushed_regs[reg_num] = addr;465const int32_t offset = addr - m_initial_sp;466m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,467/*can_replace=*/true);468m_curr_row_modified = true;469}470}471} break;472}473474return dst_len;475}476477bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,478void *baton,479const RegisterInfo *reg_info,480RegisterValue ®_value) {481482if (baton && reg_info)483return ((UnwindAssemblyInstEmulation *)baton)484->ReadRegister(instruction, reg_info, reg_value);485return false;486}487bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,488const RegisterInfo *reg_info,489RegisterValue ®_value) {490bool synthetic = GetRegisterValue(*reg_info, reg_value);491492Log *log = GetLog(LLDBLog::Unwind);493494if (log && log->GetVerbose()) {495496StreamString strm;497strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "498"synthetic_value = %i, value = ",499reg_info->name, synthetic);500DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);501log->PutString(strm.GetString());502}503return true;504}505506bool UnwindAssemblyInstEmulation::WriteRegister(507EmulateInstruction *instruction, void *baton,508const EmulateInstruction::Context &context, const RegisterInfo *reg_info,509const RegisterValue ®_value) {510if (baton && reg_info)511return ((UnwindAssemblyInstEmulation *)baton)512->WriteRegister(instruction, context, reg_info, reg_value);513return false;514}515bool UnwindAssemblyInstEmulation::WriteRegister(516EmulateInstruction *instruction, const EmulateInstruction::Context &context,517const RegisterInfo *reg_info, const RegisterValue ®_value) {518Log *log = GetLog(LLDBLog::Unwind);519520if (log && log->GetVerbose()) {521522StreamString strm;523strm.Printf(524"UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",525reg_info->name);526DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);527strm.PutCString(", context = ");528context.Dump(strm, instruction);529log->PutString(strm.GetString());530}531532SetRegisterValue(*reg_info, reg_value);533534switch (context.type) {535case EmulateInstruction::eContextInvalid:536case EmulateInstruction::eContextReadOpcode:537case EmulateInstruction::eContextImmediate:538case EmulateInstruction::eContextAdjustBaseRegister:539case EmulateInstruction::eContextRegisterPlusOffset:540case EmulateInstruction::eContextAdjustPC:541case EmulateInstruction::eContextRegisterStore:542case EmulateInstruction::eContextSupervisorCall:543case EmulateInstruction::eContextTableBranchReadMemory:544case EmulateInstruction::eContextWriteRegisterRandomBits:545case EmulateInstruction::eContextWriteMemoryRandomBits:546case EmulateInstruction::eContextAdvancePC:547case EmulateInstruction::eContextReturnFromException:548case EmulateInstruction::eContextPushRegisterOnStack:549case EmulateInstruction::eContextRegisterLoad:550// {551// const uint32_t reg_num =552// reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];553// if (reg_num != LLDB_INVALID_REGNUM)554// {555// const bool can_replace_only_if_unspecified = true;556//557// m_curr_row.SetRegisterLocationToUndefined (reg_num,558// can_replace_only_if_unspecified,559// can_replace_only_if_unspecified);560// m_curr_row_modified = true;561// }562// }563break;564565case EmulateInstruction::eContextArithmetic: {566// If we adjusted the current frame pointer by a constant then adjust the567// CFA offset568// with the same amount.569lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();570if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&571context.GetInfoType() ==572EmulateInstruction::eInfoTypeRegisterPlusOffset &&573context.info.RegisterPlusOffset.reg.kinds[kind] ==574m_cfa_reg_info.kinds[kind]) {575const int64_t offset = context.info.RegisterPlusOffset.signed_offset;576m_curr_row->GetCFAValue().IncOffset(-1 * offset);577m_curr_row_modified = true;578}579} break;580581case EmulateInstruction::eContextAbsoluteBranchRegister:582case EmulateInstruction::eContextRelativeBranchImmediate: {583if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&584context.info.ISAAndImmediate.unsigned_data32 > 0) {585m_forward_branch_offset =586context.info.ISAAndImmediateSigned.signed_data32;587} else if (context.GetInfoType() ==588EmulateInstruction::eInfoTypeISAAndImmediateSigned &&589context.info.ISAAndImmediateSigned.signed_data32 > 0) {590m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;591} else if (context.GetInfoType() ==592EmulateInstruction::eInfoTypeImmediate &&593context.info.unsigned_immediate > 0) {594m_forward_branch_offset = context.info.unsigned_immediate;595} else if (context.GetInfoType() ==596EmulateInstruction::eInfoTypeImmediateSigned &&597context.info.signed_immediate > 0) {598m_forward_branch_offset = context.info.signed_immediate;599}600} break;601602case EmulateInstruction::eContextPopRegisterOffStack: {603const uint32_t reg_num =604reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];605const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];606if (reg_num != LLDB_INVALID_REGNUM &&607generic_regnum != LLDB_REGNUM_GENERIC_SP) {608switch (context.GetInfoType()) {609case EmulateInstruction::eInfoTypeAddress:610if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&611context.info.address == m_pushed_regs[reg_num]) {612m_curr_row->SetRegisterLocationToSame(reg_num,613false /*must_replace*/);614m_curr_row_modified = true;615616// FP has been restored to its original value, we are back617// to using SP to calculate the CFA.618if (m_fp_is_cfa) {619m_fp_is_cfa = false;620lldb::RegisterKind sp_reg_kind = eRegisterKindGeneric;621uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;622RegisterInfo sp_reg_info =623*m_inst_emulator_up->GetRegisterInfo(sp_reg_kind, sp_reg_num);624RegisterValue sp_reg_val;625if (GetRegisterValue(sp_reg_info, sp_reg_val)) {626m_cfa_reg_info = sp_reg_info;627const uint32_t cfa_reg_num =628sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];629assert(cfa_reg_num != LLDB_INVALID_REGNUM);630m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(631cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());632}633}634}635break;636case EmulateInstruction::eInfoTypeISA:637assert(638(generic_regnum == LLDB_REGNUM_GENERIC_PC ||639generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&640"eInfoTypeISA used for popping a register other the PC/FLAGS");641if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {642m_curr_row->SetRegisterLocationToSame(reg_num,643false /*must_replace*/);644m_curr_row_modified = true;645}646break;647default:648assert(false && "unhandled case, add code to handle this!");649break;650}651}652} break;653654case EmulateInstruction::eContextSetFramePointer:655if (!m_fp_is_cfa) {656m_fp_is_cfa = true;657m_cfa_reg_info = *reg_info;658const uint32_t cfa_reg_num =659reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];660assert(cfa_reg_num != LLDB_INVALID_REGNUM);661m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(662cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());663m_curr_row_modified = true;664}665break;666667case EmulateInstruction::eContextRestoreStackPointer:668if (m_fp_is_cfa) {669m_fp_is_cfa = false;670m_cfa_reg_info = *reg_info;671const uint32_t cfa_reg_num =672reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];673assert(cfa_reg_num != LLDB_INVALID_REGNUM);674m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(675cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());676m_curr_row_modified = true;677}678break;679680case EmulateInstruction::eContextAdjustStackPointer:681// If we have created a frame using the frame pointer, don't follow682// subsequent adjustments to the stack pointer.683if (!m_fp_is_cfa) {684m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(685m_curr_row->GetCFAValue().GetRegisterNumber(),686m_initial_sp - reg_value.GetAsUInt64());687m_curr_row_modified = true;688}689break;690}691return true;692}693694695