""" Watch a large unaligned memory region that lldb will need multiple hardware watchpoints to cover. """ import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil class UnalignedLargeWatchpointTestCase(TestBase): def continue_and_report_stop_reason(self, process, iter_str): if self.TraceOn(): self.runCmd("script print('continue')") process.Continue() self.assertIn( process.GetState(), [lldb.eStateStopped, lldb.eStateExited], iter_str ) thread = process.GetSelectedThread() return thread.GetStopReason() NO_DEBUG_INFO_TESTCASE = True # The Windows process plugins haven't been updated to break # watchpoints into WatchpointResources yet. @skipIfWindows # Test on 64-bit targets where we probably have # four watchpoint registers that can watch doublewords (8-byte). @skipIf(archs=no_match(["arm64", "arm64e", "aarch64", "x86_64"])) def test_unaligned_large_watchpoint(self): """Test watching an unaligned region of memory that requires multiple watchpoints.""" 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 ) self.runCmd("break set -p done") self.runCmd("break set -p exiting") frame = thread.GetFrameAtIndex(0) array_addr = frame.GetValueForVariablePath("array").GetValueAsUnsigned() # Don't assume that the heap allocated array is aligned # to a 1024 byte boundary to begin with, force alignment. # wa_addr = (array_addr + 1024) & ~(1024 - 1) wa_addr = array_addr # Now make the start address unaligned. wa_addr = wa_addr + 7 err = lldb.SBError() wp_opts = lldb.SBWatchpointOptions() wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify) wp = target.WatchpointCreateByAddress(wa_addr, 22, wp_opts, err) self.assertTrue(wp.IsValid()) self.assertSuccess(err) if self.TraceOn(): self.runCmd("watch list -v") c_count = 0 reason = self.continue_and_report_stop_reason(process, "continue #%d" % c_count) while reason == lldb.eStopReasonWatchpoint: c_count = c_count + 1 reason = self.continue_and_report_stop_reason( process, "continue #%d" % c_count ) self.assertLessEqual(c_count, 22) self.assertEqual(c_count, 22) self.expect("watchpoint list -v", substrs=["hit_count = 22"]) self.assertEqual(wp.GetHitCount(), 22) target.DeleteWatchpoint(wp.GetID()) # Now try watching a 16 byte variable # (not unaligned, but a good check to do anyway) frame = thread.GetFrameAtIndex(0) err = lldb.SBError() wp = frame.locals["variable"][0].Watch(True, False, True, err) self.assertSuccess(err) if self.TraceOn(): self.runCmd("frame select 0") self.runCmd("watchpoint list") c_count = 0 reason = self.continue_and_report_stop_reason(process, "continue #%d" % c_count) while reason == lldb.eStopReasonWatchpoint: c_count = c_count + 1 reason = self.continue_and_report_stop_reason( process, "continue #%d" % c_count ) self.assertLessEqual(c_count, 4) if self.TraceOn(): self.runCmd("frame select 0") self.assertEqual(c_count, 4) self.expect("watchpoint list -v", substrs=["hit_count = 4"]) self.assertEqual(wp.GetHitCount(), 4)