Skip to content

Commit cc2431c

Browse files
committed
Refactor and generalize AArch64 watchpoint support in debugserver
Refactor the debugserver watchpiont support in anticipating of adding support for AArch64 MASK hardware watchpoints to watch larger regions of memory. debugserver already had support for handling a request to watch an unaligned region of memory up to 8 bytes using Byte Address Select watchpoints - it would split an unaligned watch request into two aligned doublewords that could be watched with two hardware watchpoints using the BAS specification. This patch generalizes that code for properly aligning, and possibly splitting, a watchpoint request into two hardware watchpoints to handle any size request. And separates out the specifics about BAS watchpoints into its own method, so a sibling method for MASK watchpoints can be dropped in next. Differential Revision: https://reviews.llvm.org/D149040 rdar://108233371 (cherry picked from commit 5679379)
1 parent 6517506 commit cc2431c

File tree

5 files changed

+267
-125
lines changed

5 files changed

+267
-125
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
3+
include Makefile.rules
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Watch 4 bytes which spawn two doubleword aligned regions.
3+
On a target that supports 8 byte watchpoints, this will
4+
need to be implemented with a hardware watchpoint on both
5+
doublewords.
6+
"""
7+
8+
9+
10+
import lldb
11+
from lldbsuite.test.decorators import *
12+
from lldbsuite.test.lldbtest import *
13+
from lldbsuite.test import lldbutil
14+
15+
class UnalignedWatchpointTestCase(TestBase):
16+
17+
def hit_watchpoint_and_continue(self, process, iter_str):
18+
process.Continue()
19+
self.assertEqual(process.GetState(), lldb.eStateStopped,
20+
iter_str)
21+
thread = process.GetSelectedThread()
22+
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonWatchpoint, iter_str)
23+
self.assertEqual(thread.GetStopReasonDataCount(), 1, iter_str)
24+
wp_num = thread.GetStopReasonDataAtIndex(0)
25+
self.assertEqual(wp_num, 1, iter_str)
26+
27+
NO_DEBUG_INFO_TESTCASE = True
28+
# debugserver on AArch64 has this feature.
29+
@skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e', 'aarch64']))
30+
@skipUnlessDarwin
31+
# debugserver only started returning an exception address within
32+
# a range lldb expects in https://reviews.llvm.org/D147820 2023-04-12.
33+
# older debugservers will return the base address of the doubleword
34+
# which lldb doesn't understand, and will stop executing without a
35+
# proper stop reason.
36+
@skipIfOutOfTreeDebugserver
37+
38+
def test_unaligned_watchpoint(self):
39+
"""Test a watchpoint that is handled by two hardware watchpoint registers."""
40+
self.build()
41+
self.main_source_file = lldb.SBFileSpec("main.c")
42+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
43+
"break here", self.main_source_file)
44+
45+
frame = thread.GetFrameAtIndex(0)
46+
47+
a_bytebuf_6 = frame.GetValueForVariablePath("a.bytebuf[6]")
48+
a_bytebuf_6_addr = a_bytebuf_6.GetAddress().GetLoadAddress(target)
49+
err = lldb.SBError()
50+
wp = target.WatchAddress(a_bytebuf_6_addr, 4, False, True, err)
51+
self.assertTrue(err.Success())
52+
self.assertTrue(wp.IsEnabled())
53+
self.assertEqual(wp.GetWatchSize(), 4)
54+
self.assertGreater(wp.GetWatchAddress() % 8, 4, "watched region spans two doublewords")
55+
56+
# We will hit our watchpoint 6 times during the execution
57+
# of the inferior. If the remote stub does not actually split
58+
# the watched region into two doubleword watchpoints, we will
59+
# exit before we get to 6 watchpoint hits.
60+
for i in range(1, 7):
61+
self.hit_watchpoint_and_continue(process, "wp hit number %s" % i)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <stdint.h>
2+
#include <stdio.h>
3+
int main() {
4+
union {
5+
uint8_t bytebuf[16];
6+
uint16_t shortbuf[8];
7+
uint64_t dwordbuf[2];
8+
} a;
9+
a.dwordbuf[0] = a.dwordbuf[1] = 0;
10+
a.bytebuf[0] = 0; // break here
11+
for (int i = 0; i < 8; i++) {
12+
a.shortbuf[i] += i;
13+
}
14+
for (int i = 0; i < 8; i++) {
15+
a.shortbuf[i] += i;
16+
}
17+
}

0 commit comments

Comments
 (0)