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