LLDB mainline
NativeRegisterContextLinux_ppc64le.cpp
Go to the documentation of this file.
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
15
16#include "lldb/Host/HostInfo.h"
19#include "lldb/Utility/Log.h"
21#include "lldb/Utility/Status.h"
22
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[] = {
52 LLDB_INVALID_REGNUM // register sets need to end with this flag
53};
54
55static const uint32_t g_fpr_regnums_ppc64le[] = {
65 LLDB_INVALID_REGNUM // register sets need to end with this flag
66};
67
68static const uint32_t g_vmx_regnums_ppc64le[] = {
78 LLDB_INVALID_REGNUM // register sets need to end with this flag
79};
80
81static const uint32_t g_vsx_regnums_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
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)
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) {
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) {
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(
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) {
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())
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:
552 }
553
554 // Check if size has a valid hardware watchpoint length.
555 if (size != 1 && size != 2 && size != 4 && size != 8)
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)
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
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
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)
698
699 if (WatchpointIsEnabled(wp_index))
700 return m_hwp_regs[wp_index].real_addr;
701 else
703}
704
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)
712
713 if (WatchpointIsEnabled(wp_index))
714 return m_hwp_regs[wp_index].hit_addr;
715
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;
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;
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__)
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
#define REG_CONTEXT_SIZE
constexpr size_t k_num_register_sets
static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets]
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:683
A subclass of DataBuffer that stores a data buffer on the heap.
uint32_t SetFromMemoryData(const RegisterInfo &reg_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
const void * GetBytes() const
An error handling class.
Definition: Status.h:44
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:83
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
@ k_num_gpr_registers_ppc64le
@ k_num_vsx_registers_ppc64le
@ k_num_vmx_registers_ppc64le
@ k_num_fpr_registers_ppc64le
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:328
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:329
uint64_t addr_t
Definition: lldb-types.h:79
uint64_t tid_t
Definition: lldb-types.h:82
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.
Registers are grouped into register sets.