delcypher created this revision.
Herald added a project: All.
delcypher requested review of this revision.
Herald added a project: LLDB.
This patch adds the following methods:
- `GetType()`
- `IsWatchVariable()`
- `GetWatchSpec()`
These effectively 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.
- `IsWatchVariable()` - This allows the caller to determine whether the
watchpoint is a variable watchpoint or an expression watchpoint.
- `GetWatchSpec()` - This allows (at least for variable watchpoints) to use a
sensible name for SBValues created from an SBWatchpoint.
The implementation of `GetWatchSpec()` isn't ideal. It currently caches
the string because `lldb_private::Watchpoint` does not publicly expose
the underlying memory its using to store the spec string. This is
probably fine though because the cost for this is only really paid if
`GetWatchSpec()` is called (unlikely given that its a new API).
rdar://105606978
Reviewersa jingham, mib, bulbazord, jasonmolenda, JDevlieghere
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D144937
Files:
lldb/bindings/interface/SBWatchpointDocstrings.i
lldb/include/lldb/API/SBType.h
lldb/include/lldb/API/SBWatchpoint.h
lldb/source/API/SBWatchpoint.cpp
lldb/test/API/python_api/watchpoint/TestSetWatchpoint.py
lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py
Index: lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py
===================================================================
--- lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py
+++ lldb/test/API/python_api/watchpoint/watchlocation/TestSetWatchlocation.py
@@ -64,6 +64,11 @@
self.DebugSBValue(value)
self.DebugSBValue(pointee)
+ # Check some API calls for expression watchpoint
+ self.assertFalse(watchpoint.IsWatchVariable())
+ self.assertEqual(watchpoint.GetWatchSpec(), '')
+ self.assertEqual(watchpoint.GetType().GetDisplayTypeName(), 'char')
+
# Hide stdout if not running with '-t' option.
if not self.TraceOn():
self.HideStdout()
Index: lldb/test/API/python_api/watchpoint/TestSetWatchpoint.py
===================================================================
--- lldb/test/API/python_api/watchpoint/TestSetWatchpoint.py
+++ lldb/test/API/python_api/watchpoint/TestSetWatchpoint.py
@@ -19,12 +19,24 @@
# Find the line number to break inside main().
self.line = line_number(
self.source, '// Set break point at this line.')
+ self.build()
# Read-write watchpoints not supported on SystemZ
@expectedFailureAll(archs=['s390x'])
def test_watch_val(self):
"""Exercise SBValue.Watch() API to set a watchpoint."""
- self.build()
+ self._test_watch_val(variable_watchpoint=False)
+ pass
+
+ @expectedFailureAll(archs=['s390x'])
+ def test_watch_variable(self):
+ """
+ Exercise some watchpoint APIs when the watchpoint
+ is created as a variable watchpoint.
+ """
+ self._test_watch_val(variable_watchpoint=True)
+
+ def _test_watch_val(self, variable_watchpoint):
exe = self.getBuildArtifact("a.out")
# Create a target by the debugger.
@@ -50,12 +62,27 @@
frame0 = thread.GetFrameAtIndex(0)
# Watch 'global' for read and write.
- value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
- error = lldb.SBError()
- watchpoint = value.Watch(True, True, True, error)
- self.assertTrue(value and watchpoint,
- "Successfully found the variable and set a watchpoint")
- self.DebugSBValue(value)
+ if variable_watchpoint:
+ # FIXME: There should probably be an API to create a variable watchpoint
+ self.runCmd('watchpoint set variable -w read_write -- global')
+ watchpoint = target.GetWatchpointAtIndex(0)
+ self.assertTrue(watchpoint.IsWatchVariable())
+ self.assertEqual(watchpoint.GetWatchSpec(), 'global')
+ # Synthesize an SBValue from the watchpoint
+ watchpoint_addr = lldb.SBAddress(watchpoint.GetWatchAddress(), target)
+ value = target.CreateValueFromAddress(
+ watchpoint.GetWatchSpec(), watchpoint_addr, watchpoint.GetType())
+ else:
+ value = frame0.FindValue('global', lldb.eValueTypeVariableGlobal)
+ error = lldb.SBError()
+ watchpoint = value.Watch(True, True, True, error)
+ self.assertTrue(value and watchpoint,
+ "Successfully found the variable and set a watchpoint")
+ self.DebugSBValue(value)
+ self.assertFalse(watchpoint.IsWatchVariable())
+ self.assertEqual(watchpoint.GetWatchSpec(), '')
+
+ self.assertEqual(watchpoint.GetType().GetDisplayTypeName(), 'int32_t')
# Hide stdout if not running with '-t' option.
if not self.TraceOn():
Index: lldb/source/API/SBWatchpoint.cpp
===================================================================
--- lldb/source/API/SBWatchpoint.cpp
+++ lldb/source/API/SBWatchpoint.cpp
@@ -17,6 +17,7 @@
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Breakpoint/WatchpointList.h"
#include "lldb/Core/StreamFile.h"
+#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Stream.h"
@@ -29,12 +30,13 @@
SBWatchpoint::SBWatchpoint() { LLDB_INSTRUMENT_VA(this); }
SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp)
- : m_opaque_wp(wp_sp) {
+ : m_opaque_wp(wp_sp), m_cached_watch_spec() {
LLDB_INSTRUMENT_VA(this, wp_sp);
}
SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs)
- : m_opaque_wp(rhs.m_opaque_wp) {
+ : m_opaque_wp(rhs.m_opaque_wp),
+ m_cached_watch_spec(rhs.m_cached_watch_spec) {
LLDB_INSTRUMENT_VA(this, rhs);
}
@@ -42,6 +44,7 @@
LLDB_INSTRUMENT_VA(this, rhs);
m_opaque_wp = rhs.m_opaque_wp;
+ m_cached_watch_spec = rhs.m_cached_watch_spec;
return *this;
}
@@ -290,3 +293,53 @@
Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP());
return sb_watchpoint;
}
+
+lldb::SBType SBWatchpoint::GetType() {
+ LLDB_INSTRUMENT_VA(this);
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ watchpoint_sp->GetTarget().GetAPIMutex());
+ const CompilerType &type = watchpoint_sp->GetCompilerType();
+ return lldb::SBType(type);
+ }
+ return lldb::SBType();
+}
+
+bool SBWatchpoint::IsWatchVariable() {
+ LLDB_INSTRUMENT_VA(this);
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ watchpoint_sp->GetTarget().GetAPIMutex());
+ return watchpoint_sp->IsWatchVariable();
+ }
+ return false;
+}
+
+const char *SBWatchpoint::GetWatchSpec() {
+ LLDB_INSTRUMENT_VA(this);
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp) {
+ std::lock_guard<std::recursive_mutex> guard(
+ watchpoint_sp->GetTarget().GetAPIMutex());
+ // We can't return `watchpoint_sp->GetWatchSpec().c_str()`
+ // because the temporary std::string will be destroyed
+ // when this function finishes. Instead we store our own
+ // copy in this class and give clients the C string used
+ // by the copy.
+ if (m_cached_watch_spec.size() == 0) {
+ m_cached_watch_spec = watchpoint_sp->GetWatchSpec();
+ } else {
+ // The string should never change otherwise we'd have to
+ // update the cached value which might invalidate pointers
+ // held by clients.
+ assert(m_cached_watch_spec == watchpoint_sp->GetWatchSpec());
+ }
+ return m_cached_watch_spec.c_str();
+ }
+ return nullptr;
+}
Index: lldb/include/lldb/API/SBWatchpoint.h
===================================================================
--- lldb/include/lldb/API/SBWatchpoint.h
+++ lldb/include/lldb/API/SBWatchpoint.h
@@ -10,6 +10,8 @@
#define LLDB_API_SBWATCHPOINT_H
#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBType.h"
+#include <string>
namespace lldb {
@@ -77,11 +79,18 @@
static lldb::SBWatchpoint GetWatchpointFromEvent(const lldb::SBEvent &event);
+ lldb::SBType GetType();
+
+ bool IsWatchVariable();
+
+ const char *GetWatchSpec();
+
private:
friend class SBTarget;
friend class SBValue;
std::weak_ptr<lldb_private::Watchpoint> m_opaque_wp;
+ std::string m_cached_watch_spec;
};
} // namespace lldb
Index: lldb/include/lldb/API/SBType.h
===================================================================
--- lldb/include/lldb/API/SBType.h
+++ lldb/include/lldb/API/SBType.h
@@ -239,6 +239,7 @@
friend class SBTypeMemberFunction;
friend class SBTypeList;
friend class SBValue;
+ friend class SBWatchpoint;
SBType(const lldb_private::CompilerType &);
SBType(const lldb::TypeSP &);
Index: lldb/bindings/interface/SBWatchpointDocstrings.i
===================================================================
--- lldb/bindings/interface/SBWatchpointDocstrings.i
+++ lldb/bindings/interface/SBWatchpointDocstrings.i
@@ -19,3 +19,20 @@
%feature("docstring", "
The watchpoint stops only if the condition expression evaluates to true."
) lldb::SBWatchpoint::SetCondition;
+
+%feature("docstring", "
+ Returns the type recorded when the watchpoint was created. For variable
+ watchpoints it is the type of the watched variable. For expression
+ watchpoints it is the type of the provided expression."
+) lldb::SBWatchpoint::GetType;
+
+%feature("docstring", "
+ Returns true if the watchpoint is a variable watchpoint. Otherwise the
+ watchpoint is an expression watchpoint or in an invalid state."
+) lldb::SBWatchpoint::IsWatchVariable;
+
+%feature("docstring", "
+ Get the spec for the watchpoint. For variable watchpoints this is the name
+ of the variable. For expression watchpoints it is empty
+ (may change if the future)."
+) lldb::SBWatchpoint::GetWatchSpec;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits