88
99#include " DAP.h"
1010#include " DAPLog.h"
11+ #include " EventHelper.h"
1112#include " Handler/RequestHandler.h"
1213#include " Handler/ResponseHandler.h"
1314#include " JSONUtils.h"
2021#include " lldb/API/SBBreakpoint.h"
2122#include " lldb/API/SBCommandInterpreter.h"
2223#include " lldb/API/SBCommandReturnObject.h"
24+ #include " lldb/API/SBEvent.h"
2325#include " lldb/API/SBLanguageRuntime.h"
2426#include " lldb/API/SBListener.h"
2527#include " lldb/API/SBProcess.h"
5254#include < mutex>
5355#include < optional>
5456#include < string>
57+ #include < thread>
5558#include < utility>
5659#include < variant>
5760
@@ -77,6 +80,48 @@ const char DEV_NULL[] = "/dev/null";
7780
7881namespace lldb_dap {
7982
83+ static std::string GetStringFromStructuredData (lldb::SBStructuredData &data,
84+ const char *key) {
85+ lldb::SBStructuredData keyValue = data.GetValueForKey (key);
86+ if (!keyValue)
87+ return std::string ();
88+
89+ const size_t length = keyValue.GetStringValue (nullptr , 0 );
90+
91+ if (length == 0 )
92+ return std::string ();
93+
94+ std::string str (length + 1 , 0 );
95+ keyValue.GetStringValue (&str[0 ], length + 1 );
96+ return str;
97+ }
98+
99+ static uint64_t GetUintFromStructuredData (lldb::SBStructuredData &data,
100+ const char *key) {
101+ lldb::SBStructuredData keyValue = data.GetValueForKey (key);
102+
103+ if (!keyValue.IsValid ())
104+ return 0 ;
105+ return keyValue.GetUnsignedIntegerValue ();
106+ }
107+
108+ static llvm::StringRef GetModuleEventReason (uint32_t event_mask) {
109+ if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded)
110+ return " new" ;
111+ if (event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded)
112+ return " removed" ;
113+ assert (event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded ||
114+ event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged);
115+ return " changed" ;
116+ }
117+
118+ // / Return string with first character capitalized.
119+ static std::string capitalize (llvm::StringRef str) {
120+ if (str.empty ())
121+ return " " ;
122+ return ((llvm::Twine)llvm::toUpper (str[0 ]) + str.drop_front ()).str ();
123+ }
124+
80125llvm::StringRef DAP::debug_adapter_path = " " ;
81126
82127DAP::DAP (Log *log, const ReplMode default_repl_mode,
@@ -94,13 +139,6 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode,
94139
95140DAP::~DAP () = default ;
96141
97- // / Return string with first character capitalized.
98- static std::string capitalize (llvm::StringRef str) {
99- if (str.empty ())
100- return " " ;
101- return ((llvm::Twine)llvm::toUpper (str[0 ]) + str.drop_front ()).str ();
102- }
103-
104142void DAP::PopulateExceptionBreakpoints () {
105143 llvm::call_once (init_exception_breakpoints_flag, [this ]() {
106144 exception_breakpoints = std::vector<ExceptionBreakpoint>{};
@@ -1390,4 +1428,213 @@ protocol::Capabilities DAP::GetCapabilities() {
13901428 return capabilities;
13911429}
13921430
1431+ void DAP::StartEventThread () {
1432+ event_thread = std::thread (&DAP::EventThread, this );
1433+ }
1434+
1435+ void DAP::StartProgressEventThread () {
1436+ progress_event_thread = std::thread (&DAP::ProgressEventThread, this );
1437+ }
1438+
1439+ void DAP::ProgressEventThread () {
1440+ lldb::SBListener listener (" lldb-dap.progress.listener" );
1441+ debugger.GetBroadcaster ().AddListener (
1442+ listener, lldb::SBDebugger::eBroadcastBitProgress |
1443+ lldb::SBDebugger::eBroadcastBitExternalProgress);
1444+ broadcaster.AddListener (listener, eBroadcastBitStopProgressThread);
1445+ lldb::SBEvent event;
1446+ bool done = false ;
1447+ while (!done) {
1448+ if (listener.WaitForEvent (1 , event)) {
1449+ const auto event_mask = event.GetType ();
1450+ if (event.BroadcasterMatchesRef (broadcaster)) {
1451+ if (event_mask & eBroadcastBitStopProgressThread) {
1452+ done = true ;
1453+ }
1454+ } else {
1455+ lldb::SBStructuredData data =
1456+ lldb::SBDebugger::GetProgressDataFromEvent (event);
1457+
1458+ const uint64_t progress_id =
1459+ GetUintFromStructuredData (data, " progress_id" );
1460+ const uint64_t completed = GetUintFromStructuredData (data, " completed" );
1461+ const uint64_t total = GetUintFromStructuredData (data, " total" );
1462+ const std::string details =
1463+ GetStringFromStructuredData (data, " details" );
1464+
1465+ if (completed == 0 ) {
1466+ if (total == UINT64_MAX) {
1467+ // This progress is non deterministic and won't get updated until it
1468+ // is completed. Send the "message" which will be the combined title
1469+ // and detail. The only other progress event for thus
1470+ // non-deterministic progress will be the completed event So there
1471+ // will be no need to update the detail.
1472+ const std::string message =
1473+ GetStringFromStructuredData (data, " message" );
1474+ SendProgressEvent (progress_id, message.c_str (), completed, total);
1475+ } else {
1476+ // This progress is deterministic and will receive updates,
1477+ // on the progress creation event VSCode will save the message in
1478+ // the create packet and use that as the title, so we send just the
1479+ // title in the progressCreate packet followed immediately by a
1480+ // detail packet, if there is any detail.
1481+ const std::string title =
1482+ GetStringFromStructuredData (data, " title" );
1483+ SendProgressEvent (progress_id, title.c_str (), completed, total);
1484+ if (!details.empty ())
1485+ SendProgressEvent (progress_id, details.c_str (), completed, total);
1486+ }
1487+ } else {
1488+ // This progress event is either the end of the progress dialog, or an
1489+ // update with possible detail. The "detail" string we send to VS Code
1490+ // will be appended to the progress dialog's initial text from when it
1491+ // was created.
1492+ SendProgressEvent (progress_id, details.c_str (), completed, total);
1493+ }
1494+ }
1495+ }
1496+ }
1497+ }
1498+
1499+ // All events from the debugger, target, process, thread and frames are
1500+ // received in this function that runs in its own thread. We are using a
1501+ // "FILE *" to output packets back to VS Code and they have mutexes in them
1502+ // them prevent multiple threads from writing simultaneously so no locking
1503+ // is required.
1504+ void DAP::EventThread () {
1505+ llvm::set_thread_name (transport.GetClientName () + " .event_handler" );
1506+ lldb::SBEvent event;
1507+ lldb::SBListener listener = debugger.GetListener ();
1508+ broadcaster.AddListener (listener, eBroadcastBitStopEventThread);
1509+ debugger.GetBroadcaster ().AddListener (
1510+ listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning);
1511+ bool done = false ;
1512+ while (!done) {
1513+ if (listener.WaitForEvent (1 , event)) {
1514+ const auto event_mask = event.GetType ();
1515+ if (lldb::SBProcess::EventIsProcessEvent (event)) {
1516+ lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent (event);
1517+ if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
1518+ auto state = lldb::SBProcess::GetStateFromEvent (event);
1519+ switch (state) {
1520+ case lldb::eStateConnected:
1521+ case lldb::eStateDetached:
1522+ case lldb::eStateInvalid:
1523+ case lldb::eStateUnloaded:
1524+ break ;
1525+ case lldb::eStateAttaching:
1526+ case lldb::eStateCrashed:
1527+ case lldb::eStateLaunching:
1528+ case lldb::eStateStopped:
1529+ case lldb::eStateSuspended:
1530+ // Only report a stopped event if the process was not
1531+ // automatically restarted.
1532+ if (!lldb::SBProcess::GetRestartedFromEvent (event)) {
1533+ SendStdOutStdErr (*this , process);
1534+ SendThreadStoppedEvent (*this );
1535+ }
1536+ break ;
1537+ case lldb::eStateRunning:
1538+ case lldb::eStateStepping:
1539+ WillContinue ();
1540+ SendContinuedEvent (*this );
1541+ break ;
1542+ case lldb::eStateExited:
1543+ lldb::SBStream stream;
1544+ process.GetStatus (stream);
1545+ SendOutput (OutputType::Console, stream.GetData ());
1546+
1547+ // When restarting, we can get an "exited" event for the process we
1548+ // just killed with the old PID, or even with no PID. In that case
1549+ // we don't have to terminate the session.
1550+ if (process.GetProcessID () == LLDB_INVALID_PROCESS_ID ||
1551+ process.GetProcessID () == restarting_process_id) {
1552+ restarting_process_id = LLDB_INVALID_PROCESS_ID;
1553+ } else {
1554+ // Run any exit LLDB commands the user specified in the
1555+ // launch.json
1556+ RunExitCommands ();
1557+ SendProcessExitedEvent (*this , process);
1558+ SendTerminatedEvent ();
1559+ done = true ;
1560+ }
1561+ break ;
1562+ }
1563+ } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
1564+ (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
1565+ SendStdOutStdErr (*this , process);
1566+ }
1567+ } else if (lldb::SBTarget::EventIsTargetEvent (event)) {
1568+ if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded ||
1569+ event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded ||
1570+ event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded ||
1571+ event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged) {
1572+ llvm::StringRef reason = GetModuleEventReason (event_mask);
1573+ const uint32_t num_modules =
1574+ lldb::SBTarget::GetNumModulesFromEvent (event);
1575+ for (uint32_t i = 0 ; i < num_modules; ++i) {
1576+ lldb::SBModule module =
1577+ lldb::SBTarget::GetModuleAtIndexFromEvent (i, event);
1578+ if (!module .IsValid ())
1579+ continue ;
1580+
1581+ llvm::json::Object body;
1582+ body.try_emplace (" reason" , reason);
1583+ body.try_emplace (" module" , CreateModule (target, module ));
1584+ llvm::json::Object module_event = CreateEventObject (" module" );
1585+ module_event.try_emplace (" body" , std::move (body));
1586+ SendJSON (llvm::json::Value (std::move (module_event)));
1587+ }
1588+ }
1589+ } else if (lldb::SBBreakpoint::EventIsBreakpointEvent (event)) {
1590+ if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
1591+ auto event_type =
1592+ lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent (event);
1593+ auto bp = Breakpoint (
1594+ *this , lldb::SBBreakpoint::GetBreakpointFromEvent (event));
1595+ // If the breakpoint was set through DAP, it will have the
1596+ // BreakpointBase::kDAPBreakpointLabel. Regardless of whether
1597+ // locations were added, removed, or resolved, the breakpoint isn't
1598+ // going away and the reason is always "changed".
1599+ if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
1600+ event_type & lldb::eBreakpointEventTypeLocationsRemoved ||
1601+ event_type & lldb::eBreakpointEventTypeLocationsResolved) &&
1602+ bp.MatchesName (BreakpointBase::kDAPBreakpointLabel )) {
1603+ // As the DAP client already knows the path of this breakpoint, we
1604+ // don't need to send it back as part of the "changed" event. This
1605+ // avoids sending paths that should be source mapped. Note that
1606+ // CreateBreakpoint doesn't apply source mapping and certain
1607+ // implementation ignore the source part of this event anyway.
1608+ llvm::json::Value source_bp = CreateBreakpoint (&bp);
1609+ source_bp.getAsObject ()->erase (" source" );
1610+
1611+ llvm::json::Object body;
1612+ body.try_emplace (" breakpoint" , source_bp);
1613+ body.try_emplace (" reason" , " changed" );
1614+
1615+ llvm::json::Object bp_event = CreateEventObject (" breakpoint" );
1616+ bp_event.try_emplace (" body" , std::move (body));
1617+
1618+ SendJSON (llvm::json::Value (std::move (bp_event)));
1619+ }
1620+ }
1621+ } else if (event_mask & lldb::eBroadcastBitError ||
1622+ event_mask & lldb::eBroadcastBitWarning) {
1623+ lldb::SBStructuredData data =
1624+ lldb::SBDebugger::GetDiagnosticFromEvent (event);
1625+ if (!data.IsValid ())
1626+ continue ;
1627+ std::string type = GetStringValue (data.GetValueForKey (" type" ));
1628+ std::string message = GetStringValue (data.GetValueForKey (" message" ));
1629+ SendOutput (OutputType::Important,
1630+ llvm::formatv (" {0}: {1}" , type, message).str ());
1631+ } else if (event.BroadcasterMatchesRef (broadcaster)) {
1632+ if (event_mask & eBroadcastBitStopEventThread) {
1633+ done = true ;
1634+ }
1635+ }
1636+ }
1637+ }
1638+ }
1639+
13931640} // namespace lldb_dap
0 commit comments