1 //===-- NativeRegisterContextLinux_arm.cpp --------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
11 #include "NativeRegisterContextLinux_arm.h"
13 #include "Plugins/Process/Linux/NativeProcessLinux.h"
14 #include "Plugins/Process/Linux/Procfs.h"
15 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
16 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
17 #include "lldb/Host/HostInfo.h"
18 #include "lldb/Utility/DataBufferHeap.h"
19 #include "lldb/Utility/Log.h"
20 #include "lldb/Utility/RegisterValue.h"
21 #include "lldb/Utility/Status.h"
26 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr))
28 #ifndef PTRACE_GETVFPREGS
29 #define PTRACE_GETVFPREGS 27
30 #define PTRACE_SETVFPREGS 28
32 #ifndef PTRACE_GETHBPREGS
33 #define PTRACE_GETHBPREGS 29
34 #define PTRACE_SETHBPREGS 30
36 #if !defined(PTRACE_TYPE_ARG3)
37 #define PTRACE_TYPE_ARG3 void *
39 #if !defined(PTRACE_TYPE_ARG4)
40 #define PTRACE_TYPE_ARG4 void *
44 using namespace lldb_private
;
45 using namespace lldb_private::process_linux
;
49 std::unique_ptr
<NativeRegisterContextLinux
>
50 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
51 const ArchSpec
&target_arch
, NativeThreadLinux
&native_thread
) {
52 return std::make_unique
<NativeRegisterContextLinux_arm
>(target_arch
,
56 llvm::Expected
<ArchSpec
>
57 NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid
) {
58 return HostInfo::GetArchitecture();
61 #endif // defined(__arm__)
63 NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
64 const ArchSpec
&target_arch
, NativeThreadProtocol
&native_thread
)
65 : NativeRegisterContextRegisterInfo(native_thread
,
66 new RegisterInfoPOSIX_arm(target_arch
)),
67 NativeRegisterContextLinux(native_thread
) {
68 assert(target_arch
.GetMachine() == llvm::Triple::arm
);
70 ::memset(&m_fpr
, 0, sizeof(m_fpr
));
71 ::memset(&m_gpr_arm
, 0, sizeof(m_gpr_arm
));
72 ::memset(&m_hwp_regs
, 0, sizeof(m_hwp_regs
));
73 ::memset(&m_hbr_regs
, 0, sizeof(m_hbr_regs
));
75 // 16 is just a maximum value, query hardware for actual watchpoint count
76 m_max_hwp_supported
= 16;
77 m_max_hbp_supported
= 16;
78 m_refresh_hwdebug_info
= true;
81 RegisterInfoPOSIX_arm
&NativeRegisterContextLinux_arm::GetRegisterInfo() const {
82 return static_cast<RegisterInfoPOSIX_arm
&>(*m_register_info_interface_up
);
85 uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const {
86 return GetRegisterInfo().GetRegisterSetCount();
89 uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const {
91 for (uint32_t set_index
= 0; set_index
< GetRegisterSetCount(); ++set_index
)
92 count
+= GetRegisterSet(set_index
)->num_registers
;
97 NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index
) const {
98 return GetRegisterInfo().GetRegisterSet(set_index
);
102 NativeRegisterContextLinux_arm::ReadRegister(const RegisterInfo
*reg_info
,
103 RegisterValue
®_value
) {
107 error
= Status::FromErrorString("reg_info NULL");
111 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
118 uint32_t full_reg
= reg
;
119 bool is_subreg
= reg_info
->invalidate_regs
&&
120 (reg_info
->invalidate_regs
[0] != LLDB_INVALID_REGNUM
);
123 // Read the full aligned 64-bit register.
124 full_reg
= reg_info
->invalidate_regs
[0];
127 error
= ReadRegisterRaw(full_reg
, reg_value
);
129 if (error
.Success()) {
130 // If our read was not aligned (for ah,bh,ch,dh), shift our returned
131 // value one byte to the right.
132 if (is_subreg
&& (reg_info
->byte_offset
& 0x1))
133 reg_value
.SetUInt64(reg_value
.GetAsUInt64() >> 8);
135 // If our return byte size was greater than the return value reg size,
136 // then use the type specified by reg_info rather than the uint64_t
138 if (reg_value
.GetByteSize() > reg_info
->byte_size
)
139 reg_value
.SetType(*reg_info
);
144 // Get pointer to m_fpr variable and set the data from it.
145 uint32_t fpr_offset
= CalculateFprOffset(reg_info
);
146 assert(fpr_offset
< sizeof m_fpr
);
147 uint8_t *src
= (uint8_t *)&m_fpr
+ fpr_offset
;
148 switch (reg_info
->byte_size
) {
150 reg_value
.SetUInt16(*(uint16_t *)src
);
153 reg_value
.SetUInt32(*(uint32_t *)src
);
156 reg_value
.SetUInt64(*(uint64_t *)src
);
159 reg_value
.SetBytes(src
, 16, GetByteOrder());
162 assert(false && "Unhandled data size.");
163 error
= Status::FromErrorStringWithFormat("unhandled byte size: %" PRIu32
,
164 reg_info
->byte_size
);
172 NativeRegisterContextLinux_arm::WriteRegister(const RegisterInfo
*reg_info
,
173 const RegisterValue
®_value
) {
175 return Status::FromErrorString("reg_info NULL");
177 const uint32_t reg_index
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
178 if (reg_index
== LLDB_INVALID_REGNUM
)
179 return Status::FromErrorStringWithFormat(
180 "no lldb regnum for %s",
181 reg_info
&& reg_info
->name
? reg_info
->name
: "<unknown register>");
183 if (IsGPR(reg_index
))
184 return WriteRegisterRaw(reg_index
, reg_value
);
186 if (IsFPR(reg_index
)) {
187 // Get pointer to m_fpr variable and set the data to it.
188 uint32_t fpr_offset
= CalculateFprOffset(reg_info
);
189 assert(fpr_offset
< sizeof m_fpr
);
190 uint8_t *dst
= (uint8_t *)&m_fpr
+ fpr_offset
;
191 ::memcpy(dst
, reg_value
.GetBytes(), reg_info
->byte_size
);
196 return Status::FromErrorString(
197 "failed - register wasn't recognized to be a GPR or an FPR, "
198 "write strategy unknown");
201 Status
NativeRegisterContextLinux_arm::ReadAllRegisterValues(
202 lldb::WritableDataBufferSP
&data_sp
) {
205 data_sp
.reset(new DataBufferHeap(REG_CONTEXT_SIZE
, 0));
214 uint8_t *dst
= data_sp
->GetBytes();
215 ::memcpy(dst
, &m_gpr_arm
, GetGPRSize());
217 ::memcpy(dst
, &m_fpr
, sizeof(m_fpr
));
222 Status
NativeRegisterContextLinux_arm::WriteAllRegisterValues(
223 const lldb::DataBufferSP
&data_sp
) {
227 error
= Status::FromErrorStringWithFormat(
228 "NativeRegisterContextLinux_arm::%s invalid data_sp provided",
233 if (data_sp
->GetByteSize() != REG_CONTEXT_SIZE
) {
234 error
= Status::FromErrorStringWithFormat(
235 "NativeRegisterContextLinux_arm::%s data_sp contained mismatched "
236 "data size, expected %" PRIu64
", actual %" PRIu64
,
237 __FUNCTION__
, (uint64_t)REG_CONTEXT_SIZE
, data_sp
->GetByteSize());
241 const uint8_t *src
= data_sp
->GetBytes();
242 if (src
== nullptr) {
243 error
= Status::FromErrorStringWithFormat(
244 "NativeRegisterContextLinux_arm::%s "
245 "DataBuffer::GetBytes() returned a null "
250 ::memcpy(&m_gpr_arm
, src
, GetRegisterInfoInterface().GetGPRSize());
256 src
+= GetRegisterInfoInterface().GetGPRSize();
257 ::memcpy(&m_fpr
, src
, sizeof(m_fpr
));
266 bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg
) const {
267 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg
) ==
268 RegisterInfoPOSIX_arm::GPRegSet
)
273 bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg
) const {
274 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg
) ==
275 RegisterInfoPOSIX_arm::FPRegSet
)
280 uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
281 Log
*log
= GetLog(POSIXLog::Breakpoints
);
283 LLDB_LOGF(log
, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__
);
287 // Read hardware breakpoint and watchpoint information.
288 error
= ReadHardwareDebugInfo();
293 LLDB_LOG(log
, "{0}", m_max_hbp_supported
);
294 return m_max_hbp_supported
;
298 NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr
,
300 Log
*log
= GetLog(POSIXLog::Breakpoints
);
301 LLDB_LOG(log
, "addr: {0:x}, size: {1:x}", addr
, size
);
303 // Read hardware breakpoint and watchpoint information.
304 Status error
= ReadHardwareDebugInfo();
307 return LLDB_INVALID_INDEX32
;
309 uint32_t control_value
= 0, bp_index
= 0;
311 // Setup address and control values.
312 // Use size to get a hint of arm vs thumb modes.
315 control_value
= (0x3 << 5) | 7;
319 control_value
= (0xfu
<< 5) | 7;
323 return LLDB_INVALID_INDEX32
;
326 // Iterate over stored breakpoints and find a free bp_index
327 bp_index
= LLDB_INVALID_INDEX32
;
328 for (uint32_t i
= 0; i
< m_max_hbp_supported
; i
++) {
329 if ((m_hbr_regs
[i
].control
& 1) == 0) {
330 bp_index
= i
; // Mark last free slot
331 } else if (m_hbr_regs
[i
].address
== addr
) {
332 return LLDB_INVALID_INDEX32
; // We do not support duplicate breakpoints.
336 if (bp_index
== LLDB_INVALID_INDEX32
)
337 return LLDB_INVALID_INDEX32
;
339 // Update breakpoint in local cache
340 m_hbr_regs
[bp_index
].real_addr
= addr
;
341 m_hbr_regs
[bp_index
].address
= addr
;
342 m_hbr_regs
[bp_index
].control
= control_value
;
344 // PTRACE call to set corresponding hardware breakpoint register.
345 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
, bp_index
);
348 m_hbr_regs
[bp_index
].address
= 0;
349 m_hbr_regs
[bp_index
].control
&= ~1;
351 return LLDB_INVALID_INDEX32
;
357 bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx
) {
358 Log
*log
= GetLog(POSIXLog::Breakpoints
);
359 LLDB_LOG(log
, "hw_idx: {0}", hw_idx
);
361 // Read hardware breakpoint and watchpoint information.
362 Status error
= ReadHardwareDebugInfo();
367 if (hw_idx
>= m_max_hbp_supported
)
370 // Create a backup we can revert to in case of failure.
371 lldb::addr_t tempAddr
= m_hbr_regs
[hw_idx
].address
;
372 uint32_t tempControl
= m_hbr_regs
[hw_idx
].control
;
374 m_hbr_regs
[hw_idx
].control
&= ~1;
375 m_hbr_regs
[hw_idx
].address
= 0;
377 // PTRACE call to clear corresponding hardware breakpoint register.
378 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
, hw_idx
);
381 m_hbr_regs
[hw_idx
].control
= tempControl
;
382 m_hbr_regs
[hw_idx
].address
= tempAddr
;
390 Status
NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
391 uint32_t &bp_index
, lldb::addr_t trap_addr
) {
392 Log
*log
= GetLog(POSIXLog::Breakpoints
);
394 LLDB_LOGF(log
, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__
);
396 lldb::addr_t break_addr
;
398 for (bp_index
= 0; bp_index
< m_max_hbp_supported
; ++bp_index
) {
399 break_addr
= m_hbr_regs
[bp_index
].address
;
401 if ((m_hbr_regs
[bp_index
].control
& 0x1) && (trap_addr
== break_addr
)) {
402 m_hbr_regs
[bp_index
].hit_addr
= trap_addr
;
407 bp_index
= LLDB_INVALID_INDEX32
;
411 Status
NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
412 Log
*log
= GetLog(POSIXLog::Breakpoints
);
414 LLDB_LOGF(log
, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__
);
418 // Read hardware breakpoint and watchpoint information.
419 error
= ReadHardwareDebugInfo();
424 lldb::addr_t tempAddr
= 0;
425 uint32_t tempControl
= 0;
427 for (uint32_t i
= 0; i
< m_max_hbp_supported
; i
++) {
428 if (m_hbr_regs
[i
].control
& 0x01) {
429 // Create a backup we can revert to in case of failure.
430 tempAddr
= m_hbr_regs
[i
].address
;
431 tempControl
= m_hbr_regs
[i
].control
;
433 // Clear breakpoints in local cache
434 m_hbr_regs
[i
].control
&= ~1;
435 m_hbr_regs
[i
].address
= 0;
437 // Ptrace call to update hardware debug registers
438 error
= WriteHardwareDebugRegs(eDREGTypeBREAK
, i
);
441 m_hbr_regs
[i
].control
= tempControl
;
442 m_hbr_regs
[i
].address
= tempAddr
;
452 uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
453 Log
*log
= GetLog(POSIXLog::Watchpoints
);
455 // Read hardware breakpoint and watchpoint information.
456 Status error
= ReadHardwareDebugInfo();
461 LLDB_LOG(log
, "{0}", m_max_hwp_supported
);
462 return m_max_hwp_supported
;
465 uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
466 lldb::addr_t addr
, size_t size
, uint32_t watch_flags
) {
467 Log
*log
= GetLog(POSIXLog::Watchpoints
);
468 LLDB_LOG(log
, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr
, size
,
471 // Read hardware breakpoint and watchpoint information.
472 Status error
= ReadHardwareDebugInfo();
475 return LLDB_INVALID_INDEX32
;
477 uint32_t control_value
= 0, wp_index
= 0, addr_word_offset
= 0, byte_mask
= 0;
478 lldb::addr_t real_addr
= addr
;
480 // Check if we are setting watchpoint other than read/write/access Also
481 // update watchpoint flag to match Arm write-read bit configuration.
482 switch (watch_flags
) {
492 return LLDB_INVALID_INDEX32
;
495 // Can't watch zero bytes
496 // Can't watch more than 4 bytes per WVR/WCR pair
498 if (size
== 0 || size
> 4)
499 return LLDB_INVALID_INDEX32
;
501 // Check 4-byte alignment for hardware watchpoint target address. Below is a
502 // hack to recalculate address and size in order to make sure we can watch
503 // non 4-byte aligned addresses as well.
505 uint8_t watch_mask
= (addr
& 0x03) + size
;
507 if (watch_mask
> 0x04)
508 return LLDB_INVALID_INDEX32
;
509 else if (watch_mask
<= 0x02)
514 addr
= addr
& (~0x03);
517 // We can only watch up to four bytes that follow a 4 byte aligned address
518 // per watchpoint register pair, so make sure we can properly encode this.
519 addr_word_offset
= addr
% 4;
520 byte_mask
= ((1u << size
) - 1u) << addr_word_offset
;
522 // Check if we need multiple watchpoint register
523 if (byte_mask
> 0xfu
)
524 return LLDB_INVALID_INDEX32
;
526 // Setup control value
527 // Make the byte_mask into a valid Byte Address Select mask
528 control_value
= byte_mask
<< 5;
530 // Turn on appropriate watchpoint flags read or write
531 control_value
|= (watch_flags
<< 3);
533 // Enable this watchpoint and make it stop in privileged or user mode;
536 // Make sure bits 1:0 are clear in our address
537 addr
&= ~((lldb::addr_t
)3);
539 // Iterate over stored watchpoints and find a free wp_index
540 wp_index
= LLDB_INVALID_INDEX32
;
541 for (uint32_t i
= 0; i
< m_max_hwp_supported
; i
++) {
542 if ((m_hwp_regs
[i
].control
& 1) == 0) {
543 wp_index
= i
; // Mark last free slot
544 } else if (m_hwp_regs
[i
].address
== addr
) {
545 return LLDB_INVALID_INDEX32
; // We do not support duplicate watchpoints.
549 if (wp_index
== LLDB_INVALID_INDEX32
)
550 return LLDB_INVALID_INDEX32
;
552 // Update watchpoint in local cache
553 m_hwp_regs
[wp_index
].real_addr
= real_addr
;
554 m_hwp_regs
[wp_index
].address
= addr
;
555 m_hwp_regs
[wp_index
].control
= control_value
;
557 // PTRACE call to set corresponding watchpoint register.
558 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
, wp_index
);
561 m_hwp_regs
[wp_index
].address
= 0;
562 m_hwp_regs
[wp_index
].control
&= ~1;
564 return LLDB_INVALID_INDEX32
;
570 bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
572 Log
*log
= GetLog(POSIXLog::Watchpoints
);
573 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
575 // Read hardware breakpoint and watchpoint information.
576 Status error
= ReadHardwareDebugInfo();
581 if (wp_index
>= m_max_hwp_supported
)
584 // Create a backup we can revert to in case of failure.
585 lldb::addr_t tempAddr
= m_hwp_regs
[wp_index
].address
;
586 uint32_t tempControl
= m_hwp_regs
[wp_index
].control
;
588 // Update watchpoint in local cache
589 m_hwp_regs
[wp_index
].control
&= ~1;
590 m_hwp_regs
[wp_index
].address
= 0;
592 // Ptrace call to update hardware debug registers
593 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
, wp_index
);
596 m_hwp_regs
[wp_index
].control
= tempControl
;
597 m_hwp_regs
[wp_index
].address
= tempAddr
;
605 Status
NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
606 // Read hardware breakpoint and watchpoint information.
607 Status error
= ReadHardwareDebugInfo();
612 lldb::addr_t tempAddr
= 0;
613 uint32_t tempControl
= 0;
615 for (uint32_t i
= 0; i
< m_max_hwp_supported
; i
++) {
616 if (m_hwp_regs
[i
].control
& 0x01) {
617 // Create a backup we can revert to in case of failure.
618 tempAddr
= m_hwp_regs
[i
].address
;
619 tempControl
= m_hwp_regs
[i
].control
;
621 // Clear watchpoints in local cache
622 m_hwp_regs
[i
].control
&= ~1;
623 m_hwp_regs
[i
].address
= 0;
625 // Ptrace call to update hardware debug registers
626 error
= WriteHardwareDebugRegs(eDREGTypeWATCH
, i
);
629 m_hwp_regs
[i
].control
= tempControl
;
630 m_hwp_regs
[i
].address
= tempAddr
;
640 uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index
) {
641 Log
*log
= GetLog(POSIXLog::Watchpoints
);
642 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
644 switch ((m_hwp_regs
[wp_index
].control
>> 5) & 0x0f) {
657 bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index
) {
658 Log
*log
= GetLog(POSIXLog::Watchpoints
);
659 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
661 if ((m_hwp_regs
[wp_index
].control
& 0x1) == 0x1)
668 NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index
,
669 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
);
674 lldb::addr_t watch_addr
;
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
;
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
;
687 wp_index
= LLDB_INVALID_INDEX32
;
692 NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index
) {
693 Log
*log
= GetLog(POSIXLog::Watchpoints
);
694 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
696 if (wp_index
>= m_max_hwp_supported
)
697 return LLDB_INVALID_ADDRESS
;
699 if (WatchpointIsEnabled(wp_index
))
700 return m_hwp_regs
[wp_index
].real_addr
;
702 return LLDB_INVALID_ADDRESS
;
706 NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index
) {
707 Log
*log
= GetLog(POSIXLog::Watchpoints
);
708 LLDB_LOG(log
, "wp_index: {0}", wp_index
);
710 if (wp_index
>= m_max_hwp_supported
)
711 return LLDB_INVALID_ADDRESS
;
713 if (WatchpointIsEnabled(wp_index
))
714 return m_hwp_regs
[wp_index
].hit_addr
;
716 return LLDB_INVALID_ADDRESS
;
719 Status
NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
722 if (!m_refresh_hwdebug_info
) {
726 unsigned int cap_val
;
728 error
= NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS
, m_thread
.GetID(),
730 sizeof(unsigned int));
735 m_max_hwp_supported
= (cap_val
>> 8) & 0xff;
736 m_max_hbp_supported
= cap_val
& 0xff;
737 m_refresh_hwdebug_info
= false;
742 Status
NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType
,
746 lldb::addr_t
*addr_buf
;
749 if (hwbType
== eDREGTypeWATCH
) {
750 addr_buf
= &m_hwp_regs
[hwb_index
].address
;
751 ctrl_buf
= &m_hwp_regs
[hwb_index
].control
;
753 error
= NativeProcessLinux::PtraceWrapper(
754 PTRACE_SETHBPREGS
, m_thread
.GetID(),
755 (PTRACE_TYPE_ARG3
)(intptr_t) - ((hwb_index
<< 1) + 1), addr_buf
,
756 sizeof(unsigned int));
761 error
= NativeProcessLinux::PtraceWrapper(
762 PTRACE_SETHBPREGS
, m_thread
.GetID(),
763 (PTRACE_TYPE_ARG3
)(intptr_t) - ((hwb_index
<< 1) + 2), ctrl_buf
,
764 sizeof(unsigned int));
766 addr_buf
= &m_hbr_regs
[hwb_index
].address
;
767 ctrl_buf
= &m_hbr_regs
[hwb_index
].control
;
769 error
= NativeProcessLinux::PtraceWrapper(
770 PTRACE_SETHBPREGS
, m_thread
.GetID(),
771 (PTRACE_TYPE_ARG3
)(intptr_t)((hwb_index
<< 1) + 1), addr_buf
,
772 sizeof(unsigned int));
777 error
= NativeProcessLinux::PtraceWrapper(
778 PTRACE_SETHBPREGS
, m_thread
.GetID(),
779 (PTRACE_TYPE_ARG3
)(intptr_t)((hwb_index
<< 1) + 2), ctrl_buf
,
780 sizeof(unsigned int));
786 uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
787 const RegisterInfo
*reg_info
) const {
788 return reg_info
->byte_offset
- GetGPRSize();
791 Status
NativeRegisterContextLinux_arm::DoReadRegisterValue(
792 uint32_t offset
, const char *reg_name
, uint32_t size
,
793 RegisterValue
&value
) {
794 // PTRACE_PEEKUSER don't work in the aarch64 linux kernel used on android
795 // devices (always return "Bad address"). To avoid using PTRACE_PEEKUSER we
796 // read out the full GPR register set instead. This approach is about 4 times
797 // slower but the performance overhead is negligible in comparison to
798 // processing time in lldb-server.
799 assert(offset
% 4 == 0 && "Try to write a register with unaligned offset");
800 if (offset
+ sizeof(uint32_t) > sizeof(m_gpr_arm
))
801 return Status::FromErrorString(
802 "Register isn't fit into the size of the GPR area");
804 Status error
= ReadGPR();
808 value
.SetUInt32(m_gpr_arm
[offset
/ sizeof(uint32_t)]);
812 Status
NativeRegisterContextLinux_arm::DoWriteRegisterValue(
813 uint32_t offset
, const char *reg_name
, const RegisterValue
&value
) {
814 // PTRACE_POKEUSER don't work in the aarch64 linux kernel used on android
815 // devices (always return "Bad address"). To avoid using PTRACE_POKEUSER we
816 // read out the full GPR register set, modify the requested register and
817 // write it back. This approach is about 4 times slower but the performance
818 // overhead is negligible in comparison to processing time in lldb-server.
819 assert(offset
% 4 == 0 && "Try to write a register with unaligned offset");
820 if (offset
+ sizeof(uint32_t) > sizeof(m_gpr_arm
))
821 return Status::FromErrorString(
822 "Register isn't fit into the size of the GPR area");
824 Status error
= ReadGPR();
828 uint32_t reg_value
= value
.GetAsUInt32();
829 // As precaution for an undefined behavior encountered while setting PC we
830 // will clear thumb bit of new PC if we are already in thumb mode; that is
831 // CPSR thumb mode bit is set.
832 if (offset
/ sizeof(uint32_t) == gpr_pc_arm
) {
833 // Check if we are already in thumb mode and thumb bit of current PC is
834 // read out to be zero and thumb bit of next PC is read out to be one.
835 if ((m_gpr_arm
[gpr_cpsr_arm
] & 0x20) && !(m_gpr_arm
[gpr_pc_arm
] & 0x01) &&
836 (value
.GetAsUInt32() & 0x01)) {
837 reg_value
&= (~1ull);
841 m_gpr_arm
[offset
/ sizeof(uint32_t)] = reg_value
;
845 Status
NativeRegisterContextLinux_arm::ReadGPR() {
847 return NativeRegisterContextLinux::ReadGPR();
850 ioVec
.iov_base
= GetGPRBuffer();
851 ioVec
.iov_len
= GetGPRSize();
853 return ReadRegisterSet(&ioVec
, GetGPRSize(), NT_PRSTATUS
);
857 Status
NativeRegisterContextLinux_arm::WriteGPR() {
859 return NativeRegisterContextLinux::WriteGPR();
862 ioVec
.iov_base
= GetGPRBuffer();
863 ioVec
.iov_len
= GetGPRSize();
865 return WriteRegisterSet(&ioVec
, GetGPRSize(), NT_PRSTATUS
);
869 Status
NativeRegisterContextLinux_arm::ReadFPR() {
871 return NativeProcessLinux::PtraceWrapper(PTRACE_GETVFPREGS
, m_thread
.GetID(),
872 nullptr, GetFPRBuffer(),
876 ioVec
.iov_base
= GetFPRBuffer();
877 ioVec
.iov_len
= GetFPRSize();
879 return ReadRegisterSet(&ioVec
, GetFPRSize(), NT_ARM_VFP
);
883 Status
NativeRegisterContextLinux_arm::WriteFPR() {
885 return NativeProcessLinux::PtraceWrapper(PTRACE_SETVFPREGS
, m_thread
.GetID(),
886 nullptr, GetFPRBuffer(),
890 ioVec
.iov_base
= GetFPRBuffer();
891 ioVec
.iov_len
= GetFPRSize();
893 return WriteRegisterSet(&ioVec
, GetFPRSize(), NT_ARM_VFP
);
897 #endif // defined(__arm__) || defined(__arm64__) || defined(__aarch64__)