10b57cec5SDimitry Andric //===-- EmulateInstructionPPC64.cpp ------------------------------*- C++-*-===// 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 "EmulateInstructionPPC64.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include <stdlib.h> 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h" 140b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h" 150b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h" 160b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT 210b57cec5SDimitry Andric #include "Plugins/Process/Utility/RegisterInfos_ppc64le.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #include "Plugins/Process/Utility/InstructionUtils.h" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace lldb; 260b57cec5SDimitry Andric using namespace lldb_private; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch) 290b57cec5SDimitry Andric : EmulateInstruction(arch) {} 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric void EmulateInstructionPPC64::Initialize() { 320b57cec5SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 330b57cec5SDimitry Andric GetPluginDescriptionStatic(), CreateInstance); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric void EmulateInstructionPPC64::Terminate() { 370b57cec5SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 380b57cec5SDimitry Andric } 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric ConstString EmulateInstructionPPC64::GetPluginNameStatic() { 410b57cec5SDimitry Andric ConstString g_plugin_name("lldb.emulate-instruction.ppc64"); 420b57cec5SDimitry Andric return g_plugin_name; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric ConstString EmulateInstructionPPC64::GetPluginName() { 460b57cec5SDimitry Andric static ConstString g_plugin_name("EmulateInstructionPPC64"); 470b57cec5SDimitry Andric return g_plugin_name; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric const char *EmulateInstructionPPC64::GetPluginDescriptionStatic() { 510b57cec5SDimitry Andric return "Emulate instructions for the PPC64 architecture."; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric EmulateInstruction * 550b57cec5SDimitry Andric EmulateInstructionPPC64::CreateInstance(const ArchSpec &arch, 560b57cec5SDimitry Andric InstructionType inst_type) { 570b57cec5SDimitry Andric if (EmulateInstructionPPC64::SupportsEmulatingInstructionsOfTypeStatic( 580b57cec5SDimitry Andric inst_type)) 590b57cec5SDimitry Andric if (arch.GetTriple().isPPC64()) 600b57cec5SDimitry Andric return new EmulateInstructionPPC64(arch); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric return nullptr; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) { 660b57cec5SDimitry Andric return arch.GetTriple().isPPC64(); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric static bool LLDBTableGetRegisterInfo(uint32_t reg_num, RegisterInfo ®_info) { 700b57cec5SDimitry Andric if (reg_num >= llvm::array_lengthof(g_register_infos_ppc64le)) 710b57cec5SDimitry Andric return false; 720b57cec5SDimitry Andric reg_info = g_register_infos_ppc64le[reg_num]; 730b57cec5SDimitry Andric return true; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric bool EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind, 770b57cec5SDimitry Andric uint32_t reg_num, 780b57cec5SDimitry Andric RegisterInfo ®_info) { 790b57cec5SDimitry Andric if (reg_kind == eRegisterKindGeneric) { 800b57cec5SDimitry Andric switch (reg_num) { 810b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_PC: 820b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 830b57cec5SDimitry Andric reg_num = gpr_pc_ppc64le; 840b57cec5SDimitry Andric break; 850b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_SP: 860b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 870b57cec5SDimitry Andric reg_num = gpr_r1_ppc64le; 880b57cec5SDimitry Andric break; 890b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_RA: 900b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 910b57cec5SDimitry Andric reg_num = gpr_lr_ppc64le; 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric case LLDB_REGNUM_GENERIC_FLAGS: 940b57cec5SDimitry Andric reg_kind = eRegisterKindLLDB; 950b57cec5SDimitry Andric reg_num = gpr_cr_ppc64le; 960b57cec5SDimitry Andric break; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric default: 990b57cec5SDimitry Andric return false; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric if (reg_kind == eRegisterKindLLDB) 1040b57cec5SDimitry Andric return LLDBTableGetRegisterInfo(reg_num, reg_info); 1050b57cec5SDimitry Andric return false; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric bool EmulateInstructionPPC64::ReadInstruction() { 1090b57cec5SDimitry Andric bool success = false; 1100b57cec5SDimitry Andric m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 1110b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &success); 1120b57cec5SDimitry Andric if (success) { 1130b57cec5SDimitry Andric Context ctx; 1140b57cec5SDimitry Andric ctx.type = eContextReadOpcode; 1150b57cec5SDimitry Andric ctx.SetNoArgs(); 1160b57cec5SDimitry Andric m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success), 1170b57cec5SDimitry Andric GetByteOrder()); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric if (!success) 1200b57cec5SDimitry Andric m_addr = LLDB_INVALID_ADDRESS; 1210b57cec5SDimitry Andric return success; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric bool EmulateInstructionPPC64::CreateFunctionEntryUnwind( 1250b57cec5SDimitry Andric UnwindPlan &unwind_plan) { 1260b57cec5SDimitry Andric unwind_plan.Clear(); 1270b57cec5SDimitry Andric unwind_plan.SetRegisterKind(eRegisterKindLLDB); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric UnwindPlan::RowSP row(new UnwindPlan::Row); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // Our previous Call Frame Address is the stack pointer 1320b57cec5SDimitry Andric row->GetCFAValue().SetIsRegisterPlusOffset(gpr_r1_ppc64le, 0); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric unwind_plan.AppendRow(row); 1350b57cec5SDimitry Andric unwind_plan.SetSourceName("EmulateInstructionPPC64"); 1360b57cec5SDimitry Andric unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 1370b57cec5SDimitry Andric unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 1380b57cec5SDimitry Andric unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le); 1390b57cec5SDimitry Andric return true; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric EmulateInstructionPPC64::Opcode * 1430b57cec5SDimitry Andric EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) { 1440b57cec5SDimitry Andric static EmulateInstructionPPC64::Opcode g_opcodes[] = { 1450b57cec5SDimitry Andric {0xfc0007ff, 0x7c0002a6, &EmulateInstructionPPC64::EmulateMFSPR, 1460b57cec5SDimitry Andric "mfspr RT, SPR"}, 1470b57cec5SDimitry Andric {0xfc000003, 0xf8000000, &EmulateInstructionPPC64::EmulateSTD, 1480b57cec5SDimitry Andric "std RS, DS(RA)"}, 1490b57cec5SDimitry Andric {0xfc000003, 0xf8000001, &EmulateInstructionPPC64::EmulateSTD, 1500b57cec5SDimitry Andric "stdu RS, DS(RA)"}, 1510b57cec5SDimitry Andric {0xfc0007fe, 0x7c000378, &EmulateInstructionPPC64::EmulateOR, 1520b57cec5SDimitry Andric "or RA, RS, RB"}, 1530b57cec5SDimitry Andric {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI, 1540b57cec5SDimitry Andric "addi RT, RA, SI"}, 1550b57cec5SDimitry Andric {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD, 1560b57cec5SDimitry Andric "ld RT, DS(RA)"}}; 1570b57cec5SDimitry Andric static const size_t k_num_ppc_opcodes = llvm::array_lengthof(g_opcodes); 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric for (size_t i = 0; i < k_num_ppc_opcodes; ++i) { 1600b57cec5SDimitry Andric if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value) 1610b57cec5SDimitry Andric return &g_opcodes[i]; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric return nullptr; 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) { 1670b57cec5SDimitry Andric const uint32_t opcode = m_opcode.GetOpcode32(); 1680b57cec5SDimitry Andric // LLDB_LOG(log, "PPC64::EvaluateInstruction: opcode={0:X+8}", opcode); 1690b57cec5SDimitry Andric Opcode *opcode_data = GetOpcodeForInstruction(opcode); 1700b57cec5SDimitry Andric if (!opcode_data) 1710b57cec5SDimitry Andric return false; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric // LLDB_LOG(log, "PPC64::EvaluateInstruction: {0}", opcode_data->name); 1740b57cec5SDimitry Andric const bool auto_advance_pc = 1750b57cec5SDimitry Andric evaluate_options & eEmulateInstructionOptionAutoAdvancePC; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric bool success = false; 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric uint32_t orig_pc_value = 0; 1800b57cec5SDimitry Andric if (auto_advance_pc) { 1810b57cec5SDimitry Andric orig_pc_value = 1820b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); 1830b57cec5SDimitry Andric if (!success) 1840b57cec5SDimitry Andric return false; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // Call the Emulate... function. 1880b57cec5SDimitry Andric success = (this->*opcode_data->callback)(opcode); 1890b57cec5SDimitry Andric if (!success) 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric if (auto_advance_pc) { 1930b57cec5SDimitry Andric uint32_t new_pc_value = 1940b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success); 1950b57cec5SDimitry Andric if (!success) 1960b57cec5SDimitry Andric return false; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric if (auto_advance_pc && (new_pc_value == orig_pc_value)) { 1990b57cec5SDimitry Andric EmulateInstruction::Context context; 2000b57cec5SDimitry Andric context.type = eContextAdvancePC; 2010b57cec5SDimitry Andric context.SetNoArgs(); 2020b57cec5SDimitry Andric if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_ppc64le, 2030b57cec5SDimitry Andric orig_pc_value + 4)) 2040b57cec5SDimitry Andric return false; 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric return true; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric bool EmulateInstructionPPC64::EmulateMFSPR(uint32_t opcode) { 2110b57cec5SDimitry Andric uint32_t rt = Bits32(opcode, 25, 21); 2120b57cec5SDimitry Andric uint32_t spr = Bits32(opcode, 20, 11); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric enum { SPR_LR = 0x100 }; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // For now, we're only insterested in 'mfspr r0, lr' 2170b57cec5SDimitry Andric if (rt != gpr_r0_ppc64le || spr != SPR_LR) 2180b57cec5SDimitry Andric return false; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 2210b57cec5SDimitry Andric LLDB_LOG(log, "EmulateMFSPR: {0:X+8}: mfspr r0, lr", m_addr); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric bool success; 2240b57cec5SDimitry Andric uint64_t lr = 2250b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); 2260b57cec5SDimitry Andric if (!success) 2270b57cec5SDimitry Andric return false; 2280b57cec5SDimitry Andric Context context; 2290b57cec5SDimitry Andric context.type = eContextWriteRegisterRandomBits; 2300b57cec5SDimitry Andric WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_r0_ppc64le, lr); 2310b57cec5SDimitry Andric LLDB_LOG(log, "EmulateMFSPR: success!"); 2320b57cec5SDimitry Andric return true; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) { 2360b57cec5SDimitry Andric uint32_t rt = Bits32(opcode, 25, 21); 2370b57cec5SDimitry Andric uint32_t ra = Bits32(opcode, 20, 16); 2380b57cec5SDimitry Andric uint32_t ds = Bits32(opcode, 15, 2); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric int32_t ids = llvm::SignExtend32<16>(ds << 2); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // For now, tracking only loads from 0(r1) to r1 (0(r1) is the ABI defined 2430b57cec5SDimitry Andric // location to save previous SP) 2440b57cec5SDimitry Andric if (ra != gpr_r1_ppc64le || rt != gpr_r1_ppc64le || ids != 0) 2450b57cec5SDimitry Andric return false; 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 2480b57cec5SDimitry Andric LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra); 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric RegisterInfo r1_info; 2510b57cec5SDimitry Andric if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, r1_info)) 2520b57cec5SDimitry Andric return false; 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // restore SP 2550b57cec5SDimitry Andric Context ctx; 2560b57cec5SDimitry Andric ctx.type = eContextRestoreStackPointer; 2570b57cec5SDimitry Andric ctx.SetRegisterToRegisterPlusOffset(r1_info, r1_info, 0); 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, 0); 2600b57cec5SDimitry Andric LLDB_LOG(log, "EmulateLD: success!"); 2610b57cec5SDimitry Andric return true; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) { 2650b57cec5SDimitry Andric uint32_t rs = Bits32(opcode, 25, 21); 2660b57cec5SDimitry Andric uint32_t ra = Bits32(opcode, 20, 16); 2670b57cec5SDimitry Andric uint32_t ds = Bits32(opcode, 15, 2); 2680b57cec5SDimitry Andric uint32_t u = Bits32(opcode, 1, 0); 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // For now, tracking only stores to r1 2710b57cec5SDimitry Andric if (ra != gpr_r1_ppc64le) 2720b57cec5SDimitry Andric return false; 2730b57cec5SDimitry Andric // ... and only stores of SP, FP and LR (moved into r0 by a previous mfspr) 2740b57cec5SDimitry Andric if (rs != gpr_r1_ppc64le && rs != gpr_r31_ppc64le && rs != gpr_r30_ppc64le && 2750b57cec5SDimitry Andric rs != gpr_r0_ppc64le) 2760b57cec5SDimitry Andric return false; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric bool success; 2790b57cec5SDimitry Andric uint64_t rs_val = ReadRegisterUnsigned(eRegisterKindLLDB, rs, 0, &success); 2800b57cec5SDimitry Andric if (!success) 2810b57cec5SDimitry Andric return false; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric int32_t ids = llvm::SignExtend32<16>(ds << 2); 2840b57cec5SDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 2850b57cec5SDimitry Andric LLDB_LOG(log, "EmulateSTD: {0:X+8}: std{1} r{2}, {3}(r{4})", m_addr, 2860b57cec5SDimitry Andric u ? "u" : "", rs, ids, ra); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // Make sure that r0 is really holding LR value (this won't catch unlikely 2890b57cec5SDimitry Andric // cases, such as r0 being overwritten after mfspr) 2900b57cec5SDimitry Andric uint32_t rs_num = rs; 2910b57cec5SDimitry Andric if (rs == gpr_r0_ppc64le) { 2920b57cec5SDimitry Andric uint64_t lr = 2930b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success); 2940b57cec5SDimitry Andric if (!success || lr != rs_val) 2950b57cec5SDimitry Andric return false; 2960b57cec5SDimitry Andric rs_num = gpr_lr_ppc64le; 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric // set context 3000b57cec5SDimitry Andric RegisterInfo rs_info; 3010b57cec5SDimitry Andric if (!GetRegisterInfo(eRegisterKindLLDB, rs_num, rs_info)) 3020b57cec5SDimitry Andric return false; 3030b57cec5SDimitry Andric RegisterInfo ra_info; 3040b57cec5SDimitry Andric if (!GetRegisterInfo(eRegisterKindLLDB, ra, ra_info)) 3050b57cec5SDimitry Andric return false; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric Context ctx; 3080b57cec5SDimitry Andric ctx.type = eContextPushRegisterOnStack; 3090b57cec5SDimitry Andric ctx.SetRegisterToRegisterPlusOffset(rs_info, ra_info, ids); 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric // store 3120b57cec5SDimitry Andric uint64_t ra_val = ReadRegisterUnsigned(eRegisterKindLLDB, ra, 0, &success); 3130b57cec5SDimitry Andric if (!success) 3140b57cec5SDimitry Andric return false; 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric lldb::addr_t addr = ra_val + ids; 3170b57cec5SDimitry Andric WriteMemory(ctx, addr, &rs_val, sizeof(rs_val)); 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric // update RA? 3200b57cec5SDimitry Andric if (u) { 3210b57cec5SDimitry Andric Context ctx; 3220b57cec5SDimitry Andric // NOTE Currently, RA will always be equal to SP(r1) 3230b57cec5SDimitry Andric ctx.type = eContextAdjustStackPointer; 3240b57cec5SDimitry Andric WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, addr); 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric LLDB_LOG(log, "EmulateSTD: success!"); 3280b57cec5SDimitry Andric return true; 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric bool EmulateInstructionPPC64::EmulateOR(uint32_t opcode) { 3320b57cec5SDimitry Andric uint32_t rs = Bits32(opcode, 25, 21); 3330b57cec5SDimitry Andric uint32_t ra = Bits32(opcode, 20, 16); 3340b57cec5SDimitry Andric uint32_t rb = Bits32(opcode, 15, 11); 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric // to be safe, process only the known 'mr r31/r30, r1' prologue instructions 3370b57cec5SDimitry Andric if (m_fp != LLDB_INVALID_REGNUM || rs != rb || 3380b57cec5SDimitry Andric (ra != gpr_r30_ppc64le && ra != gpr_r31_ppc64le) || rb != gpr_r1_ppc64le) 3390b57cec5SDimitry Andric return false; 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 3420b57cec5SDimitry Andric LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb); 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric // set context 3450b57cec5SDimitry Andric RegisterInfo ra_info; 3460b57cec5SDimitry Andric if (!GetRegisterInfo(eRegisterKindLLDB, ra, ra_info)) 3470b57cec5SDimitry Andric return false; 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric Context ctx; 3500b57cec5SDimitry Andric ctx.type = eContextSetFramePointer; 3510b57cec5SDimitry Andric ctx.SetRegister(ra_info); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric // move 3540b57cec5SDimitry Andric bool success; 3550b57cec5SDimitry Andric uint64_t rb_val = ReadRegisterUnsigned(eRegisterKindLLDB, rb, 0, &success); 3560b57cec5SDimitry Andric if (!success) 3570b57cec5SDimitry Andric return false; 3580b57cec5SDimitry Andric WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, rb_val); 3590b57cec5SDimitry Andric m_fp = ra; 3600b57cec5SDimitry Andric LLDB_LOG(log, "EmulateOR: success!"); 3610b57cec5SDimitry Andric return true; 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) { 3650b57cec5SDimitry Andric uint32_t rt = Bits32(opcode, 25, 21); 3660b57cec5SDimitry Andric uint32_t ra = Bits32(opcode, 20, 16); 3670b57cec5SDimitry Andric uint32_t si = Bits32(opcode, 15, 0); 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric // handle stack adjustments only 3700b57cec5SDimitry Andric // (this is a typical epilogue operation, with ra == r1. If it's 3710b57cec5SDimitry Andric // something else, then we won't know the correct value of ra) 3720b57cec5SDimitry Andric if (rt != gpr_r1_ppc64le || ra != gpr_r1_ppc64le) 3730b57cec5SDimitry Andric return false; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric int32_t si_val = llvm::SignExtend32<16>(si); 3760b57cec5SDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 3770b57cec5SDimitry Andric LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val); 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // set context 3800b57cec5SDimitry Andric RegisterInfo r1_info; 3810b57cec5SDimitry Andric if (!GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le, r1_info)) 3820b57cec5SDimitry Andric return false; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric Context ctx; 3850b57cec5SDimitry Andric ctx.type = eContextRestoreStackPointer; 3860b57cec5SDimitry Andric ctx.SetRegisterToRegisterPlusOffset(r1_info, r1_info, 0); 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // adjust SP 3890b57cec5SDimitry Andric bool success; 3900b57cec5SDimitry Andric uint64_t r1 = 3910b57cec5SDimitry Andric ReadRegisterUnsigned(eRegisterKindLLDB, gpr_r1_ppc64le, 0, &success); 3920b57cec5SDimitry Andric if (!success) 3930b57cec5SDimitry Andric return false; 3940b57cec5SDimitry Andric WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val); 3950b57cec5SDimitry Andric LLDB_LOG(log, "EmulateADDI: success!"); 3960b57cec5SDimitry Andric return true; 3970b57cec5SDimitry Andric } 398