Jason Molenda 3692267ca8
[lldb] Add 'modify' type watchpoints, make it default (#66308)
Watchpoints in lldb can be either 'read', 'write', or 'read/write'. This
is exposing the actual behavior of hardware watchpoints. gdb has a
different behavior: a "write" type watchpoint only stops when the
watched memory region *changes*.

A user is using a watchpoint for one of three reasons:

1. Want to find what is changing/corrupting this memory.
2. Want to find what is writing to this memory.
3. Want to find what is reading from this memory.

I believe (1) is the most common use case for watchpoints, and it
currently can't be done in lldb -- the user needs to continue every time
the same value is written to the watched-memory manually. I think gdb's
behavior is the correct one. There are some use cases where a developer
wants to find every function that writes/reads to/from a memory region,
regardless of value, I want to still allow that functionality.

This is also a bit of groundwork for my large watchpoint support
proposal
https://discourse.llvm.org/t/rfc-large-watchpoint-support-in-lldb/72116
where I will be adding support for AArch64 MASK watchpoints which watch
power-of-2 memory regions. A user might ask to watch 24 bytes, and a
MASK watchpoint stub can do this with a 32-byte MASK watchpoint if it is
properly aligned. And we need to ignore writes to the final 8 bytes of
that watched region, and not show those hits to the user.

This patch adds a new 'modify' watchpoint type and it is the default.

rdar://108234227
2023-09-18 19:16:45 -07:00

40 lines
1.3 KiB
Python

"""
Confirm that lldb modify watchpoints only stop
when the value being watched changes.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class ModifyWatchpointTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def test_modify_watchpoint(self):
"""Test that a modify watchpoint only stops when the value changes."""
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("watch set variable value")
process.Continue()
frame = process.GetSelectedThread().GetFrameAtIndex(0)
self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 10)
process.Continue()
frame = process.GetSelectedThread().GetFrameAtIndex(0)
self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 5)
process.Continue()
frame = process.GetSelectedThread().GetFrameAtIndex(0)
self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 7)
process.Continue()
frame = process.GetSelectedThread().GetFrameAtIndex(0)
self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 9)