Skip to content

Commit b1a421f

Browse files
committed
[lldb][ARM] Port Arm Linux to use NativeRegisterContextDBReg
Which is also used by AArch64 and LoongArch. To do this I had to make some adjustments to NativeRegisterContextDBReg: * New method AdjustBreakpoint. This is like AdjustWatchpoint, but only Arm needs to adjust breakpoints. For Arm this method removes the bottom address bits according to the mode. * MakeWatchControlValue now takes the address too. Arm uses this to generate the byte mask. To test this, I ran the test suite as usual on Arm and found no new failures, then ran it again with all test programs compiled with `-mthumb`. This means the binaries will be entirely Thumb code. Finally I tested it on AArch64, but this is mostly a build test, as I did not run the entire test suite compiled to AArch32 mode. Prior to this change, these tests failed with `-mthumb`: ``` Failed Tests (14): lldb-api :: commands/process/reverse-continue/TestReverseContinue.py lldb-api :: functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py lldb-api :: functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py lldb-api :: functionalities/reverse-execution/TestReverseContinueBreakpoints.py lldb-api :: functionalities/reverse-execution/TestReverseContinueWatchpoints.py lldb-api :: functionalities/tail_call_frames/disambiguate_call_site/TestDisambiguateCallSite.py lldb-api :: functionalities/tail_call_frames/disambiguate_paths_to_common_sink/TestDisambiguatePathsToCommonSink.py lldb-api :: functionalities/tail_call_frames/disambiguate_tail_call_seq/TestDisambiguateTailCallSeq.py lldb-api :: functionalities/tail_call_frames/inlining_and_tail_calls/TestInliningAndTailCalls.py lldb-api :: functionalities/tail_call_frames/sbapi_support/TestTailCallFrameSBAPI.py lldb-api :: functionalities/tail_call_frames/thread_step_out_message/TestArtificialFrameStepOutMessage.py lldb-api :: functionalities/thread/jump/TestThreadJump.py lldb-api :: lang/c/vla/TestVLA.py lldb-api :: linux/sepdebugsymlink/TestTargetSymbolsSepDebugSymlink.py ``` After this change, no new failures occured. So I am confident it is correct. Looking into those failures, it's a few things: * Something in the reverse execution wrapper that I can't figure out, but is likely nothing to do with the real breakpoints. * The inability to tail call when building thumb code, because the call goes via. a veneer that might do a mode switch. * Assumptions about source locations being in speciifc places. None of which are massive issues I feel like need fixing before doing this port.
1 parent 49d5dd3 commit b1a421f

11 files changed

+243
-534
lines changed

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

Lines changed: 50 additions & 479 deletions
Large diffs are not rendered by default.

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

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

1414
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
15-
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
15+
#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h"
1616
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
1717
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
1818

@@ -21,7 +21,8 @@ namespace process_linux {
2121

2222
class NativeProcessLinux;
2323

24-
class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
24+
class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux,
25+
public NativeRegisterContextDBReg_arm {
2526
public:
2627
NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
2728
NativeThreadProtocol &native_thread);
@@ -42,39 +43,6 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
4243

4344
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
4445

45-
// Hardware breakpoints/watchpoint management functions
46-
47-
uint32_t NumSupportedHardwareBreakpoints() override;
48-
49-
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
50-
51-
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
52-
53-
Status ClearAllHardwareBreakpoints() override;
54-
55-
Status GetHardwareBreakHitIndex(uint32_t &bp_index,
56-
lldb::addr_t trap_addr) override;
57-
58-
uint32_t NumSupportedHardwareWatchpoints() override;
59-
60-
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
61-
uint32_t watch_flags) override;
62-
63-
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
64-
65-
Status ClearAllHardwareWatchpoints() override;
66-
67-
Status GetWatchpointHitIndex(uint32_t &wp_index,
68-
lldb::addr_t trap_addr) override;
69-
70-
lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
71-
72-
lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
73-
74-
uint32_t GetWatchpointSize(uint32_t wp_index);
75-
76-
bool WatchpointIsEnabled(uint32_t wp_index);
77-
7846
protected:
7947
Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
8048
uint32_t size, RegisterValue &value) override;
@@ -100,23 +68,16 @@ class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
10068
uint32_t m_gpr_arm[k_num_gpr_registers_arm];
10169
RegisterInfoPOSIX_arm::FPU m_fpr;
10270

103-
std::array<NativeRegisterContextDBReg::DREG, 16>
104-
m_hbr_regs; // Arm native linux hardware breakpoints
105-
std::array<NativeRegisterContextDBReg::DREG, 16>
106-
m_hwp_regs; // Arm native linux hardware watchpoints
107-
108-
uint32_t m_max_hwp_supported;
109-
uint32_t m_max_hbp_supported;
11071
bool m_refresh_hwdebug_info;
11172

