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(name: GetPluginNameStatic(),
36 description: GetPluginDescriptionStatic(), create_callback: CreateInstance);
37}
38
39void EmulateInstructionPPC64::Terminate() {
40 PluginManager::UnregisterPlugin(create_callback: 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(reg_kind: eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC,
103 LLDB_INVALID_ADDRESS, success_ptr: &success);
104 if (success) {
105 Context ctx;
106 ctx.type = eContextReadOpcode;
107 ctx.SetNoArgs();
108 m_opcode.SetOpcode32(inst: ReadMemoryUnsigned(context: ctx, addr: m_addr, byte_size: 4, fail_value: 0, success_ptr: &success),
109 order: 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(reg_num: gpr_r1_ppc64le, offset: 0);
125
126 unwind_plan.AppendRow(row_sp: 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 {.mask: 0xfc0007ff, .value: 0x7c0002a6, .callback: &EmulateInstructionPPC64::EmulateMFSPR,
139 .name: "mfspr RT, SPR"},
140 {.mask: 0xfc000003, .value: 0xf8000000, .callback: &EmulateInstructionPPC64::EmulateSTD,
141 .name: "std RS, DS(RA)"},
142 {.mask: 0xfc000003, .value: 0xf8000001, .callback: &EmulateInstructionPPC64::EmulateSTD,
143 .name: "stdu RS, DS(RA)"},
144 {.mask: 0xfc0007fe, .value: 0x7c000378, .callback: &EmulateInstructionPPC64::EmulateOR,
145 .name: "or RA, RS, RB"},
146 {.mask: 0xfc000000, .value: 0x38000000, .callback: &EmulateInstructionPPC64::EmulateADDI,
147 .name: "addi RT, RA, SI"},
148 {.mask: 0xfc000003, .value: 0xe8000000, .callback: &EmulateInstructionPPC64::EmulateLD,
149 .name: "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(reg_kind: eRegisterKindLLDB, reg_num: gpr_pc_ppc64le, fail_value: 0, success_ptr: &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(reg_kind: eRegisterKindLLDB, reg_num: gpr_pc_ppc64le, fail_value: 0, success_ptr: &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, reg_kind: eRegisterKindLLDB, reg_num: gpr_pc_ppc64le,
196 reg_value: 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(bits: opcode, msbit: 25, lsbit: 21);
205 uint32_t spr = Bits32(bits: opcode, msbit: 20, lsbit: 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(mask: 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(reg_kind: eRegisterKindLLDB, reg_num: gpr_lr_ppc64le, fail_value: 0, success_ptr: &success);
219 if (!success)
220 return false;
221 Context context;
222 context.type = eContextWriteRegisterRandomBits;
223 WriteRegisterUnsigned(context, reg_kind: eRegisterKindLLDB, reg_num: gpr_r0_ppc64le, reg_value: lr);
224 LLDB_LOG(log, "EmulateMFSPR: success!");
225 return true;
226}
227
228bool EmulateInstructionPPC64::EmulateLD(uint32_t opcode) {
229 uint32_t rt = Bits32(bits: opcode, msbit: 25, lsbit: 21);
230 uint32_t ra = Bits32(bits: opcode, msbit: 20, lsbit: 16);
231 uint32_t ds = Bits32(bits: opcode, msbit: 15, lsbit: 2);
232
233 int32_t ids = llvm::SignExtend32<16>(X: 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(mask: 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(reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_ppc64le);
245 if (!r1_info)
246 return false;
247
248 // restore SP
249 Context ctx;
250 ctx.type = eContextRestoreStackPointer;
251 ctx.SetRegisterToRegisterPlusOffset(data_reg: *r1_info, base_reg: *r1_info, offset: 0);
252
253 WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_ppc64le, reg_value: 0);
254 LLDB_LOG(log, "EmulateLD: success!");
255 return true;
256}
257
258bool EmulateInstructionPPC64::EmulateSTD(uint32_t opcode) {
259 uint32_t rs = Bits32(bits: opcode, msbit: 25, lsbit: 21);
260 uint32_t ra = Bits32(bits: opcode, msbit: 20, lsbit: 16);
261 uint32_t ds = Bits32(bits: opcode, msbit: 15, lsbit: 2);
262 uint32_t u = Bits32(bits: opcode, msbit: 1, lsbit: 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(reg_kind: eRegisterKindLLDB, reg_num: rs, fail_value: 0, success_ptr: &success);
274 if (!success)
275 return false;
276
277 int32_t ids = llvm::SignExtend32<16>(X: ds << 2);
278 Log *log = GetLog(mask: 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(reg_kind: eRegisterKindLLDB, reg_num: gpr_lr_ppc64le, fail_value: 0, success_ptr: &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(reg_kind: eRegisterKindLLDB, reg_num: rs_num);
296 if (!rs_info)
297 return false;
298 std::optional<RegisterInfo> ra_info = GetRegisterInfo(reg_kind: eRegisterKindLLDB, reg_num: ra);
299 if (!ra_info)
300 return false;
301
302 Context ctx;
303 ctx.type = eContextPushRegisterOnStack;
304 ctx.SetRegisterToRegisterPlusOffset(data_reg: *rs_info, base_reg: *ra_info, offset: ids);
305
306 // store
307 uint64_t ra_val = ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: ra, fail_value: 0, success_ptr: &success);
308 if (!success)
309 return false;
310
311 lldb::addr_t addr = ra_val + ids;
312 WriteMemory(context: ctx, addr, src: &rs_val, src_len: 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(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: ra, reg_value: 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(bits: opcode, msbit: 25, lsbit: 21);
328 uint32_t ra = Bits32(bits: opcode, msbit: 20, lsbit: 16);
329 uint32_t rb = Bits32(bits: opcode, msbit: 15, lsbit: 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(mask: 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(reg_kind: eRegisterKindLLDB, reg_num: 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(reg_kind: eRegisterKindLLDB, reg_num: rb, fail_value: 0, success_ptr: &success);
351 if (!success)
352 return false;
353 WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: ra, reg_value: 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(bits: opcode, msbit: 25, lsbit: 21);
361 uint32_t ra = Bits32(bits: opcode, msbit: 20, lsbit: 16);
362 uint32_t si = Bits32(bits: opcode, msbit: 15, lsbit: 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>(X: si);
371 Log *log = GetLog(mask: 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(reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_ppc64le);
377 if (!r1_info)
378 return false;
379
380 Context ctx;
381 ctx.type = eContextRestoreStackPointer;
382 ctx.SetRegisterToRegisterPlusOffset(data_reg: *r1_info, base_reg: *r1_info, offset: 0);
383
384 // adjust SP
385 bool success;
386 uint64_t r1 =
387 ReadRegisterUnsigned(reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_ppc64le, fail_value: 0, success_ptr: &success);
388 if (!success)
389 return false;
390 WriteRegisterUnsigned(context: ctx, reg_kind: eRegisterKindLLDB, reg_num: gpr_r1_ppc64le, reg_value: r1 + si_val);
391 LLDB_LOG(log, "EmulateADDI: success!");
392 return true;
393}
394

source code of lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp