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