Skip to content

Commit 55a363f

Browse files
committed
[LLDB] Expose several methods in SBWatchpoint
This patch adds the following methods: * `GetType()` * `GetWatchValueKind()` * `GetWatchSpec()` * `IsWatchingReads()` * `IsWatchingWrites()` These mostly expose methods that `lldb_private::Watchpoint` already had. Tests are included that exercise these new methods. The motivation for exposing these are as follows: * `GetType()` - With this information and the address from a watchpoint it is now possible to construct an SBValue from an SBWatchpoint. Previously this wasn't possible. The included test case illustrates doing this. * `GetWatchValueKind()` - This allows the caller to determine whether the watchpoint is a variable watchpoint or an expression watchpoint. A new enum (`WatchpointValueKind`) has been introduced to represent the return values. Unfortunately the name `WatchpointKind` was already taken. * `GetWatchSpec()` - This allows (at least for variable watchpoints) to use a sensible name for SBValues created from an SBWatchpoint. * `IsWatchingReads()` - This allow checking if a watchpoint is monitoring read accesses. * `IsWatchingWRites()` - This allow checking if a watchpoint is monitoring write accesses. rdar://105606978 Reviewers: jingham, mib, bulbazord, jasonmolenda, JDevlieghere Differential Revision: https://reviews.llvm.org/D144937
1 parent c574e93 commit 55a363f

File tree

8 files changed

+194
-6
lines changed

8 files changed

+194
-6
lines changed

lldb/bindings/interface/SBWatchpointDocstrings.i

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,30 @@ watchpoints of the target."
1919
%feature("docstring", "
2020
The watchpoint stops only if the condition expression evaluates to true."
2121
) lldb::SBWatchpoint::SetCondition;
22+
23+
%feature("docstring", "
24+
Returns the type recorded when the watchpoint was created. For variable
25+
watchpoints it is the type of the watched variable. For expression
26+
watchpoints it is the type of the provided expression."
27+
) lldb::SBWatchpoint::GetType;
28+
29+
%feature("docstring", "
30+
Returns the kind of value that was watched when the watchpoint was created.
31+
Returns one of the following eWatchPointValueKindVariable,
32+
eWatchPointValueKindExpression, eWatchPointValueKindInvalid.
33+
"
34+
) lldb::SBWatchpoint::GetWatchValueKind;
35+
36+
%feature("docstring", "
37+
Get the spec for the watchpoint. For variable watchpoints this is the name
38+
of the variable. For expression watchpoints it is empty
39+
(may change in the future)."
40+
) lldb::SBWatchpoint::GetWatchSpec;
41+
42+
%feature("docstring", "
43+
Returns true if the watchpoint is watching reads. Returns false otherwise."
44+
) lldb::SBWatchpoint::IsWatchingReads;
45+
46+
%feature("docstring", "
47+
Returns true if the watchpoint is watching writes. Returns false otherwise."
48+
) lldb::SBWatchpoint::IsWatchingWrites;

lldb/docs/python_api_enums.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,3 +1407,24 @@ The result from a command interpreter run.
14071407
.. py:data:: eCommandInterpreterResultQuitRequested
14081408
14091409
Stopped because quit was requested.
1410+
1411+
1412+
.. _WatchPointValueKind:
1413+
1414+
WatchPointValueKind
1415+
-------------------
1416+
1417+
The type of value that the watchpoint was created to monitor.
1418+
1419+
.. py:data:: eWatchPointValueKindInvalid
1420+
1421+
Invalid kind.
1422+
1423+
.. py:data:: eWatchPointValueKindVariable
1424+
1425+
Watchpoint was created watching a variable
1426+
1427+
.. py:data:: eWatchPointValueKindExpression
1428+
1429+
Watchpoint was created watching the result of an expression that was
1430+
evaluated at creation time.

