"""
Test LLDB can set and hit watchpoints on tagged addresses
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class TestWatchTaggedAddresses(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Skip this test if not running on AArch64 target that supports PAC
if not self.isAArch64PAuth():
self.skipTest("Target must support pointer authentication.")
# Set source filename.
self.source = "main.c"
# Invoke the default build rule.
self.build()
# Get the path of the executable
exe = self.getBuildArtifact("a.out")
# Create a target by the debugger.
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
@skipIf(archs=no_match(["aarch64"]))
@skipIf(oslist=no_match(["linux"]))
def test_watch_hit_tagged_ptr_access(self):
"""
Test that LLDB hits watchpoint installed on an untagged address with
memory access by a tagged pointer.
"""
# Add a breakpoint to set a watchpoint when stopped on the breakpoint.
lldbutil.run_break_set_by_symbol(self, "main")
# Run the program.
self.runCmd("run", RUN_SUCCEEDED)
# We should be stopped due to the breakpoint.
self.expect(
"thread list",
STOPPED_DUE_TO_BREAKPOINT,
substrs=["stopped", "stop reason = breakpoint"],
)
# Set the watchpoint variable declaration line number.
self.decl = line_number(self.source, "// Watchpoint variable declaration.")
# Now let's set a watchpoint on 'global_var'.
self.expect(
"watchpoint set variable global_var",
WATCHPOINT_CREATED,
substrs=[
"Watchpoint created",
"size = 4",
"type = m",
"%s:%d" % (self.source, self.decl),
],
)
self.verify_watch_hits()
@skipIf(archs=no_match(["aarch64"]))
@skipIf(oslist=no_match(["linux"]))
def test_watch_set_on_tagged_ptr(self):
"""Test that LLDB can install and hit watchpoint on a tagged address"""
# Find the line number to break inside main().
self.line = line_number(self.source, "// Set break point at this line.")
# Add a breakpoint to set a watchpoint when stopped on the breakpoint.
lldbutil.run_break_set_by_file_and_line(
self, None, self.line, num_expected_locations=1
)
# Run the program.
self.runCmd("run", RUN_SUCCEEDED)
# We should be stopped due to the breakpoint.
self.expect(
"thread list",
STOPPED_DUE_TO_BREAKPOINT,
substrs=["stopped", "stop reason = breakpoint"],
)
# Now let's set a expression watchpoint on 'tagged_ptr'.
self.expect(
"watchpoint set expression -s 4 -- tagged_ptr",
WATCHPOINT_CREATED,
substrs=["Watchpoint created", "size = 4", "type = m"],
)
self.verify_watch_hits()
def verify_watch_hits(self):
# Use the '-v' option to do verbose listing of the watchpoint.
# The hit count should be 0 initially.
self.expect(
"watchpoint list -v",
substrs=["Number of supported hardware watchpoints:", "hit_count = 0"],
)
self.runCmd("process continue")
# We should be stopped again due to the watchpoint (read_write type).
# The stop reason of the thread should be watchpoint.
self.expect(
"thread backtrace",
STOPPED_DUE_TO_WATCHPOINT,
substrs=["stop reason = watchpoint"],
)
self.runCmd("process continue")
# We should be stopped again due to the watchpoint (read_write type).
# The stop reason of the thread should be watchpoint.
self.expect(
"thread backtrace",
STOPPED_DUE_TO_WATCHPOINT,
substrs=["stop reason = watchpoint"],
)
# Use the '-v' option to do verbose listing of the watchpoint.
# The hit count should now be 2.
self.expect("watchpoint list -v", substrs=["hit_count = 2"])
# On some hardware, during __do_global_dtors_aux a flag is set near
# the global which can trigger the watchpoint. So we must remove it.
self.runCmd("watchpoint delete 1")
self.runCmd("process continue")
# There should be no more watchpoint hit and the process status should
# be 'exited'.
self.expect("process status", substrs=["exited"])