LLDB mainline
EmulateInstructionPPC64.cpp
Go to the documentation of this file.
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
10
11#include <cstdlib>
12#include <optional>
13
20
21#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
23
25
26using namespace lldb;
27using namespace lldb_private;
28
30
32 : EmulateInstruction(arch) {}
33
37}
38
41}
42
44 return "Emulate instructions for the PPC64 architecture.";
45}
46
49 InstructionType inst_type) {
51 inst_type))
52 if (arch.GetTriple().isPPC64())
53 return new EmulateInstructionPPC64(arch);
54
55 return nullptr;
56}
57
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>
70 uint32_t reg_num) {
71 if (reg_kind == eRegisterKindGeneric) {
72 switch (reg_num) {
74 reg_kind = eRegisterKindLLDB;
75 reg_num = gpr_pc_ppc64le;
76 break;
78 reg_kind = eRegisterKindLLDB;
79 reg_num = gpr_r1_ppc64le;
80 break;
82 reg_kind = eRegisterKindLLDB;
83 reg_num = gpr_lr_ppc64le;
84 break;
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
101 bool success = false;
103 LLDB_INVALID_ADDRESS, &success);
104 if (success) {
105 Context ctx;
107 ctx.SetNoArgs();
108 m_opcode.SetOpcode32(ReadMemoryUnsigned(ctx, m_addr, 4, 0, &success),
109 GetByteOrder());
110 }
111 if (!success)
113 return success;
114}
115
117 UnwindPlan &unwind_plan) {
118 unwind_plan.Clear();
120
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");
132 return true;
133}
134
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 =
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 =
188 if (!success)
189 return false;
190
191 if (new_pc_value == orig_pc_value) {
193 context.type = eContextAdvancePC;
194 context.SetNoArgs();
196 orig_pc_value + 4))
197 return false;
198 }
199 }
200 return true;
201}
202
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 =
219 if (!success)
220 return false;
221 Context context;
224 LLDB_LOG(log, "EmulateMFSPR: success!");
225 return true;
226}
227
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 =
245 if (!r1_info)
246 return false;
247
248 // restore SP
249 Context ctx;
251 ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);
252
254 LLDB_LOG(log, "EmulateLD: success!");
255 return true;
256}
257
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 =
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 =
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;
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)
320 }
321
322 LLDB_LOG(log, "EmulateSTD: success!");
323 return true;
324}
325
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 ||
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;
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;
354 m_fp = ra;
355 LLDB_LOG(log, "EmulateOR: success!");
356 return true;
357}
358
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 =
377 if (!r1_info)
378 return false;
379
380 Context ctx;
382 ctx.SetRegisterToRegisterPlusOffset(*r1_info, *r1_info, 0);
383
384 // adjust SP
385 bool success;
386 uint64_t r1 =
388 if (!success)
389 return false;
391 LLDB_LOG(log, "EmulateADDI: success!");
392 return true;
393}
static std::optional< RegisterInfo > LLDBTableGetRegisterInfo(uint32_t reg_num)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:359
#define LLDB_PLUGIN_DEFINE_ADV(ClassName, PluginName)
Definition: PluginManager.h:26
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:450
bool SetTargetTriple(const ArchSpec &arch) override
static EmulateInstruction * CreateInstance(const ArchSpec &arch, InstructionType inst_type)
std::optional< RegisterInfo > GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num) override
bool EvaluateInstruction(uint32_t evaluate_options) override
bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan) override
static bool SupportsEmulatingInstructionsOfTypeStatic(InstructionType inst_type)
"lldb/Core/EmulateInstruction.h" A class that allows emulation of CPU opcodes.
lldb::ByteOrder GetByteOrder() const
bool WriteRegisterUnsigned(const Context &context, const RegisterInfo &reg_info, uint64_t reg_value)
bool WriteMemory(const Context &context, lldb::addr_t addr, const void *src, size_t src_len)
uint64_t ReadMemoryUnsigned(const Context &context, lldb::addr_t addr, size_t byte_size, uint64_t fail_value, bool *success_ptr)
uint64_t ReadRegisterUnsigned(const RegisterInfo &reg_info, uint64_t fail_value, bool *success_ptr)
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition: UnwindPlan.h:517
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:452
void SetReturnAddressRegister(uint32_t regnum)
Definition: UnwindPlan.h:454
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:379
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:410
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:493
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:581
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:505
#define LLDB_REGNUM_GENERIC_RA
Definition: lldb-defines.h:59
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:57
#define LLDB_REGNUM_GENERIC_FLAGS
Definition: lldb-defines.h:60
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:56
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:331
InstructionType
Instruction types.
static uint32_t Bits32(const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
Definition: SBAddress.h:15
uint64_t addr_t
Definition: lldb-types.h:80
RegisterKind
Register numbering types.
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
@ eRegisterKindLLDB
lldb's internal register numbers
bool(EmulateInstructionPPC64::* callback)(uint32_t opcode)
void SetRegisterToRegisterPlusOffset(RegisterInfo data_reg, RegisterInfo base_reg, int64_t offset)