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