Skip to content

Commit 9dfc0e3

Browse files
committed
[lldb][AArch64] Fix hardware breakpoint/watchpoint to arm32 debugee on arm64.
When debugging arm32 process on arm64 machine, arm64 lldb-server will use `NativeRegisterContextLinux_arm`, but it should use 64-bit ptrace commands for hardware watchpoint/breakpoint. See: torvalds/linux@5d220ff There have been many conditional compilation handling arm32 debuggees on arm64, but this one is missed out. To reuse the 64-bit implementation, I separate the shared code from `NativeRegisterContextLinux_arm64.cpp` to `NativeRegisterContextLinuxArm64Shared.cpp`, with other adjustments to share data structures of debug registers.
1 parent 8f4ce76 commit 9dfc0e3

File tree

7 files changed

+111
-126
lines changed

7 files changed

+111
-126
lines changed

lldb/source/Plugins/Process/Linux/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessLinux
88
NativeRegisterContextLinux.cpp
99
NativeRegisterContextLinux_arm.cpp
1010
NativeRegisterContextLinux_arm64.cpp
11+
NativeRegisterContextLinuxArm64Shared.cpp
1112
NativeRegisterContextLinux_loongarch64.cpp
1213
NativeRegisterContextLinux_ppc64le.cpp
1314
NativeRegisterContextLinux_riscv64.cpp
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "NativeRegisterContextLinuxArm64Shared.h"
2+
3+
using namespace lldb_private::process_linux::arm64;
4+
5+
namespace lldb_private {
6+
namespace process_linux {
7+
namespace arm64 {
8+
9+
namespace {
10+
Status ReadHardwareDebugInfoHelper(int regset, ::pid_t tid,
11+
uint32_t &max_supported) {
12+
struct iovec ioVec;
13+
struct user_hwdebug_state dreg_state;
14+
Status error;
15+
16+
ioVec.iov_base = &dreg_state;
17+
ioVec.iov_len = sizeof(dreg_state);
18+
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
19+
&ioVec, ioVec.iov_len);
20+
21+
if (error.Fail())
22+
return error;
23+
24+
max_supported = dreg_state.dbg_info & 0xff;
25+
return error;
26+
}
27+
} // namespace
28+
29+
Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported,
30+
uint32_t &max_hbp_supported) {
31+
Status error =
32+
ReadHardwareDebugInfoHelper(NT_ARM_HW_WATCH, tid, max_hwp_supported);
33+
34+
if (error.Fail())
35+
return error;
36+
37+
return ReadHardwareDebugInfoHelper(NT_ARM_HW_BREAK, tid, max_hbp_supported);
38+
}
39+
40+
Status WriteHardwareDebugRegs(
41+
int hwbType, ::pid_t tid, uint32_t max_supported,
42+
const std::array<NativeRegisterContextDBReg::DREG, 16> &regs) {
43+
struct iovec ioVec;
44+
struct user_hwdebug_state dreg_state;
45+
int regset = hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH
46+
? NT_ARM_HW_WATCH
47+
: NT_ARM_HW_BREAK;
48+
memset(&dreg_state, 0, sizeof(dreg_state));
49+
ioVec.iov_base = &dreg_state;
50+
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
51+
(sizeof(dreg_state.dbg_regs[0]) * max_supported);
52+
for (uint32_t i = 0; i < max_supported; i++) {
53+
dreg_state.dbg_regs[i].addr = regs[i].address;
54+
dreg_state.dbg_regs[i].ctrl = regs[i].control;
55+
}
56+
57+
return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, &regset,
58+
&ioVec, ioVec.iov_len);
59+
}
60+
61+
} // namespace arm64
62+
} // namespace process_linux
63+
} // namespace lldb_private
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "Plugins/Process/Linux/NativeProcessLinux.h"
2+
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
3+
#include "lldb/Utility/Status.h"
4+
#include <asm/ptrace.h>
5+
#include <cstdint>
6+
#include <elf.h>
7+
#include <sys/ptrace.h>
8+
#include <sys/uio.h>
9+
10+
namespace lldb_private {
11+
namespace process_linux {
12+
namespace arm64 {
13+
14+
Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported,
15+
uint32_t &max_hbp_supported);
16+
17+
Status WriteHardwareDebugRegs(
18+
int hwbType, ::pid_t tid, uint32_t max_supported,
19+
const std::array<NativeRegisterContextDBReg::DREG, 16> &regs);
20+
21+
} // namespace arm64
22+
} // namespace process_linux
23+
} // namespace lldb_private

lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp

Lines changed: 8 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
1010

1111
#include "NativeRegisterContextLinux_arm.h"
12+
#include "NativeRegisterContextLinuxArm64Shared.h"
1213

1314
#include "Plugins/Process/Linux/NativeProcessLinux.h"
1415
#include "Plugins/Process/Linux/Procfs.h"
@@ -744,34 +745,8 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
744745

745746
return error;
746747
#else // __aarch64__
747-
::pid_t tid = m_thread.GetID();
748-
749-
int regset = NT_ARM_HW_WATCH;
750-
struct iovec ioVec;
751-
struct user_hwdebug_state dreg_state;
752-
753-
ioVec.iov_base = &dreg_state;
754-
ioVec.iov_len = sizeof(dreg_state);
755-
756-
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
757-
&ioVec, ioVec.iov_len);
758-
759-
if (error.Fail())
760-
return error;
761-
762-
m_max_hwp_supported = dreg_state.dbg_info & 0xff;
763-
764-
regset = NT_ARM_HW_BREAK;
765-
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
766-
&ioVec, ioVec.iov_len);
767-
768-
if (error.Fail())
769-
return error;
770-
771-
m_max_hbp_supported = dreg_state.dbg_info & 0xff;
772-
m_refresh_hwdebug_info = false;
773-
774-
return error;
748+
return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
749+
m_max_hbp_supported);
775750
#endif // __arm__
776751
}
777752

@@ -819,38 +794,11 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType,
819794

820795
return error;
821796
#else // __aarch64__
822-
struct iovec ioVec;
823-
struct user_hwdebug_state dreg_state;
824-
int regset;
825-
826-
memset(&dreg_state, 0, sizeof(dreg_state));
827-
ioVec.iov_base = &dreg_state;
828-
829-
switch (hwbType) {
830-
case eDREGTypeWATCH:
831-
regset = NT_ARM_HW_WATCH;
832-
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
833-
(sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
834-
835-
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
836-
dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
837-
dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
838-
}
839-
break;
840-
case eDREGTypeBREAK:
841-
regset = NT_ARM_HW_BREAK;
842-
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
843-
(sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
844-
845-
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
846-
dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address;
847-
dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control;
848-
}
849-
break;
850-
}
851-
852-
return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
853-
&regset, &ioVec, ioVec.iov_len);
797+
uint32_t max_supported =
798+
(hwbType == eDREGTypeWATCH) ? m_max_hwp_supported : m_max_hbp_supported;
799+
auto &regs = (hwbType == eDREGTypeWATCH) ? m_hwp_regs : m_hbr_regs;
800+
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
801+
regs);
854802
#endif // __arm__
855803
}
856804

lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define lldb_NativeRegisterContextLinux_arm_h
1313

1414
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
15+
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
1516
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
1617
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
1718

@@ -74,8 +75,10 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
7475

7576
bool WatchpointIsEnabled(uint32_t wp_index);
7677

77-
// Debug register type select
78-
enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
78+
using DREGType = NativeRegisterContextDBReg::DREGType;
79+
static const DREGType eDREGTypeBREAK = DREGType::eDREGTypeBREAK;
80+
static const DREGType eDREGTypeWATCH = DREGType::eDREGTypeWATCH;
81+
using DREG = NativeRegisterContextDBReg::DREG;
7982