11273
bool IsGPR(unsigned reg) const;
11374

11475
bool IsFPR(unsigned reg) const;
11576

116-
Status ReadHardwareDebugInfo();
77+
llvm::Error ReadHardwareDebugInfo() override;
11778

118-
Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
119-
int hwb_index);
79+
llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
80+
llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index) override;
12081

12182
uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
12283

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility
1313
MemoryTagManagerAArch64MTE.cpp
1414
NativeProcessSoftwareSingleStep.cpp
1515
NativeRegisterContextDBReg.cpp
16+
NativeRegisterContextDBReg_arm.cpp
1617
NativeRegisterContextDBReg_arm64.cpp
1718
NativeRegisterContextDBReg_loongarch.cpp
1819
NativeRegisterContextDBReg_x86.cpp

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
222222
addr = adjusted->addr;
223223

224224
// Check if we are setting watchpoint other than read/write/access Also
225-
// update watchpoint flag to match AArch64/LoongArch write-read bit
225+
// update watchpoint flag to match ARM/AArch64/LoongArch write-read bit
226226
// configuration.
227227
switch (watch_flags) {
228228
case lldb::eWatchpointKindWrite:
@@ -237,7 +237,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
237237
return LLDB_INVALID_INDEX32;
238238
}
239239

240-
control_value = MakeWatchControlValue(size, watch_flags);
240+
control_value = MakeWatchControlValue(addr, size, watch_flags);
241241

242242
// Iterate over stored watchpoints and find a free wp_index
243243
wp_index = LLDB_INVALID_INDEX32;

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
1313

1414
#include <array>
15+
#include <optional>
1516

1617
// Common utilities for hardware breakpoints and hardware watchpoints on AArch64
1718
// and LoongArch.
@@ -76,17 +77,26 @@ class NativeRegisterContextDBReg
7677

7778
// On AArch64 and Loongarch the hardware breakpoint length size is 4, and the
7879
// target address must 4-byte alignment.
79-
bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
80+
virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
8081
return (size == 4) && !(addr & 0x3);
8182
}
83+
8284
struct WatchpointDetails {
8385
size_t size;
8486
lldb::addr_t addr;
8587
};
8688
virtual std::optional<WatchpointDetails>
8789
AdjustWatchpoint(const WatchpointDetails &details) = 0;
90+
91+
using BreakpointDetails = WatchpointDetails;
92+
virtual std::optional<BreakpointDetails>
93+
AdjustBreakpoint(const BreakpointDetails &details) {
94+
return details;
95+
}
96+
8897
virtual uint32_t MakeBreakControlValue(size_t size) = 0;
89-
virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 0;
98+
virtual uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
99+
uint32_t watch_flags) = 0;
90100
virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
91101

