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
20#include "lldb/Host/HostInfo.h"
23#include "lldb/Utility/Log.h"
25#include "lldb/Utility/Status.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 <asm/ptrace.h>
30#include <elf.h>
31#include <sys/socket.h>
32
33#define REG_CONTEXT_SIZE \
34 (GetGPRSize() + GetFPRSize() + sizeof(m_vmx_ppc64le) + sizeof(m_vsx_ppc64le))
35using namespace lldb;
36using namespace lldb_private;
37using namespace lldb_private::process_linux;
38
39static const uint32_t g_gpr_regnums_ppc64le[] = {
51 LLDB_INVALID_REGNUM // register sets need to end with this flag
52};
53
54static const uint32_t g_fpr_regnums_ppc64le[] = {
64 LLDB_INVALID_REGNUM // register sets need to end with this flag
65};
66
67static const uint32_t g_vmx_regnums_ppc64le[] = {
77 LLDB_INVALID_REGNUM // register sets need to end with this flag
78};
79
80static const uint32_t g_vsx_regnums_ppc64le[] = {
97 LLDB_INVALID_REGNUM // register sets need to end with this flag
98};
99
100// Number of register sets provided by this context.
101static constexpr int k_num_register_sets = 4;
102
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
114std::unique_ptr<NativeRegisterContextLinux>
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
126llvm::Expected<ArchSpec>
128 return HostInfo::GetArchitecture();
129}
130
131NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
132 const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
134 native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)),
135 NativeRegisterContextLinux(native_thread) {
136 if (target_arch.GetMachine() != llvm::Triple::ppc64le) {
137 llvm_unreachable("Unhandled target architecture.");
138 }
139
140 ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
141 ::memset(&m_fpr_ppc64le, 0, sizeof(m_fpr_ppc64le));
142 ::memset(&m_vmx_ppc64le, 0, sizeof(m_vmx_ppc64le));
143 ::memset(&m_vsx_ppc64le, 0, sizeof(m_vsx_ppc64le));
144}
145
146uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
147 return k_num_register_sets;
148}
149
150const RegisterSet *
151NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
152 if (set_index < k_num_register_sets)
153 return &g_reg_sets_ppc64le[set_index];
154
155 return nullptr;
156}
157
158uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
159 uint32_t count = 0;
160 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
161 count += g_reg_sets_ppc64le[set_index].num_registers;
162 return count;
163}
164
165Status NativeRegisterContextLinux_ppc64le::ReadRegister(
166 const RegisterInfo *reg_info, RegisterValue &reg_value) {
168
169 if (!reg_info) {
170 error = Status::FromErrorString("reg_info NULL");
171 return error;
172 }
173
174 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
175
176 if (IsFPR(reg)) {
177 error = ReadFPR();
178 if (error.Fail())
179 return error;
180
181 // Get pointer to m_fpr_ppc64le variable and set the data from it.
182 uint32_t fpr_offset = CalculateFprOffset(reg_info);
183 assert(fpr_offset < sizeof m_fpr_ppc64le);
184 uint8_t *src = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
185 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
187 } else if (IsVSX(reg)) {
188 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
189 assert(vsx_offset < sizeof(m_vsx_ppc64le));
190
191 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
192 error = ReadVSX();
193 if (error.Fail())
194 return error;
195
196 error = ReadFPR();
197 if (error.Fail())
198 return error;
199
200 uint64_t value[2];
201 uint8_t *dst, *src;
202 dst = (uint8_t *)&value;
203 src = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
204 ::memcpy(dst, src, 8);
205 dst += 8;
206 src = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
207 ::memcpy(dst, src, 8);
208 reg_value.SetFromMemoryData(*reg_info, &value, reg_info->byte_size,
210 } else {
211 error = ReadVMX();
212 if (error.Fail())
213 return error;
214
215 // Get pointer to m_vmx_ppc64le variable and set the data from it.
216 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
217 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
218 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
220 }
221 } else if (IsVMX(reg)) {
222 error = ReadVMX();
223 if (error.Fail())
224 return error;
225
226 // Get pointer to m_vmx_ppc64le variable and set the data from it.
227 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
228 assert(vmx_offset < sizeof m_vmx_ppc64le);
229 uint8_t *src = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
230 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
232 } else if (IsGPR(reg)) {
233 error = ReadGPR();
234 if (error.Fail())
235 return error;
236
237 uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
238 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,
240 } else {
242 "failed - register wasn't recognized to be a GPR, FPR, VSX "
243 "or VMX, read strategy unknown");
244 }
245
246 return error;
247}
248
249Status NativeRegisterContextLinux_ppc64le::WriteRegister(
250 const RegisterInfo *reg_info, const RegisterValue &reg_value) {
252 if (!reg_info)
253 return Status::FromErrorString("reg_info NULL");
254
255 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
256 if (reg_index == LLDB_INVALID_REGNUM)
258 "no lldb regnum for %s",
259 reg_info && reg_info->name ? reg_info->name : "<unknown register>");
260
261 if (IsGPR(reg_index)) {
262 error = ReadGPR();
263 if (error.Fail())
264 return error;
265
266 uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset;
267 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
268
269 error = WriteGPR();
270 if (error.Fail())
271 return error;
272
273 return Status();
274 }
275
276 if (IsFPR(reg_index)) {
277 error = ReadFPR();
278 if (error.Fail())
279 return error;
280
281 // Get pointer to m_fpr_ppc64le variable and set the data to it.
282 uint32_t fpr_offset = CalculateFprOffset(reg_info);
283 assert(fpr_offset < GetFPRSize());
284 uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
285 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
286
287 error = WriteFPR();
288 if (error.Fail())
289 return error;
290
291 return Status();
292 }
293
294 if (IsVMX(reg_index)) {
295 error = ReadVMX();
296 if (error.Fail())
297 return error;
298
299 // Get pointer to m_vmx_ppc64le variable and set the data to it.
300 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
301 assert(vmx_offset < sizeof(m_vmx_ppc64le));
302 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
303 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
304
305 error = WriteVMX();
306 if (error.Fail())
307 return error;
308
309 return Status();
310 }
311
312 if (IsVSX(reg_index)) {
313 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
314 assert(vsx_offset < sizeof(m_vsx_ppc64le));
315
316 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
317 error = ReadVSX();
318 if (error.Fail())
319 return error;
320
321 error = ReadFPR();
322 if (error.Fail())
323 return error;
324
325 uint64_t value[2];
326 ::memcpy(value, reg_value.GetBytes(), 16);
327 uint8_t *dst, *src;
328 src = (uint8_t *)value;
329 dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
330 ::memcpy(dst, src, 8);
331 src += 8;
332 dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
333 ::memcpy(dst, src, 8);
334
335 WriteVSX();
336 WriteFPR();
337 } else {
338 error = ReadVMX();
339 if (error.Fail())
340 return error;
341
342 // Get pointer to m_vmx_ppc64le variable and set the data from it.
343 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
344 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
345 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
346 WriteVMX();
347 }
348
349 return Status();
350 }
351
353 "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) {
396 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
397 __FUNCTION__);
398 return error;
399 }
400
401 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
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) {
412 "NativeRegisterContextLinux_ppc64le::%s "
413 "DataBuffer::GetBytes() returned a null "
414 "pointer",
415 __FUNCTION__);
416 return error;
417 }
418
419 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
420 error = WriteGPR();
421
422 if (error.Fail())
423 return error;
424
425 src += GetGPRSize();
426 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
427
428 error = WriteFPR();
429 if (error.Fail())
430 return error;
431
432 src += GetFPRSize();
433 ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
434
435 error = WriteVMX();
436 if (error.Fail())
437 return error;
438
439 src += sizeof(m_vmx_ppc64le);
440 ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
441 error = WriteVSX();
442
443 return error;
444}
445
446bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
447 return reg <= k_last_gpr_ppc64le; // GPR's come first.
448}
449
450bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
451 return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
452}
453
454uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
455 const RegisterInfo *reg_info) const {
456 return reg_info->byte_offset -
457 GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
458}
459
460uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
461 const RegisterInfo *reg_info) const {
462 return reg_info->byte_offset -
463 GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
464}
465
466uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
467 const RegisterInfo *reg_info) const {
468 return reg_info->byte_offset -
469 GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
470}
471
472Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
473 int regset = NT_PPC_VMX;
474 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
475 &regset, &m_vmx_ppc64le,
476 sizeof(m_vmx_ppc64le));
477}
478
479Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
480 int regset = NT_PPC_VMX;
481 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
482 &regset, &m_vmx_ppc64le,
483 sizeof(m_vmx_ppc64le));
484}
485
486Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
487 int regset = NT_PPC_VSX;
488 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
489 &regset, &m_vsx_ppc64le,
490 sizeof(m_vsx_ppc64le));
491}
492
493Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
494 int regset = NT_PPC_VSX;
495 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
496 &regset, &m_vsx_ppc64le,
497 sizeof(m_vsx_ppc64le));
498}
499
500bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
501 return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
502}
503
504bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
505 return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
506}
507
508uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
510
511 // Read hardware breakpoint and watchpoint information.
513
514 if (error.Fail())
515 return 0;
516
517 LLDB_LOG(log, "{0}", m_max_hwp_supported);
518 return m_max_hwp_supported;
519}
520
521uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
522 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
524 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
525 watch_flags);
526
527 // Read hardware breakpoint and watchpoint information.
529
530 if (error.Fail())
532
533 uint32_t control_value = 0, wp_index = 0;
534 lldb::addr_t real_addr = addr;
535 uint32_t rw_mode = 0;
536
537 // Check if we are setting watchpoint other than read/write/access Update
538 // watchpoint flag to match ppc64le write-read bit configuration.
539 switch (watch_flags) {
540 case eWatchpointKindWrite:
541 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
542 watch_flags = 2;
543 break;
544 case eWatchpointKindRead:
545 rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
546 watch_flags = 1;
547 break;
548 case (eWatchpointKindRead | eWatchpointKindWrite):
549 rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
550 break;
551 default:
553 }
554
555 // Check if size has a valid hardware watchpoint length.
556 if (size != 1 && size != 2 && size != 4 && size != 8)
558
559 // Check 8-byte alignment for hardware watchpoint target address. Below is a
560 // hack to recalculate address and size in order to make sure we can watch
561 // non 8-byte aligned addresses as well.
562 if (addr & 0x07) {
563
564 addr_t begin = llvm::alignDown(addr, 8);
565 addr_t end = llvm::alignTo(addr + size, 8);
566 size = llvm::PowerOf2Ceil(end - begin);
567
568 addr = addr & (~0x07);
569 }
570
571 // Setup control value
572 control_value = watch_flags << 3;
573 control_value |= ((1 << size) - 1) << 5;
574 control_value |= (2 << 1) | 1;
575
576 // Iterate over stored watchpoints and find a free wp_index
577 wp_index = LLDB_INVALID_INDEX32;
578 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
579 if ((m_hwp_regs[i].control & 1) == 0) {
580 wp_index = i; // Mark last free slot
581 } else if (m_hwp_regs[i].address == addr) {
582 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
583 }
584 }
585
586 if (wp_index == LLDB_INVALID_INDEX32)
588
589 // Update watchpoint in local cache
590 m_hwp_regs[wp_index].real_addr = real_addr;
591 m_hwp_regs[wp_index].address = addr;
592 m_hwp_regs[wp_index].control = control_value;
593 m_hwp_regs[wp_index].mode = rw_mode;
594
595 // PTRACE call to set corresponding watchpoint register.
597
598 if (error.Fail()) {
599 m_hwp_regs[wp_index].address = 0;
600 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
601
603 }
604
605 return wp_index;
606}
607
608bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
609 uint32_t wp_index) {
611 LLDB_LOG(log, "wp_index: {0}", wp_index);
612
613 // Read hardware breakpoint and watchpoint information.
615
616 if (error.Fail())
617 return false;
618
619 if (wp_index >= m_max_hwp_supported)
620 return false;
621
622 // Create a backup we can revert to in case of failure.
623 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
624 uint32_t tempControl = m_hwp_regs[wp_index].control;
625 long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
626
627 // Update watchpoint in local cache
628 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
629 m_hwp_regs[wp_index].address = 0;
630 m_hwp_regs[wp_index].slot = 0;
631 m_hwp_regs[wp_index].mode = 0;
632
633 // Ptrace call to update hardware debug registers
634 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
635 m_thread.GetID(), 0, tempSlot);
636
637 if (error.Fail()) {
638 m_hwp_regs[wp_index].control = tempControl;
639 m_hwp_regs[wp_index].address = tempAddr;
640 m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
641
642 return false;
643 }
644
645 return true;
646}
647
648uint32_t
649NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
651 LLDB_LOG(log, "wp_index: {0}", wp_index);
652
653 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
654 if (llvm::isPowerOf2_32(control + 1)) {
655 return llvm::popcount(control);
656 }
657
658 return 0;
659}
660
661bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
662 uint32_t wp_index) {
664 LLDB_LOG(log, "wp_index: {0}", wp_index);
665
666 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
667}
668
669Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
670 uint32_t &wp_index, lldb::addr_t trap_addr) {
672 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
673
674 uint32_t watch_size;
675 lldb::addr_t watch_addr;
676
677 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
678 watch_size = GetWatchpointSize(wp_index);
679 watch_addr = m_hwp_regs[wp_index].address;
680
681 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
682 trap_addr <= watch_addr + watch_size) {
683 m_hwp_regs[wp_index].hit_addr = trap_addr;
684 return Status();
685 }
686 }
687
688 wp_index = LLDB_INVALID_INDEX32;
689 return Status();
690}
691
693NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
695 LLDB_LOG(log, "wp_index: {0}", wp_index);
696
697 if (wp_index >= m_max_hwp_supported)
699
700 if (WatchpointIsEnabled(wp_index))
701 return m_hwp_regs[wp_index].real_addr;
702 else
704}
705
707NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
709 LLDB_LOG(log, "wp_index: {0}", wp_index);
710
711 if (wp_index >= m_max_hwp_supported)
713
714 if (WatchpointIsEnabled(wp_index))
715 return m_hwp_regs[wp_index].hit_addr;
716
718}
719
720Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
721 if (!m_refresh_hwdebug_info) {
722 return Status();
723 }
724
725 ::pid_t tid = m_thread.GetID();
726
727 struct ppc_debug_info hwdebug_info;
729
731 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
732
733 if (error.Fail())
734 return error;
735
736 m_max_hwp_supported = hwdebug_info.num_data_bps;
737 m_max_hbp_supported = hwdebug_info.num_instruction_bps;
738 m_refresh_hwdebug_info = false;
739
740 return error;
741}
742
743Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
744 struct ppc_hw_breakpoint reg_state;
746 long ret;
747
748 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
749 reg_state.addr = m_hwp_regs[i].address;
750 reg_state.trigger_type = m_hwp_regs[i].mode;
751 reg_state.version = 1;
752 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
753 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
754 reg_state.addr2 = 0;
755 reg_state.condition_value = 0;
756
757 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
758 m_thread.GetID(), 0, &reg_state,
759 sizeof(reg_state), &ret);
760
761 if (error.Fail())
762 return error;
763
764 m_hwp_regs[i].slot = ret;
765 }
766
767 return error;
768}
769
770#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:375
#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:338
uint64_t pid_t
Definition lldb-types.h:84
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:85
@ 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.