lldb/include/lldb/API/SBType.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ class SBType {
239239
friend class SBTypeMemberFunction;
240240
friend class SBTypeList;
241241
friend class SBValue;
242+
friend class SBWatchpoint;
242243

243244
SBType(const lldb_private::CompilerType &);
244245
SBType(const lldb::TypeSP &);

lldb/include/lldb/API/SBWatchpoint.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_API_SBWATCHPOINT_H
1111

1212
#include "lldb/API/SBDefines.h"
13+
#include "lldb/API/SBType.h"
1314

1415
namespace lldb {
1516

@@ -77,6 +78,16 @@ class LLDB_API SBWatchpoint {
7778

7879
static lldb::SBWatchpoint GetWatchpointFromEvent(const lldb::SBEvent &event);
7980

81+
lldb::SBType GetType();
82+
83+
WatchpointValueKind GetWatchValueKind();
84+
85+
const char *GetWatchSpec();
86+
87+
bool IsWatchingReads();
88+
89+
bool IsWatchingWrites();
90+
8091
private:
8192
friend class SBTarget;
8293
friend class SBValue;

lldb/include/lldb/lldb-enumerations.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,15 @@ enum DWIMPrintVerbosity {
12191219
eDWIMPrintVerbosityFull,
12201220
};
12211221

1222+
enum WatchpointValueKind {
1223+
eWatchPointValueKindInvalid = 0,
1224+
///< Watchpoint was created watching a variable
1225+
eWatchPointValueKindVariable = 1,
1226+
///< Watchpoint was created watching the result of an expression that was
1227+
///< evaluated at creation time.
1228+
eWatchPointValueKindExpression = 2,
1229+
};
1230+
12221231
} // namespace lldb
12231232

12241233
#endif // LLDB_LLDB_ENUMERATIONS_H

lldb/source/API/SBWatchpoint.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/Breakpoint/Watchpoint.h"
1818
#include "lldb/Breakpoint/WatchpointList.h"
1919
#include "lldb/Core/StreamFile.h"
20+
#include "lldb/Symbol/CompilerType.h"
2021
#include "lldb/Target/Process.h"
2122
#include "lldb/Target/Target.h"
2223
#include "lldb/Utility/Stream.h"
@@ -290,3 +291,72 @@ SBWatchpoint SBWatchpoint::GetWatchpointFromEvent(const lldb::SBEvent &event) {
290291
Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP());
291292
return sb_watchpoint;
292293
}
294+
295+
lldb::SBType SBWatchpoint::GetType() {
296+
LLDB_INSTRUMENT_VA(this);
297+
298+
lldb::WatchpointSP watchpoint_sp(GetSP());
299+
if (watchpoint_sp) {
300+
std::lock_guard<std::recursive_mutex> guard(
301+
watchpoint_sp->GetTarget().GetAPIMutex());
302+
const CompilerType &type = watchpoint_sp->GetCompilerType();
303+
return lldb::SBType(type);
304+
}
305+
return lldb::SBType();
306+
}
307+
308+
WatchpointValueKind SBWatchpoint::GetWatchValueKind() {
309+
LLDB_INSTRUMENT_VA(this);
310+
311+
lldb::WatchpointSP watchpoint_sp(GetSP());
312+
if (watchpoint_sp) {
313+
std::lock_guard<std::recursive_mutex> guard(
314+
watchpoint_sp->GetTarget().GetAPIMutex());
315+
if (watchpoint_sp->IsWatchVariable())
316+
return WatchpointValueKind::eWatchPointValueKindVariable;
317+
return WatchpointValueKind::eWatchPointValueKindExpression;
318+
}
319+
return WatchpointValueKind::eWatchPointValueKindInvalid;
320+
}
321+
322+
const char *SBWatchpoint::GetWatchSpec() {
323+
LLDB_INSTRUMENT_VA(this);
324+
325+
lldb::WatchpointSP watchpoint_sp(GetSP());
326+
if (watchpoint_sp) {
327+
std::lock_guard<std::recursive_mutex> guard(
328+
watchpoint_sp->GetTarget().GetAPIMutex());
329+
// Store the result of `GetWatchSpec()` as a ConstString
330+
// so that the C string we return has a sufficiently long
331+
// lifetime. Note this a memory leak but should be fairly
332+
// low impact.
333+
return ConstString(watchpoint_sp->GetWatchSpec()).AsCString();
334+
}
335+
return nullptr;
336+
}
337+
338+
bool SBWatchpoint::IsWatchingReads() {
339+
LLDB_INSTRUMENT_VA(this);
340+
lldb::WatchpointSP watchpoint_sp(GetSP());
341+
if (watchpoint_sp) {
342+
std::lock_guard<std::recursive_mutex> guard(
343+
watchpoint_sp->GetTarget().GetAPIMutex());
344+
345+
return watchpoint_sp->WatchpointRead();
346+
}
347+
348+
return false;
349+
}
350+
351+
bool SBWatchpoint::IsWatchingWrites() {
352+
LLDB_INSTRUMENT_VA(this);
353+
lldb::WatchpointSP watchpoint_sp(GetSP());
354+
if (watchpoint_sp) {
355+
std::lock_guard<std::recursive_mutex> guard(
356+
watchpoint_sp->GetTarget().GetAPIMutex());
357+
358+
return watchpoint_sp->WatchpointWrite();
359+
}
360+
361+
return false;
362+
}

lldb/test/API/python_api/watchpoint/TestSetWatchpoint.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,24 @@ def setUp(self):
1919
# Find the line number to break inside main().
2020
self.line = line_number(
2121
self.source, '// Set break point at this line.')
22+
self.build()
2223

2324
# Read-write watchpoints not supported on SystemZ
2425
@expectedFailureAll(archs=['s390x'])
2526
def test_watch_val(self):
2627
"""Exercise SBValue.Watch() API to set a watchpoint."""
27-
self.build()
28+
self._test_watch_val(variable_watchpoint=False)
29+
pass
30+
31+
@expectedFailureAll(archs=['s390x'])
32+
def test_watch_variable(self):
33+
"""
34+
Exercise some watchpoint APIs when the watchpoint
35+
is created as a variable watchpoint.
36+
"""
37+
self._test_watch_val(variable_watchpoint=True)
38+
39+
def _test_watch_val(self, variable_watchpoint):
2840
exe = self.getBuildArtifact("a.out")
2941

3042
# Create a target by the debugger.
@@ -50,12 +62,40 @@ def test_watch_val(self):
5062
frame0 = thread.GetFrameAtIndex(0)
5163

5264
# Watch 'global' for read and write.
53-
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
54-
error = lldb.SBError()
55-
watchpoint = value.Watch(True, True, True, error)
56-
self.assertTrue(value and watchpoint,
65+
if variable_watchpoint:
66+
# FIXME: There should probably be an API to create a
67+
# variable watchpoint.
68+
self.runCmd('watchpoint set variable -w read_write -- global')
69+
watchpoint = target.GetWatchpointAtIndex(0)
70+
self.assertEqual(watchpoint.GetWatchValueKind(),
71+
lldb.eWatchPointValueKindVariable)
72+
self.assertEqual(watchpoint.GetWatchSpec(), 'global')
73+
# Synthesize an SBValue from the watchpoint
74+
watchpoint_addr = lldb.SBAddress(watchpoint.GetWatchAddress(),
75+
target)
76+
value = target.CreateValueFromAddress(
77+
watchpoint.GetWatchSpec(),
78+
watchpoint_addr, watchpoint.GetType())
79+
else:
80+
value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
81+
error = lldb.SBError()
82+
watchpoint = value.Watch(True, True, True, error)
83+
self.assertTrue(value and watchpoint,
5784
"Successfully found the variable and set a watchpoint")
58-
self.DebugSBValue(value)
85+
self.DebugSBValue(value)
86+
self.assertEqual(watchpoint.GetWatchValueKind(),
87+
lldb.eWatchPointValueKindExpression)
88+
# FIXME: The spec should probably be '&global' given that the kind
89+
# is reported as eWatchPointValueKindExpression. If the kind is
90+
# actually supposed to be eWatchPointValueKindVariable then the spec
91+
# should probably be 'global'.
92+
self.assertEqual(watchpoint.GetWatchSpec(), None)
93+
94+
self.assertEqual(watchpoint.GetType().GetDisplayTypeName(), 'int32_t')
95+
self.assertEqual(value.GetName(), 'global')
96+
self.assertEqual(value.GetType(), watchpoint.GetType())
97+
self.assertTrue(watchpoint.IsWatchingReads())
98+
self.assertTrue(watchpoint.IsWatchingWrites())
5999

60100
# Hide stdout if not running with '-t' option.
61101
if not self.TraceOn():

lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ def test_watch_location(self):
6464
self.DebugSBValue(value)
6565
self.DebugSBValue(pointee)
6666

67+
# Check some API calls return expected values
68+
self.assertEqual(watchpoint.GetWatchValueKind(),
69+
lldb.eWatchPointValueKindExpression)
70+
# FIXME: The spec should probably be 'g_char_ptr'
71+
self.assertEqual(watchpoint.GetWatchSpec(), None)
72+
self.assertEqual(watchpoint.GetType().GetDisplayTypeName(), 'char')
73+
self.assertFalse(watchpoint.IsWatchingReads())
74+
self.assertTrue(watchpoint.IsWatchingWrites())
75+
6776
# Hide stdout if not running with '-t' option.
6877
if not self.TraceOn():
6978
self.HideStdout()

0 commit comments

Comments
 (0)