"""
Watch 4 bytes which spawn two doubleword aligned regions.
On a target that supports 8 byte watchpoints, this will
need to be implemented with a hardware watchpoint on both
doublewords.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class UnalignedWatchpointTestCase(TestBase):
def hit_watchpoint_and_continue(self, process, iter_str):
process.Continue()
self.assertEqual(process.GetState(), lldb.eStateStopped, iter_str)
thread = process.GetSelectedThread()
self.assertEqual(thread.GetStopReason(), lldb.eStopReasonWatchpoint, iter_str)
self.assertEqual(thread.GetStopReasonDataCount(), 1, iter_str)
wp_num = thread.GetStopReasonDataAtIndex(0)
self.assertEqual(wp_num, 1, iter_str)
NO_DEBUG_INFO_TESTCASE = True
# debugserver on AArch64 has this feature.
@skipIf(archs=no_match(["arm64", "arm64e", "aarch64"]))
@skipUnlessDarwin
# debugserver only started returning an exception address within
# a range lldb expects in https://reviews.llvm.org/D147820 2023-04-12.
# older debugservers will return the base address of the doubleword
# which lldb doesn't understand, and will stop executing without a
# proper stop reason.
@skipIfOutOfTreeDebugserver
def test_unaligned_watchpoint(self):
"""Test a watchpoint that is handled by two hardware watchpoint registers."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "break here", self.main_source_file
)
thread.StepOver()
frame = thread.GetFrameAtIndex(0)
a_bytebuf_6 = frame.GetValueForVariablePath("a.bytebuf[6]")
a_bytebuf_6_addr = a_bytebuf_6.GetAddress().GetLoadAddress(target)
err = lldb.SBError()
wp_opts = lldb.SBWatchpointOptions()
wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
wp = target.WatchpointCreateByAddress(a_bytebuf_6_addr, 4, wp_opts, err)
self.assertTrue(err.Success())
self.assertTrue(wp.IsEnabled())
self.assertEqual(wp.GetWatchSize(), 4)
self.assertGreater(
wp.GetWatchAddress() % 8, 4, "watched region spans two doublewords"
)
# We will hit our watchpoint 6 times during the execution
# of the inferior. If the remote stub does not actually split
# the watched region into two doubleword watchpoints, we will
# exit before we get to 6 watchpoint hits.
for i in range(1, 7):
self.hit_watchpoint_and_continue(process, "wp hit number %s" % i)