xref: /llvm-project/lldb/tools/lldb-dap/DAP.cpp (revision 873426bea3dd67d80dd10650e64e91c69796614f)
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 "JSONUtils.h"
11 #include "LLDBUtils.h"
12 #include "OutputRedirector.h"
13 #include "lldb/API/SBBreakpoint.h"
14 #include "lldb/API/SBCommandInterpreter.h"
15 #include "lldb/API/SBCommandReturnObject.h"
16 #include "lldb/API/SBLanguageRuntime.h"
17 #include "lldb/API/SBListener.h"
18 #include "lldb/API/SBProcess.h"
19 #include "lldb/API/SBStream.h"
20 #include "lldb/Host/FileSystem.h"
21 #include "lldb/Utility/Status.h"
22 #include "lldb/lldb-defines.h"
23 #include "lldb/lldb-enumerations.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/StringExtras.h"
26 #include "llvm/ADT/Twine.h"
27 #include "llvm/Support/Error.h"
28 #include "llvm/Support/ErrorHandling.h"
29 #include "llvm/Support/FormatVariadic.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <algorithm>
32 #include <cassert>
33 #include <chrono>
34 #include <cstdarg>
35 #include <cstdio>
36 #include <fstream>
37 #include <mutex>
38 #include <utility>
39 
40 #if defined(_WIN32)
41 #define NOMINMAX
42 #include <fcntl.h>
43 #include <io.h>
44 #include <windows.h>
45 #else
46 #include <unistd.h>
47 #endif
48 
49 using namespace lldb_dap;
50 
51 namespace {
52 #ifdef _WIN32
53 const char DEV_NULL[] = "nul";
54 #else
55 const char DEV_NULL[] = "/dev/null";
56 #endif
57 } // namespace
58 
59 namespace lldb_dap {
60 
61 DAP::DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode,
62          StreamDescriptor input, StreamDescriptor output)
63     : debug_adaptor_path(path), log(log), input(std::move(input)),
64       output(std::move(output)), broadcaster("lldb-dap"),
65       exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID),
66       stop_at_entry(false), is_attach(false),
67       enable_auto_variable_summaries(false),
68       enable_synthetic_child_debugging(false),
69       display_extended_backtrace(false),
70       restarting_process_id(LLDB_INVALID_PROCESS_ID),
71       configuration_done_sent(false), waiting_for_run_in_terminal(false),
72       progress_event_reporter(
73           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
74       reverse_request_seq(0), repl_mode(repl_mode) {}
75 
76 DAP::~DAP() = default;
77 
78 /// Return string with first character capitalized.
79 static std::string capitalize(llvm::StringRef str) {
80   if (str.empty())
81     return "";
82   return ((llvm::Twine)llvm::toUpper(str[0]) + str.drop_front()).str();
83 }
84 
85 void DAP::PopulateExceptionBreakpoints() {
86   llvm::call_once(init_exception_breakpoints_flag, [this]() {
87     exception_breakpoints = std::vector<ExceptionBreakpoint>{};
88 
89     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) {
90       exception_breakpoints->emplace_back(*this, "cpp_catch", "C++ Catch",
91                                           lldb::eLanguageTypeC_plus_plus);
92       exception_breakpoints->emplace_back(*this, "cpp_throw", "C++ Throw",
93                                           lldb::eLanguageTypeC_plus_plus);
94     }
95     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) {
96       exception_breakpoints->emplace_back(
97           *this, "objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC);
98       exception_breakpoints->emplace_back(
99           *this, "objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC);
100     }
101     if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) {
102       exception_breakpoints->emplace_back(*this, "swift_catch", "Swift Catch",
103                                           lldb::eLanguageTypeSwift);
104       exception_breakpoints->emplace_back(*this, "swift_throw", "Swift Throw",
105                                           lldb::eLanguageTypeSwift);
106     }
107     // Besides handling the hardcoded list of languages from above, we try to
108     // find any other languages that support exception breakpoints using the
109     // SB API.
110     for (int raw_lang = lldb::eLanguageTypeUnknown;
111          raw_lang < lldb::eNumLanguageTypes; ++raw_lang) {
112       lldb::LanguageType lang = static_cast<lldb::LanguageType>(raw_lang);
113 
114       // We first discard any languages already handled above.
115       if (lldb::SBLanguageRuntime::LanguageIsCFamily(lang) ||
116           lang == lldb::eLanguageTypeSwift)
117         continue;
118 
119       if (!lldb::SBDebugger::SupportsLanguage(lang))
120         continue;
121 
122       const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(lang);
123       if (!name)
124         continue;
125       std::string raw_lang_name = name;
126       std::string capitalized_lang_name = capitalize(name);
127 
128       if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(lang)) {
129         const char *raw_throw_keyword =
130             lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(lang);
131         std::string throw_keyword =
132             raw_throw_keyword ? raw_throw_keyword : "throw";
133 
134         exception_breakpoints->emplace_back(
135             *this, raw_lang_name + "_" + throw_keyword,
136             capitalized_lang_name + " " + capitalize(throw_keyword), lang);
137       }
138 
139       if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(lang)) {
140         const char *raw_catch_keyword =
141             lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(lang);
142         std::string catch_keyword =
143             raw_catch_keyword ? raw_catch_keyword : "catch";
144 
145         exception_breakpoints->emplace_back(
146             *this, raw_lang_name + "_" + catch_keyword,
147             capitalized_lang_name + " " + capitalize(catch_keyword), lang);
148       }
149     }
150     assert(!exception_breakpoints->empty() && "should not be empty");
151   });
152 }
153 
154 ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) {
155   // PopulateExceptionBreakpoints() is called after g_dap.debugger is created
156   // in a request-initialize.
157   //
158   // But this GetExceptionBreakpoint() method may be called before attaching, in
159   // which case, we may not have populated the filter yet.
160   //
161   // We also cannot call PopulateExceptionBreakpoints() in DAP::DAP() because
162   // we need SBDebugger::Initialize() to have been called before this.
163   //
164   // So just calling PopulateExceptionBreakoints(),which does lazy-populating
165   // seems easiest. Two other options include:
166   //  + call g_dap.PopulateExceptionBreakpoints() in lldb-dap.cpp::main()
167   //    right after the call to SBDebugger::Initialize()
168   //  + Just call PopulateExceptionBreakpoints() to get a fresh list  everytime
169   //    we query (a bit overkill since it's not likely to change?)
170   PopulateExceptionBreakpoints();
171 
172   for (auto &bp : *exception_breakpoints) {
173     if (bp.filter == filter)
174       return &bp;
175   }
176   return nullptr;
177 }
178 
179 ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
180   // See comment in the other GetExceptionBreakpoint().
181   PopulateExceptionBreakpoints();
182 
183   for (auto &bp : *exception_breakpoints) {
184     if (bp.bp.GetID() == bp_id)
185       return &bp;
186   }
187   return nullptr;
188 }
189 
190 llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) {
191   in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true);
192 
193   if (auto Error = out.RedirectTo([this](llvm::StringRef output) {
194         SendOutput(OutputType::Stdout, output);
195       }))
196     return Error;
197 
198   if (overrideOut) {
199     auto fd = out.GetWriteFileDescriptor();
200     if (auto Error = fd.takeError())
201       return Error;
202 
203     if (dup2(*fd, fileno(overrideOut)) == -1)
204       return llvm::errorCodeToError(llvm::errnoAsErrorCode());
205   }
206 
207   if (auto Error = err.RedirectTo([this](llvm::StringRef output) {
208         SendOutput(OutputType::Stderr, output);
209       }))
210     return Error;
211 
212   if (overrideErr) {
213     auto fd = err.GetWriteFileDescriptor();
214     if (auto Error = fd.takeError())
215       return Error;
216 
217     if (dup2(*fd, fileno(overrideErr)) == -1)
218       return llvm::errorCodeToError(llvm::errnoAsErrorCode());
219   }
220 
221   return llvm::Error::success();
222 }
223 
224 void DAP::StopIO() {
225   out.Stop();
226   err.Stop();
227 }
228 
229 // Send the JSON in "json_str" to the "out" stream. Correctly send the
230 // "Content-Length:" field followed by the length, followed by the raw
231 // JSON bytes.
232 void DAP::SendJSON(const std::string &json_str) {
233   output.write_full("Content-Length: ");
234   output.write_full(llvm::utostr(json_str.size()));
235   output.write_full("\r\n\r\n");
236   output.write_full(json_str);
237 }
238 
239 // Serialize the JSON value into a string and send the JSON packet to
240 // the "out" stream.
241 void DAP::SendJSON(const llvm::json::Value &json) {
242   std::string json_str;
243   llvm::raw_string_ostream strm(json_str);
244   strm << json;
245   static std::mutex mutex;
246   std::lock_guard<std::mutex> locker(mutex);
247   SendJSON(json_str);
248 
249   if (log) {
250     auto now = std::chrono::duration<double>(
251         std::chrono::system_clock::now().time_since_epoch());
252     *log << llvm::formatv("{0:f9} <-- ", now.count()).str() << std::endl
253          << "Content-Length: " << json_str.size() << "\r\n\r\n"
254          << llvm::formatv("{0:2}", json).str() << std::endl;
255   }
256 }
257 
258 // Read a JSON packet from the "in" stream.
259 std::string DAP::ReadJSON() {
260   std::string length_str;
261   std::string json_str;
262   int length;
263 
264   if (!input.read_expected(log, "Content-Length: "))
265     return json_str;
266 
267   if (!input.read_line(log, length_str))
268     return json_str;
269 
270   if (!llvm::to_integer(length_str, length))
271     return json_str;
272 
273   if (!input.read_expected(log, "\r\n"))
274     return json_str;
275 
276   if (!input.read_full(log, length, json_str))
277     return json_str;
278 
279   if (log) {
280     auto now = std::chrono::duration<double>(
281         std::chrono::system_clock::now().time_since_epoch());
282     *log << llvm::formatv("{0:f9} --> ", now.count()).str() << std::endl
283          << "Content-Length: " << length << "\r\n\r\n";
284   }
285   return json_str;
286 }
287 
288 // "OutputEvent": {
289 //   "allOf": [ { "$ref": "#/definitions/Event" }, {
290 //     "type": "object",
291 //     "description": "Event message for 'output' event type. The event
292 //                     indicates that the target has produced some output.",
293 //     "properties": {
294 //       "event": {
295 //         "type": "string",
296 //         "enum": [ "output" ]
297 //       },
298 //       "body": {
299 //         "type": "object",
300 //         "properties": {
301 //           "category": {
302 //             "type": "string",
303 //             "description": "The output category. If not specified,
304 //                             'console' is assumed.",
305 //             "_enum": [ "console", "stdout", "stderr", "telemetry" ]
306 //           },
307 //           "output": {
308 //             "type": "string",
309 //             "description": "The output to report."
310 //           },
311 //           "variablesReference": {
312 //             "type": "number",
313 //             "description": "If an attribute 'variablesReference' exists
314 //                             and its value is > 0, the output contains
315 //                             objects which can be retrieved by passing
316 //                             variablesReference to the VariablesRequest."
317 //           },
318 //           "source": {
319 //             "$ref": "#/definitions/Source",
320 //             "description": "An optional source location where the output
321 //                             was produced."
322 //           },
323 //           "line": {
324 //             "type": "integer",
325 //             "description": "An optional source location line where the
326 //                             output was produced."
327 //           },
328 //           "column": {
329 //             "type": "integer",
330 //             "description": "An optional source location column where the
331 //                             output was produced."
332 //           },
333 //           "data": {
334 //             "type":["array","boolean","integer","null","number","object",
335 //                     "string"],
336 //             "description": "Optional data to report. For the 'telemetry'
337 //                             category the data will be sent to telemetry, for
338 //                             the other categories the data is shown in JSON
339 //                             format."
340 //           }
341 //         },
342 //         "required": ["output"]
343 //       }
344 //     },
345 //     "required": [ "event", "body" ]
346 //   }]
347 // }
348 void DAP::SendOutput(OutputType o, const llvm::StringRef output) {
349   if (output.empty())
350     return;
351 
352   const char *category = nullptr;
353   switch (o) {
354   case OutputType::Console:
355     category = "console";
356     break;
357   case OutputType::Stdout:
358     category = "stdout";
359     break;
360   case OutputType::Stderr:
361     category = "stderr";
362     break;
363   case OutputType::Telemetry:
364     category = "telemetry";
365     break;
366   }
367 
368   // Send each line of output as an individual event, including the newline if
369   // present.
370   ::size_t idx = 0;
371   do {
372     ::size_t end = output.find('\n', idx);
373     if (end == llvm::StringRef::npos)
374       end = output.size() - 1;
375     llvm::json::Object event(CreateEventObject("output"));
376     llvm::json::Object body;
377     body.try_emplace("category", category);
378     EmplaceSafeString(body, "output", output.slice(idx, end + 1).str());
379     event.try_emplace("body", std::move(body));
380     SendJSON(llvm::json::Value(std::move(event)));
381     idx = end + 1;
382   } while (idx < output.size());
383 }
384 
385 // interface ProgressStartEvent extends Event {
386 //   event: 'progressStart';
387 //
388 //   body: {
389 //     /**
390 //      * An ID that must be used in subsequent 'progressUpdate' and
391 //      'progressEnd'
392 //      * events to make them refer to the same progress reporting.
393 //      * IDs must be unique within a debug session.
394 //      */
395 //     progressId: string;
396 //
397 //     /**
398 //      * Mandatory (short) title of the progress reporting. Shown in the UI to
399 //      * describe the long running operation.
400 //      */
401 //     title: string;
402 //
403 //     /**
404 //      * The request ID that this progress report is related to. If specified a
405 //      * debug adapter is expected to emit
406 //      * progress events for the long running request until the request has
407 //      been
408 //      * either completed or cancelled.
409 //      * If the request ID is omitted, the progress report is assumed to be
410 //      * related to some general activity of the debug adapter.
411 //      */
412 //     requestId?: number;
413 //
414 //     /**
415 //      * If true, the request that reports progress may be canceled with a
416 //      * 'cancel' request.
417 //      * So this property basically controls whether the client should use UX
418 //      that
419 //      * supports cancellation.
420 //      * Clients that don't support cancellation are allowed to ignore the
421 //      * setting.
422 //      */
423 //     cancellable?: boolean;
424 //
425 //     /**
426 //      * Optional, more detailed progress message.
427 //      */
428 //     message?: string;
429 //
430 //     /**
431 //      * Optional progress percentage to display (value range: 0 to 100). If
432 //      * omitted no percentage will be shown.
433 //      */
434 //     percentage?: number;
435 //   };
436 // }
437 //
438 // interface ProgressUpdateEvent extends Event {
439 //   event: 'progressUpdate';
440 //
441 //   body: {
442 //     /**
443 //      * The ID that was introduced in the initial 'progressStart' event.
444 //      */
445 //     progressId: string;
446 //
447 //     /**
448 //      * Optional, more detailed progress message. If omitted, the previous
449 //      * message (if any) is used.
450 //      */
451 //     message?: string;
452 //
453 //     /**
454 //      * Optional progress percentage to display (value range: 0 to 100). If
455 //      * omitted no percentage will be shown.
456 //      */
457 //     percentage?: number;
458 //   };
459 // }
460 //
461 // interface ProgressEndEvent extends Event {
462 //   event: 'progressEnd';
463 //
464 //   body: {
465 //     /**
466 //      * The ID that was introduced in the initial 'ProgressStartEvent'.
467 //      */
468 //     progressId: string;
469 //
470 //     /**
471 //      * Optional, more detailed progress message. If omitted, the previous
472 //      * message (if any) is used.
473 //      */
474 //     message?: string;
475 //   };
476 // }
477 
478 void DAP::SendProgressEvent(uint64_t progress_id, const char *message,
479                             uint64_t completed, uint64_t total) {
480   progress_event_reporter.Push(progress_id, message, completed, total);
481 }
482 
483 void __attribute__((format(printf, 3, 4)))
484 DAP::SendFormattedOutput(OutputType o, const char *format, ...) {
485   char buffer[1024];
486   va_list args;
487   va_start(args, format);
488   int actual_length = vsnprintf(buffer, sizeof(buffer), format, args);
489   va_end(args);
490   SendOutput(
491       o, llvm::StringRef(buffer, std::min<int>(actual_length, sizeof(buffer))));
492 }
493 
494 ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
495   const auto num = thread.GetStopReasonDataCount();
496   // Check to see if have hit an exception breakpoint and change the
497   // reason to "exception", but only do so if all breakpoints that were
498   // hit are exception breakpoints.
499   ExceptionBreakpoint *exc_bp = nullptr;
500   for (size_t i = 0; i < num; i += 2) {
501     // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
502     // thread.GetStopReasonDataAtIndex(i+1) will return the location
503     // within that breakpoint. We only care about the bp ID so we can
504     // see if this is an exception breakpoint that is getting hit.
505     lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
506     exc_bp = GetExceptionBreakpoint(bp_id);
507     // If any breakpoint is not an exception breakpoint, then stop and
508     // report this as a normal breakpoint
509     if (exc_bp == nullptr)
510       return nullptr;
511   }
512   return exc_bp;
513 }
514 
515 lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) {
516   auto tid = GetSigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
517   return target.GetProcess().GetThreadByID(tid);
518 }
519 
520 lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
521   const uint64_t frame_id = GetUnsigned(arguments, "frameId", UINT64_MAX);
522   lldb::SBProcess process = target.GetProcess();
523   // Upper 32 bits is the thread index ID
524   lldb::SBThread thread =
525       process.GetThreadByIndexID(GetLLDBThreadIndexID(frame_id));
526   // Lower 32 bits is the frame index
527   return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id));
528 }
529 
530 llvm::json::Value DAP::CreateTopLevelScopes() {
531   llvm::json::Array scopes;
532   scopes.emplace_back(
533       CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false));
534   scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS,
535                                   variables.globals.GetSize(), false));
536   scopes.emplace_back(CreateScope("Registers", VARREF_REGS,
537                                   variables.registers.GetSize(), false));
538   return llvm::json::Value(std::move(scopes));
539 }
540 
541 ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression,
542                              bool partial_expression) {
543   // Check for the escape hatch prefix.
544   if (!expression.empty() &&
545       llvm::StringRef(expression).starts_with(command_escape_prefix)) {
546     expression = expression.substr(command_escape_prefix.size());
547     return ReplMode::Command;
548   }
549 
550   switch (repl_mode) {
551   case ReplMode::Variable:
552     return ReplMode::Variable;
553   case ReplMode::Command:
554     return ReplMode::Command;
555   case ReplMode::Auto:
556     // To determine if the expression is a command or not, check if the first
557     // term is a variable or command. If it's a variable in scope we will prefer
558     // that behavior and give a warning to the user if they meant to invoke the
559     // operation as a command.
560     //
561     // Example use case:
562     //   int p and expression "p + 1" > variable
563     //   int i and expression "i" > variable
564     //   int var and expression "va" > command
565     std::pair<llvm::StringRef, llvm::StringRef> token =
566         llvm::getToken(expression);
567 
568     // If the first token is not fully finished yet, we can't
569     // determine whether this will be a variable or a lldb command.
570     if (partial_expression && token.second.empty())
571       return ReplMode::Auto;
572 
573     std::string term = token.first.str();
574     lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
575     bool term_is_command = interpreter.CommandExists(term.c_str()) ||
576                            interpreter.UserCommandExists(term.c_str()) ||
577                            interpreter.AliasExists(term.c_str());
578     bool term_is_variable = frame.FindVariable(term.c_str()).IsValid();
579 
580     // If we have both a variable and command, warn the user about the conflict.
581     if (term_is_command && term_is_variable) {
582       llvm::errs()
583           << "Warning: Expression '" << term
584           << "' is both an LLDB command and variable. It will be evaluated as "
585              "a variable. To evaluate the expression as an LLDB command, use '"
586           << command_escape_prefix << "' as a prefix.\n";
587     }
588 
589     // Variables take preference to commands in auto, since commands can always
590     // be called using the command_escape_prefix
591     return term_is_variable  ? ReplMode::Variable
592            : term_is_command ? ReplMode::Command
593                              : ReplMode::Variable;
594   }
595 
596   llvm_unreachable("enum cases exhausted.");
597 }
598 
599 bool DAP::RunLLDBCommands(llvm::StringRef prefix,
600                           llvm::ArrayRef<std::string> commands) {
601   bool required_command_failed = false;
602   std::string output =
603       ::RunLLDBCommands(debugger, prefix, commands, required_command_failed);
604   SendOutput(OutputType::Console, output);
605   return !required_command_failed;
606 }
607 
608 static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) {
609   return llvm::createStringError(
610       llvm::inconvertibleErrorCode(),
611       llvm::formatv(
612           "Failed to run {0} commands. See the Debug Console for more details.",
613           category)
614           .str()
615           .c_str());
616 }
617 
618 llvm::Error
619 DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) {
620   if (!RunLLDBCommands("Running attachCommands:", attach_commands))
621     return createRunLLDBCommandsErrorMessage("attach");
622   return llvm::Error::success();
623 }
624 
625 llvm::Error
626 DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) {
627   if (!RunLLDBCommands("Running launchCommands:", launch_commands))
628     return createRunLLDBCommandsErrorMessage("launch");
629   return llvm::Error::success();
630 }
631 
632 llvm::Error DAP::RunInitCommands() {
633   if (!RunLLDBCommands("Running initCommands:", init_commands))
634     return createRunLLDBCommandsErrorMessage("initCommands");
635   return llvm::Error::success();
636 }
637 
638 llvm::Error DAP::RunPreInitCommands() {
639   if (!RunLLDBCommands("Running preInitCommands:", pre_init_commands))
640     return createRunLLDBCommandsErrorMessage("preInitCommands");
641   return llvm::Error::success();
642 }
643 
644 llvm::Error DAP::RunPreRunCommands() {
645   if (!RunLLDBCommands("Running preRunCommands:", pre_run_commands))
646     return createRunLLDBCommandsErrorMessage("preRunCommands");
647   return llvm::Error::success();
648 }
649 
650 void DAP::RunPostRunCommands() {
651   RunLLDBCommands("Running postRunCommands:", post_run_commands);
652 }
653 void DAP::RunStopCommands() {
654   RunLLDBCommands("Running stopCommands:", stop_commands);
655 }
656 
657 void DAP::RunExitCommands() {
658   RunLLDBCommands("Running exitCommands:", exit_commands);
659 }
660 
661 void DAP::RunTerminateCommands() {
662   RunLLDBCommands("Running terminateCommands:", terminate_commands);
663 }
664 
665 lldb::SBTarget
666 DAP::CreateTargetFromArguments(const llvm::json::Object &arguments,
667                                lldb::SBError &error) {
668   // Grab the name of the program we need to debug and create a target using
669   // the given program as an argument. Executable file can be a source of target
670   // architecture and platform, if they differ from the host. Setting exe path
671   // in launch info is useless because Target.Launch() will not change
672   // architecture and platform, therefore they should be known at the target
673   // creation. We also use target triple and platform from the launch
674   // configuration, if given, since in some cases ELF file doesn't contain
675   // enough information to determine correct arch and platform (or ELF can be
676   // omitted at all), so it is good to leave the user an apportunity to specify
677   // those. Any of those three can be left empty.
678   llvm::StringRef target_triple = GetString(arguments, "targetTriple");
679   llvm::StringRef platform_name = GetString(arguments, "platformName");
680   llvm::StringRef program = GetString(arguments, "program");
681   auto target = this->debugger.CreateTarget(
682       program.data(), target_triple.data(), platform_name.data(),
683       true, // Add dependent modules.
684       error);
685 
686   if (error.Fail()) {
687     // Update message if there was an error.
688     error.SetErrorStringWithFormat(
689         "Could not create a target for a program '%s': %s.", program.data(),
690         error.GetCString());
691   }
692 
693   return target;
694 }
695 
696 void DAP::SetTarget(const lldb::SBTarget target) {
697   this->target = target;
698 
699   if (target.IsValid()) {
700     // Configure breakpoint event listeners for the target.
701     lldb::SBListener listener = this->debugger.GetListener();
702     listener.StartListeningForEvents(
703         this->target.GetBroadcaster(),
704         lldb::SBTarget::eBroadcastBitBreakpointChanged);
705     listener.StartListeningForEvents(this->broadcaster,
706                                      eBroadcastBitStopEventThread);
707   }
708 }
709 
710 PacketStatus DAP::GetNextObject(llvm::json::Object &object) {
711   std::string json = ReadJSON();
712   if (json.empty())
713     return PacketStatus::EndOfFile;
714 
715   llvm::StringRef json_sref(json);
716   llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
717   if (!json_value) {
718     auto error = json_value.takeError();
719     if (log) {
720       std::string error_str;
721       llvm::raw_string_ostream strm(error_str);
722       strm << error;
723       *log << "error: failed to parse JSON: " << error_str << std::endl
724            << json << std::endl;
725     }
726     return PacketStatus::JSONMalformed;
727   }
728 
729   if (log) {
730     *log << llvm::formatv("{0:2}", *json_value).str() << std::endl;
731   }
732 
733   llvm::json::Object *object_ptr = json_value->getAsObject();
734   if (!object_ptr) {
735     if (log)
736       *log << "error: json packet isn't a object" << std::endl;
737     return PacketStatus::JSONNotObject;
738   }
739   object = *object_ptr;
740   return PacketStatus::Success;
741 }
742 
743 bool DAP::HandleObject(const llvm::json::Object &object) {
744   const auto packet_type = GetString(object, "type");
745   if (packet_type == "request") {
746     const auto command = GetString(object, "command");
747     auto handler_pos = request_handlers.find(command);
748     if (handler_pos == request_handlers.end()) {
749       if (log)
750         *log << "error: unhandled command \"" << command.data() << "\""
751              << std::endl;
752       return false; // Fail
753     }
754 
755     handler_pos->second(*this, object);
756     return true; // Success
757   }
758 
759   if (packet_type == "response") {
760     auto id = GetSigned(object, "request_seq", 0);
761     ResponseCallback response_handler = [](llvm::Expected<llvm::json::Value>) {
762       llvm::errs() << "Unhandled response\n";
763     };
764 
765     {
766       std::lock_guard<std::mutex> locker(call_mutex);
767       auto inflight = inflight_reverse_requests.find(id);
768       if (inflight != inflight_reverse_requests.end()) {
769         response_handler = std::move(inflight->second);
770         inflight_reverse_requests.erase(inflight);
771       }
772     }
773 
774     // Result should be given, use null if not.
775     if (GetBoolean(object, "success", false)) {
776       llvm::json::Value Result = nullptr;
777       if (auto *B = object.get("body")) {
778         Result = std::move(*B);
779       }
780       response_handler(Result);
781     } else {
782       llvm::StringRef message = GetString(object, "message");
783       if (message.empty()) {
784         message = "Unknown error, response failed";
785       }
786       response_handler(llvm::createStringError(
787           std::error_code(-1, std::generic_category()), message));
788     }
789 
790     return true;
791   }
792 
793   return false;
794 }
795 
796 llvm::Error DAP::Loop() {
797   while (!disconnecting) {
798     llvm::json::Object object;
799     lldb_dap::PacketStatus status = GetNextObject(object);
800 
801     if (status == lldb_dap::PacketStatus::EndOfFile) {
802       break;
803     }
804 
805     if (status != lldb_dap::PacketStatus::Success) {
806       return llvm::createStringError(llvm::inconvertibleErrorCode(),
807                                      "failed to send packet");
808     }
809 
810     if (!HandleObject(object)) {
811       return llvm::createStringError(llvm::inconvertibleErrorCode(),
812                                      "unhandled packet");
813     }
814   }
815 
816   return llvm::Error::success();
817 }
818 
819 void DAP::SendReverseRequest(llvm::StringRef command,
820                              llvm::json::Value arguments,
821                              ResponseCallback callback) {
822   int64_t id;
823   {
824     std::lock_guard<std::mutex> locker(call_mutex);
825     id = ++reverse_request_seq;
826     inflight_reverse_requests.emplace(id, std::move(callback));
827   }
828 
829   SendJSON(llvm::json::Object{
830       {"type", "request"},
831       {"seq", id},
832       {"command", command},
833       {"arguments", std::move(arguments)},
834   });
835 }
836 
837 void DAP::RegisterRequestCallback(std::string request,
838                                   RequestCallback callback) {
839   request_handlers[request] = callback;
840 }
841 
842 lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
843   lldb::SBError error;
844   lldb::SBProcess process = target.GetProcess();
845   if (!process.IsValid()) {
846     error.SetErrorString("invalid process");
847     return error;
848   }
849   auto timeout_time =
850       std::chrono::steady_clock::now() + std::chrono::seconds(seconds);
851   while (std::chrono::steady_clock::now() < timeout_time) {
852     const auto state = process.GetState();
853     switch (state) {
854     case lldb::eStateAttaching:
855     case lldb::eStateConnected:
856     case lldb::eStateInvalid:
857     case lldb::eStateLaunching:
858     case lldb::eStateRunning:
859     case lldb::eStateStepping:
860     case lldb::eStateSuspended:
861       break;
862     case lldb::eStateDetached:
863       error.SetErrorString("process detached during launch or attach");
864       return error;
865     case lldb::eStateExited:
866       error.SetErrorString("process exited during launch or attach");
867       return error;
868     case lldb::eStateUnloaded:
869       error.SetErrorString("process unloaded during launch or attach");
870       return error;
871     case lldb::eStateCrashed:
872     case lldb::eStateStopped:
873       return lldb::SBError(); // Success!
874     }
875     std::this_thread::sleep_for(std::chrono::microseconds(250));
876   }
877   error.SetErrorStringWithFormat("process failed to stop within %u seconds",
878                                  seconds);
879   return error;
880 }
881 
882 void Variables::Clear() {
883   locals.Clear();
884   globals.Clear();
885   registers.Clear();
886   referenced_variables.clear();
887 }
888 
889 int64_t Variables::GetNewVariableReference(bool is_permanent) {
890   if (is_permanent)
891     return next_permanent_var_ref++;
892   return next_temporary_var_ref++;
893 }
894 
895 bool Variables::IsPermanentVariableReference(int64_t var_ref) {
896   return var_ref >= PermanentVariableStartIndex;
897 }
898 
899 lldb::SBValue Variables::GetVariable(int64_t var_ref) const {
900   if (IsPermanentVariableReference(var_ref)) {
901     auto pos = referenced_permanent_variables.find(var_ref);
902     if (pos != referenced_permanent_variables.end())
903       return pos->second;
904   } else {
905     auto pos = referenced_variables.find(var_ref);
906     if (pos != referenced_variables.end())
907       return pos->second;
908   }
909   return lldb::SBValue();
910 }
911 
912 int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) {
913   int64_t var_ref = GetNewVariableReference(is_permanent);
914   if (is_permanent)
915     referenced_permanent_variables.insert(std::make_pair(var_ref, variable));
916   else
917     referenced_variables.insert(std::make_pair(var_ref, variable));
918   return var_ref;
919 }
920 
921 bool StartDebuggingRequestHandler::DoExecute(
922     lldb::SBDebugger debugger, char **command,
923     lldb::SBCommandReturnObject &result) {
924   // Command format like: `start-debugging <launch|attach> <configuration>`
925   if (!command) {
926     result.SetError("Invalid use of start-debugging, expected format "
927                     "`start-debugging <launch|attach> <configuration>`.");
928     return false;
929   }
930 
931   if (!command[0] || llvm::StringRef(command[0]).empty()) {
932     result.SetError("start-debugging request type missing.");
933     return false;
934   }
935 
936   if (!command[1] || llvm::StringRef(command[1]).empty()) {
937     result.SetError("start-debugging debug configuration missing.");
938     return false;
939   }
940 
941   llvm::StringRef request{command[0]};
942   std::string raw_configuration{command[1]};
943 
944   llvm::Expected<llvm::json::Value> configuration =
945       llvm::json::parse(raw_configuration);
946 
947   if (!configuration) {
948     llvm::Error err = configuration.takeError();
949     std::string msg = "Failed to parse json configuration: " +
950                       llvm::toString(std::move(err)) + "\n\n" +
951                       raw_configuration;
952     result.SetError(msg.c_str());
953     return false;
954   }
955 
956   dap.SendReverseRequest(
957       "startDebugging",
958       llvm::json::Object{{"request", request},
959                          {"configuration", std::move(*configuration)}},
960       [](llvm::Expected<llvm::json::Value> value) {
961         if (!value) {
962           llvm::Error err = value.takeError();
963           llvm::errs() << "reverse start debugging request failed: "
964                        << llvm::toString(std::move(err)) << "\n";
965         }
966       });
967 
968   result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
969 
970   return true;
971 }
972 
973 bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger,
974                                        char **command,
975                                        lldb::SBCommandReturnObject &result) {
976   // Command format like: `repl-mode <variable|command|auto>?`
977   // If a new mode is not specified report the current mode.
978   if (!command || llvm::StringRef(command[0]).empty()) {
979     std::string mode;
980     switch (dap.repl_mode) {
981     case ReplMode::Variable:
982       mode = "variable";
983       break;
984     case ReplMode::Command:
985       mode = "command";
986       break;
987     case ReplMode::Auto:
988       mode = "auto";
989       break;
990     }
991 
992     result.Printf("lldb-dap repl-mode %s.\n", mode.c_str());
993     result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
994 
995     return true;
996   }
997 
998   llvm::StringRef new_mode{command[0]};
999 
1000   if (new_mode == "variable") {
1001     dap.repl_mode = ReplMode::Variable;
1002   } else if (new_mode == "command") {
1003     dap.repl_mode = ReplMode::Command;
1004   } else if (new_mode == "auto") {
1005     dap.repl_mode = ReplMode::Auto;
1006   } else {
1007     lldb::SBStream error_message;
1008     error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', "
1009                          "'command' or 'auto'.\n",
1010                          new_mode.data());
1011     result.SetError(error_message.GetData());
1012     return false;
1013   }
1014 
1015   result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data());
1016   result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1017   return true;
1018 }
1019 
1020 // Sends a DAP event with an optional body.
1021 //
1022 // See
1023 // https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent
1024 bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger,
1025                                         char **command,
1026                                         lldb::SBCommandReturnObject &result) {
1027   // Command format like: `send-event <name> <body>?`
1028   if (!command || !command[0] || llvm::StringRef(command[0]).empty()) {
1029     result.SetError("Not enough arguments found, expected format "
1030                     "`lldb-dap send-event <name> <body>?`.");
1031     return false;
1032   }
1033 
1034   llvm::StringRef name{command[0]};
1035   // Events that are stateful and should be handled by lldb-dap internally.
1036   const std::array internal_events{"breakpoint", "capabilities", "continued",
1037                                    "exited",     "initialize",   "loadedSource",
1038                                    "module",     "process",      "stopped",
1039                                    "terminated", "thread"};
1040   if (std::find(internal_events.begin(), internal_events.end(), name) !=
1041       std::end(internal_events)) {
1042     std::string msg =
1043         llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" "
1044                       "should be handled by lldb-dap internally.",
1045                       name)
1046             .str();
1047     result.SetError(msg.c_str());
1048     return false;
1049   }
1050 
1051   llvm::json::Object event(CreateEventObject(name));
1052 
1053   if (command[1] && !llvm::StringRef(command[1]).empty()) {
1054     // See if we have unused arguments.
1055     if (command[2]) {
1056       result.SetError(
1057           "Additional arguments found, expected `lldb-dap send-event "
1058           "<name> <body>?`.");
1059       return false;
1060     }
1061 
1062     llvm::StringRef raw_body{command[1]};
1063 
1064     llvm::Expected<llvm::json::Value> body = llvm::json::parse(raw_body);
1065 
1066     if (!body) {
1067       llvm::Error err = body.takeError();
1068       std::string msg = "Failed to parse custom event body: " +
1069                         llvm::toString(std::move(err));
1070       result.SetError(msg.c_str());
1071       return false;
1072     }
1073 
1074     event.try_emplace("body", std::move(*body));
1075   }
1076 
1077   dap.SendJSON(llvm::json::Value(std::move(event)));
1078   result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1079   return true;
1080 }
1081 
1082 void DAP::SetFrameFormat(llvm::StringRef format) {
1083   if (format.empty())
1084     return;
1085   lldb::SBError error;
1086   frame_format = lldb::SBFormat(format.str().c_str(), error);
1087   if (error.Fail()) {
1088     SendOutput(OutputType::Console,
1089                llvm::formatv(
1090                    "The provided frame format '{0}' couldn't be parsed: {1}\n",
1091                    format, error.GetCString())
1092                    .str());
1093   }
1094 }
1095 
1096 void DAP::SetThreadFormat(llvm::StringRef format) {
1097   if (format.empty())
1098     return;
1099   lldb::SBError error;
1100   thread_format = lldb::SBFormat(format.str().c_str(), error);
1101   if (error.Fail()) {
1102     SendOutput(OutputType::Console,
1103                llvm::formatv(
1104                    "The provided thread format '{0}' couldn't be parsed: {1}\n",
1105                    format, error.GetCString())
1106                    .str());
1107   }
1108 }
1109 
1110 InstructionBreakpoint *
1111 DAP::GetInstructionBreakpoint(const lldb::break_id_t bp_id) {
1112   for (auto &bp : instruction_breakpoints) {
1113     if (bp.second.bp.GetID() == bp_id)
1114       return &bp.second;
1115   }
1116   return nullptr;
1117 }
1118 
1119 InstructionBreakpoint *
1120 DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) {
1121   const auto num = thread.GetStopReasonDataCount();
1122   InstructionBreakpoint *inst_bp = nullptr;
1123   for (size_t i = 0; i < num; i += 2) {
1124     // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
1125     // thread.GetStopReasonDataAtIndex(i+1) will return the location
1126     // within that breakpoint. We only care about the bp ID so we can
1127     // see if this is an instruction breakpoint that is getting hit.
1128     lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
1129     inst_bp = GetInstructionBreakpoint(bp_id);
1130     // If any breakpoint is not an instruction breakpoint, then stop and
1131     // report this as a normal breakpoint
1132     if (inst_bp == nullptr)
1133       return nullptr;
1134   }
1135   return inst_bp;
1136 }
1137 
1138 } // namespace lldb_dap
1139