1//===-- EmulateInstructionPPC64.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "EmulateInstructionPPC64.h"
10
11#include <cstdlib>
12#include <optional>
13
14#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
15#include "lldb/Core/PluginManager.h"
16#include "lldb/Symbol/UnwindPlan.h"
17#include "lldb/Utility/ArchSpec.h"
18#include "lldb/Utility/ConstString.h"
19#include "lldb/Utility/LLDBLog.h"
20
21#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
22#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
23
24#include "Plugins/Process/Utility/InstructionUtils.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29LLDB_PLUGIN_DEFINE_ADV(EmulateInstructionPPC64, InstructionPPC64)
30
31EmulateInstructionPPC64::EmulateInstructionPPC64(const ArchSpec &arch)
32    : EmulateInstruction(arch) {}
33
34void EmulateInstructionPPC64::Initialize() {
35  PluginManager::RegisterPlugin(GetPluginNameStatic(),
36                                GetPluginDescriptionStatic(), CreateInstance);
37}
38
39void EmulateInstructionPPC64::Terminate() {
40  PluginManager::UnregisterPlugin(CreateInstance);
41}
42
43llvm::StringRef EmulateInstructionPPC64::GetPluginDescriptionStatic() {
44  return "Emulate instructions for the PPC64 architecture.";
45}
46
47EmulateInstruction *
48EmulateInstructionPPC64::CreateInstance(const ArchSpec &arch,
49                                        InstructionType inst_type) {
50  if (EmulateInstructionPPC64::SupportsEmulatingInstructionsOfTypeStatic(
51          inst_type))
52    if (arch.GetTriple().isPPC64())
53      return new EmulateInstructionPPC64(arch);
54
55  return nullptr;
56}
57
58bool EmulateInstructionPPC64::SetTargetTriple(const ArchSpec &arch) {
59  return arch.GetTriple().isPPC64();
60}
61
62static std::optional<RegisterInfo> LLDBTableGetRegisterInfo(uint32_t reg_num) {
63  if (reg_num >= std::size(g_register_infos_ppc64le))
64    return {};
65  return g_register_infos_ppc64le[reg_num];
66}
67
68std::optional<RegisterInfo>
69EmulateInstructionPPC64::GetRegisterInfo(RegisterKind reg_kind,
70                                         uint32_t reg_num) {
71  if (reg_kind == eRegisterKindGeneric) {
72    switch (reg_num) {
73    case LLDB_REGNUM_GENERIC_PC:
74      reg_kind = eRegisterKindLLDB;
75      reg_num = gpr_pc_ppc64le;
76      break;
77    case LLDB_REGNUM_GENERIC_SP:
78      reg_kind = eRegisterKindLLDB;
79      reg_num = gpr_r1_ppc64le;
80      break;
81    case LLDB_REGNUM_GENERIC_RA:
82      reg_kind = eRegisterKindLLDB;
83      reg_num = gpr_lr_ppc64le;
84      break;
85    case LLDB_REGNUM_GENERIC_FLAGS:
86      reg_kind = eRegisterKindLLDB;
87      reg_num = gpr_cr_ppc64le;
88      break;
89
90    default:
91      return {};
92    }
93  }
94
95  if (reg_kind == eRegisterKindLLDB)
96    return LLDBTableGetRegisterInfo(reg_num);
97  return {};
98}
99
100bool EmulateInstructionPPC64::ReadInstruction() {
101  bool success = false;
102  m_addr = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
103                                LLDB_INVALID_ADDRESS, &success);
104  if (success) {
105    Context ctx;
106    ctx.type = eContextReadOpcode;
107    ctx.SetNoArgs();
108    m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success),
109                         GetByteOrder());
110  }
111  if (!success)
112    m_addr = LLDB_INVALID_ADDRESS;
113  return success;
114}
115
116bool EmulateInstructionPPC64::CreateFunctionEntryUnwind(
117    UnwindPlan &unwind_plan) {
118  unwind_plan.Clear();
119  unwind_plan.SetRegisterKind(eRegisterKindLLDB);
120
121  UnwindPlan::RowSP row(new UnwindPlan::Row);
122
123  // Our previous Call Frame Address is the stack pointer
124  row->GetCFAValue().SetIsRegisterPlusOffset(gpr_r1_ppc64le, 0);
125
126  unwind_plan.AppendRow(row);
127  unwind_plan.SetSourceName("EmulateInstructionPPC64");
128  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
129  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
130  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
131  unwind_plan.SetReturnAddressRegister(gpr_lr_ppc64le);
132  return true;
133}
134
135EmulateInstructionPPC64::Opcode *
136EmulateInstructionPPC64::GetOpcodeForInstruction(uint32_t opcode) {
137  static EmulateInstructionPPC64::Opcode g_opcodes[] = {
138      {0xfc0007ff, 0x7c0002a6, &EmulateInstructionPPC64::EmulateMFSPR,
139       "mfspr RT, SPR"},
140      {0xfc000003, 0xf8000000, &EmulateInstructionPPC64::EmulateSTD,
141       "std RS, DS(RA)"},
142      {0xfc000003, 0xf8000001, &EmulateInstructionPPC64::EmulateSTD,
143       "stdu RS, DS(RA)"},
144      {0xfc0007fe, 0x7c000378, &EmulateInstructionPPC64::EmulateOR,
145       "or RA, RS, RB"},
146      {0xfc000000, 0x38000000, &EmulateInstructionPPC64::EmulateADDI,
147       "addi RT, RA, SI"},
148      {0xfc000003, 0xe8000000, &EmulateInstructionPPC64::EmulateLD,
149       "ld RT, DS(RA)"}};
150  static const size_t k_num_ppc_opcodes = std::size(g_opcodes);
151
152  for (size_t i = 0; i < k_num_ppc_opcodes; ++i) {
153    if ((g_opcodes[i].mask & opcode) == g_opcodes[i].value)
154      return &g_opcodes[i];
155  }
156  return nullptr;
157}
158
159bool EmulateInstructionPPC64::EvaluateInstruction(uint32_t evaluate_options) {
160  const uint32_t opcode = m_opcode.GetOpcode32();
161  // LLDB_LOG(log, "PPC64::EvaluateInstruction: opcode={0:X+8}", opcode);
162  Opcode *opcode_data = GetOpcodeForInstruction(opcode);
163  if (!opcode_data)
164    return false;
165
166  // LLDB_LOG(log, "PPC64::EvaluateInstruction: {0}", opcode_data->name);
167  const bool auto_advance_pc =
168      evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
169
170  bool success = false;
171
172  uint32_t orig_pc_value = 0;
173  if (auto_advance_pc) {
174    orig_pc_value =
175        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
176    if (!success)
177      return false;
178  }
179
180  // Call the Emulate... function.
181  success = (this->*opcode_data->callback)(opcode);
182  if (!success)
183    return false;
184
185  if (auto_advance_pc) {
186    uint32_t new_pc_value =
187        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_pc_ppc64le, 0, &success);
188    if (!success)
189      return false;
190
191    if (new_pc_value == orig_pc_value) {
192      EmulateInstruction::Context context;
193      context.type = eContextAdvancePC;
194      context.SetNoArgs();
195      if (!WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_pc_ppc64le,
196                                 orig_pc_value + 4))
197        return false;
198    }
199  }
200  return true;
201}
202
203bool EmulateInstructionPPC64::EmulateMFSPR(uint32_t opcode) {
204  uint32_t rt = Bits32(opcode, 25, 21);
205  uint32_t spr = Bits32(opcode, 20, 11);
206
207  enum { SPR_LR = 0x100 };
208
209  // For now, we're only insterested in 'mfspr r0, lr'
210  if (rt != gpr_r0_ppc64le || spr != SPR_LR)
211    return false;
212
213  Log *log = GetLog(LLDBLog::Unwind);
214  LLDB_LOG(log, "EmulateMFSPR: {0:X+8}: mfspr r0, lr", m_addr);
215
216  bool success;
217  uint64_t lr =
218      ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);
219  if (!success)
220    return false;
221  Context context;
222  context.type = eContextWriteRegisterRandomBits;
223  WriteRegisterUnsigned(context, eRegisterKindLLDB, gpr_r0_ppc64le, lr);
224  LLDB_LOG(log, "EmulateMFSPR: success!");
225  return true;
226}
227
228bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) {
229  uint32_t rt = Bits32(opcode, 25, 21);
230  uint32_t ra = Bits32(opcode, 20, 16);
231  uint32_t ds = Bits32(opcode, 15, 2);
232
233  int32_t ids = llvm::SignExtend32<16>(ds << 2);
234
235  // For now, tracking only loads from 0(r1) to r1 (0(r1) is the ABI defined
236  // location to save previous SP)
237  if (ra != gpr_r1_ppc64le || rt != gpr_r1_ppc64le || ids != 0)
238    return false;
239
240  Log *log = GetLog(LLDBLog::Unwind);
241  LLDB_LOG(log, "EmulateLD: {0:X+8}: ld r{1}, {2}(r{3})", m_addr, rt, ids, ra);
242
243  std::optional<RegisterInfo> r1_info =
244      GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);
245  if (!r1_info)
246    return false;
247
248  // restore SP
249  Context ctx;
250  ctx.type = eContextRestoreStackPointer;
251  ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);
252
253  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, 0);
254  LLDB_LOG(log, "EmulateLD: success!");
255  return true;
256}
257
258bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) {
259  uint32_t rs = Bits32(opcode, 25, 21);
260  uint32_t ra = Bits32(opcode, 20, 16);
261  uint32_t ds = Bits32(opcode, 15, 2);
262  uint32_t u = Bits32(opcode, 1, 0);
263
264  // For now, tracking only stores to r1
265  if (ra != gpr_r1_ppc64le)
266    return false;
267  // ... and only stores of SP, FP and LR (moved into r0 by a previous mfspr)
268  if (rs != gpr_r1_ppc64le && rs != gpr_r31_ppc64le && rs != gpr_r30_ppc64le &&
269      rs != gpr_r0_ppc64le)
270    return false;
271
272  bool success;
273  uint64_t rs_val = ReadRegisterUnsigned(eRegisterKindLLDB, rs, 0, &success);
274  if (!success)
275    return false;
276
277  int32_t ids = llvm::SignExtend32<16>(ds << 2);
278  Log *log = GetLog(LLDBLog::Unwind);
279  LLDB_LOG(log, "EmulateSTD: {0:X+8}: std{1} r{2}, {3}(r{4})", m_addr,
280           u ? "u" : "", rs, ids, ra);
281
282  // Make sure that r0 is really holding LR value (this won't catch unlikely
283  // cases, such as r0 being overwritten after mfspr)
284  uint32_t rs_num = rs;
285  if (rs == gpr_r0_ppc64le) {
286    uint64_t lr =
287        ReadRegisterUnsigned(eRegisterKindLLDB, gpr_lr_ppc64le, 0, &success);
288    if (!success || lr != rs_val)
289      return false;
290    rs_num = gpr_lr_ppc64le;
291  }
292
293  // set context
294  std::optional<RegisterInfo> rs_info =
295      GetRegisterInfo(eRegisterKindLLDB, rs_num);
296  if (!rs_info)
297    return false;
298  std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);
299  if (!ra_info)
300    return false;
301
302  Context ctx;
303  ctx.type = eContextPushRegisterOnStack;
304  ctx.SetRegisterToRegisterPlusOffset(*rs_info, *ra_info, ids);
305
306  // store
307  uint64_t ra_val = ReadRegisterUnsigned(eRegisterKindLLDB, ra, 0, &success);
308  if (!success)
309    return false;
310
311  lldb::addr_t addr = ra_val + ids;
312  WriteMemory(ctx, addr, &rs_val, sizeof(rs_val));
313
314  // update RA?
315  if (u) {
316    Context ctx;
317    // NOTE Currently, RA will always be equal to SP(r1)
318    ctx.type = eContextAdjustStackPointer;
319    WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, addr);
320  }
321
322  LLDB_LOG(log, "EmulateSTD: success!");
323  return true;
324}
325
326bool EmulateInstructionPPC64::EmulateOR(uint32_t opcode) {
327  uint32_t rs = Bits32(opcode, 25, 21);
328  uint32_t ra = Bits32(opcode, 20, 16);
329  uint32_t rb = Bits32(opcode, 15, 11);
330
331  // to be safe, process only the known 'mr r31/r30, r1' prologue instructions
332  if (m_fp != LLDB_INVALID_REGNUM || rs != rb ||
333      (ra != gpr_r30_ppc64le && ra != gpr_r31_ppc64le) || rb != gpr_r1_ppc64le)
334    return false;
335
336  Log *log = GetLog(LLDBLog::Unwind);
337  LLDB_LOG(log, "EmulateOR: {0:X+8}: mr r{1}, r{2}", m_addr, ra, rb);
338
339  // set context
340  std::optional<RegisterInfo> ra_info = GetRegisterInfo(eRegisterKindLLDB, ra);
341  if (!ra_info)
342    return false;
343
344  Context ctx;
345  ctx.type = eContextSetFramePointer;
346  ctx.SetRegister(*ra_info);
347
348  // move
349  bool success;
350  uint64_t rb_val = ReadRegisterUnsigned(eRegisterKindLLDB, rb, 0, &success);
351  if (!success)
352    return false;
353  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, ra, rb_val);
354  m_fp = ra;
355  LLDB_LOG(log, "EmulateOR: success!");
356  return true;
357}
358
359bool EmulateInstructionPPC64::EmulateADDI(uint32_t opcode) {
360  uint32_t rt = Bits32(opcode, 25, 21);
361  uint32_t ra = Bits32(opcode, 20, 16);
362  uint32_t si = Bits32(opcode, 15, 0);
363
364  // handle stack adjustments only
365  // (this is a typical epilogue operation, with ra == r1. If it's
366  //  something else, then we won't know the correct value of ra)
367  if (rt != gpr_r1_ppc64le || ra != gpr_r1_ppc64le)
368    return false;
369
370  int32_t si_val = llvm::SignExtend32<16>(si);
371  Log *log = GetLog(LLDBLog::Unwind);
372  LLDB_LOG(log, "EmulateADDI: {0:X+8}: addi r1, r1, {1}", m_addr, si_val);
373
374  // set context
375  std::optional<RegisterInfo> r1_info =
376      GetRegisterInfo(eRegisterKindLLDB, gpr_r1_ppc64le);
377  if (!r1_info)
378    return false;
379
380  Context ctx;
381  ctx.type = eContextRestoreStackPointer;
382  ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);
383
384  // adjust SP
385  bool success;
386  uint64_t r1 =
387      ReadRegisterUnsigned(eRegisterKindLLDB, gpr_r1_ppc64le, 0, &success);
388  if (!success)
389    return false;
390  WriteRegisterUnsigned(ctx, eRegisterKindLLDB, gpr_r1_ppc64le, r1 + si_val);
391  LLDB_LOG(log, "EmulateADDI: success!");
392  return true;
393}
394