92102
virtual llvm::Error ReadHardwareDebugInfo() = 0;
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//===-- NativeRegisterContextDBReg_arm.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+
#include "NativeRegisterContextDBReg_arm.h"
10+
11+
#include "lldb/Utility/LLDBLog.h"
12+
#include "lldb/Utility/Log.h"
13+
#include "lldb/Utility/RegisterValue.h"
14+
15+
using namespace lldb_private;
16+
17+
uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) {
18+
Log *log = GetLog(LLDBLog::Watchpoints);
19+
LLDB_LOG(log, "wp_index: {0}", wp_index);
20+
21+
switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
22+
case 0x01:
23+
return 1;
24+
case 0x03:
25+
return 2;
26+
case 0x07:
27+
return 3;
28+
case 0x0f:
29+
return 4;
30+
default:
31+
return 0;
32+
}
33+
}
34+
35+
std::optional<NativeRegisterContextDBReg::BreakpointDetails>
36+
NativeRegisterContextDBReg_arm::AdjustBreakpoint(
37+
const BreakpointDetails &details) {
38+
BreakpointDetails bd = details;
39+
// Use size to get a hint of arm vs thumb modes.
40+
switch (bd.size) {
41+
case 2:
42+
bd.addr &= ~1;
43+
break;
44+
case 4:
45+
bd.addr &= ~3;
46+
break;
47+
default:
48+
return {};
49+
}
50+
51+
return bd;
52+
}
53+
54+
std::optional<NativeRegisterContextDBReg::WatchpointDetails>
55+
NativeRegisterContextDBReg_arm::AdjustWatchpoint(
56+
const WatchpointDetails &details) {
57+
auto [size, addr] = details;
58+
59+
if (size == 0 || size > 4)
60+
return {};
61+
62+
// Check 4-byte alignment for hardware watchpoint target address. Below is a
63+
// hack to recalculate address and size in order to make sure we can watch
64+
// non 4-byte aligned addresses as well.
65+
if (addr & 0x03) {
66+
uint8_t watch_mask = (addr & 0x03) + size;
67+
if (watch_mask > 0x04)
68+
return {};
69+
else if (watch_mask <= 0x02)
70+
size = 2;
71+
else
72+
size = 4;
73+
74+
addr = addr & (~0x03);
75+
}
76+
77+
return WatchpointDetails{size, addr};
78+
}
79+
80+
uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
81+
switch (size) {
82+
case 2:
83+
return (0x3 << 5) | 7;
84+
case 4:
85+
return (0xfu << 5) | 7;
86+
default:
87+
// We assume that AdjustBreakpoint would have caught this earlier.
88+
llvm_unreachable("Invalid breakpoint size.");
89+
}
90+
}
91+
92+
uint32_t NativeRegisterContextDBReg_arm::MakeWatchControlValue(
93+
lldb::addr_t addr, size_t size, uint32_t watch_flags) {
94+
uint32_t addr_word_offset = 0, byte_mask = 0;
95+
96+
// We can only watch up to four bytes that follow a 4 byte aligned address
97+
// per watchpoint register pair, so make sure we can properly encode this.
98+
addr_word_offset = addr % 4;
99+
byte_mask = ((1u << size) - 1u) << addr_word_offset;
100+
101+
// Check if we need multiple watchpoint register
102+
if (byte_mask > 0xfu)
103+
return LLDB_INVALID_INDEX32;
104+
105+
// Setup control value
106+
// Make the byte_mask into a valid Byte Address Select mask
107+
uint32_t control_value = byte_mask << 5;
108+
109+
// Turn on appropriate watchpoint flags read or write
110+
control_value |= (watch_flags << 3);
111+
112+
// Enable this watchpoint and make it stop in privileged or user mode;
113+
control_value |= 7;
114+
115+
return control_value;
116+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===-- NativeRegisterContextDBReg_arm.h ------------------------*- C++ -*-===//
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+
#ifndef lldb_NativeRegisterContextDBReg_arm_h
10+
#define lldb_NativeRegisterContextDBReg_arm_h
11+
12+
#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
13+
14+
namespace lldb_private {
15+
16+
class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg {
17+
public:
18+
NativeRegisterContextDBReg_arm()
19+
: NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {}
20+
21+
private:
22+
uint32_t GetWatchpointSize(uint32_t wp_index) override;
23+
24+
std::optional<WatchpointDetails>
25+
AdjustWatchpoint(const WatchpointDetails &details) override;
26+
27+
std::optional<BreakpointDetails>
28+
AdjustBreakpoint(const BreakpointDetails &details) override;
29+
30+
uint32_t MakeBreakControlValue(size_t size) override;
31+
32+
uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
33+
uint32_t watch_flags) override;
34+
35+
bool ValidateBreakpoint(size_t size, lldb::addr_t addr) override {
36+
// Break on 4 or 2 byte instructions.
37+
return size == 4 || size == 2;
38+
}
39+
40+
virtual llvm::Error WriteHardwareDebugReg(DREGType hwbType,
41+
int hwb_index) = 0;
42+
};
43+
44+
} // namespace lldb_private
45+
46+
#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h

lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ uint32_t NativeRegisterContextDBReg_arm64::MakeBreakControlValue(size_t size) {
7878
return m_hw_dbg_enable_bit | pac_bits | encoded_size;
7979
}
8080

81-
uint32_t
82-
NativeRegisterContextDBReg_arm64::MakeWatchControlValue(size_t size,
83-
uint32_t watch_flags) {
81+
uint32_t NativeRegisterContextDBReg_arm64::MakeWatchControlValue(
82+
lldb::addr_t addr, size_t size, uint32_t watch_flags) {
83+
(void)addr;
84+
8485
// PAC (bits 2:1): 0b10
8586
const uint32_t pac_bits = 2 << 1;
8687

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class NativeRegisterContextDBReg_arm64 : public NativeRegisterContextDBReg {
2626

2727
uint32_t MakeBreakControlValue(size_t size) override;
2828

29-
uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
29+
uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
30+
uint32_t watch_flags) override;
3031
};
3132

3233
} // namespace lldb_private

lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ NativeRegisterContextDBReg_loongarch::MakeBreakControlValue(size_t size) {
5252
}
5353

5454
uint32_t NativeRegisterContextDBReg_loongarch::MakeWatchControlValue(
55-
size_t size, uint32_t watch_flags) {
55+
lldb::addr_t addr, size_t size, uint32_t watch_flags) {
56+
(void)addr;
5657
// Encoding hardware watchpoint control value.
5758
// Size encoded:
5859
// case 1 : 0b11

0 commit comments

Comments
 (0)