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 lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits