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))
36using namespace lldb;
37using namespace lldb_private;
38using namespace lldb_private::process_linux;
39
40static 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
55static 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
68static 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
81static 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.
102static constexpr int k_num_register_sets = 4;
103
104static 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
115std::unique_ptr<NativeRegisterContextLinux>
116NativeRegisterContextLinux::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
127llvm::Expected<ArchSpec>
128NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {
129 return HostInfo::GetArchitecture();
130}
131
132NativeRegisterContextLinux_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
148uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
149 return k_num_register_sets;
150}
151
152const RegisterSet *
153NativeRegisterContextLinux_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
160uint32_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
167Status 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
250Status 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
357Status 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
390Status 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
445bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
446 return reg <= k_last_gpr_ppc64le; // GPR's come first.
447}
448
449bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
450 return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
451}
452
453uint32_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
459uint32_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
465uint32_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
471Status 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
478Status 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
485Status 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
492Status 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
499bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
500 return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
501}
502
503bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
504 return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
505}
506
507uint32_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
520uint32_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
607bool 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
647uint32_t
648NativeRegisterContextLinux_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::popcount(control);
655 }
656
657 return 0;
658}
659
660bool 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
668Status 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
691lldb::addr_t
692NativeRegisterContextLinux_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
705lldb::addr_t
706NativeRegisterContextLinux_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
719Status 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
742Status 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

source code of lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp