Skip to content

Commit 7e452e1

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 (cherry picked from commit 55a363f)
1 parent 5919e1b commit 7e452e1

File tree

8 files changed

+182
-6
lines changed

8 files changed

+182
-6
lines changed

lldb/bindings/interface/SBWatchpoint.i

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,21 @@ public:
9191
GetWatchpointFromEvent (const lldb::SBEvent& event);
9292

9393
STRING_EXTENSION_LEVEL(SBWatchpoint, lldb::eDescriptionLevelVerbose)
94+
95+
lldb::SBType
96+
GetType();
97+
98+
WatchpointValueKind
99+
GetWatchValueKind();
100+
101+
const char *
102+
GetWatchSpec();
103+
104+
bool
105+
IsWatchingReads();
106+
107+
bool
108+
IsWatchingWrites();
94109
};
95110

96111
} // namespace lldb

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
@@ -236,6 +236,7 @@ class SBType {
236236
friend class SBTypeMemberFunction;
237237
friend class SBTypeList;
238238
friend class SBValue;
239+
friend class SBWatchpoint;
239240

240241
SBType(const lldb_private::CompilerType &);
241242
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

@@ -73,6 +74,16 @@ class LLDB_API SBWatchpoint {
7374

7475
static lldb::SBWatchpoint GetWatchpointFromEvent(const lldb::SBEvent &event);
7576

77+
lldb::SBType GetType();
78+
79+
WatchpointValueKind GetWatchValueKind();
80+
81+
const char *GetWatchSpec();
82+
83+
bool IsWatchingReads();
84+
85+
bool IsWatchingWrites();
86+
7687
private:
7788
friend class SBTarget;
7889
friend class SBValue;

lldb/include/lldb/lldb-enumerations.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,15 @@ enum DWIMPrintVerbosity {
12451245
eDWIMPrintVerbosityFull,
12461246
};
12471247

1248+
enum WatchpointValueKind {
1249+
eWatchPointValueKindInvalid = 0,
1250+
///< Watchpoint was created watching a variable
1251+
eWatchPointValueKindVariable = 1,
1252+
///< Watchpoint was created watching the result of an expression that was
1253+
///< evaluated at creation time.
1254+
eWatchPointValueKindExpression = 2,
1255+
};
1256+
12481257
} // namespace lldb
12491258

12501259
#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)