1 //===-- NativeRegisterContextLinux_ppc64le.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 // This implementation is related to the OpenPOWER ABI for Power Architecture
10 // 64-bit ELF V2 ABI
11 
12 #if defined(__powerpc64__)
13 
14 #include "NativeRegisterContextLinux_ppc64le.h"
15 
16 #include "lldb/Host/common/NativeProcessProtocol.h"
17 #include "lldb/Utility/DataBufferHeap.h"
18 #include "lldb/Utility/Log.h"
19 #include "lldb/Utility/RegisterValue.h"
20 #include "lldb/Utility/Status.h"
21 
22 #include "Plugins/Process/Linux/NativeProcessLinux.h"
23 #include "Plugins/Process/Linux/Procfs.h"
24 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
25 #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
26 
27 // System includes - They have to be included after framework includes because
28 // they define some macros which collide with variable names in other modules
29 #include <sys/socket.h>
30 #include <elf.h>
31 #include <asm/ptrace.h>
32 
33 #define REG_CONTEXT_SIZE                                                       \
34   (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le))
35 using namespace lldb;
36 using namespace lldb_private;
37 using namespace lldb_private::process_linux;
38 
39 static const uint32_t g_gpr_regnums_ppc64le[] = {
40     gpr_r0_ppc64le,   gpr_r1_ppc64le,  gpr_r2_ppc64le,     gpr_r3_ppc64le,
41     gpr_r4_ppc64le,   gpr_r5_ppc64le,  gpr_r6_ppc64le,     gpr_r7_ppc64le,
42     gpr_r8_ppc64le,   gpr_r9_ppc64le,  gpr_r10_ppc64le,    gpr_r11_ppc64le,
43     gpr_r12_ppc64le,  gpr_r13_ppc64le, gpr_r14_ppc64le,    gpr_r15_ppc64le,
44     gpr_r16_ppc64le,  gpr_r17_ppc64le, gpr_r18_ppc64le,    gpr_r19_ppc64le,
45     gpr_r20_ppc64le,  gpr_r21_ppc64le, gpr_r22_ppc64le,    gpr_r23_ppc64le,
46     gpr_r24_ppc64le,  gpr_r25_ppc64le, gpr_r26_ppc64le,    gpr_r27_ppc64le,
47     gpr_r28_ppc64le,  gpr_r29_ppc64le, gpr_r30_ppc64le,    gpr_r31_ppc64le,
48     gpr_pc_ppc64le,   gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
49     gpr_lr_ppc64le,   gpr_xer_ppc64le, gpr_cr_ppc64le,     gpr_softe_ppc64le,
50     gpr_trap_ppc64le,
51     LLDB_INVALID_REGNUM // register sets need to end with this flag
52 };
53 
54 static const uint32_t g_fpr_regnums_ppc64le[] = {
55     fpr_f0_ppc64le,    fpr_f1_ppc64le,  fpr_f2_ppc64le,  fpr_f3_ppc64le,
56     fpr_f4_ppc64le,    fpr_f5_ppc64le,  fpr_f6_ppc64le,  fpr_f7_ppc64le,
57     fpr_f8_ppc64le,    fpr_f9_ppc64le,  fpr_f10_ppc64le, fpr_f11_ppc64le,
58     fpr_f12_ppc64le,   fpr_f13_ppc64le, fpr_f14_ppc64le, fpr_f15_ppc64le,
59     fpr_f16_ppc64le,   fpr_f17_ppc64le, fpr_f18_ppc64le, fpr_f19_ppc64le,
60     fpr_f20_ppc64le,   fpr_f21_ppc64le, fpr_f22_ppc64le, fpr_f23_ppc64le,
61     fpr_f24_ppc64le,   fpr_f25_ppc64le, fpr_f26_ppc64le, fpr_f27_ppc64le,
62     fpr_f28_ppc64le,   fpr_f29_ppc64le, fpr_f30_ppc64le, fpr_f31_ppc64le,
63     fpr_fpscr_ppc64le,
64     LLDB_INVALID_REGNUM // register sets need to end with this flag
65 };
66 
67 static const uint32_t g_vmx_regnums_ppc64le[] = {
68     vmx_vr0_ppc64le,  vmx_vr1_ppc64le,    vmx_vr2_ppc64le,  vmx_vr3_ppc64le,
69     vmx_vr4_ppc64le,  vmx_vr5_ppc64le,    vmx_vr6_ppc64le,  vmx_vr7_ppc64le,
70     vmx_vr8_ppc64le,  vmx_vr9_ppc64le,    vmx_vr10_ppc64le, vmx_vr11_ppc64le,
71     vmx_vr12_ppc64le, vmx_vr13_ppc64le,   vmx_vr14_ppc64le, vmx_vr15_ppc64le,
72     vmx_vr16_ppc64le, vmx_vr17_ppc64le,   vmx_vr18_ppc64le, vmx_vr19_ppc64le,
73     vmx_vr20_ppc64le, vmx_vr21_ppc64le,   vmx_vr22_ppc64le, vmx_vr23_ppc64le,
74     vmx_vr24_ppc64le, vmx_vr25_ppc64le,   vmx_vr26_ppc64le, vmx_vr27_ppc64le,
75     vmx_vr28_ppc64le, vmx_vr29_ppc64le,   vmx_vr30_ppc64le, vmx_vr31_ppc64le,
76     vmx_vscr_ppc64le, vmx_vrsave_ppc64le,
77     LLDB_INVALID_REGNUM // register sets need to end with this flag
78 };
79 
80 static const uint32_t g_vsx_regnums_ppc64le[] = {
81     vsx_vs0_ppc64le,  vsx_vs1_ppc64le,  vsx_vs2_ppc64le,  vsx_vs3_ppc64le,
82     vsx_vs4_ppc64le,  vsx_vs5_ppc64le,  vsx_vs6_ppc64le,  vsx_vs7_ppc64le,
83     vsx_vs8_ppc64le,  vsx_vs9_ppc64le,  vsx_vs10_ppc64le, vsx_vs11_ppc64le,
84     vsx_vs12_ppc64le, vsx_vs13_ppc64le, vsx_vs14_ppc64le, vsx_vs15_ppc64le,
85     vsx_vs16_ppc64le, vsx_vs17_ppc64le, vsx_vs18_ppc64le, vsx_vs19_ppc64le,
86     vsx_vs20_ppc64le, vsx_vs21_ppc64le, vsx_vs22_ppc64le, vsx_vs23_ppc64le,
87     vsx_vs24_ppc64le, vsx_vs25_ppc64le, vsx_vs26_ppc64le, vsx_vs27_ppc64le,
88     vsx_vs28_ppc64le, vsx_vs29_ppc64le, vsx_vs30_ppc64le, vsx_vs31_ppc64le,
89     vsx_vs32_ppc64le, vsx_vs33_ppc64le, vsx_vs34_ppc64le, vsx_vs35_ppc64le,
90     vsx_vs36_ppc64le, vsx_vs37_ppc64le, vsx_vs38_ppc64le, vsx_vs39_ppc64le,
91     vsx_vs40_ppc64le, vsx_vs41_ppc64le, vsx_vs42_ppc64le, vsx_vs43_ppc64le,
92     vsx_vs44_ppc64le, vsx_vs45_ppc64le, vsx_vs46_ppc64le, vsx_vs47_ppc64le,
93     vsx_vs48_ppc64le, vsx_vs49_ppc64le, vsx_vs50_ppc64le, vsx_vs51_ppc64le,
94     vsx_vs52_ppc64le, vsx_vs53_ppc64le, vsx_vs54_ppc64le, vsx_vs55_ppc64le,
95     vsx_vs56_ppc64le, vsx_vs57_ppc64le, vsx_vs58_ppc64le, vsx_vs59_ppc64le,
96     vsx_vs60_ppc64le, vsx_vs61_ppc64le, vsx_vs62_ppc64le, vsx_vs63_ppc64le,
97     LLDB_INVALID_REGNUM // register sets need to end with this flag
98 };
99 
100 // Number of register sets provided by this context.
101 static constexpr int k_num_register_sets = 4;
102 
103 static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
104     {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
105      g_gpr_regnums_ppc64le},
106     {"Floating Point Registers", "fpr", k_num_fpr_registers_ppc64le,
107      g_fpr_regnums_ppc64le},
108     {"AltiVec/VMX Registers", "vmx", k_num_vmx_registers_ppc64le,
109      g_vmx_regnums_ppc64le},
110     {"VSX Registers", "vsx", k_num_vsx_registers_ppc64le,
111      g_vsx_regnums_ppc64le},
112 };
113 
114 std::unique_ptr<NativeRegisterContextLinux>
CreateHostNativeRegisterContextLinux(const ArchSpec & target_arch,NativeThreadLinux & native_thread)115 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
116     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
117   switch (target_arch.GetMachine()) {
118   case llvm::Triple::ppc64le:
119     return std::make_unique<NativeRegisterContextLinux_ppc64le>(target_arch,
120                                                                  native_thread);
121   default:
122     llvm_unreachable("have no register context for architecture");
123   }
124 }
125 
NativeRegisterContextLinux_ppc64le(const ArchSpec & target_arch,NativeThreadProtocol & native_thread)126 NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
127     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
128     : NativeRegisterContextRegisterInfo(
129           native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)),
130       NativeRegisterContextLinux(native_thread) {
131   if (target_arch.GetMachine() != llvm::Triple::ppc64le) {
132     llvm_unreachable("Unhandled target architecture.");
133   }
134 
135   ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
136   ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le));
137   ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le));
138   ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le));
139   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
140 }
141 
GetRegisterSetCount() const142 uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
143   return k_num_register_sets;
144 }
145 
146 const RegisterSet *
GetRegisterSet(uint32_t set_index) const147 NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
148   if (set_index < k_num_register_sets)
149     return &g_reg_sets_ppc64le[set_index];
150 
151   return nullptr;
152 }
153 
GetUserRegisterCount() const154 uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
155   uint32_t count = 0;
156   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
157     count += g_reg_sets_ppc64le[set_index].num_registers;
158   return count;
159 }
160 
ReadRegister(const RegisterInfo * reg_info,RegisterValue & reg_value)161 Status NativeRegisterContextLinux_ppc64le::ReadRegister(
162     const RegisterInfo *reg_info, RegisterValue &reg_value) {
163   Status error;
164 
165   if (!reg_info) {
166     error.SetErrorString("reg_info NULL");
167     return error;
168   }
169 
170   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
171 
172   if (IsFPR(reg)) {
173     error = ReadFPR();
174     if (error.Fail())
175       return error;
176 
177     // Get pointer to m_fpr_ppc64le variable and set the data from it.
178     uint32_t fpr_offset = CalculateFprOffset(reg_info);
179     assert(fpr_offset < sizeof m_fpr_ppc64le);
180     uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
181     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
182                                 eByteOrderLittle, error);
183   } else if (IsVSX(reg)) {
184     uint32_t vsx_offset = CalculateVsxOffset(reg_info);
185     assert(vsx_offset < sizeof(m_vsx_ppc64le));
186 
187     if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
188       error = ReadVSX();
189       if (error.Fail())
190         return error;
191 
192       error = ReadFPR();
193       if (error.Fail())
194         return error;
195 
196       uint64_t value[2];
197       uint8_t *dst, *src;
198       dst = (uint8_t *)&value;
199       src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
200       ::memcpy(dst, src, 8);
201       dst += 8;
202       src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
203       ::memcpy(dst, src, 8);
204       reg_value.SetFromMemoryData(reg_info, &value, reg_info->byte_size,
205                                   eByteOrderLittle, error);
206     } else {
207       error = ReadVMX();
208       if (error.Fail())
209         return error;
210 
211       // Get pointer to m_vmx_ppc64le variable and set the data from it.
212       uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
213       uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
214       reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
215                                   eByteOrderLittle, error);
216     }
217   } else if (IsVMX(reg)) {
218     error = ReadVMX();
219     if (error.Fail())
220       return error;
221 
222     // Get pointer to m_vmx_ppc64le variable and set the data from it.
223     uint32_t vmx_offset = CalculateVmxOffset(reg_info);
224     assert(vmx_offset < sizeof m_vmx_ppc64le);
225     uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
226     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
227                                 eByteOrderLittle, error);
228   } else if (IsGPR(reg)) {
229     error = ReadGPR();
230     if (error.Fail())
231       return error;
232 
233     uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
234     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
235                                 eByteOrderLittle, error);
236   } else {
237     return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
238                   "or VMX, read strategy unknown");
239   }
240 
241   return error;
242 }
243 
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & reg_value)244 Status NativeRegisterContextLinux_ppc64le::WriteRegister(
245     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
246   Status error;
247   if (!reg_info)
248     return Status("reg_info NULL");
249 
250   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
251   if (reg_index == LLDB_INVALID_REGNUM)
252     return Status("no lldb regnum for %s", reg_info && reg_info->name
253                                                ? reg_info->name
254                                                : "<unknown register>");
255 
256   if (IsGPR(reg_index)) {
257     error = ReadGPR();
258     if (error.Fail())
259       return error;
260 
261     uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset;
262     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
263 
264     error = WriteGPR();
265     if (error.Fail())
266       return error;
267 
268     return Status();
269   }
270 
271   if (IsFPR(reg_index)) {
272     error = ReadFPR();
273     if (error.Fail())
274       return error;
275 
276     // Get pointer to m_fpr_ppc64le variable and set the data to it.
277     uint32_t fpr_offset = CalculateFprOffset(reg_info);
278     assert(fpr_offset < GetFPRSize());
279     uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
280     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
281 
282     error = WriteFPR();
283     if (error.Fail())
284       return error;
285 
286     return Status();
287   }
288 
289   if (IsVMX(reg_index)) {
290     error = ReadVMX();
291     if (error.Fail())
292       return error;
293 
294     // Get pointer to m_vmx_ppc64le variable and set the data to it.
295     uint32_t vmx_offset = CalculateVmxOffset(reg_info);
296     assert(vmx_offset < sizeof(m_vmx_ppc64le));
297     uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
298     ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
299 
300     error = WriteVMX();
301     if (error.Fail())
302       return error;
303 
304     return Status();
305   }
306 
307   if (IsVSX(reg_index)) {
308     uint32_t vsx_offset = CalculateVsxOffset(reg_info);
309     assert(vsx_offset < sizeof(m_vsx_ppc64le));
310 
311     if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
312       error = ReadVSX();
313       if (error.Fail())
314         return error;
315 
316       error = ReadFPR();
317       if (error.Fail())
318         return error;
319 
320       uint64_t value[2];
321       ::memcpy(value, reg_value.GetBytes(), 16);
322       uint8_t *dst, *src;
323       src = (uint8_t *)value;
324       dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
325       ::memcpy(dst, src, 8);
326       src += 8;
327       dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
328       ::memcpy(dst, src, 8);
329 
330       WriteVSX();
331       WriteFPR();
332     } else {
333       error = ReadVMX();
334       if (error.Fail())
335         return error;
336 
337       // Get pointer to m_vmx_ppc64le variable and set the data from it.
338       uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
339       uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
340       ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
341       WriteVMX();
342     }
343 
344     return Status();
345   }
346 
347   return Status("failed - register wasn't recognized to be a GPR, FPR, VSX "
348                 "or VMX, write strategy unknown");
349 }
350 
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)351 Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
352     lldb::WritableDataBufferSP &data_sp) {
353   Status error;
354 
355   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
356   error = ReadGPR();
357   if (error.Fail())
358     return error;
359 
360   error = ReadFPR();
361   if (error.Fail())
362     return error;
363 
364   error = ReadVMX();
365   if (error.Fail())
366     return error;
367 
368   error = ReadVSX();
369   if (error.Fail())
370     return error;
371 
372   uint8_t *dst = data_sp->GetBytes();
373   ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
374   dst += GetGPRSize();
375   ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
376   dst += GetFPRSize();
377   ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le));
378   dst += sizeof(m_vmx_ppc64le);
379   ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le));
380 
381   return error;
382 }
383 
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)384 Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
385     const lldb::DataBufferSP &data_sp) {
386   Status error;
387 
388   if (!data_sp) {
389     error.SetErrorStringWithFormat(
390         "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
391         __FUNCTION__);
392     return error;
393   }
394 
395   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
396     error.SetErrorStringWithFormat(
397         "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
398         "data size, expected %" PRIu64 ", actual %" PRIu64,
399         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
400     return error;
401   }
402 
403   const uint8_t *src = data_sp->GetBytes();
404   if (src == nullptr) {
405     error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s "
406                                    "DataBuffer::GetBytes() returned a null "
407                                    "pointer",
408                                    __FUNCTION__);
409     return error;
410   }
411 
412   ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
413   error = WriteGPR();
414 
415   if (error.Fail())
416     return error;
417 
418   src += GetGPRSize();
419   ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
420 
421   error = WriteFPR();
422   if (error.Fail())
423     return error;
424 
425   src += GetFPRSize();
426   ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
427 
428   error = WriteVMX();
429   if (error.Fail())
430     return error;
431 
432   src += sizeof(m_vmx_ppc64le);
433   ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
434   error = WriteVSX();
435 
436   return error;
437 }
438 
IsGPR(unsigned reg) const439 bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
440   return reg <= k_last_gpr_ppc64le; // GPR's come first.
441 }
442 
IsFPR(unsigned reg) const443 bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
444   return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
445 }
446 
CalculateFprOffset(const RegisterInfo * reg_info) const447 uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
448     const RegisterInfo *reg_info) const {
449   return reg_info->byte_offset -
450          GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
451 }
452 
CalculateVmxOffset(const RegisterInfo * reg_info) const453 uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
454     const RegisterInfo *reg_info) const {
455   return reg_info->byte_offset -
456          GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
457 }
458 
CalculateVsxOffset(const RegisterInfo * reg_info) const459 uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
460     const RegisterInfo *reg_info) const {
461   return reg_info->byte_offset -
462          GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
463 }
464 
ReadVMX()465 Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
466   int regset = NT_PPC_VMX;
467   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
468                                            &regset, &m_vmx_ppc64le,
469                                            sizeof(m_vmx_ppc64le));
470 }
471 
WriteVMX()472 Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
473   int regset = NT_PPC_VMX;
474   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
475                                            &regset, &m_vmx_ppc64le,
476                                            sizeof(m_vmx_ppc64le));
477 }
478 
ReadVSX()479 Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
480   int regset = NT_PPC_VSX;
481   return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
482                                            &regset, &m_vsx_ppc64le,
483                                            sizeof(m_vsx_ppc64le));
484 }
485 
WriteVSX()486 Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
487   int regset = NT_PPC_VSX;
488   return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
489                                            &regset, &m_vsx_ppc64le,
490                                            sizeof(m_vsx_ppc64le));
491 }
492 
IsVMX(unsigned reg)493 bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
494   return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
495 }
496 
IsVSX(unsigned reg)497 bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
498   return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
499 }
500 
NumSupportedHardwareWatchpoints()501 uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
502   Log *log = GetLog(POSIXLog::Watchpoints);
503 
504   // Read hardware breakpoint and watchpoint information.
505   Status error = ReadHardwareDebugInfo();
506 
507   if (error.Fail())
508     return 0;
509 
510   LLDB_LOG(log, "{0}", m_max_hwp_supported);
511   return m_max_hwp_supported;
512 }
513 
SetHardwareWatchpoint(lldb::addr_t addr,size_t size,uint32_t watch_flags)514 uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
515     lldb::addr_t addr, size_t size, uint32_t watch_flags) {
516   Log *log = GetLog(POSIXLog::Watchpoints);
517   LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
518            watch_flags);
519 
520   // Read hardware breakpoint and watchpoint information.
521   Status error = ReadHardwareDebugInfo();
522 
523   if (error.Fail())
524     return LLDB_INVALID_INDEX32;
525 
526   uint32_t control_value = 0, wp_index = 0;
527   lldb::addr_t real_addr = addr;
528   uint32_t rw_mode = 0;
529 
530   // Check if we are setting watchpoint other than read/write/access Update
531   // watchpoint flag to match ppc64le write-read bit configuration.
532   switch (watch_flags) {
533   case eWatchpointKindWrite:
534     rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
535     watch_flags = 2;
536     break;
537   case eWatchpointKindRead:
538     rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
539     watch_flags = 1;
540     break;
541   case (eWatchpointKindRead | eWatchpointKindWrite):
542     rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
543     break;
544   default:
545     return LLDB_INVALID_INDEX32;
546   }
547 
548   // Check if size has a valid hardware watchpoint length.
549   if (size != 1 && size != 2 && size != 4 && size != 8)
550     return LLDB_INVALID_INDEX32;
551 
552   // Check 8-byte alignment for hardware watchpoint target address. Below is a
553   // hack to recalculate address and size in order to make sure we can watch
554   // non 8-byte aligned addresses as well.
555   if (addr & 0x07) {
556 
557     addr_t begin = llvm::alignDown(addr, 8);
558     addr_t end = llvm::alignTo(addr + size, 8);
559     size = llvm::PowerOf2Ceil(end - begin);
560 
561     addr = addr & (~0x07);
562   }
563 
564   // Setup control value
565   control_value = watch_flags << 3;
566   control_value |= ((1 << size) - 1) << 5;
567   control_value |= (2 << 1) | 1;
568 
569   // Iterate over stored watchpoints and find a free wp_index
570   wp_index = LLDB_INVALID_INDEX32;
571   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
572     if ((m_hwp_regs[i].control & 1) == 0) {
573       wp_index = i; // Mark last free slot
574     } else if (m_hwp_regs[i].address == addr) {
575       return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
576     }
577   }
578 
579   if (wp_index == LLDB_INVALID_INDEX32)
580     return LLDB_INVALID_INDEX32;
581 
582   // Update watchpoint in local cache
583   m_hwp_regs[wp_index].real_addr = real_addr;
584   m_hwp_regs[wp_index].address = addr;
585   m_hwp_regs[wp_index].control = control_value;
586   m_hwp_regs[wp_index].mode = rw_mode;
587 
588   // PTRACE call to set corresponding watchpoint register.
589   error = WriteHardwareDebugRegs();
590 
591   if (error.Fail()) {
592     m_hwp_regs[wp_index].address = 0;
593     m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
594 
595     return LLDB_INVALID_INDEX32;
596   }
597 
598   return wp_index;
599 }
600 
ClearHardwareWatchpoint(uint32_t wp_index)601 bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
602     uint32_t wp_index) {
603   Log *log = GetLog(POSIXLog::Watchpoints);
604   LLDB_LOG(log, "wp_index: {0}", wp_index);
605 
606   // Read hardware breakpoint and watchpoint information.
607   Status error = ReadHardwareDebugInfo();
608 
609   if (error.Fail())
610     return false;
611 
612   if (wp_index >= m_max_hwp_supported)
613     return false;
614 
615   // Create a backup we can revert to in case of failure.
616   lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
617   uint32_t tempControl = m_hwp_regs[wp_index].control;
618   long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
619 
620   // Update watchpoint in local cache
621   m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
622   m_hwp_regs[wp_index].address = 0;
623   m_hwp_regs[wp_index].slot = 0;
624   m_hwp_regs[wp_index].mode = 0;
625 
626   // Ptrace call to update hardware debug registers
627   error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
628                                             m_thread.GetID(), 0, tempSlot);
629 
630   if (error.Fail()) {
631     m_hwp_regs[wp_index].control = tempControl;
632     m_hwp_regs[wp_index].address = tempAddr;
633     m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
634 
635     return false;
636   }
637 
638   return true;
639 }
640 
641 uint32_t
GetWatchpointSize(uint32_t wp_index)642 NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
643   Log *log = GetLog(POSIXLog::Watchpoints);
644   LLDB_LOG(log, "wp_index: {0}", wp_index);
645 
646   unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
647   if (llvm::isPowerOf2_32(control + 1)) {
648     return llvm::countPopulation(control);
649   }
650 
651   return 0;
652 }
653 
WatchpointIsEnabled(uint32_t wp_index)654 bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
655     uint32_t wp_index) {
656   Log *log = GetLog(POSIXLog::Watchpoints);
657   LLDB_LOG(log, "wp_index: {0}", wp_index);
658 
659   return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
660 }
661 
GetWatchpointHitIndex(uint32_t & wp_index,lldb::addr_t trap_addr)662 Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
663     uint32_t &wp_index, lldb::addr_t trap_addr) {
664   Log *log = GetLog(POSIXLog::Watchpoints);
665   LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
666 
667   uint32_t watch_size;
668   lldb::addr_t watch_addr;
669 
670   for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
671     watch_size = GetWatchpointSize(wp_index);
672     watch_addr = m_hwp_regs[wp_index].address;
673 
674     if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
675         trap_addr <= watch_addr + watch_size) {
676       m_hwp_regs[wp_index].hit_addr = trap_addr;
677       return Status();
678     }
679   }
680 
681   wp_index = LLDB_INVALID_INDEX32;
682   return Status();
683 }
684 
685 lldb::addr_t
GetWatchpointAddress(uint32_t wp_index)686 NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
687   Log *log = GetLog(POSIXLog::Watchpoints);
688   LLDB_LOG(log, "wp_index: {0}", wp_index);
689 
690   if (wp_index >= m_max_hwp_supported)
691     return LLDB_INVALID_ADDRESS;
692 
693   if (WatchpointIsEnabled(wp_index))
694     return m_hwp_regs[wp_index].real_addr;
695   else
696     return LLDB_INVALID_ADDRESS;
697 }
698 
699 lldb::addr_t
GetWatchpointHitAddress(uint32_t wp_index)700 NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
701   Log *log = GetLog(POSIXLog::Watchpoints);
702   LLDB_LOG(log, "wp_index: {0}", wp_index);
703 
704   if (wp_index >= m_max_hwp_supported)
705     return LLDB_INVALID_ADDRESS;
706 
707   if (WatchpointIsEnabled(wp_index))
708     return m_hwp_regs[wp_index].hit_addr;
709 
710   return LLDB_INVALID_ADDRESS;
711 }
712 
ReadHardwareDebugInfo()713 Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
714   if (!m_refresh_hwdebug_info) {
715     return Status();
716   }
717 
718   ::pid_t tid = m_thread.GetID();
719 
720   struct ppc_debug_info hwdebug_info;
721   Status error;
722 
723   error = NativeProcessLinux::PtraceWrapper(
724       PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
725 
726   if (error.Fail())
727     return error;
728 
729   m_max_hwp_supported = hwdebug_info.num_data_bps;
730   m_max_hbp_supported = hwdebug_info.num_instruction_bps;
731   m_refresh_hwdebug_info = false;
732 
733   return error;
734 }
735 
WriteHardwareDebugRegs()736 Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
737   struct ppc_hw_breakpoint reg_state;
738   Status error;
739   long ret;
740 
741   for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
742     reg_state.addr = m_hwp_regs[i].address;
743     reg_state.trigger_type = m_hwp_regs[i].mode;
744     reg_state.version = 1;
745     reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
746     reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
747     reg_state.addr2 = 0;
748     reg_state.condition_value = 0;
749 
750     error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
751                                               m_thread.GetID(), 0, &reg_state,
752                                               sizeof(reg_state), &ret);
753 
754     if (error.Fail())
755       return error;
756 
757     m_hwp_regs[i].slot = ret;
758   }
759 
760   return error;
761 }
762 
763 #endif // defined(__powerpc64__)
764