1//===-- DAP.cpp -------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DAP.h"
10#include "DAPLog.h"
11#include "EventHelper.h"
12#include "ExceptionBreakpoint.h"
13#include "Handler/RequestHandler.h"
14#include "Handler/ResponseHandler.h"
15#include "JSONUtils.h"
16#include "LLDBUtils.h"
17#include "OutputRedirector.h"
18#include "Protocol/ProtocolBase.h"
19#include "Protocol/ProtocolEvents.h"
20#include "Protocol/ProtocolRequests.h"
21#include "Protocol/ProtocolTypes.h"
22#include "ProtocolUtils.h"
23#include "Transport.h"
24#include "lldb/API/SBBreakpoint.h"
25#include "lldb/API/SBCommandInterpreter.h"
26#include "lldb/API/SBCommandReturnObject.h"
27#include "lldb/API/SBEvent.h"
28#include "lldb/API/SBLanguageRuntime.h"
29#include "lldb/API/SBListener.h"
30#include "lldb/API/SBProcess.h"
31#include "lldb/API/SBStream.h"
32#include "lldb/Utility/IOObject.h"
33#include "lldb/Utility/Status.h"
34#include "lldb/lldb-defines.h"
35#include "lldb/lldb-enumerations.h"
36#include "lldb/lldb-types.h"
37#include "llvm/ADT/ArrayRef.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/ScopeExit.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/StringRef.h"
42#include "llvm/ADT/Twine.h"
43#include "llvm/Support/Chrono.h"
44#include "llvm/Support/Error.h"
45#include "llvm/Support/ErrorHandling.h"
46#include "llvm/Support/FormatVariadic.h"
47#include "llvm/Support/raw_ostream.h"
48#include <algorithm>
49#include <cassert>
50#include <chrono>
51#include <condition_variable>
52#include <cstdarg>
53#include <cstdint>
54#include <cstdio>
55#include <fstream>
56#include <future>
57#include <memory>
58#include <mutex>
59#include <optional>
60#include <string>
61#include <thread>
62#include <utility>
63#include <variant>
64
65#if defined(_WIN32)
66#define NOMINMAX
67#include <fcntl.h>
68#include <io.h>
69#include <windows.h>
70#else
71#include <unistd.h>
72#endif
73
74using namespace lldb_dap;
75using namespace lldb_dap::protocol;
76using namespace lldb_private;
77
78namespace {
79#ifdef _WIN32
80const char DEV_NULL[] = "nul";
81#else
82const char DEV_NULL[] = "/dev/null";
83#endif
84} // namespace
85
86namespace lldb_dap {
87
88static std::string GetStringFromStructuredData(lldb::SBStructuredData &data,
89 const char *key) {
90 lldb::SBStructuredData keyValue = data.GetValueForKey(key);
91 if (!keyValue)
92 return std::string();
93
94 const size_t length = keyValue.GetStringValue(dst: nullptr, dst_len: 0);
95
96 if (length == 0)
97 return std::string();
98
99 std::string str(length + 1, 0);
100 keyValue.GetStringValue(dst: &str[0], dst_len: length + 1);
101 return str;
102}
103
104static uint64_t GetUintFromStructuredData(lldb::SBStructuredData &data,
105 const char *key) {
106 lldb::SBStructuredData keyValue = data.GetValueForKey(key);
107
108 if (!keyValue.IsValid())
109 return 0;
110 return keyValue.GetUnsignedIntegerValue();
111}
112
113/// Return string with first character capitalized.
114static std::string capitalize(llvm::StringRef str) {
115 if (str.empty())
116 return "";
117 return ((llvm::Twine)llvm::toUpper(x: str[0]) + str.drop_front()).str();
118}
119
120llvm::StringRef DAP::debug_adapter_path = "";
121
122DAP::DAP(Log *log, const ReplMode default_repl_mode,
123 std::vector<std::string> pre_init_commands, Transport &transport)
124 : log(log), transport(transport), broadcaster("lldb-dap"),
125 progress_event_reporter(
126 [&](const ProgressEvent &event) { SendJSON(json: event.ToJSON()); }),
127 repl_mode(default_repl_mode) {
128 configuration.preInitCommands = std::move(pre_init_commands);
129 RegisterRequests();
130}
131
132DAP::~DAP() = default;
133
134void DAP::PopulateExceptionBreakpoints() {
135 if (lldb::SBDebugger::SupportsLanguage(language: lldb::eLanguageTypeC_plus_plus)) {
136 exception_breakpoints.emplace_back(args&: *this, args: "cpp_catch", args: "C++ Catch",
137 args: lldb::eLanguageTypeC_plus_plus,
138 args: eExceptionKindCatch);
139 exception_breakpoints.emplace_back(args&: *this, args: "cpp_throw", args: "C++ Throw",
140 args: lldb::eLanguageTypeC_plus_plus,
141 args: eExceptionKindThrow);
142 }
143
144 if (lldb::SBDebugger::SupportsLanguage(language: lldb::eLanguageTypeObjC)) {
145 exception_breakpoints.emplace_back(args&: *this, args: "objc_catch", args: "Objective-C Catch",
146 args: lldb::eLanguageTypeObjC,
147 args: eExceptionKindCatch);
148 exception_breakpoints.emplace_back(args&: *this, args: "objc_throw", args: "Objective-C Throw",
149 args: lldb::eLanguageTypeObjC,
150 args: eExceptionKindThrow);
151 }
152
153 if (lldb::SBDebugger::SupportsLanguage(language: lldb::eLanguageTypeSwift)) {
154 exception_breakpoints.emplace_back(args&: *this, args: "swift_catch", args: "Swift Catch",
155 args: lldb::eLanguageTypeSwift,
156 args: eExceptionKindCatch);
157 exception_breakpoints.emplace_back(args&: *this, args: "swift_throw", args: "Swift Throw",
158 args: lldb::eLanguageTypeSwift,
159 args: eExceptionKindThrow);
160 }
161
162 // Besides handling the hardcoded list of languages from above, we try to find
163 // any other languages that support exception breakpoints using the SB API.
164 for (int raw_lang = lldb::eLanguageTypeUnknown;
165 raw_lang < lldb::eNumLanguageTypes; ++raw_lang) {
166 lldb::LanguageType lang = static_cast<lldb::LanguageType>(raw_lang);
167
168 // We first discard any languages already handled above.
169 if (lldb::SBLanguageRuntime::LanguageIsCFamily(language: lang) ||
170 lang == lldb::eLanguageTypeSwift)
171 continue;
172
173 if (!lldb::SBDebugger::SupportsLanguage(language: lang))
174 continue;
175
176 const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(language: lang);
177 if (!name)
178 continue;
179 std::string raw_lang_name = name;
180 std::string capitalized_lang_name = capitalize(str: name);
181
182 if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(language: lang)) {
183 const char *raw_throw_keyword =
184 lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(language: lang);
185 std::string throw_keyword =
186 raw_throw_keyword ? raw_throw_keyword : "throw";
187
188 exception_breakpoints.emplace_back(
189 args&: *this, args: raw_lang_name + "_" + throw_keyword,
190 args: capitalized_lang_name + " " + capitalize(str: throw_keyword), args&: lang,
191 args: eExceptionKindThrow);
192 }
193
194 if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(language: lang)) {
195 const char *raw_catch_keyword =
196 lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(language: lang);
197 std::string catch_keyword =
198 raw_catch_keyword ? raw_catch_keyword : "catch";
199
200 exception_breakpoints.emplace_back(
201 args&: *this, args: raw_lang_name + "_" + catch_keyword,
202 args: capitalized_lang_name + " " + capitalize(str: catch_keyword), args&: lang,
203 args: eExceptionKindCatch);
204 }
205 }
206}
207
208ExceptionBreakpoint *DAP::GetExceptionBreakpoint(llvm::StringRef filter) {
209 for (auto &bp : exception_breakpoints) {
210 if (bp.GetFilter() == filter)
211 return &bp;
212 }
213 return nullptr;
214}
215
216ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
217 for (auto &bp : exception_breakpoints) {
218 if (bp.GetID() == bp_id)
219 return &bp;
220 }
221 return nullptr;
222}
223
224llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) {
225 in = lldb::SBFile(std::fopen(filename: DEV_NULL, modes: "r"), /*transfer_ownership=*/true);
226
227 if (auto Error = out.RedirectTo(file_override: overrideOut, callback: [this](llvm::StringRef output) {
228 SendOutput(o: OutputType::Console, output);
229 }))
230 return Error;
231
232 if (auto Error = err.RedirectTo(file_override: overrideErr, callback: [this](llvm::StringRef output) {
233 SendOutput(o: OutputType::Console, output);
234 }))
235 return Error;
236
237 return llvm::Error::success();
238}
239
240void DAP::StopEventHandlers() {
241 if (event_thread.joinable()) {
242 broadcaster.BroadcastEventByType(event_type: eBroadcastBitStopEventThread);
243 event_thread.join();
244 }
245 if (progress_event_thread.joinable()) {
246 broadcaster.BroadcastEventByType(event_type: eBroadcastBitStopProgressThread);
247 progress_event_thread.join();
248 }
249}
250
251// Serialize the JSON value into a string and send the JSON packet to
252// the "out" stream.
253void DAP::SendJSON(const llvm::json::Value &json) {
254 // FIXME: Instead of parsing the output message from JSON, pass the `Message`
255 // as parameter to `SendJSON`.
256 Message message;
257 llvm::json::Path::Root root;
258 if (!fromJSON(json, message, root)) {
259 DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}",
260 transport.GetClientName());
261 return;
262 }
263 Send(message);
264}
265
266void DAP::Send(const Message &message) {
267 // FIXME: After all the requests have migrated from LegacyRequestHandler >
268 // RequestHandler<> this should be handled in RequestHandler<>::operator().
269 if (auto *resp = std::get_if<Response>(ptr: &message);
270 resp && debugger.InterruptRequested()) {
271 // Clear the interrupt request.
272 debugger.CancelInterruptRequest();
273
274 // If the debugger was interrupted, convert this response into a 'cancelled'
275 // response because we might have a partial result.
276 Response cancelled{/*request_seq=*/resp->request_seq,
277 /*command=*/resp->command,
278 /*success=*/false,
279 /*message=*/eResponseMessageCancelled,
280 /*body=*/std::nullopt};
281 if (llvm::Error err = transport.Write(t: cancelled))
282 DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}",
283 transport.GetClientName());
284 return;
285 }
286
287 if (llvm::Error err = transport.Write(t: message))
288 DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}",
289 transport.GetClientName());
290}
291
292// "OutputEvent": {
293// "allOf": [ { "$ref": "#/definitions/Event" }, {
294// "type": "object",
295// "description": "Event message for 'output' event type. The event
296// indicates that the target has produced some output.",
297// "properties": {
298// "event": {
299// "type": "string",
300// "enum": [ "output" ]
301// },
302// "body": {
303// "type": "object",
304// "properties": {
305// "category": {
306// "type": "string",
307// "description": "The output category. If not specified,
308// 'console' is assumed.",
309// "_enum": [ "console", "stdout", "stderr", "telemetry" ]
310// },
311// "output": {
312// "type": "string",
313// "description": "The output to report."
314// },
315// "variablesReference": {
316// "type": "number",
317// "description": "If an attribute 'variablesReference' exists
318// and its value is > 0, the output contains
319// objects which can be retrieved by passing
320// variablesReference to the VariablesRequest."
321// },
322// "source": {
323// "$ref": "#/definitions/Source",
324// "description": "An optional source location where the output
325// was produced."
326// },
327// "line": {
328// "type": "integer",
329// "description": "An optional source location line where the
330// output was produced."
331// },
332// "column": {
333// "type": "integer",
334// "description": "An optional source location column where the
335// output was produced."
336// },
337// "data": {
338// "type":["array","boolean","integer","null","number","object",
339// "string"],
340// "description": "Optional data to report. For the 'telemetry'
341// category the data will be sent to telemetry, for
342// the other categories the data is shown in JSON
343// format."
344// }
345// },
346// "required": ["output"]
347// }
348// },
349// "required": [ "event", "body" ]
350// }]
351// }
352void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
353 if (output.empty())
354 return;
355
356 const char *category = nullptr;
357 switch (o) {
358 case OutputType::Console:
359 category = "console";
360 break;
361 case OutputType::Important:
362 category = "important";
363 break;
364 case OutputType::Stdout:
365 category = "stdout";
366 break;
367 case OutputType::Stderr:
368 category = "stderr";
369 break;
370 case OutputType::Telemetry:
371 category = "telemetry";
372 break;
373 }
374
375 // Send each line of output as an individual event, including the newline if
376 // present.
377 ::size_t idx = 0;
378 do {
379 ::size_t end = output.find(C: '\n', From: idx);
380 if (end == llvm::StringRef::npos)
381 end = output.size() - 1;
382 llvm::json::Object event(CreateEventObject(event_name: "output"));
383 llvm::json::Object body;
384 body.try_emplace(K: "category", Args&: category);
385 EmplaceSafeString(obj&: body, key: "output", str: output.slice(Start: idx, End: end + 1).str());
386 event.try_emplace(K: "body", Args: std::move(body));
387 SendJSON(json: llvm::json::Value(std::move(event)));
388 idx = end + 1;
389 } while (idx < output.size());
390}
391
392// interface ProgressStartEvent extends Event {
393// event: 'progressStart';
394//
395// body: {
396// /**
397// * An ID that must be used in subsequent 'progressUpdate' and
398// 'progressEnd'
399// * events to make them refer to the same progress reporting.
400// * IDs must be unique within a debug session.
401// */
402// progressId: string;
403//
404// /**
405// * Mandatory (short) title of the progress reporting. Shown in the UI to
406// * describe the long running operation.
407// */
408// title: string;
409//
410// /**
411// * The request ID that this progress report is related to. If specified a
412// * debug adapter is expected to emit
413// * progress events for the long running request until the request has
414// been
415// * either completed or cancelled.
416// * If the request ID is omitted, the progress report is assumed to be
417// * related to some general activity of the debug adapter.
418// */
419// requestId?: number;
420//
421// /**
422// * If true, the request that reports progress may be canceled with a
423// * 'cancel' request.
424// * So this property basically controls whether the client should use UX
425// that
426// * supports cancellation.
427// * Clients that don't support cancellation are allowed to ignore the
428// * setting.
429// */
430// cancellable?: boolean;
431//
432// /**
433// * Optional, more detailed progress message.
434// */
435// message?: string;
436//
437// /**
438// * Optional progress percentage to display (value range: 0 to 100). If
439// * omitted no percentage will be shown.
440// */
441// percentage?: number;
442// };
443// }
444//
445// interface ProgressUpdateEvent extends Event {
446// event: 'progressUpdate';
447//
448// body: {
449// /**
450// * The ID that was introduced in the initial 'progressStart' event.
451// */
452// progressId: string;
453//
454// /**
455// * Optional, more detailed progress message. If omitted, the previous
456// * message (if any) is used.
457// */
458// message?: string;
459//
460// /**
461// * Optional progress percentage to display (value range: 0 to 100). If
462// * omitted no percentage will be shown.
463// */
464// percentage?: number;
465// };
466// }
467//
468// interface ProgressEndEvent extends Event {
469// event: 'progressEnd';
470//
471// body: {
472// /**
473// * The ID that was introduced in the initial 'ProgressStartEvent'.
474// */
475// progressId: string;
476//
477// /**
478// * Optional, more detailed progress message. If omitted, the previous
479// * message (if any) is used.
480// */
481// message?: string;
482// };
483// }
484
485void DAP::SendProgressEvent(uint64_t progress_id, const char *message,
486 uint64_t completed, uint64_t total) {
487 progress_event_reporter.Push(progress_id, message, completed, total);
488}
489
490void __attribute__((format(printf, 3, 4)))
491DAP::SendFormattedOutput(OutputType o, const char *format, ...) {
492 char buffer[1024];
493 va_list args;
494 va_start(args, format);
495 int actual_length = vsnprintf(s: buffer, maxlen: sizeof(buffer), format: format, arg: args);
496 va_end(args);
497 SendOutput(
498 o, output: llvm::StringRef(buffer, std::min<int>(a: actual_length, b: sizeof(buffer))));
499}
500
501int32_t DAP::CreateSourceReference(lldb::addr_t address) {
502 std::lock_guard<std::mutex> guard(m_source_references_mutex);
503 auto iter = llvm::find(Range&: m_source_references, Val: address);
504 if (iter != m_source_references.end())
505 return std::distance(first: m_source_references.begin(), last: iter) + 1;
506
507 m_source_references.emplace_back(args&: address);
508 return static_cast<int32_t>(m_source_references.size());
509}
510
511std::optional<lldb::addr_t> DAP::GetSourceReferenceAddress(int32_t reference) {
512 std::lock_guard<std::mutex> guard(m_source_references_mutex);
513 if (reference <= LLDB_DAP_INVALID_SRC_REF)
514 return std::nullopt;
515
516 if (static_cast<size_t>(reference) > m_source_references.size())
517 return std::nullopt;
518
519 return m_source_references[reference - 1];
520}
521
522ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
523 const auto num = thread.GetStopReasonDataCount();
524 // Check to see if have hit an exception breakpoint and change the
525 // reason to "exception", but only do so if all breakpoints that were
526 // hit are exception breakpoints.
527 ExceptionBreakpoint *exc_bp = nullptr;
528 for (size_t i = 0; i < num; i += 2) {
529 // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
530 // thread.GetStopReasonDataAtIndex(i+1) will return the location
531 // within that breakpoint. We only care about the bp ID so we can
532 // see if this is an exception breakpoint that is getting hit.
533 lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(idx: i);
534 exc_bp = GetExceptionBreakpoint(bp_id);
535 // If any breakpoint is not an exception breakpoint, then stop and
536 // report this as a normal breakpoint
537 if (exc_bp == nullptr)
538 return nullptr;
539 }
540 return exc_bp;
541}
542
543lldb::SBThread DAP::GetLLDBThread(lldb::tid_t tid) {
544 return target.GetProcess().GetThreadByID(sb_thread_id: tid);
545}
546
547lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) {
548 auto tid = GetInteger<int64_t>(obj: arguments, key: "threadId")
549 .value_or(LLDB_INVALID_THREAD_ID);
550 return target.GetProcess().GetThreadByID(sb_thread_id: tid);
551}
552
553lldb::SBFrame DAP::GetLLDBFrame(uint64_t frame_id) {
554 lldb::SBProcess process = target.GetProcess();
555 // Upper 32 bits is the thread index ID
556 lldb::SBThread thread =
557 process.GetThreadByIndexID(index_id: GetLLDBThreadIndexID(dap_frame_id: frame_id));
558 // Lower 32 bits is the frame index
559 return thread.GetFrameAtIndex(idx: GetLLDBFrameID(dap_frame_id: frame_id));
560}
561
562lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
563 const auto frame_id =
564 GetInteger<uint64_t>(obj: arguments, key: "frameId").value_or(UINT64_MAX);
565 return GetLLDBFrame(frame_id);
566}
567
568ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
569 bool partial_expression) {
570 // Check for the escape hatch prefix.
571 if (!expression.empty() &&
572 llvm::StringRef(expression)
573 .starts_with(Prefix: configuration.commandEscapePrefix)) {
574 expression = expression.substr(pos: configuration.commandEscapePrefix.size());
575 return ReplMode::Command;
576 }
577
578 switch (repl_mode) {
579 case ReplMode::Variable:
580 return ReplMode::Variable;
581 case ReplMode::Command:
582 return ReplMode::Command;
583 case ReplMode::Auto:
584 // To determine if the expression is a command or not, check if the first
585 // term is a variable or command. If it's a variable in scope we will prefer
586 // that behavior and give a warning to the user if they meant to invoke the
587 // operation as a command.
588 //
589 // Example use case:
590 // int p and expression "p + 1" > variable
591 // int i and expression "i" > variable
592 // int var and expression "va" > command
593 std::pair<llvm::StringRef, llvm::StringRef> token =
594 llvm::getToken(Source: expression);
595
596 // If the first token is not fully finished yet, we can't
597 // determine whether this will be a variable or a lldb command.
598 if (partial_expression && token.second.empty())
599 return ReplMode::Auto;
600
601 std::string term = token.first.str();
602 lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
603 bool term_is_command = interpreter.CommandExists(cmd: term.c_str()) ||
604 interpreter.UserCommandExists(cmd: term.c_str()) ||
605 interpreter.AliasExists(cmd: term.c_str());
606 bool term_is_variable = frame.FindVariable(var_name: term.c_str()).IsValid();
607
608 // If we have both a variable and command, warn the user about the conflict.
609 if (term_is_command && term_is_variable) {
610 llvm::errs()
611 << "Warning: Expression '" << term
612 << "' is both an LLDB command and variable. It will be evaluated as "
613 "a variable. To evaluate the expression as an LLDB command, use '"
614 << configuration.commandEscapePrefix << "' as a prefix.\n";
615 }
616
617 // Variables take preference to commands in auto, since commands can always
618 // be called using the command_escape_prefix
619 return term_is_variable ? ReplMode::Variable
620 : term_is_command ? ReplMode::Command
621 : ReplMode::Variable;
622 }
623
624 llvm_unreachable("enum cases exhausted.");
625}
626
627std::optional<protocol::Source> DAP::ResolveSource(const lldb::SBFrame &frame) {
628 if (!frame.IsValid())
629 return std::nullopt;
630
631 const lldb::SBAddress frame_pc = frame.GetPCAddress();
632 if (DisplayAssemblySource(debugger, address: frame_pc))
633 return ResolveAssemblySource(address: frame_pc);
634
635 return CreateSource(file: frame.GetLineEntry().GetFileSpec());
636}
637
638std::optional<protocol::Source> DAP::ResolveSource(lldb::SBAddress address) {
639 if (DisplayAssemblySource(debugger, address))
640 return ResolveAssemblySource(address);
641
642 lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address);
643 if (!line_entry.IsValid())
644 return std::nullopt;
645
646 return CreateSource(file: line_entry.GetFileSpec());
647}
648
649std::optional<protocol::Source>
650DAP::ResolveAssemblySource(lldb::SBAddress address) {
651 lldb::SBSymbol symbol = address.GetSymbol();
652 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
653 std::string name;
654 if (symbol.IsValid()) {
655 load_addr = symbol.GetStartAddress().GetLoadAddress(target);
656 name = symbol.GetName();
657 } else {
658 load_addr = address.GetLoadAddress(target);
659 name = GetLoadAddressString(addr: load_addr);
660 }
661
662 if (load_addr == LLDB_INVALID_ADDRESS)
663 return std::nullopt;
664
665 protocol::Source source;
666 source.sourceReference = CreateSourceReference(address: load_addr);
667 lldb::SBModule module = address.GetModule();
668 if (module.IsValid()) {
669 lldb::SBFileSpec file_spec = module.GetFileSpec();
670 if (file_spec.IsValid()) {
671 std::string path = GetSBFileSpecPath(file_spec);
672 if (!path.empty())
673 source.path = path + '`' + name;
674 }
675 }
676
677 source.name = std::move(name);
678
679 // Mark the source as deemphasized since users will only be able to view
680 // assembly for these frames.
681 source.presentationHint =
682 protocol::Source::eSourcePresentationHintDeemphasize;
683
684 return source;
685}
686
687bool DAP::RunLLDBCommands(llvm::StringRef prefix,
688 llvm::ArrayRef<std::string> commands) {
689 bool required_command_failed = false;
690 std::string output = ::RunLLDBCommands(
691 debugger, prefix, commands, required_command_failed,
692 /*parse_command_directives*/ true, /*echo_commands*/ true);
693 SendOutput(o: OutputType::Console, output);
694 return !required_command_failed;
695}
696
697static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) {
698 return llvm::createStringError(
699 EC: llvm::inconvertibleErrorCode(),
700 S: llvm::formatv(
701 Fmt: "Failed to run {0} commands. See the Debug Console for more details.",
702 Vals&: category)
703 .str()
704 .c_str());
705}
706
707llvm::Error
708DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) {
709 if (!RunLLDBCommands(prefix: "Running attachCommands:", commands: attach_commands))
710 return createRunLLDBCommandsErrorMessage(category: "attach");
711 return llvm::Error::success();
712}
713
714llvm::Error
715DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) {
716 if (!RunLLDBCommands(prefix: "Running launchCommands:", commands: launch_commands))
717 return createRunLLDBCommandsErrorMessage(category: "launch");
718 return llvm::Error::success();
719}
720
721llvm::Error DAP::RunInitCommands() {
722 if (!RunLLDBCommands(prefix: "Running initCommands:", commands: configuration.initCommands))
723 return createRunLLDBCommandsErrorMessage(category: "initCommands");
724 return llvm::Error::success();
725}
726
727llvm::Error DAP::RunPreInitCommands() {
728 if (!RunLLDBCommands(prefix: "Running preInitCommands:",
729 commands: configuration.preInitCommands))
730 return createRunLLDBCommandsErrorMessage(category: "preInitCommands");
731 return llvm::Error::success();
732}
733
734llvm::Error DAP::RunPreRunCommands() {
735 if (!RunLLDBCommands(prefix: "Running preRunCommands:", commands: configuration.preRunCommands))
736 return createRunLLDBCommandsErrorMessage(category: "preRunCommands");
737 return llvm::Error::success();
738}
739
740void DAP::RunPostRunCommands() {
741 RunLLDBCommands(prefix: "Running postRunCommands:", commands: configuration.postRunCommands);
742}
743void DAP::RunStopCommands() {
744 RunLLDBCommands(prefix: "Running stopCommands:", commands: configuration.stopCommands);
745}
746
747void DAP::RunExitCommands() {
748 RunLLDBCommands(prefix: "Running exitCommands:", commands: configuration.exitCommands);
749}
750
751void DAP::RunTerminateCommands() {
752 RunLLDBCommands(prefix: "Running terminateCommands:",
753 commands: configuration.terminateCommands);
754}
755
756lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
757 // Grab the name of the program we need to debug and create a target using
758 // the given program as an argument. Executable file can be a source of target
759 // architecture and platform, if they differ from the host. Setting exe path
760 // in launch info is useless because Target.Launch() will not change
761 // architecture and platform, therefore they should be known at the target
762 // creation. We also use target triple and platform from the launch
763 // configuration, if given, since in some cases ELF file doesn't contain
764 // enough information to determine correct arch and platform (or ELF can be
765 // omitted at all), so it is good to leave the user an opportunity to specify
766 // those. Any of those three can be left empty.
767 auto target = this->debugger.CreateTarget(
768 /*filename=*/configuration.program.data(),
769 /*target_triple=*/configuration.targetTriple.data(),
770 /*platform_name=*/configuration.platformName.data(),
771 /*add_dependent_modules=*/true, // Add dependent modules.
772 error);
773
774 return target;
775}
776
777void DAP::SetTarget(const lldb::SBTarget target) {
778 this->target = target;
779
780 if (target.IsValid()) {
781 // Configure breakpoint event listeners for the target.
782 lldb::SBListener listener = this->debugger.GetListener();
783 listener.StartListeningForEvents(
784 broadcaster: this->target.GetBroadcaster(),
785 event_mask: lldb::SBTarget::eBroadcastBitBreakpointChanged |
786 lldb::SBTarget::eBroadcastBitModulesLoaded |
787 lldb::SBTarget::eBroadcastBitModulesUnloaded |
788 lldb::SBTarget::eBroadcastBitSymbolsLoaded |
789 lldb::SBTarget::eBroadcastBitSymbolsChanged);
790 listener.StartListeningForEvents(broadcaster: this->broadcaster,
791 event_mask: eBroadcastBitStopEventThread);
792 }
793}
794
795bool DAP::HandleObject(const Message &M) {
796 TelemetryDispatcher dispatcher(&debugger);
797 dispatcher.Set(key: "client_name", value: transport.GetClientName().str());
798 if (const auto *req = std::get_if<Request>(ptr: &M)) {
799 {
800 std::lock_guard<std::mutex> guard(m_active_request_mutex);
801 m_active_request = req;
802
803 // Clear the interrupt request prior to invoking a handler.
804 if (debugger.InterruptRequested())
805 debugger.CancelInterruptRequest();
806 }
807
808 auto cleanup = llvm::make_scope_exit(F: [&]() {
809 std::scoped_lock<std::mutex> active_request_lock(m_active_request_mutex);
810 m_active_request = nullptr;
811 });
812
813 auto handler_pos = request_handlers.find(Key: req->command);
814 dispatcher.Set(key: "client_data",
815 value: llvm::Twine("request_command:", req->command).str());
816 if (handler_pos != request_handlers.end()) {
817 handler_pos->second->Run(*req);
818 return true; // Success
819 }
820
821 dispatcher.Set(key: "error",
822 value: llvm::Twine("unhandled-command:" + req->command).str());
823 DAP_LOG(log, "({0}) error: unhandled command '{1}'",
824 transport.GetClientName(), req->command);
825 return false; // Fail
826 }
827
828 if (const auto *resp = std::get_if<Response>(ptr: &M)) {
829 std::unique_ptr<ResponseHandler> response_handler;
830 {
831 std::lock_guard<std::mutex> guard(call_mutex);
832 auto inflight = inflight_reverse_requests.find(Val: resp->request_seq);
833 if (inflight != inflight_reverse_requests.end()) {
834 response_handler = std::move(inflight->second);
835 inflight_reverse_requests.erase(I: inflight);
836 }
837 }
838
839 if (!response_handler)
840 response_handler =
841 std::make_unique<UnknownResponseHandler>(args: "", args: resp->request_seq);
842
843 // Result should be given, use null if not.
844 if (resp->success) {
845 (*response_handler)(resp->body);
846 dispatcher.Set(key: "client_data",
847 value: llvm::Twine("response_command:", resp->command).str());
848 } else {
849 llvm::StringRef message = "Unknown error, response failed";
850 if (resp->message) {
851 message =
852 std::visit(visitor: llvm::makeVisitor(
853 Callables: [](const std::string &message) -> llvm::StringRef {
854 return message;
855 },
856 Callables: [](const protocol::ResponseMessage &message)
857 -> llvm::StringRef {
858 switch (message) {
859 case protocol::eResponseMessageCancelled:
860 return "cancelled";
861 case protocol::eResponseMessageNotStopped:
862 return "notStopped";
863 }
864 llvm_unreachable("unknown response message kind.");
865 }),
866 variants: *resp->message);
867 }
868 dispatcher.Set(key: "error", value: message.str());
869
870 (*response_handler)(llvm::createStringError(
871 EC: std::error_code(-1, std::generic_category()), S: message));
872 }
873
874 return true;
875 }
876
877 dispatcher.Set(key: "error", value: "Unsupported protocol message");
878 DAP_LOG(log, "Unsupported protocol message");
879
880 return false;
881}
882
883void DAP::SendTerminatedEvent() {
884 // Prevent races if the process exits while we're being asked to disconnect.
885 llvm::call_once(flag&: terminated_event_flag, F: [&] {
886 RunTerminateCommands();
887 // Send a "terminated" event
888 llvm::json::Object event(CreateTerminatedEventObject(target));
889 SendJSON(json: llvm::json::Value(std::move(event)));
890 });
891}
892
893llvm::Error DAP::Disconnect() { return Disconnect(terminateDebuggee: !is_attach); }
894
895llvm::Error DAP::Disconnect(bool terminateDebuggee) {
896 lldb::SBError error;
897 lldb::SBProcess process = target.GetProcess();
898 auto state = process.GetState();
899 switch (state) {
900 case lldb::eStateInvalid:
901 case lldb::eStateUnloaded:
902 case lldb::eStateDetached:
903 case lldb::eStateExited:
904 break;
905 case lldb::eStateConnected:
906 case lldb::eStateAttaching:
907 case lldb::eStateLaunching:
908 case lldb::eStateStepping:
909 case lldb::eStateCrashed:
910 case lldb::eStateSuspended:
911 case lldb::eStateStopped:
912 case lldb::eStateRunning: {
913 ScopeSyncMode scope_sync_mode(debugger);
914 error = terminateDebuggee ? process.Kill() : process.Detach();
915 break;
916 }
917 }
918
919 SendTerminatedEvent();
920
921 disconnecting = true;
922
923 return ToError(error);
924}
925
926bool DAP::IsCancelled(const protocol::Request &req) {
927 std::lock_guard<std::mutex> guard(m_cancelled_requests_mutex);
928 return m_cancelled_requests.contains(V: req.seq);
929}
930
931void DAP::ClearCancelRequest(const CancelArguments &args) {
932 std::lock_guard<std::mutex> guard(m_cancelled_requests_mutex);
933 if (args.requestId)
934 m_cancelled_requests.erase(V: *args.requestId);
935}
936
937template <typename T>
938static std::optional<T> getArgumentsIfRequest(const Message &pm,
939 llvm::StringLiteral command) {
940 auto *const req = std::get_if<Request>(ptr: &pm);
941 if (!req || req->command != command)
942 return std::nullopt;
943
944 T args;
945 llvm::json::Path::Root root;
946 if (!fromJSON(req->arguments, args, root))
947 return std::nullopt;
948
949 return args;
950}
951
952llvm::Error DAP::Loop() {
953 // Can't use \a std::future<llvm::Error> because it doesn't compile on
954 // Windows.
955 std::future<lldb::SBError> queue_reader =
956 std::async(policy: std::launch::async, fn: [&]() -> lldb::SBError {
957 llvm::set_thread_name(transport.GetClientName() + ".transport_handler");
958 auto cleanup = llvm::make_scope_exit(F: [&]() {
959 // Ensure we're marked as disconnecting when the reader exits.
960 disconnecting = true;
961 m_queue_cv.notify_all();
962 });
963
964 while (!disconnecting) {
965 llvm::Expected<Message> next =
966 transport.Read<protocol::Message>(timeout: std::chrono::seconds(1));
967 if (next.errorIsA<TransportEOFError>()) {
968 consumeError(Err: next.takeError());
969 break;
970 }
971
972 // If the read timed out, continue to check if we should disconnect.
973 if (next.errorIsA<TransportTimeoutError>()) {
974 consumeError(Err: next.takeError());
975 continue;
976 }
977
978 if (llvm::Error err = next.takeError()) {
979 lldb::SBError errWrapper;
980 errWrapper.SetErrorString(llvm::toString(E: std::move(err)).c_str());
981 return errWrapper;
982 }
983
984 if (const protocol::Request *req =
985 std::get_if<protocol::Request>(ptr: &*next);
986 req && req->arguments == "disconnect")
987 disconnecting = true;
988
989 const std::optional<CancelArguments> cancel_args =
990 getArgumentsIfRequest<CancelArguments>(pm: *next, command: "cancel");
991 if (cancel_args) {
992 {
993 std::lock_guard<std::mutex> guard(m_cancelled_requests_mutex);
994 if (cancel_args->requestId)
995 m_cancelled_requests.insert(V: *cancel_args->requestId);
996 }
997
998 // If a cancel is requested for the active request, make a best
999 // effort attempt to interrupt.
1000 std::lock_guard<std::mutex> guard(m_active_request_mutex);
1001 if (m_active_request &&
1002 cancel_args->requestId == m_active_request->seq) {
1003 DAP_LOG(
1004 log,
1005 "({0}) interrupting inflight request (command={1} seq={2})",
1006 transport.GetClientName(), m_active_request->command,
1007 m_active_request->seq);
1008 debugger.RequestInterrupt();
1009 }
1010 }
1011
1012 {
1013 std::lock_guard<std::mutex> guard(m_queue_mutex);
1014 m_queue.push_back(x: std::move(*next));
1015 }
1016 m_queue_cv.notify_one();
1017 }
1018
1019 return lldb::SBError();
1020 });
1021
1022 auto cleanup = llvm::make_scope_exit(F: [&]() {
1023 out.Stop();
1024 err.Stop();
1025 StopEventHandlers();
1026 });
1027
1028 while (true) {
1029 std::unique_lock<std::mutex> lock(m_queue_mutex);
1030 m_queue_cv.wait(lock&: lock, p: [&] { return disconnecting || !m_queue.empty(); });
1031
1032 if (disconnecting && m_queue.empty())
1033 break;
1034
1035 Message next = m_queue.front();
1036 m_queue.pop_front();
1037
1038 // Unlock while we're processing the event.
1039 lock.unlock();
1040
1041 if (!HandleObject(M: next))
1042 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
1043 S: "unhandled packet");
1044 }
1045
1046 return ToError(error: queue_reader.get());
1047}
1048
1049lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) {
1050 lldb::SBError error;
1051 lldb::SBProcess process = target.GetProcess();
1052 if (!process.IsValid()) {
1053 error.SetErrorString("invalid process");
1054 return error;
1055 }
1056 auto timeout_time =
1057 std::chrono::steady_clock::now() + std::chrono::seconds(seconds);
1058 while (std::chrono::steady_clock::now() < timeout_time) {
1059 const auto state = process.GetState();
1060 switch (state) {
1061 case lldb::eStateUnloaded:
1062 case lldb::eStateAttaching:
1063 case lldb::eStateConnected:
1064 case lldb::eStateInvalid:
1065 case lldb::eStateLaunching:
1066 case lldb::eStateRunning:
1067 case lldb::eStateStepping:
1068 case lldb::eStateSuspended:
1069 break;
1070 case lldb::eStateDetached:
1071 error.SetErrorString("process detached during launch or attach");
1072 return error;
1073 case lldb::eStateExited:
1074 error.SetErrorString("process exited during launch or attach");
1075 return error;
1076 case lldb::eStateCrashed:
1077 case lldb::eStateStopped:
1078 return lldb::SBError(); // Success!
1079 }
1080 std::this_thread::sleep_for(rtime: std::chrono::microseconds(250));
1081 }
1082 error.SetErrorString(
1083 llvm::formatv(Fmt: "process failed to stop within {0}", Vals&: seconds)
1084 .str()
1085 .c_str());
1086 return error;
1087}
1088
1089void DAP::ConfigureSourceMaps() {
1090 if (configuration.sourceMap.empty() && configuration.sourcePath.empty())
1091 return;
1092
1093 std::string sourceMapCommand;
1094 llvm::raw_string_ostream strm(sourceMapCommand);
1095 strm << "settings set target.source-map ";
1096
1097 if (!configuration.sourceMap.empty()) {
1098 for (const auto &kv : configuration.sourceMap) {
1099 strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
1100 }
1101 } else if (!configuration.sourcePath.empty()) {
1102 strm << "\".\" \"" << configuration.sourcePath << "\"";
1103 }
1104
1105 RunLLDBCommands(prefix: "Setting source map:", commands: {sourceMapCommand});
1106}
1107
1108void DAP::SetConfiguration(const protocol::Configuration &config,
1109 bool is_attach) {
1110 configuration = config;
1111 stop_at_entry = config.stopOnEntry;
1112 this->is_attach = is_attach;
1113
1114 if (configuration.customFrameFormat)
1115 SetFrameFormat(*configuration.customFrameFormat);
1116 if (configuration.customThreadFormat)
1117 SetThreadFormat(*configuration.customThreadFormat);
1118}
1119
1120void DAP::SetFrameFormat(llvm::StringRef format) {
1121 lldb::SBError error;
1122 frame_format = lldb::SBFormat(format.str().c_str(), error);
1123 if (error.Fail()) {
1124 SendOutput(o: OutputType::Console,
1125 output: llvm::formatv(
1126 Fmt: "The provided frame format '{0}' couldn't be parsed: {1}\n",
1127 Vals&: format, Vals: error.GetCString())
1128 .str());
1129 }
1130}
1131
1132void DAP::SetThreadFormat(llvm::StringRef format) {
1133 lldb::SBError error;
1134 thread_format = lldb::SBFormat(format.str().c_str(), error);
1135 if (error.Fail()) {
1136 SendOutput(o: OutputType::Console,
1137 output: llvm::formatv(
1138 Fmt: "The provided thread format '{0}' couldn't be parsed: {1}\n",
1139 Vals&: format, Vals: error.GetCString())
1140 .str());
1141 }
1142}
1143
1144InstructionBreakpoint *
1145DAP::GetInstructionBreakpoint(const lldb::break_id_t bp_id) {
1146 for (auto &bp : instruction_breakpoints) {
1147 if (bp.second.GetID() == bp_id)
1148 return &bp.second;
1149 }
1150 return nullptr;
1151}
1152
1153InstructionBreakpoint *
1154DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) {
1155 const auto num = thread.GetStopReasonDataCount();
1156 InstructionBreakpoint *inst_bp = nullptr;
1157 for (size_t i = 0; i < num; i += 2) {
1158 // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
1159 // thread.GetStopReasonDataAtIndex(i+1) will return the location
1160 // within that breakpoint. We only care about the bp ID so we can
1161 // see if this is an instruction breakpoint that is getting hit.
1162 lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(idx: i);
1163 inst_bp = GetInstructionBreakpoint(bp_id);
1164 // If any breakpoint is not an instruction breakpoint, then stop and
1165 // report this as a normal breakpoint
1166 if (inst_bp == nullptr)
1167 return nullptr;
1168 }
1169 return inst_bp;
1170}
1171
1172protocol::Capabilities DAP::GetCapabilities() {
1173 protocol::Capabilities capabilities;
1174
1175 // Supported capabilities that are not specific to a single request.
1176 capabilities.supportedFeatures = {
1177 protocol::eAdapterFeatureLogPoints,
1178 protocol::eAdapterFeatureSteppingGranularity,
1179 protocol::eAdapterFeatureValueFormattingOptions,
1180 };
1181
1182 // Capabilities associated with specific requests.
1183 for (auto &kv : request_handlers) {
1184 llvm::SmallDenseSet<AdapterFeature, 1> features =
1185 kv.second->GetSupportedFeatures();
1186 capabilities.supportedFeatures.insert(I: features.begin(), E: features.end());
1187 }
1188
1189 // Available filters or options for the setExceptionBreakpoints request.
1190 PopulateExceptionBreakpoints();
1191 std::vector<protocol::ExceptionBreakpointsFilter> filters;
1192 for (const auto &exc_bp : exception_breakpoints)
1193 filters.emplace_back(args: CreateExceptionBreakpointFilter(bp: exc_bp));
1194 capabilities.exceptionBreakpointFilters = std::move(filters);
1195
1196 // FIXME: This should be registered based on the supported languages?
1197 std::vector<std::string> completion_characters;
1198 completion_characters.emplace_back(args: ".");
1199 // FIXME: I wonder if we should remove this key... its very aggressive
1200 // triggering and accepting completions.
1201 completion_characters.emplace_back(args: " ");
1202 completion_characters.emplace_back(args: "\t");
1203 capabilities.completionTriggerCharacters = std::move(completion_characters);
1204
1205 // Put in non-DAP specification lldb specific information.
1206 capabilities.lldbExtVersion = debugger.GetVersionString();
1207
1208 return capabilities;
1209}
1210
1211void DAP::StartEventThread() {
1212 event_thread = std::thread(&DAP::EventThread, this);
1213}
1214
1215void DAP::StartProgressEventThread() {
1216 progress_event_thread = std::thread(&DAP::ProgressEventThread, this);
1217}
1218
1219void DAP::ProgressEventThread() {
1220 lldb::SBListener listener("lldb-dap.progress.listener");
1221 debugger.GetBroadcaster().AddListener(
1222 listener, event_mask: lldb::SBDebugger::eBroadcastBitProgress |
1223 lldb::SBDebugger::eBroadcastBitExternalProgress);
1224 broadcaster.AddListener(listener, event_mask: eBroadcastBitStopProgressThread);
1225 lldb::SBEvent event;
1226 bool done = false;
1227 while (!done) {
1228 if (listener.WaitForEvent(num_seconds: 1, event)) {
1229 const auto event_mask = event.GetType();
1230 if (event.BroadcasterMatchesRef(broadcaster)) {
1231 if (event_mask & eBroadcastBitStopProgressThread) {
1232 done = true;
1233 }
1234 } else {
1235 lldb::SBStructuredData data =
1236 lldb::SBDebugger::GetProgressDataFromEvent(event);
1237
1238 const uint64_t progress_id =
1239 GetUintFromStructuredData(data, key: "progress_id");
1240 const uint64_t completed = GetUintFromStructuredData(data, key: "completed");
1241 const uint64_t total = GetUintFromStructuredData(data, key: "total");
1242 const std::string details =
1243 GetStringFromStructuredData(data, key: "details");
1244
1245 if (completed == 0) {
1246 if (total == UINT64_MAX) {
1247 // This progress is non deterministic and won't get updated until it
1248 // is completed. Send the "message" which will be the combined title
1249 // and detail. The only other progress event for thus
1250 // non-deterministic progress will be the completed event So there
1251 // will be no need to update the detail.
1252 const std::string message =
1253 GetStringFromStructuredData(data, key: "message");
1254 SendProgressEvent(progress_id, message: message.c_str(), completed, total);
1255 } else {
1256 // This progress is deterministic and will receive updates,
1257 // on the progress creation event VSCode will save the message in
1258 // the create packet and use that as the title, so we send just the
1259 // title in the progressCreate packet followed immediately by a
1260 // detail packet, if there is any detail.
1261 const std::string title =
1262 GetStringFromStructuredData(data, key: "title");
1263 SendProgressEvent(progress_id, message: title.c_str(), completed, total);
1264 if (!details.empty())
1265 SendProgressEvent(progress_id, message: details.c_str(), completed, total);
1266 }
1267 } else {
1268 // This progress event is either the end of the progress dialog, or an
1269 // update with possible detail. The "detail" string we send to VS Code
1270 // will be appended to the progress dialog's initial text from when it
1271 // was created.
1272 SendProgressEvent(progress_id, message: details.c_str(), completed, total);
1273 }
1274 }
1275 }
1276 }
1277}
1278
1279// All events from the debugger, target, process, thread and frames are
1280// received in this function that runs in its own thread. We are using a
1281// "FILE *" to output packets back to VS Code and they have mutexes in them
1282// them prevent multiple threads from writing simultaneously so no locking
1283// is required.
1284void DAP::EventThread() {
1285 llvm::set_thread_name(transport.GetClientName() + ".event_handler");
1286 lldb::SBEvent event;
1287 lldb::SBListener listener = debugger.GetListener();
1288 broadcaster.AddListener(listener, event_mask: eBroadcastBitStopEventThread);
1289 debugger.GetBroadcaster().AddListener(
1290 listener, event_mask: lldb::eBroadcastBitError | lldb::eBroadcastBitWarning);
1291 bool done = false;
1292 while (!done) {
1293 if (listener.WaitForEvent(num_seconds: 1, event)) {
1294 const auto event_mask = event.GetType();
1295 if (lldb::SBProcess::EventIsProcessEvent(event)) {
1296 lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
1297 if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
1298 auto state = lldb::SBProcess::GetStateFromEvent(event);
1299 switch (state) {
1300 case lldb::eStateConnected:
1301 case lldb::eStateDetached:
1302 case lldb::eStateInvalid:
1303 case lldb::eStateUnloaded:
1304 break;
1305 case lldb::eStateAttaching:
1306 case lldb::eStateCrashed:
1307 case lldb::eStateLaunching:
1308 case lldb::eStateStopped:
1309 case lldb::eStateSuspended:
1310 // Only report a stopped event if the process was not
1311 // automatically restarted.
1312 if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
1313 SendStdOutStdErr(dap&: *this, process);
1314 if (llvm::Error err = SendThreadStoppedEvent(dap&: *this))
1315 DAP_LOG_ERROR(log, std::move(err),
1316 "({1}) reporting thread stopped: {0}",
1317 transport.GetClientName());
1318 }
1319 break;
1320 case lldb::eStateRunning:
1321 case lldb::eStateStepping:
1322 WillContinue();
1323 SendContinuedEvent(dap&: *this);
1324 break;
1325 case lldb::eStateExited:
1326 lldb::SBStream stream;
1327 process.GetStatus(status&: stream);
1328 SendOutput(o: OutputType::Console, output: stream.GetData());
1329
1330 // When restarting, we can get an "exited" event for the process we
1331 // just killed with the old PID, or even with no PID. In that case
1332 // we don't have to terminate the session.
1333 if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
1334 process.GetProcessID() == restarting_process_id) {
1335 restarting_process_id = LLDB_INVALID_PROCESS_ID;
1336 } else {
1337 // Run any exit LLDB commands the user specified in the
1338 // launch.json
1339 RunExitCommands();
1340 SendProcessExitedEvent(dap&: *this, process);
1341 SendTerminatedEvent();
1342 done = true;
1343 }
1344 break;
1345 }
1346 } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
1347 (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
1348 SendStdOutStdErr(dap&: *this, process);
1349 }
1350 } else if (lldb::SBTarget::EventIsTargetEvent(event)) {
1351 if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded ||
1352 event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded ||
1353 event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded ||
1354 event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged) {
1355 const uint32_t num_modules =
1356 lldb::SBTarget::GetNumModulesFromEvent(event);
1357 const bool remove_module =
1358 event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded;
1359
1360 std::lock_guard<std::mutex> guard(modules_mutex);
1361 for (uint32_t i = 0; i < num_modules; ++i) {
1362 lldb::SBModule module =
1363 lldb::SBTarget::GetModuleAtIndexFromEvent(idx: i, event);
1364
1365 std::optional<protocol::Module> p_module =
1366 CreateModule(target, module, id_only: remove_module);
1367 if (!p_module)
1368 continue;
1369
1370 llvm::StringRef module_id = p_module->id;
1371
1372 const bool module_exists = modules.contains(key: module_id);
1373 if (remove_module && module_exists) {
1374 modules.erase(Key: module_id);
1375 Send(message: protocol::Event{
1376 .event: "module", .body: ModuleEventBody{.module: std::move(p_module).value(),
1377 .reason: ModuleEventBody::eReasonRemoved}});
1378 } else if (module_exists) {
1379 Send(message: protocol::Event{
1380 .event: "module", .body: ModuleEventBody{.module: std::move(p_module).value(),
1381 .reason: ModuleEventBody::eReasonChanged}});
1382 } else if (!remove_module) {
1383 modules.insert(key: module_id);
1384 Send(message: protocol::Event{
1385 .event: "module", .body: ModuleEventBody{.module: std::move(p_module).value(),
1386 .reason: ModuleEventBody::eReasonNew}});
1387 }
1388 }
1389 }
1390 } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
1391 if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
1392 auto event_type =
1393 lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
1394 auto bp = Breakpoint(
1395 *this, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
1396 // If the breakpoint was set through DAP, it will have the
1397 // BreakpointBase::kDAPBreakpointLabel. Regardless of whether
1398 // locations were added, removed, or resolved, the breakpoint isn't
1399 // going away and the reason is always "changed".
1400 if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
1401 event_type & lldb::eBreakpointEventTypeLocationsRemoved ||
1402 event_type & lldb::eBreakpointEventTypeLocationsResolved) &&
1403 bp.MatchesName(name: BreakpointBase::kDAPBreakpointLabel)) {
1404 // As the DAP client already knows the path of this breakpoint, we
1405 // don't need to send it back as part of the "changed" event. This
1406 // avoids sending paths that should be source mapped. Note that
1407 // CreateBreakpoint doesn't apply source mapping and certain
1408 // implementation ignore the source part of this event anyway.
1409 llvm::json::Value source_bp = bp.ToProtocolBreakpoint();
1410 source_bp.getAsObject()->erase(K: "source");
1411
1412 llvm::json::Object body;
1413 body.try_emplace(K: "breakpoint", Args&: source_bp);
1414 body.try_emplace(K: "reason", Args: "changed");
1415
1416 llvm::json::Object bp_event = CreateEventObject(event_name: "breakpoint");
1417 bp_event.try_emplace(K: "body", Args: std::move(body));
1418
1419 SendJSON(json: llvm::json::Value(std::move(bp_event)));
1420 }
1421 }
1422 } else if (event_mask & lldb::eBroadcastBitError ||
1423 event_mask & lldb::eBroadcastBitWarning) {
1424 lldb::SBStructuredData data =
1425 lldb::SBDebugger::GetDiagnosticFromEvent(event);
1426 if (!data.IsValid())
1427 continue;
1428 std::string type = GetStringValue(data: data.GetValueForKey(key: "type"));
1429 std::string message = GetStringValue(data: data.GetValueForKey(key: "message"));
1430 SendOutput(o: OutputType::Important,
1431 output: llvm::formatv(Fmt: "{0}: {1}", Vals&: type, Vals&: message).str());
1432 } else if (event.BroadcasterMatchesRef(broadcaster)) {
1433 if (event_mask & eBroadcastBitStopEventThread) {
1434 done = true;
1435 }
1436 }
1437 }
1438 }
1439}
1440
1441std::vector<protocol::Breakpoint> DAP::SetSourceBreakpoints(
1442 const protocol::Source &source,
1443 const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints) {
1444 std::vector<protocol::Breakpoint> response_breakpoints;
1445 if (source.sourceReference) {
1446 // Breakpoint set by assembly source.
1447 auto &existing_breakpoints =
1448 m_source_assembly_breakpoints[*source.sourceReference];
1449 response_breakpoints =
1450 SetSourceBreakpoints(source, breakpoints, existing_breakpoints);
1451 } else {
1452 // Breakpoint set by a regular source file.
1453 const auto path = source.path.value_or(u: "");
1454 auto &existing_breakpoints = m_source_breakpoints[path];
1455 response_breakpoints =
1456 SetSourceBreakpoints(source, breakpoints, existing_breakpoints);
1457 }
1458
1459 return response_breakpoints;
1460}
1461
1462std::vector<protocol::Breakpoint> DAP::SetSourceBreakpoints(
1463 const protocol::Source &source,
1464 const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints,
1465 SourceBreakpointMap &existing_breakpoints) {
1466 std::vector<protocol::Breakpoint> response_breakpoints;
1467
1468 SourceBreakpointMap request_breakpoints;
1469 if (breakpoints) {
1470 for (const auto &bp : *breakpoints) {
1471 SourceBreakpoint src_bp(*this, bp);
1472 std::pair<uint32_t, uint32_t> bp_pos(src_bp.GetLine(),
1473 src_bp.GetColumn());
1474 request_breakpoints.try_emplace(k: bp_pos, args&: src_bp);
1475
1476 const auto [iv, inserted] =
1477 existing_breakpoints.try_emplace(k: bp_pos, args&: src_bp);
1478 // We check if this breakpoint already exists to update it.
1479 if (inserted) {
1480 if (llvm::Error error = iv->second.SetBreakpoint(source)) {
1481 protocol::Breakpoint invalid_breakpoint;
1482 invalid_breakpoint.message = llvm::toString(E: std::move(error));
1483 invalid_breakpoint.verified = false;
1484 response_breakpoints.push_back(x: std::move(invalid_breakpoint));
1485 existing_breakpoints.erase(position: iv);
1486 continue;
1487 }
1488 } else {
1489 iv->second.UpdateBreakpoint(request_bp: src_bp);
1490 }
1491
1492 protocol::Breakpoint response_breakpoint =
1493 iv->second.ToProtocolBreakpoint();
1494 response_breakpoint.source = source;
1495
1496 if (!response_breakpoint.line &&
1497 src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER)
1498 response_breakpoint.line = src_bp.GetLine();
1499 if (!response_breakpoint.column &&
1500 src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER)
1501 response_breakpoint.column = src_bp.GetColumn();
1502 response_breakpoints.push_back(x: std::move(response_breakpoint));
1503 }
1504 }
1505
1506 // Delete any breakpoints in this source file that aren't in the
1507 // request_bps set. There is no call to remove breakpoints other than
1508 // calling this function with a smaller or empty "breakpoints" list.
1509 for (auto it = existing_breakpoints.begin();
1510 it != existing_breakpoints.end();) {
1511 auto request_pos = request_breakpoints.find(x: it->first);
1512 if (request_pos == request_breakpoints.end()) {
1513 // This breakpoint no longer exists in this source file, delete it
1514 target.BreakpointDelete(break_id: it->second.GetID());
1515 it = existing_breakpoints.erase(position: it);
1516 } else {
1517 ++it;
1518 }
1519 }
1520
1521 return response_breakpoints;
1522}
1523
1524void DAP::RegisterRequests() {
1525 RegisterRequest<AttachRequestHandler>();
1526 RegisterRequest<BreakpointLocationsRequestHandler>();
1527 RegisterRequest<CancelRequestHandler>();
1528 RegisterRequest<CompletionsRequestHandler>();
1529 RegisterRequest<ConfigurationDoneRequestHandler>();
1530 RegisterRequest<ContinueRequestHandler>();
1531 RegisterRequest<DataBreakpointInfoRequestHandler>();
1532 RegisterRequest<DisassembleRequestHandler>();
1533 RegisterRequest<DisconnectRequestHandler>();
1534 RegisterRequest<EvaluateRequestHandler>();
1535 RegisterRequest<ExceptionInfoRequestHandler>();
1536 RegisterRequest<InitializeRequestHandler>();
1537 RegisterRequest<LaunchRequestHandler>();
1538 RegisterRequest<LocationsRequestHandler>();
1539 RegisterRequest<NextRequestHandler>();
1540 RegisterRequest<PauseRequestHandler>();
1541 RegisterRequest<ReadMemoryRequestHandler>();
1542 RegisterRequest<RestartRequestHandler>();
1543 RegisterRequest<ScopesRequestHandler>();
1544 RegisterRequest<SetBreakpointsRequestHandler>();
1545 RegisterRequest<SetDataBreakpointsRequestHandler>();
1546 RegisterRequest<SetExceptionBreakpointsRequestHandler>();
1547 RegisterRequest<SetFunctionBreakpointsRequestHandler>();
1548 RegisterRequest<SetInstructionBreakpointsRequestHandler>();
1549 RegisterRequest<SetVariableRequestHandler>();
1550 RegisterRequest<SourceRequestHandler>();
1551 RegisterRequest<StackTraceRequestHandler>();
1552 RegisterRequest<StepInRequestHandler>();
1553 RegisterRequest<StepInTargetsRequestHandler>();
1554 RegisterRequest<StepOutRequestHandler>();
1555 RegisterRequest<ThreadsRequestHandler>();
1556 RegisterRequest<VariablesRequestHandler>();
1557 RegisterRequest<WriteMemoryRequestHandler>();
1558
1559 // Custom requests
1560 RegisterRequest<CompileUnitsRequestHandler>();
1561 RegisterRequest<ModulesRequestHandler>();
1562
1563 // Testing requests
1564 RegisterRequest<TestGetTargetBreakpointsRequestHandler>();
1565}
1566
1567} // namespace lldb_dap
1568

source code of lldb/tools/lldb-dap/DAP.cpp