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