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 ®_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 ®_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 ®set, &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 ®set, &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 ®set, &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 ®set, &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, ®_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