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 = Status::FromErrorString("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::FromErrorString(
244 "failed - register wasn't recognized to be a GPR, FPR, VSX "
245 "or VMX, read strategy unknown");
246 }
247
248 return error;
249}
250
251Status NativeRegisterContextLinux_ppc64le::WriteRegister(
252 const RegisterInfo *reg_info, const RegisterValue &reg_value) {
254 if (!reg_info)
255 return Status::FromErrorString("reg_info NULL");
256
257 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
258 if (reg_index == LLDB_INVALID_REGNUM)
259 return Status::FromErrorStringWithFormat(
260 "no lldb regnum for %s",
261 reg_info && reg_info->name ? reg_info->name : "<unknown register>");
262
263 if (IsGPR(reg_index)) {
264 error = ReadGPR();
265 if (error.Fail())
266 return error;
267
268 uint8_t *dst = (uint8_t *)&m_gpr_ppc64le + reg_info->byte_offset;
269 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
270
271 error = WriteGPR();
272 if (error.Fail())
273 return error;
274
275 return Status();
276 }
277
278 if (IsFPR(reg_index)) {
279 error = ReadFPR();
280 if (error.Fail())
281 return error;
282
283 // Get pointer to m_fpr_ppc64le variable and set the data to it.
284 uint32_t fpr_offset = CalculateFprOffset(reg_info);
285 assert(fpr_offset < GetFPRSize());
286 uint8_t *dst = (uint8_t *)&m_fpr_ppc64le + fpr_offset;
287 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
288
289 error = WriteFPR();
290 if (error.Fail())
291 return error;
292
293 return Status();
294 }
295
296 if (IsVMX(reg_index)) {
297 error = ReadVMX();
298 if (error.Fail())
299 return error;
300
301 // Get pointer to m_vmx_ppc64le variable and set the data to it.
302 uint32_t vmx_offset = CalculateVmxOffset(reg_info);
303 assert(vmx_offset < sizeof(m_vmx_ppc64le));
304 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
305 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
306
307 error = WriteVMX();
308 if (error.Fail())
309 return error;
310
311 return Status();
312 }
313
314 if (IsVSX(reg_index)) {
315 uint32_t vsx_offset = CalculateVsxOffset(reg_info);
316 assert(vsx_offset < sizeof(m_vsx_ppc64le));
317
318 if (vsx_offset < sizeof(m_vsx_ppc64le) / 2) {
319 error = ReadVSX();
320 if (error.Fail())
321 return error;
322
323 error = ReadFPR();
324 if (error.Fail())
325 return error;
326
327 uint64_t value[2];
328 ::memcpy(value, reg_value.GetBytes(), 16);
329 uint8_t *dst, *src;
330 src = (uint8_t *)value;
331 dst = (uint8_t *)&m_vsx_ppc64le + vsx_offset / 2;
332 ::memcpy(dst, src, 8);
333 src += 8;
334 dst = (uint8_t *)&m_fpr_ppc64le + vsx_offset / 2;
335 ::memcpy(dst, src, 8);
336
337 WriteVSX();
338 WriteFPR();
339 } else {
340 error = ReadVMX();
341 if (error.Fail())
342 return error;
343
344 // Get pointer to m_vmx_ppc64le variable and set the data from it.
345 uint32_t vmx_offset = vsx_offset - sizeof(m_vsx_ppc64le) / 2;
346 uint8_t *dst = (uint8_t *)&m_vmx_ppc64le + vmx_offset;
347 ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
348 WriteVMX();
349 }
350
351 return Status();
352 }
353
354 return Status::FromErrorString(
355 "failed - register wasn't recognized to be a GPR, FPR, VSX "
356 "or VMX, write strategy unknown");
357}
358
359Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
362
363 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
364 error = ReadGPR();
365 if (error.Fail())
366 return error;
367
368 error = ReadFPR();
369 if (error.Fail())
370 return error;
371
372 error = ReadVMX();
373 if (error.Fail())
374 return error;
375
376 error = ReadVSX();
377 if (error.Fail())
378 return error;
379
380 uint8_t *dst = data_sp->GetBytes();
381 ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
382 dst += GetGPRSize();
383 ::memcpy(dst, &m_fpr_ppc64le, GetFPRSize());
384 dst += GetFPRSize();
385 ::memcpy(dst, &m_vmx_ppc64le, sizeof(m_vmx_ppc64le));
386 dst += sizeof(m_vmx_ppc64le);
387 ::memcpy(dst, &m_vsx_ppc64le, sizeof(m_vsx_ppc64le));
388
389 return error;
390}
391
392Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
393 const lldb::DataBufferSP &data_sp) {
395
396 if (!data_sp) {
397 error = Status::FromErrorStringWithFormat(
398 "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
399 __FUNCTION__);
400 return error;
401 }
402
403 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
404 error = Status::FromErrorStringWithFormat(
405 "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
406 "data size, expected %" PRIu64 ", actual %" PRIu64,
407 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
408 return error;
409 }
410
411 const uint8_t *src = data_sp->GetBytes();
412 if (src == nullptr) {
413 error = Status::FromErrorStringWithFormat(
414 "NativeRegisterContextLinux_ppc64le::%s "
415 "DataBuffer::GetBytes() returned a null "
416 "pointer",
417 __FUNCTION__);
418 return error;
419 }
420
421 ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
422 error = WriteGPR();
423
424 if (error.Fail())
425 return error;
426
427 src += GetGPRSize();
428 ::memcpy(&m_fpr_ppc64le, src, GetFPRSize());
429
430 error = WriteFPR();
431 if (error.Fail())
432 return error;
433
434 src += GetFPRSize();
435 ::memcpy(&m_vmx_ppc64le, src, sizeof(m_vmx_ppc64le));
436
437 error = WriteVMX();
438 if (error.Fail())
439 return error;
440
441 src += sizeof(m_vmx_ppc64le);
442 ::memcpy(&m_vsx_ppc64le, src, sizeof(m_vsx_ppc64le));
443 error = WriteVSX();
444
445 return error;
446}
447
448bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
449 return reg <= k_last_gpr_ppc64le; // GPR's come first.
450}
451
452bool NativeRegisterContextLinux_ppc64le::IsFPR(unsigned reg) const {
453 return (k_first_fpr_ppc64le <= reg && reg <= k_last_fpr_ppc64le);
454}
455
456uint32_t NativeRegisterContextLinux_ppc64le::CalculateFprOffset(
457 const RegisterInfo *reg_info) const {
458 return reg_info->byte_offset -
459 GetRegisterInfoAtIndex(k_first_fpr_ppc64le)->byte_offset;
460}
461
462uint32_t NativeRegisterContextLinux_ppc64le::CalculateVmxOffset(
463 const RegisterInfo *reg_info) const {
464 return reg_info->byte_offset -
465 GetRegisterInfoAtIndex(k_first_vmx_ppc64le)->byte_offset;
466}
467
468uint32_t NativeRegisterContextLinux_ppc64le::CalculateVsxOffset(
469 const RegisterInfo *reg_info) const {
470 return reg_info->byte_offset -
471 GetRegisterInfoAtIndex(k_first_vsx_ppc64le)->byte_offset;
472}
473
474Status NativeRegisterContextLinux_ppc64le::ReadVMX() {
475 int regset = NT_PPC_VMX;
476 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVRREGS, m_thread.GetID(),
477 &regset, &m_vmx_ppc64le,
478 sizeof(m_vmx_ppc64le));
479}
480
481Status NativeRegisterContextLinux_ppc64le::WriteVMX() {
482 int regset = NT_PPC_VMX;
483 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVRREGS, m_thread.GetID(),
484 &regset, &m_vmx_ppc64le,
485 sizeof(m_vmx_ppc64le));
486}
487
488Status NativeRegisterContextLinux_ppc64le::ReadVSX() {
489 int regset = NT_PPC_VSX;
490 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVSRREGS, m_thread.GetID(),
491 &regset, &m_vsx_ppc64le,
492 sizeof(m_vsx_ppc64le));
493}
494
495Status NativeRegisterContextLinux_ppc64le::WriteVSX() {
496 int regset = NT_PPC_VSX;
497 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVSRREGS, m_thread.GetID(),
498 &regset, &m_vsx_ppc64le,
499 sizeof(m_vsx_ppc64le));
500}
501
502bool NativeRegisterContextLinux_ppc64le::IsVMX(unsigned reg) {
503 return (reg >= k_first_vmx_ppc64le) && (reg <= k_last_vmx_ppc64le);
504}
505
506bool NativeRegisterContextLinux_ppc64le::IsVSX(unsigned reg) {
507 return (reg >= k_first_vsx_ppc64le) && (reg <= k_last_vsx_ppc64le);
508}
509
510uint32_t NativeRegisterContextLinux_ppc64le::NumSupportedHardwareWatchpoints() {
511 Log *log = GetLog(POSIXLog::Watchpoints);
512
513 // Read hardware breakpoint and watchpoint information.
514 Status error = ReadHardwareDebugInfo();
515
516 if (error.Fail())
517 return 0;
518
519 LLDB_LOG(log, "{0}", m_max_hwp_supported);
520 return m_max_hwp_supported;
521}
522
523uint32_t NativeRegisterContextLinux_ppc64le::SetHardwareWatchpoint(
524 lldb::addr_t addr, size_t size, uint32_t watch_flags) {
525 Log *log = GetLog(POSIXLog::Watchpoints);
526 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
527 watch_flags);
528
529 // Read hardware breakpoint and watchpoint information.
530 Status error = ReadHardwareDebugInfo();
531
532 if (error.Fail())
534
535 uint32_t control_value = 0, wp_index = 0;
536 lldb::addr_t real_addr = addr;
537 uint32_t rw_mode = 0;
538
539 // Check if we are setting watchpoint other than read/write/access Update
540 // watchpoint flag to match ppc64le write-read bit configuration.
541 switch (watch_flags) {
542 case eWatchpointKindWrite:
543 rw_mode = PPC_BREAKPOINT_TRIGGER_WRITE;
544 watch_flags = 2;
545 break;
546 case eWatchpointKindRead:
547 rw_mode = PPC_BREAKPOINT_TRIGGER_READ;
548 watch_flags = 1;
549 break;
550 case (eWatchpointKindRead | eWatchpointKindWrite):
551 rw_mode = PPC_BREAKPOINT_TRIGGER_RW;
552 break;
553 default:
555 }
556
557 // Check if size has a valid hardware watchpoint length.
558 if (size != 1 && size != 2 && size != 4 && size != 8)
560
561 // Check 8-byte alignment for hardware watchpoint target address. Below is a
562 // hack to recalculate address and size in order to make sure we can watch
563 // non 8-byte aligned addresses as well.
564 if (addr & 0x07) {
565
566 addr_t begin = llvm::alignDown(addr, 8);
567 addr_t end = llvm::alignTo(addr + size, 8);
568 size = llvm::PowerOf2Ceil(end - begin);
569
570 addr = addr & (~0x07);
571 }
572
573 // Setup control value
574 control_value = watch_flags << 3;
575 control_value |= ((1 << size) - 1) << 5;
576 control_value |= (2 << 1) | 1;
577
578 // Iterate over stored watchpoints and find a free wp_index
579 wp_index = LLDB_INVALID_INDEX32;
580 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
581 if ((m_hwp_regs[i].control & 1) == 0) {
582 wp_index = i; // Mark last free slot
583 } else if (m_hwp_regs[i].address == addr) {
584 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
585 }
586 }
587
588 if (wp_index == LLDB_INVALID_INDEX32)
590
591 // Update watchpoint in local cache
592 m_hwp_regs[wp_index].real_addr = real_addr;
593 m_hwp_regs[wp_index].address = addr;
594 m_hwp_regs[wp_index].control = control_value;
595 m_hwp_regs[wp_index].mode = rw_mode;
596
597 // PTRACE call to set corresponding watchpoint register.
598 error = WriteHardwareDebugRegs();
599
600 if (error.Fail()) {
601 m_hwp_regs[wp_index].address = 0;
602 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
603
605 }
606
607 return wp_index;
608}
609
610bool NativeRegisterContextLinux_ppc64le::ClearHardwareWatchpoint(
611 uint32_t wp_index) {
612 Log *log = GetLog(POSIXLog::Watchpoints);
613 LLDB_LOG(log, "wp_index: {0}", wp_index);
614
615 // Read hardware breakpoint and watchpoint information.
616 Status error = ReadHardwareDebugInfo();
617
618 if (error.Fail())
619 return false;
620
621 if (wp_index >= m_max_hwp_supported)
622 return false;
623
624 // Create a backup we can revert to in case of failure.
625 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
626 uint32_t tempControl = m_hwp_regs[wp_index].control;
627 long *tempSlot = reinterpret_cast<long *>(m_hwp_regs[wp_index].slot);
628
629 // Update watchpoint in local cache
630 m_hwp_regs[wp_index].control &= llvm::maskTrailingZeros<uint32_t>(1);
631 m_hwp_regs[wp_index].address = 0;
632 m_hwp_regs[wp_index].slot = 0;
633 m_hwp_regs[wp_index].mode = 0;
634
635 // Ptrace call to update hardware debug registers
636 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_DELHWDEBUG,
637 m_thread.GetID(), 0, tempSlot);
638
639 if (error.Fail()) {
640 m_hwp_regs[wp_index].control = tempControl;
641 m_hwp_regs[wp_index].address = tempAddr;
642 m_hwp_regs[wp_index].slot = reinterpret_cast<long>(tempSlot);
643
644 return false;
645 }
646
647 return true;
648}
649
650uint32_t
651NativeRegisterContextLinux_ppc64le::GetWatchpointSize(uint32_t wp_index) {
652 Log *log = GetLog(POSIXLog::Watchpoints);
653 LLDB_LOG(log, "wp_index: {0}", wp_index);
654
655 unsigned control = (m_hwp_regs[wp_index].control >> 5) & 0xff;
656 if (llvm::isPowerOf2_32(control + 1)) {
657 return llvm::popcount(control);
658 }
659
660 return 0;
661}
662
663bool NativeRegisterContextLinux_ppc64le::WatchpointIsEnabled(
664 uint32_t wp_index) {
665 Log *log = GetLog(POSIXLog::Watchpoints);
666 LLDB_LOG(log, "wp_index: {0}", wp_index);
667
668 return !!((m_hwp_regs[wp_index].control & 0x1) == 0x1);
669}
670
671Status NativeRegisterContextLinux_ppc64le::GetWatchpointHitIndex(
672 uint32_t &wp_index, lldb::addr_t trap_addr) {
673 Log *log = GetLog(POSIXLog::Watchpoints);
674 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
675
676 uint32_t watch_size;
677 lldb::addr_t watch_addr;
678
679 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
680 watch_size = GetWatchpointSize(wp_index);
681 watch_addr = m_hwp_regs[wp_index].address;
682
683 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
684 trap_addr <= watch_addr + watch_size) {
685 m_hwp_regs[wp_index].hit_addr = trap_addr;
686 return Status();
687 }
688 }
689
690 wp_index = LLDB_INVALID_INDEX32;
691 return Status();
692}
693
695NativeRegisterContextLinux_ppc64le::GetWatchpointAddress(uint32_t wp_index) {
696 Log *log = GetLog(POSIXLog::Watchpoints);
697 LLDB_LOG(log, "wp_index: {0}", wp_index);
698
699 if (wp_index >= m_max_hwp_supported)
701
702 if (WatchpointIsEnabled(wp_index))
703 return m_hwp_regs[wp_index].real_addr;
704 else
706}
707
709NativeRegisterContextLinux_ppc64le::GetWatchpointHitAddress(uint32_t wp_index) {
710 Log *log = GetLog(POSIXLog::Watchpoints);
711 LLDB_LOG(log, "wp_index: {0}", wp_index);
712
713 if (wp_index >= m_max_hwp_supported)
715
716 if (WatchpointIsEnabled(wp_index))
717 return m_hwp_regs[wp_index].hit_addr;
718
720}
721
722Status NativeRegisterContextLinux_ppc64le::ReadHardwareDebugInfo() {
723 if (!m_refresh_hwdebug_info) {
724 return Status();
725 }
726
727 ::pid_t tid = m_thread.GetID();
728
729 struct ppc_debug_info hwdebug_info;
731
732 error = NativeProcessLinux::PtraceWrapper(
733 PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info, sizeof(hwdebug_info));
734
735 if (error.Fail())
736 return error;
737
738 m_max_hwp_supported = hwdebug_info.num_data_bps;
739 m_max_hbp_supported = hwdebug_info.num_instruction_bps;
740 m_refresh_hwdebug_info = false;
741
742 return error;
743}
744
745Status NativeRegisterContextLinux_ppc64le::WriteHardwareDebugRegs() {
746 struct ppc_hw_breakpoint reg_state;
748 long ret;
749
750 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
751 reg_state.addr = m_hwp_regs[i].address;
752 reg_state.trigger_type = m_hwp_regs[i].mode;
753 reg_state.version = 1;
754 reg_state.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
755 reg_state.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
756 reg_state.addr2 = 0;
757 reg_state.condition_value = 0;
758
759 error = NativeProcessLinux::PtraceWrapper(PPC_PTRACE_SETHWDEBUG,
760 m_thread.GetID(), 0, &reg_state,
761 sizeof(reg_state), &ret);
762
763 if (error.Fail())
764 return error;
765
766 m_hwp_regs[i].slot = ret;
767 }
768
769 return error;
770}
771
772#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:369
#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:701
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:118
#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.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:332
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:336
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:337
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.