diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h index a906727f938a3..ca29696065eab 100644 --- a/lldb/include/lldb/API/SBBreakpointLocation.h +++ b/lldb/include/lldb/API/SBBreakpointLocation.h @@ -48,11 +48,13 @@ class LLDB_API SBBreakpointLocation { void SetCondition(const char *condition); const char *GetCondition(); - + void SetAutoContinue(bool auto_continue); bool GetAutoContinue(); + void SetCallback(SBBreakpointHitCallback callback, void *baton); + void SetScriptCallbackFunction(const char *callback_function_name); SBError SetScriptCallbackFunction(const char *callback_function_name, diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 6c03aba15447f..a253530f5718b 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -28,6 +28,8 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" +#include "SBBreakpointOptionCommon.h" + using namespace lldb; using namespace lldb_private; @@ -198,6 +200,21 @@ bool SBBreakpointLocation::GetAutoContinue() { return false; } +void SBBreakpointLocation::SetCallback(SBBreakpointHitCallback callback, + void *baton) { + LLDB_INSTRUMENT_VA(this, callback, baton); + + BreakpointLocationSP loc_sp = GetSP(); + + if (loc_sp) { + std::lock_guard guard( + loc_sp->GetTarget().GetAPIMutex()); + BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton)); + loc_sp->SetCallback(SBBreakpointCallbackBaton::PrivateBreakpointHitCallback, + baton_sp, false); + } +} + void SBBreakpointLocation::SetScriptCallbackFunction( const char *callback_function_name) { LLDB_INSTRUMENT_VA(this, callback_function_name); diff --git a/lldb/test/API/api/multithreaded/TestMultithreaded.py b/lldb/test/API/api/multithreaded/TestMultithreaded.py index 231eb9ffefc42..33759906243a4 100644 --- a/lldb/test/API/api/multithreaded/TestMultithreaded.py +++ b/lldb/test/API/api/multithreaded/TestMultithreaded.py @@ -18,6 +18,7 @@ def setUp(self): self.generateSource('driver.cpp') self.generateSource('listener_test.cpp') self.generateSource('test_breakpoint_callback.cpp') + self.generateSource('test_breakpoint_location_callback.cpp') self.generateSource('test_listener_event_description.cpp') self.generateSource('test_listener_event_process_state.cpp') self.generateSource('test_listener_resume.cpp') @@ -41,6 +42,15 @@ def test_breakpoint_callback(self): self.build_and_test('driver.cpp test_breakpoint_callback.cpp', 'test_breakpoint_callback') + @skipIfRemote + @skipIfNoSBHeaders + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows + def test_breakpoint_location_callback(self): + """Test the that SBBreakpointLocation callback is invoked when a breakpoint is hit. """ + self.build_and_test('driver.cpp test_breakpoint_location_callback.cpp', + 'test_breakpoint_location_callback') + @skipIfRemote @skipIfNoSBHeaders # clang-cl does not support throw or catch (llvm.org/pr24538) diff --git a/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp.template b/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp.template new file mode 100644 index 0000000000000..0b0dc5652e850 --- /dev/null +++ b/lldb/test/API/api/multithreaded/test_breakpoint_location_callback.cpp.template @@ -0,0 +1,52 @@ + +// LLDB C++ API Test: verify that the function registered with +// SBBreakpoint.SetCallback() is invoked when a breakpoint is hit. + +#include +#include +#include +#include + +%include_SB_APIs% + +#include "common.h" + +using namespace std; +using namespace lldb; + +mutex g_mutex; +condition_variable g_condition; +int g_breakpoint_hit_count = 0; + +bool BPCallback (void *baton, + SBProcess &process, + SBThread &thread, + SBBreakpointLocation &location) { + lock_guard lock(g_mutex); + g_breakpoint_hit_count += 1; + g_condition.notify_all(); + return true; +} + +void test(SBDebugger &dbg, vector args) { + dbg.SetAsync(false); + SBTarget target = dbg.CreateTarget(args.at(0).c_str()); + if (!target.IsValid()) throw Exception("invalid target"); + + SBBreakpoint breakpoint = target.BreakpointCreateByName("next"); + if (!breakpoint.IsValid()) throw Exception("invalid breakpoint"); + + if(breakpoint.GetNumLocations() != 1) throw Exception("unexpected amount of breakpoint locations"); + SBBreakpointLocation breakpoint_location = breakpoint.GetLocationAtIndex(0); + breakpoint_location.SetCallback(BPCallback, 0); + + std::unique_ptr working_dir(get_working_dir()); + SBProcess process = target.LaunchSimple (0, 0, working_dir.get()); + + { + unique_lock lock(g_mutex); + g_condition.wait_for(lock, chrono::seconds(5)); + if (g_breakpoint_hit_count != 1) + throw Exception("Breakpoint hit count expected to be 1"); + } +}