Index: lldb/bindings/interface/SBDebugger.i =================================================================== --- lldb/bindings/interface/SBDebugger.i +++ lldb/bindings/interface/SBDebugger.i @@ -119,7 +119,9 @@ public: enum { - eBroadcastBitProgress = (1 << 0) + eBroadcastBitProgress = (1 << 0), + eBroadcastBitWarning = (1 << 1), + eBroadcastBitError = (1 << 2), }; @@ -129,6 +131,8 @@ uint64_t &OUTPUT, bool &OUTPUT); + lldb::SBStructuredData GetDiagnosticFromEvent(const lldb::SBEvent &event); + SBBroadcaster GetBroadcaster(); static void Index: lldb/include/lldb/API/SBDebugger.h =================================================================== --- lldb/include/lldb/API/SBDebugger.h +++ lldb/include/lldb/API/SBDebugger.h @@ -33,7 +33,11 @@ class LLDB_API SBDebugger { public: - FLAGS_ANONYMOUS_ENUM(){eBroadcastBitProgress = (1 << 0)}; + FLAGS_ANONYMOUS_ENUM(){ + eBroadcastBitProgress = (1 << 0), + eBroadcastBitWarning = (1 << 1), + eBroadcastBitError = (1 << 2), + }; SBDebugger(); @@ -79,6 +83,8 @@ uint64_t &completed, uint64_t &total, bool &is_debugger_specific); + lldb::SBStructuredData GetDiagnosticFromEvent(const lldb::SBEvent &event); + lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs); static void Initialize(); Index: lldb/include/lldb/Core/DebuggerEvents.h =================================================================== --- lldb/include/lldb/Core/DebuggerEvents.h +++ lldb/include/lldb/Core/DebuggerEvents.h @@ -59,6 +59,7 @@ ~DiagnosticEventData() {} const std::string &GetMessage() const { return m_message; } + bool IsDebuggerSpecific() const { return m_debugger_specific; } Type GetType() const { return m_type; } llvm::StringRef GetPrefix() const; Index: lldb/source/API/SBDebugger.cpp =================================================================== --- lldb/source/API/SBDebugger.cpp +++ lldb/source/API/SBDebugger.cpp @@ -164,6 +164,26 @@ return progress_data->GetMessage().c_str(); } +lldb::SBStructuredData +SBDebugger::GetDiagnosticFromEvent(const lldb::SBEvent &event) { + LLDB_INSTRUMENT_VA(event); + + const DiagnosticEventData *diagnostic_data = + DiagnosticEventData::GetEventDataFromEvent(event.get()); + if (!diagnostic_data) + return {}; + + auto dictionary = std::make_unique(); + dictionary->AddStringItem("message", diagnostic_data->GetMessage()); + dictionary->AddStringItem("type", diagnostic_data->GetPrefix()); + dictionary->AddBooleanItem("debugger_specific", + diagnostic_data->IsDebuggerSpecific()); + + SBStructuredData data; + data.m_impl_up->SetObjectSP(std::move(dictionary)); + return data; +} + SBBroadcaster SBDebugger::GetBroadcaster() { LLDB_INSTRUMENT_VA(this); SBBroadcaster broadcaster(&m_opaque_sp->GetBroadcaster(), false); Index: lldb/test/API/functionalities/diagnostic_reporting/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/diagnostic_reporting/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules Index: lldb/test/API/functionalities/diagnostic_reporting/TestDiagnosticReporting.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/diagnostic_reporting/TestDiagnosticReporting.py @@ -0,0 +1,65 @@ +""" +Test that we are able to broadcast and receive diagnostic events from lldb +""" +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil +import threading + + +class TestDiagnosticReporting(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + eBroadcastBitStopDiagnosticThread = (1 << 0) + + def setUp(self): + TestBase.setUp(self) + self.diagnostic_events = [] + + def fetch_events(self): + event = lldb.SBEvent() + + done = False + while not done: + if self.listener.WaitForEvent(1, event): + event_mask = event.GetType() + if event.BroadcasterMatchesRef(self.test_broadcaster): + if event_mask & self.eBroadcastBitStopDiagnosticThread: + done = True + elif event.BroadcasterMatchesRef(self.diagnostic_broadcaster): + ret_args = lldb.SBDebugger().GetDiagnosticFromEvent(event) + self.assertGreater(len(ret_args), 1) + + message = ret_args[0] + if message: + self.diagnostic_events.append((message, event)) + + def test_dwarf_symbol_loading_diagnostic_report(self): + """Test that we are able to fetch dwarf symbol loading diagnostic events""" + self.build() + + self.listener = lldb.SBListener("lldb.diagnostic.listener") + self.test_broadcaster = lldb.SBBroadcaster('lldb.broadcaster.test') + self.listener.StartListeningForEvents( + self.test_broadcaster, self.eBroadcastBitStopDiagnosticThread) + + self.diagnostic_broadcaster = self.dbg.GetBroadcaster() + self.diagnostic_broadcaster.AddListener( + self.listener, lldb.SBDebugger.eBroadcastBitWarning) + self.diagnostic_broadcaster.AddListener( + self.listener, lldb.SBDebugger.eBroadcastBitError) + + listener_thread = threading.Thread(target=self.fetch_events) + listener_thread.start() + + lldbutil.run_to_source_breakpoint(self, 'break here', + lldb.SBFileSpec('main.c')) + + self.test_broadcaster.BroadcastEventByType( + self.eBroadcastBitStopDiagnosticThread) + listener_thread.join() + + # Not the most useful tests. We except no diagnostics. + self.assertEquals(len(self.diagnostic_events), 0) Index: lldb/test/API/functionalities/diagnostic_reporting/main.c =================================================================== --- /dev/null +++ lldb/test/API/functionalities/diagnostic_reporting/main.c @@ -0,0 +1,11 @@ +int bar(int b) { return b * b; } + +int foo(int f) { + int b = bar(f); // break here + return b; +} + +int main() { + int f = foo(42); + return f; +}