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 &reg_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 &reg_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