8083
protected:
8184
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
@@ -102,17 +105,8 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
102105
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
103106
RegisterInfoPOSIX_arm::FPU m_fpr;
104107

105-
// Debug register info for hardware breakpoints and watchpoints management.
106-
struct DREG {
107-
lldb::addr_t address; // Breakpoint/watchpoint address value.
108-
lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
109-
// occurred.
110-
lldb::addr_t real_addr; // Address value that should cause target to stop.
111-
uint32_t control; // Breakpoint/watchpoint control value.
112-
};
113-
114-
struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints
115-
struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints
108+
std::array<DREG, 16> m_hbr_regs; // Arm native linux hardware breakpoints
109+
std::array<DREG, 16> m_hwp_regs; // Arm native linux hardware watchpoints
116110

117111
uint32_t m_max_hwp_supported;
118112
uint32_t m_max_hbp_supported;

lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "NativeRegisterContextLinuxArm64Shared.h"
910
#if defined(__arm64__) || defined(__aarch64__)
1011

1112
#include "NativeRegisterContextLinux_arm.h"
@@ -1146,68 +1147,23 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
11461147

11471148
::pid_t tid = m_thread.GetID();
11481149

1149-
int regset = NT_ARM_HW_WATCH;
1150-
struct iovec ioVec;
1151-
struct user_hwdebug_state dreg_state;
1152-
Status error;
1153-
1154-
ioVec.iov_base = &dreg_state;
1155-
ioVec.iov_len = sizeof(dreg_state);
1156-
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
1157-
&ioVec, ioVec.iov_len);
1158-
1159-
if (error.Fail())
1160-
return error.ToError();
1161-
1162-
m_max_hwp_supported = dreg_state.dbg_info & 0xff;
1163-
1164-
regset = NT_ARM_HW_BREAK;
1165-
error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
1166-
&ioVec, ioVec.iov_len);
1167-
1150+
Status error = arm64::ReadHardwareDebugInfo(tid, m_max_hwp_supported,
1151+
m_max_hbp_supported);
11681152
if (error.Fail())
11691153
return error.ToError();
11701154

1171-
m_max_hbp_supported = dreg_state.dbg_info & 0xff;
11721155
m_refresh_hwdebug_info = false;
11731156

11741157
return llvm::Error::success();
11751158
}
11761159

11771160
llvm::Error
11781161
NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
1179-
struct iovec ioVec;
1180-
struct user_hwdebug_state dreg_state;
1181-
int regset;
1182-
1183-
memset(&dreg_state, 0, sizeof(dreg_state));
1184-
ioVec.iov_base = &dreg_state;
1185-
1186-
switch (hwbType) {
1187-
case eDREGTypeWATCH:
1188-
regset = NT_ARM_HW_WATCH;
1189-
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
1190-
(sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
1191-
1192-
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
1193-
dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
1194-
dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
1195-
}
1196-
break;
1197-
case eDREGTypeBREAK:
1198-
regset = NT_ARM_HW_BREAK;
1199-
ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) +
1200-
(sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
1201-
1202-
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
1203-
dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
1204-
dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
1205-
}
1206-
break;
1207-
}
1208-
1209-
return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
1210-
&regset, &ioVec, ioVec.iov_len)
1162+
uint32_t max_supported =
1163+
(hwbType == eDREGTypeWATCH) ? m_max_hwp_supported : m_max_hbp_supported;
1164+
auto &regs = (hwbType == eDREGTypeWATCH) ? m_hwp_regs : m_hbp_regs;
1165+
return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported,
1166+
regs)
12111167
.ToError();
12121168
}
12131169

lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ class NativeRegisterContextDBReg
5151

5252
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
5353

54-
protected:
5554
// Debug register type select
5655
enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
5756

@@ -64,6 +63,7 @@ class NativeRegisterContextDBReg
6463
uint32_t control; // Breakpoint/watchpoint control value.
6564
};
6665

66+
protected:
6767
std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints
6868
std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints
6969

0 commit comments

Comments
 (0)