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>
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>
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}
146
147uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
148 return k_num_register_sets;
149}
150
151const RegisterSet *
152NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
153 if (set_index < k_num_register_sets)
154 return &g_reg_sets_ppc64le[set_index];
155
156 return nullptr;
157}
158
159uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
160 uint32_t count = 0;
161 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
162 count += g_reg_sets_ppc64le[set_index].num_registers;
163 return count;
164}
165
166Status NativeRegisterContextLinux_ppc64le::ReadRegister(
167 const RegisterInfo *reg_info, RegisterValue &reg_value) {
169
170 if (!reg_info) {
171 error = Status::FromErrorString("reg_info NULL");
172 return error;
173 }
174
175 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
176
177 if (IsFPR(reg)) {
178 error = ReadFPR();
179 if (error.Fail())
180 return error;
181
182 // Get pointer to m_fpr_ppc64le variable and set the data from it.
183 uint32_t fpr_offset = CalculateFprOffset(reg_info);
184 assert(fpr_offset < sizeof m_fpr_ppc64le);
185 uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
186 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
188 } else if (IsVSX(reg)) {
189 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
190 assert(vsx_offset < sizeof(m_vsx_ppc64le));
191
192 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
193 error = ReadVSX();
194 if (error.Fail())
195 return error;
196
197 error = ReadFPR();
198 if (error.Fail())
199 return error;
200
201 uint64_t value[2];
202 uint8_t *dst, *src;
203 dst = (uint8_t *)&value;
204 src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
205 ::memcpy(dst, src, 8);
206 dst += 8;
207 src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
208 ::memcpy(dst, src, 8);
209 reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size,
211 } else {
212 error = ReadVMX();
213 if (error.Fail())
214 return error;
215
216 // Get pointer to m_vmx_ppc64le variable and set the data from it.
217 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
218 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
219 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
221 }
222 } else if (IsVMX(reg)) {
223 error = ReadVMX();
224 if (error.Fail())
225 return error;
226
227 // Get pointer to m_vmx_ppc64le variable and set the data from it.
228 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
229 assert(vmx_offset < sizeof m_vmx_ppc64le);
230 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
231 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
233 } else if (IsGPR(reg)) {
234 error = ReadGPR();
235 if (error.Fail())
236 return error;
237
238 uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
239 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
241 } else {
243 "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::FromErrorString("reg_info NULL");
255
256 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
257 if (reg_index == LLDB_INVALID_REGNUM)
259 "no lldb regnum for %s",
260 reg_info && reg_info->name ? reg_info->name : "<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
354 "failed - register wasn't recognized to be a GPR, FPR, VSX "
355 "or VMX, write strategy unknown");
356}
357
358Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
361
362 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
363 error = ReadGPR();
364 if (error.Fail())
365 return error;
366
367 error = ReadFPR();
368 if (error.Fail())
369 return error;
370
371 error = ReadVMX();
372 if (error.Fail())
373 return error;
374
375 error = ReadVSX();
376 if (error.Fail())
377 return error;
378
379 uint8_t *dst = data_sp->GetBytes();
380 ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
381 dst += GetGPRSize();
382 ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
383 dst += GetFPRSize();
384 ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le));
385 dst += sizeof(m_vmx_ppc64le);
386 ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le));
387
388 return error;
389}
390
391Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
392 const lldb::DataBufferSP &data_sp) {
394
395 if (!data_sp) {
397 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
398 __FUNCTION__);
399 return error;
400 }
401
402 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
404 "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
405 "data size, expected %" PRIu64 ", actual %" PRIu64,
406 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
407 return error;
408 }
409
410 const uint8_t *src = data_sp->GetBytes();
411 if (src == nullptr) {
413 "NativeRegisterContextLinux_ppc64le::%s "
414 "DataBuffer::GetBytes() returned a null "
415 "pointer",
416 __FUNCTION__);
417 return error;
418 }
419
420 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
421 error = WriteGPR();
422
423 if (error.Fail())
424 return error;
425
426 src += GetGPRSize();
427 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
428
429 error = WriteFPR();
430 if (error.Fail())
431 return error;
432
433 src += GetFPRSize();
434 ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
435
436 error = WriteVMX();
437 if (error.Fail())
438 return error;
439
440 src += sizeof(m_vmx_ppc64le);
441 ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
442 error = WriteVSX();
443
444 return error;
445}
446
447bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
448 return reg <= k_last_gpr_ppc64le; // GPR's come first.
449}
450
451bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
452 return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
453}
454
455uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
456 const RegisterInfo *reg_info) const {
457 return reg_info->byte_offset -
458 GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
459}
460
461uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
462 const RegisterInfo *reg_info) const {
463 return reg_info->byte_offset -
464 GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
465}
466
467uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
468 const RegisterInfo *reg_info) const {
469 return reg_info->byte_offset -
470 GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
471}
472
473Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
474 int regset = NT_PPC_VMX;
475 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
476 &regset, &m_vmx_ppc64le,
477 sizeof(m_vmx_ppc64le));
478}
479
480Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
481 int regset = NT_PPC_VMX;
482 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
483 &regset, &m_vmx_ppc64le,
484 sizeof(m_vmx_ppc64le));
485}
486
487Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
488 int regset = NT_PPC_VSX;
489 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
490 &regset, &m_vsx_ppc64le,
491 sizeof(m_vsx_ppc64le));
492}
493
494Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
495 int regset = NT_PPC_VSX;
496 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
497 &regset, &m_vsx_ppc64le,
498 sizeof(m_vsx_ppc64le));
499}
500
501bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
502 return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
503}
504
505bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
506 return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
507}
508
509uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
511
512 // Read hardware breakpoint and watchpoint information.
514
515 if (error.Fail())
516 return 0;
517
518 LLDB_LOG(log, "{0}", m_max_hwp_supported);
519 return m_max_hwp_supported;
520}
521
522uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
523 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
525 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
526 watch_flags);
527
528 // Read hardware breakpoint and watchpoint information.
530
531 if (error.Fail())
533
534 uint32_t control_value = 0, wp_index = 0;
535 lldb::addr_t real_addr = addr;
536 uint32_t rw_mode = 0;
537
538 // Check if we are setting watchpoint other than read/write/access Update
539 // watchpoint flag to match ppc64le write-read bit configuration.
540 switch (watch_flags) {
541 case eWatchpointKindWrite:
542 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
543 watch_flags = 2;
544 break;
545 case eWatchpointKindRead:
546 rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
547 watch_flags = 1;
548 break;
549 case (eWatchpointKindRead | eWatchpointKindWrite):
550 rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
551 break;
552 default:
554 }
555
556 // Check if size has a valid hardware watchpoint length.
557 if (size != 1 && size != 2 && size != 4 && size != 8)
559
560 // Check 8-byte alignment for hardware watchpoint target address. Below is a
561 // hack to recalculate address and size in order to make sure we can watch
562 // non 8-byte aligned addresses as well.
563 if (addr & 0x07) {
564
565 addr_t begin = llvm::alignDown(addr, 8);
566 addr_t end = llvm::alignTo(addr + size, 8);
567 size = llvm::PowerOf2Ceil(end - begin);
568
569 addr = addr & (~0x07);
570 }
571
572 // Setup control value
573 control_value = watch_flags << 3;
574 control_value |= ((1 << size) - 1) << 5;
575 control_value |= (2 << 1) | 1;
576
577 // Iterate over stored watchpoints and find a free wp_index
578 wp_index = LLDB_INVALID_INDEX32;
579 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
580 if ((m_hwp_regs[i].control & 1) == 0) {
581 wp_index = i; // Mark last free slot
582 } else if (m_hwp_regs[i].address == addr) {
583 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
584 }
585 }
586
587 if (wp_index == LLDB_INVALID_INDEX32)
589
590 // Update watchpoint in local cache
591 m_hwp_regs[wp_index].real_addr = real_addr;
592 m_hwp_regs[wp_index].address = addr;
593 m_hwp_regs[wp_index].control = control_value;
594 m_hwp_regs[wp_index].mode = rw_mode;
595
596 // PTRACE call to set corresponding watchpoint register.
598
599 if (error.Fail()) {
600 m_hwp_regs[wp_index].address = 0;
601 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
602
604 }
605
606 return wp_index;
607}
608
609bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
610 uint32_t wp_index) {
612 LLDB_LOG(log, "wp_index: {0}", wp_index);
613
614 // Read hardware breakpoint and watchpoint information.
616
617 if (error.Fail())
618 return false;
619
620 if (wp_index >= m_max_hwp_supported)
621 return false;
622
623 // Create a backup we can revert to in case of failure.
624 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
625 uint32_t tempControl = m_hwp_regs[wp_index].control;
626 long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
627
628 // Update watchpoint in local cache
629 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
630 m_hwp_regs[wp_index].address = 0;
631 m_hwp_regs[wp_index].slot = 0;
632 m_hwp_regs[wp_index].mode = 0;
633
634 // Ptrace call to update hardware debug registers
635 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
636 m_thread.GetID(), 0, tempSlot);
637
638 if (error.Fail()) {
639 m_hwp_regs[wp_index].control = tempControl;
640 m_hwp_regs[wp_index].address = tempAddr;
641 m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
642
643 return false;
644 }
645
646 return true;
647}
648
649uint32_t
650NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
652 LLDB_LOG(log, "wp_index: {0}", wp_index);
653
654 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
655 if (llvm::isPowerOf2_32(control + 1)) {
656 return llvm::popcount(control);
657 }
658
659 return 0;
660}
661
662bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
663 uint32_t wp_index) {
665 LLDB_LOG(log, "wp_index: {0}", wp_index);
666
667 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
668}
669
670Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
671 uint32_t &wp_index, lldb::addr_t trap_addr) {
673 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
674
675 uint32_t watch_size;
676 lldb::addr_t watch_addr;
677
678 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
679 watch_size = GetWatchpointSize(wp_index);
680 watch_addr = m_hwp_regs[wp_index].address;
681
682 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
683 trap_addr <= watch_addr + watch_size) {
684 m_hwp_regs[wp_index].hit_addr = trap_addr;
685 return Status();
686 }
687 }
688
689 wp_index = LLDB_INVALID_INDEX32;
690 return Status();
691}
692
694NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
696 LLDB_LOG(log, "wp_index: {0}", wp_index);
697
698 if (wp_index >= m_max_hwp_supported)
700
701 if (WatchpointIsEnabled(wp_index))
702 return m_hwp_regs[wp_index].real_addr;
703 else
705}
706
708NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
710 LLDB_LOG(log, "wp_index: {0}", wp_index);
711
712 if (wp_index >= m_max_hwp_supported)
714
715 if (WatchpointIsEnabled(wp_index))
716 return m_hwp_regs[wp_index].hit_addr;
717
719}
720
721Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
722 if (!m_refresh_hwdebug_info) {
723 return Status();
724 }
725
726 ::pid_t tid = m_thread.GetID();
727
728 struct ppc_debug_info hwdebug_info;
730
732 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
733
734 if (error.Fail())
735 return error;
736
737 m_max_hwp_supported = hwdebug_info.num_data_bps;
738 m_max_hbp_supported = hwdebug_info.num_instruction_bps;
739 m_refresh_hwdebug_info = false;
740
741 return error;
742}
743
744Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
745 struct ppc_hw_breakpoint reg_state;
747 long ret;
748
749 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
750 reg_state.addr = m_hwp_regs[i].address;
751 reg_state.trigger_type = m_hwp_regs[i].mode;
752 reg_state.version = 1;
753 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
754 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
755 reg_state.addr2 = 0;
756 reg_state.condition_value = 0;
757
758 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
759 m_thread.GetID(), 0, &reg_state,
760 sizeof(reg_state), &ret);
761
762 if (error.Fail())
763 return error;
764
765 m_hwp_regs[i].slot = ret;
766 }
767
768 return error;
769}
770
771#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:364
#define REG_CONTEXT_SIZE
static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets]
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
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr=nullptr, void *data=nullptr, size_t data_size=0, long *result=nullptr)
}
static std::unique_ptr< NativeRegisterContextLinux > CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, NativeThreadLinux &native_thread)
static llvm::Expected< ArchSpec > DetermineArchitecture(lldb::tid_t tid)
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_REGNUM
@ k_num_gpr_registers_ppc64le
@ k_num_vsx_registers_ppc64le
@ k_num_vmx_registers_ppc64le
@ k_num_fpr_registers_ppc64le
Status WriteHardwareDebugRegs(int hwbType, ::pid_t tid, uint32_t max_supported, const std::array< NativeRegisterContextDBReg::DREG, 16 > &regs)
Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported, uint32_t &max_hbp_supported)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:327
uint64_t pid_t
Definition lldb-types.h:83
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
uint64_t tid_t
Definition lldb-types.h:84
@ 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.