xref: /llvm-project/lldb/tools/lldb-dap/JSONUtils.cpp (revision 22561cfb443267905d4190f0e2a738e6b412457f)
1 //===-- JSONUtils.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 "JSONUtils.h"
10 
11 #include "BreakpointBase.h"
12 #include "DAP.h"
13 #include "ExceptionBreakpoint.h"
14 #include "LLDBUtils.h"
15 #include "lldb/API/SBAddress.h"
16 #include "lldb/API/SBCompileUnit.h"
17 #include "lldb/API/SBDeclaration.h"
18 #include "lldb/API/SBEnvironment.h"
19 #include "lldb/API/SBError.h"
20 #include "lldb/API/SBFileSpec.h"
21 #include "lldb/API/SBFrame.h"
22 #include "lldb/API/SBFunction.h"
23 #include "lldb/API/SBLineEntry.h"
24 #include "lldb/API/SBModule.h"
25 #include "lldb/API/SBQueue.h"
26 #include "lldb/API/SBSection.h"
27 #include "lldb/API/SBStream.h"
28 #include "lldb/API/SBStringList.h"
29 #include "lldb/API/SBStructuredData.h"
30 #include "lldb/API/SBTarget.h"
31 #include "lldb/API/SBThread.h"
32 #include "lldb/API/SBType.h"
33 #include "lldb/API/SBValue.h"
34 #include "lldb/Host/PosixApi.h" // IWYU pragma: keep
35 #include "lldb/lldb-defines.h"
36 #include "lldb/lldb-enumerations.h"
37 #include "lldb/lldb-types.h"
38 #include "llvm/ADT/DenseMap.h"
39 #include "llvm/ADT/StringExtras.h"
40 #include "llvm/ADT/StringRef.h"
41 #include "llvm/Support/Compiler.h"
42 #include "llvm/Support/Format.h"
43 #include "llvm/Support/FormatVariadic.h"
44 #include "llvm/Support/Path.h"
45 #include "llvm/Support/ScopedPrinter.h"
46 #include "llvm/Support/raw_ostream.h"
47 #include <chrono>
48 #include <climits>
49 #include <cstddef>
50 #include <iomanip>
51 #include <optional>
52 #include <sstream>
53 #include <string>
54 #include <utility>
55 #include <vector>
56 
57 namespace lldb_dap {
58 
59 void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
60                        llvm::StringRef str) {
61   if (LLVM_LIKELY(llvm::json::isUTF8(str)))
62     obj.try_emplace(key, str.str());
63   else
64     obj.try_emplace(key, llvm::json::fixUTF8(str));
65 }
66 
67 llvm::StringRef GetAsString(const llvm::json::Value &value) {
68   if (auto s = value.getAsString())
69     return *s;
70   return llvm::StringRef();
71 }
72 
73 // Gets a string from a JSON object using the key, or returns an empty string.
74 llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key,
75                           llvm::StringRef defaultValue) {
76   if (std::optional<llvm::StringRef> value = obj.getString(key))
77     return *value;
78   return defaultValue;
79 }
80 
81 llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key,
82                           llvm::StringRef defaultValue) {
83   if (obj == nullptr)
84     return defaultValue;
85   return GetString(*obj, key, defaultValue);
86 }
87 
88 // Gets an unsigned integer from a JSON object using the key, or returns the
89 // specified fail value.
90 uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
91                      uint64_t fail_value) {
92   if (auto value = obj.getInteger(key))
93     return (uint64_t)*value;
94   return fail_value;
95 }
96 
97 uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
98                      uint64_t fail_value) {
99   if (obj == nullptr)
100     return fail_value;
101   return GetUnsigned(*obj, key, fail_value);
102 }
103 
104 bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
105                 bool fail_value) {
106   if (auto value = obj.getBoolean(key))
107     return *value;
108   if (auto value = obj.getInteger(key))
109     return *value != 0;
110   return fail_value;
111 }
112 
113 bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
114                 bool fail_value) {
115   if (obj == nullptr)
116     return fail_value;
117   return GetBoolean(*obj, key, fail_value);
118 }
119 
120 int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
121                   int64_t fail_value) {
122   if (auto value = obj.getInteger(key))
123     return *value;
124   return fail_value;
125 }
126 
127 int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
128                   int64_t fail_value) {
129   if (obj == nullptr)
130     return fail_value;
131   return GetSigned(*obj, key, fail_value);
132 }
133 
134 bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) {
135   return obj.find(key) != obj.end();
136 }
137 
138 std::string EncodeMemoryReference(lldb::addr_t addr) {
139   return "0x" + llvm::utohexstr(addr);
140 }
141 
142 std::optional<lldb::addr_t>
143 DecodeMemoryReference(llvm::StringRef memoryReference) {
144   if (!memoryReference.starts_with("0x"))
145     return std::nullopt;
146 
147   lldb::addr_t addr;
148   if (memoryReference.consumeInteger(0, addr))
149     return std::nullopt;
150 
151   return addr;
152 }
153 
154 std::vector<std::string> GetStrings(const llvm::json::Object *obj,
155                                     llvm::StringRef key) {
156   std::vector<std::string> strs;
157   const auto *json_array = obj->getArray(key);
158   if (!json_array)
159     return strs;
160   for (const auto &value : *json_array) {
161     switch (value.kind()) {
162     case llvm::json::Value::String:
163       strs.push_back(value.getAsString()->str());
164       break;
165     case llvm::json::Value::Number:
166     case llvm::json::Value::Boolean:
167       strs.push_back(llvm::to_string(value));
168       break;
169     case llvm::json::Value::Null:
170     case llvm::json::Value::Object:
171     case llvm::json::Value::Array:
172       break;
173     }
174   }
175   return strs;
176 }
177 
178 std::unordered_map<std::string, std::string>
179 GetStringMap(const llvm::json::Object &obj, llvm::StringRef key) {
180   std::unordered_map<std::string, std::string> strs;
181   const auto *const json_object = obj.getObject(key);
182   if (!json_object)
183     return strs;
184 
185   for (const auto &[key, value] : *json_object) {
186     switch (value.kind()) {
187     case llvm::json::Value::String:
188       strs.emplace(key.str(), value.getAsString()->str());
189       break;
190     case llvm::json::Value::Number:
191     case llvm::json::Value::Boolean:
192       strs.emplace(key.str(), llvm::to_string(value));
193       break;
194     case llvm::json::Value::Null:
195     case llvm::json::Value::Object:
196     case llvm::json::Value::Array:
197       break;
198     }
199   }
200   return strs;
201 }
202 
203 static bool IsClassStructOrUnionType(lldb::SBType t) {
204   return (t.GetTypeClass() & (lldb::eTypeClassUnion | lldb::eTypeClassStruct |
205                               lldb::eTypeClassArray)) != 0;
206 }
207 
208 /// Create a short summary for a container that contains the summary of its
209 /// first children, so that the user can get a glimpse of its contents at a
210 /// glance.
211 static std::optional<std::string>
212 TryCreateAutoSummaryForContainer(lldb::SBValue &v) {
213   if (!v.MightHaveChildren())
214     return std::nullopt;
215   /// As this operation can be potentially slow, we limit the total time spent
216   /// fetching children to a few ms.
217   const auto max_evaluation_time = std::chrono::milliseconds(10);
218   /// We don't want to generate a extremely long summary string, so we limit its
219   /// length.
220   const size_t max_length = 32;
221 
222   auto start = std::chrono::steady_clock::now();
223   std::string summary;
224   llvm::raw_string_ostream os(summary);
225   os << "{";
226 
227   llvm::StringRef separator = "";
228 
229   for (size_t i = 0, e = v.GetNumChildren(); i < e; ++i) {
230     // If we reached the time limit or exceeded the number of characters, we
231     // dump `...` to signal that there are more elements in the collection.
232     if (summary.size() > max_length ||
233         (std::chrono::steady_clock::now() - start) > max_evaluation_time) {
234       os << separator << "...";
235       break;
236     }
237     lldb::SBValue child = v.GetChildAtIndex(i);
238 
239     if (llvm::StringRef name = child.GetName(); !name.empty()) {
240       llvm::StringRef desc;
241       if (llvm::StringRef summary = child.GetSummary(); !summary.empty())
242         desc = summary;
243       else if (llvm::StringRef value = child.GetValue(); !value.empty())
244         desc = value;
245       else if (IsClassStructOrUnionType(child.GetType()))
246         desc = "{...}";
247       else
248         continue;
249 
250       // If the child is an indexed entry, we don't show its index to save
251       // characters.
252       if (name.starts_with("["))
253         os << separator << desc;
254       else
255         os << separator << name << ":" << desc;
256       separator = ", ";
257     }
258   }
259   os << "}";
260 
261   if (summary == "{...}" || summary == "{}")
262     return std::nullopt;
263   return summary;
264 }
265 
266 /// Try to create a summary string for the given value that doesn't have a
267 /// summary of its own.
268 static std::optional<std::string> TryCreateAutoSummary(lldb::SBValue &value) {
269   // We use the dereferenced value for generating the summary.
270   if (value.GetType().IsPointerType() || value.GetType().IsReferenceType())
271     value = value.Dereference();
272 
273   // We only support auto summaries for containers.
274   return TryCreateAutoSummaryForContainer(value);
275 }
276 
277 void FillResponse(const llvm::json::Object &request,
278                   llvm::json::Object &response) {
279   // Fill in all of the needed response fields to a "request" and set "success"
280   // to true by default.
281   response.try_emplace("type", "response");
282   response.try_emplace("seq", (int64_t)0);
283   EmplaceSafeString(response, "command", GetString(request, "command"));
284   const int64_t seq = GetSigned(request, "seq", 0);
285   response.try_emplace("request_seq", seq);
286   response.try_emplace("success", true);
287 }
288 
289 // "Scope": {
290 //   "type": "object",
291 //   "description": "A Scope is a named container for variables. Optionally
292 //                   a scope can map to a source or a range within a source.",
293 //   "properties": {
294 //     "name": {
295 //       "type": "string",
296 //       "description": "Name of the scope such as 'Arguments', 'Locals'."
297 //     },
298 //     "presentationHint": {
299 //       "type": "string",
300 //       "description": "An optional hint for how to present this scope in the
301 //                       UI. If this attribute is missing, the scope is shown
302 //                       with a generic UI.",
303 //       "_enum": [ "arguments", "locals", "registers" ],
304 //     },
305 //     "variablesReference": {
306 //       "type": "integer",
307 //       "description": "The variables of this scope can be retrieved by
308 //                       passing the value of variablesReference to the
309 //                       VariablesRequest."
310 //     },
311 //     "namedVariables": {
312 //       "type": "integer",
313 //       "description": "The number of named variables in this scope. The
314 //                       client can use this optional information to present
315 //                       the variables in a paged UI and fetch them in chunks."
316 //     },
317 //     "indexedVariables": {
318 //       "type": "integer",
319 //       "description": "The number of indexed variables in this scope. The
320 //                       client can use this optional information to present
321 //                       the variables in a paged UI and fetch them in chunks."
322 //     },
323 //     "expensive": {
324 //       "type": "boolean",
325 //       "description": "If true, the number of variables in this scope is
326 //                       large or expensive to retrieve."
327 //     },
328 //     "source": {
329 //       "$ref": "#/definitions/Source",
330 //       "description": "Optional source for this scope."
331 //     },
332 //     "line": {
333 //       "type": "integer",
334 //       "description": "Optional start line of the range covered by this
335 //                       scope."
336 //     },
337 //     "column": {
338 //       "type": "integer",
339 //       "description": "Optional start column of the range covered by this
340 //                       scope."
341 //     },
342 //     "endLine": {
343 //       "type": "integer",
344 //       "description": "Optional end line of the range covered by this scope."
345 //     },
346 //     "endColumn": {
347 //       "type": "integer",
348 //       "description": "Optional end column of the range covered by this
349 //                       scope."
350 //     }
351 //   },
352 //   "required": [ "name", "variablesReference", "expensive" ]
353 // }
354 llvm::json::Value CreateScope(const llvm::StringRef name,
355                               int64_t variablesReference,
356                               int64_t namedVariables, bool expensive) {
357   llvm::json::Object object;
358   EmplaceSafeString(object, "name", name.str());
359 
360   // TODO: Support "arguments" scope. At the moment lldb-dap includes the
361   // arguments into the "locals" scope.
362   if (variablesReference == VARREF_LOCALS) {
363     object.try_emplace("presentationHint", "locals");
364   } else if (variablesReference == VARREF_REGS) {
365     object.try_emplace("presentationHint", "registers");
366   }
367 
368   object.try_emplace("variablesReference", variablesReference);
369   object.try_emplace("expensive", expensive);
370   object.try_emplace("namedVariables", namedVariables);
371   return llvm::json::Value(std::move(object));
372 }
373 
374 // "Breakpoint": {
375 //   "type": "object",
376 //   "description": "Information about a Breakpoint created in setBreakpoints
377 //                   or setFunctionBreakpoints.",
378 //   "properties": {
379 //     "id": {
380 //       "type": "integer",
381 //       "description": "An optional unique identifier for the breakpoint."
382 //     },
383 //     "verified": {
384 //       "type": "boolean",
385 //       "description": "If true breakpoint could be set (but not necessarily
386 //                       at the desired location)."
387 //     },
388 //     "message": {
389 //       "type": "string",
390 //       "description": "An optional message about the state of the breakpoint.
391 //                       This is shown to the user and can be used to explain
392 //                       why a breakpoint could not be verified."
393 //     },
394 //     "source": {
395 //       "$ref": "#/definitions/Source",
396 //       "description": "The source where the breakpoint is located."
397 //     },
398 //     "line": {
399 //       "type": "integer",
400 //       "description": "The start line of the actual range covered by the
401 //                       breakpoint."
402 //     },
403 //     "column": {
404 //       "type": "integer",
405 //       "description": "An optional start column of the actual range covered
406 //                       by the breakpoint."
407 //     },
408 //     "endLine": {
409 //       "type": "integer",
410 //       "description": "An optional end line of the actual range covered by
411 //                       the breakpoint."
412 //     },
413 //     "endColumn": {
414 //       "type": "integer",
415 //       "description": "An optional end column of the actual range covered by
416 //                       the breakpoint. If no end line is given, then the end
417 //                       column is assumed to be in the start line."
418 //     }
419 //   },
420 //   "required": [ "verified" ]
421 // }
422 llvm::json::Value CreateBreakpoint(BreakpointBase *bp,
423                                    std::optional<llvm::StringRef> request_path,
424                                    std::optional<uint32_t> request_line,
425                                    std::optional<uint32_t> request_column) {
426   llvm::json::Object object;
427   if (request_path)
428     object.try_emplace("source", CreateSource(*request_path));
429   bp->CreateJsonObject(object);
430   // We try to add request_line as a fallback
431   if (request_line)
432     object.try_emplace("line", *request_line);
433   if (request_column)
434     object.try_emplace("column", *request_column);
435   return llvm::json::Value(std::move(object));
436 }
437 
438 static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) {
439   uint64_t debug_info_size = 0;
440   llvm::StringRef section_name(section.GetName());
441   if (section_name.starts_with(".debug") ||
442       section_name.starts_with("__debug") ||
443       section_name.starts_with(".apple") || section_name.starts_with("__apple"))
444     debug_info_size += section.GetFileByteSize();
445   size_t num_sub_sections = section.GetNumSubSections();
446   for (size_t i = 0; i < num_sub_sections; i++) {
447     debug_info_size +=
448         GetDebugInfoSizeInSection(section.GetSubSectionAtIndex(i));
449   }
450   return debug_info_size;
451 }
452 
453 static uint64_t GetDebugInfoSize(lldb::SBModule module) {
454   uint64_t debug_info_size = 0;
455   size_t num_sections = module.GetNumSections();
456   for (size_t i = 0; i < num_sections; i++) {
457     debug_info_size += GetDebugInfoSizeInSection(module.GetSectionAtIndex(i));
458   }
459   return debug_info_size;
460 }
461 
462 static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) {
463   std::ostringstream oss;
464   oss << std::fixed << std::setprecision(1);
465   if (debug_info < 1024) {
466     oss << debug_info << "B";
467   } else if (debug_info < 1024 * 1024) {
468     double kb = double(debug_info) / 1024.0;
469     oss << kb << "KB";
470   } else if (debug_info < 1024 * 1024 * 1024) {
471     double mb = double(debug_info) / (1024.0 * 1024.0);
472     oss << mb << "MB";
473   } else {
474     double gb = double(debug_info) / (1024.0 * 1024.0 * 1024.0);
475     oss << gb << "GB";
476   }
477   return oss.str();
478 }
479 
480 llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module) {
481   llvm::json::Object object;
482   if (!target.IsValid() || !module.IsValid())
483     return llvm::json::Value(std::move(object));
484 
485   const char *uuid = module.GetUUIDString();
486   object.try_emplace("id", uuid ? std::string(uuid) : std::string(""));
487   object.try_emplace("name", std::string(module.GetFileSpec().GetFilename()));
488   char module_path_arr[PATH_MAX];
489   module.GetFileSpec().GetPath(module_path_arr, sizeof(module_path_arr));
490   std::string module_path(module_path_arr);
491   object.try_emplace("path", module_path);
492   if (module.GetNumCompileUnits() > 0) {
493     std::string symbol_str = "Symbols loaded.";
494     std::string debug_info_size;
495     uint64_t debug_info = GetDebugInfoSize(module);
496     if (debug_info > 0) {
497       debug_info_size = ConvertDebugInfoSizeToString(debug_info);
498     }
499     object.try_emplace("symbolStatus", symbol_str);
500     object.try_emplace("debugInfoSize", debug_info_size);
501     char symbol_path_arr[PATH_MAX];
502     module.GetSymbolFileSpec().GetPath(symbol_path_arr,
503                                        sizeof(symbol_path_arr));
504     std::string symbol_path(symbol_path_arr);
505     object.try_emplace("symbolFilePath", symbol_path);
506   } else {
507     object.try_emplace("symbolStatus", "Symbols not found.");
508   }
509   std::string loaded_addr = std::to_string(
510       module.GetObjectFileHeaderAddress().GetLoadAddress(target));
511   object.try_emplace("addressRange", loaded_addr);
512   std::string version_str;
513   uint32_t version_nums[3];
514   uint32_t num_versions =
515       module.GetVersion(version_nums, sizeof(version_nums) / sizeof(uint32_t));
516   for (uint32_t i = 0; i < num_versions; ++i) {
517     if (!version_str.empty())
518       version_str += ".";
519     version_str += std::to_string(version_nums[i]);
520   }
521   if (!version_str.empty())
522     object.try_emplace("version", version_str);
523   return llvm::json::Value(std::move(object));
524 }
525 
526 void AppendBreakpoint(BreakpointBase *bp, llvm::json::Array &breakpoints,
527                       std::optional<llvm::StringRef> request_path,
528                       std::optional<uint32_t> request_line) {
529   breakpoints.emplace_back(CreateBreakpoint(bp, request_path, request_line));
530 }
531 
532 // "Event": {
533 //   "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
534 //     "type": "object",
535 //     "description": "Server-initiated event.",
536 //     "properties": {
537 //       "type": {
538 //         "type": "string",
539 //         "enum": [ "event" ]
540 //       },
541 //       "event": {
542 //         "type": "string",
543 //         "description": "Type of event."
544 //       },
545 //       "body": {
546 //         "type": [ "array", "boolean", "integer", "null", "number" ,
547 //                   "object", "string" ],
548 //         "description": "Event-specific information."
549 //       }
550 //     },
551 //     "required": [ "type", "event" ]
552 //   }]
553 // },
554 // "ProtocolMessage": {
555 //   "type": "object",
556 //   "description": "Base class of requests, responses, and events.",
557 //   "properties": {
558 //         "seq": {
559 //           "type": "integer",
560 //           "description": "Sequence number."
561 //         },
562 //         "type": {
563 //           "type": "string",
564 //           "description": "Message type.",
565 //           "_enum": [ "request", "response", "event" ]
566 //         }
567 //   },
568 //   "required": [ "seq", "type" ]
569 // }
570 llvm::json::Object CreateEventObject(const llvm::StringRef event_name) {
571   llvm::json::Object event;
572   event.try_emplace("seq", 0);
573   event.try_emplace("type", "event");
574   EmplaceSafeString(event, "event", event_name);
575   return event;
576 }
577 
578 // "ExceptionBreakpointsFilter": {
579 //   "type": "object",
580 //   "description": "An ExceptionBreakpointsFilter is shown in the UI as an
581 //                   option for configuring how exceptions are dealt with.",
582 //   "properties": {
583 //     "filter": {
584 //       "type": "string",
585 //       "description": "The internal ID of the filter. This value is passed
586 //                       to the setExceptionBreakpoints request."
587 //     },
588 //     "label": {
589 //       "type": "string",
590 //       "description": "The name of the filter. This will be shown in the UI."
591 //     },
592 //     "default": {
593 //       "type": "boolean",
594 //       "description": "Initial value of the filter. If not specified a value
595 //                       'false' is assumed."
596 //     }
597 //   },
598 //   "required": [ "filter", "label" ]
599 // }
600 llvm::json::Value
601 CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
602   llvm::json::Object object;
603   EmplaceSafeString(object, "filter", bp.filter);
604   EmplaceSafeString(object, "label", bp.label);
605   object.try_emplace("default", bp.default_value);
606   return llvm::json::Value(std::move(object));
607 }
608 
609 // "Source": {
610 //   "type": "object",
611 //   "description": "A Source is a descriptor for source code. It is returned
612 //                   from the debug adapter as part of a StackFrame and it is
613 //                   used by clients when specifying breakpoints.",
614 //   "properties": {
615 //     "name": {
616 //       "type": "string",
617 //       "description": "The short name of the source. Every source returned
618 //                       from the debug adapter has a name. When sending a
619 //                       source to the debug adapter this name is optional."
620 //     },
621 //     "path": {
622 //       "type": "string",
623 //       "description": "The path of the source to be shown in the UI. It is
624 //                       only used to locate and load the content of the
625 //                       source if no sourceReference is specified (or its
626 //                       value is 0)."
627 //     },
628 //     "sourceReference": {
629 //       "type": "number",
630 //       "description": "If sourceReference > 0 the contents of the source must
631 //                       be retrieved through the SourceRequest (even if a path
632 //                       is specified). A sourceReference is only valid for a
633 //                       session, so it must not be used to persist a source."
634 //     },
635 //     "presentationHint": {
636 //       "type": "string",
637 //       "description": "An optional hint for how to present the source in the
638 //                       UI. A value of 'deemphasize' can be used to indicate
639 //                       that the source is not available or that it is
640 //                       skipped on stepping.",
641 //       "enum": [ "normal", "emphasize", "deemphasize" ]
642 //     },
643 //     "origin": {
644 //       "type": "string",
645 //       "description": "The (optional) origin of this source: possible values
646 //                       'internal module', 'inlined content from source map',
647 //                       etc."
648 //     },
649 //     "sources": {
650 //       "type": "array",
651 //       "items": {
652 //         "$ref": "#/definitions/Source"
653 //       },
654 //       "description": "An optional list of sources that are related to this
655 //                       source. These may be the source that generated this
656 //                       source."
657 //     },
658 //     "adapterData": {
659 //       "type":["array","boolean","integer","null","number","object","string"],
660 //       "description": "Optional data that a debug adapter might want to loop
661 //                       through the client. The client should leave the data
662 //                       intact and persist it across sessions. The client
663 //                       should not interpret the data."
664 //     },
665 //     "checksums": {
666 //       "type": "array",
667 //       "items": {
668 //         "$ref": "#/definitions/Checksum"
669 //       },
670 //       "description": "The checksums associated with this file."
671 //     }
672 //   }
673 // }
674 llvm::json::Value CreateSource(const lldb::SBFileSpec &file) {
675   llvm::json::Object object;
676   if (file.IsValid()) {
677     const char *name = file.GetFilename();
678     if (name)
679       EmplaceSafeString(object, "name", name);
680     char path[PATH_MAX] = "";
681     if (file.GetPath(path, sizeof(path)) &&
682         lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) {
683       EmplaceSafeString(object, "path", std::string(path));
684     }
685   }
686   return llvm::json::Value(std::move(object));
687 }
688 
689 llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry) {
690   return CreateSource(line_entry.GetFileSpec());
691 }
692 
693 llvm::json::Value CreateSource(llvm::StringRef source_path) {
694   llvm::json::Object source;
695   llvm::StringRef name = llvm::sys::path::filename(source_path);
696   EmplaceSafeString(source, "name", name);
697   EmplaceSafeString(source, "path", source_path);
698   return llvm::json::Value(std::move(source));
699 }
700 
701 static std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) {
702   auto line_entry = frame.GetLineEntry();
703   // A line entry of 0 indicates the line is compiler generated i.e. no source
704   // file is associated with the frame.
705   if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0)
706     return CreateSource(line_entry);
707 
708   return {};
709 }
710 
711 // "StackFrame": {
712 //   "type": "object",
713 //   "description": "A Stackframe contains the source location.",
714 //   "properties": {
715 //     "id": {
716 //       "type": "integer",
717 //       "description": "An identifier for the stack frame. It must be unique
718 //                       across all threads. This id can be used to retrieve
719 //                       the scopes of the frame with the 'scopesRequest' or
720 //                       to restart the execution of a stackframe."
721 //     },
722 //     "name": {
723 //       "type": "string",
724 //       "description": "The name of the stack frame, typically a method name."
725 //     },
726 //     "source": {
727 //       "$ref": "#/definitions/Source",
728 //       "description": "The optional source of the frame."
729 //     },
730 //     "line": {
731 //       "type": "integer",
732 //       "description": "The line within the file of the frame. If source is
733 //                       null or doesn't exist, line is 0 and must be ignored."
734 //     },
735 //     "column": {
736 //       "type": "integer",
737 //       "description": "The column within the line. If source is null or
738 //                       doesn't exist, column is 0 and must be ignored."
739 //     },
740 //     "endLine": {
741 //       "type": "integer",
742 //       "description": "An optional end line of the range covered by the
743 //                       stack frame."
744 //     },
745 //     "endColumn": {
746 //       "type": "integer",
747 //       "description": "An optional end column of the range covered by the
748 //                       stack frame."
749 //     },
750 //     "instructionPointerReference": {
751 // 	     "type": "string",
752 // 	     "description": "A memory reference for the current instruction
753 //                         pointer in this frame."
754 //     },
755 //     "moduleId": {
756 //       "type": ["integer", "string"],
757 //       "description": "The module associated with this frame, if any."
758 //     },
759 //     "presentationHint": {
760 //       "type": "string",
761 //       "enum": [ "normal", "label", "subtle" ],
762 //       "description": "An optional hint for how to present this frame in
763 //                       the UI. A value of 'label' can be used to indicate
764 //                       that the frame is an artificial frame that is used
765 //                       as a visual label or separator. A value of 'subtle'
766 //                       can be used to change the appearance of a frame in
767 //                       a 'subtle' way."
768 //     }
769 //   },
770 //   "required": [ "id", "name", "line", "column" ]
771 // }
772 llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
773                                    lldb::SBFormat &format) {
774   llvm::json::Object object;
775   int64_t frame_id = MakeDAPFrameID(frame);
776   object.try_emplace("id", frame_id);
777 
778   std::string frame_name;
779   lldb::SBStream stream;
780   if (format && frame.GetDescriptionWithFormat(format, stream).Success()) {
781     frame_name = stream.GetData();
782 
783     // `function_name` can be a nullptr, which throws an error when assigned to
784     // an `std::string`.
785   } else if (const char *name = frame.GetDisplayFunctionName()) {
786     frame_name = name;
787   }
788 
789   if (frame_name.empty()) {
790     // If the function name is unavailable, display the pc address as a 16-digit
791     // hex string, e.g. "0x0000000000012345"
792     llvm::raw_string_ostream os(frame_name);
793     os << llvm::format_hex(frame.GetPC(), 18);
794   }
795 
796   // We only include `[opt]` if a custom frame format is not specified.
797   if (!format && frame.GetFunction().GetIsOptimized())
798     frame_name += " [opt]";
799 
800   EmplaceSafeString(object, "name", frame_name);
801 
802   auto source = CreateSource(frame);
803 
804   if (source) {
805     object.try_emplace("source", *source);
806     auto line_entry = frame.GetLineEntry();
807     auto line = line_entry.GetLine();
808     if (line && line != LLDB_INVALID_LINE_NUMBER)
809       object.try_emplace("line", line);
810     else
811       object.try_emplace("line", 0);
812     auto column = line_entry.GetColumn();
813     object.try_emplace("column", column);
814   } else {
815     object.try_emplace("line", 0);
816     object.try_emplace("column", 0);
817   }
818 
819   const auto pc = frame.GetPC();
820   if (pc != LLDB_INVALID_ADDRESS) {
821     std::string formatted_addr = "0x" + llvm::utohexstr(pc);
822     object.try_emplace("instructionPointerReference", formatted_addr);
823   }
824 
825   if (frame.IsArtificial() || frame.IsHidden())
826     object.try_emplace("presentationHint", "subtle");
827 
828   return llvm::json::Value(std::move(object));
829 }
830 
831 llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread,
832                                                 lldb::SBFormat &format) {
833   std::string name;
834   lldb::SBStream stream;
835   if (format && thread.GetDescriptionWithFormat(format, stream).Success()) {
836     name = stream.GetData();
837   } else {
838     const uint32_t thread_idx = thread.GetExtendedBacktraceOriginatingIndexID();
839     const char *queue_name = thread.GetQueueName();
840     if (queue_name != nullptr) {
841       name = llvm::formatv("Enqueued from {0} (Thread {1})", queue_name,
842                            thread_idx);
843     } else {
844       name = llvm::formatv("Thread {0}", thread_idx);
845     }
846   }
847 
848   return llvm::json::Value(llvm::json::Object{{"id", thread.GetThreadID() + 1},
849                                               {"name", name},
850                                               {"presentationHint", "label"}});
851 }
852 
853 // "Thread": {
854 //   "type": "object",
855 //   "description": "A Thread",
856 //   "properties": {
857 //     "id": {
858 //       "type": "integer",
859 //       "description": "Unique identifier for the thread."
860 //     },
861 //     "name": {
862 //       "type": "string",
863 //       "description": "A name of the thread."
864 //     }
865 //   },
866 //   "required": [ "id", "name" ]
867 // }
868 llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format) {
869   llvm::json::Object object;
870   object.try_emplace("id", (int64_t)thread.GetThreadID());
871   std::string thread_str;
872   lldb::SBStream stream;
873   if (format && thread.GetDescriptionWithFormat(format, stream).Success()) {
874     thread_str = stream.GetData();
875   } else {
876     const char *thread_name = thread.GetName();
877     const char *queue_name = thread.GetQueueName();
878 
879     if (thread_name) {
880       thread_str = std::string(thread_name);
881     } else if (queue_name) {
882       auto kind = thread.GetQueue().GetKind();
883       std::string queue_kind_label = "";
884       if (kind == lldb::eQueueKindSerial) {
885         queue_kind_label = " (serial)";
886       } else if (kind == lldb::eQueueKindConcurrent) {
887         queue_kind_label = " (concurrent)";
888       }
889 
890       thread_str =
891           llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(),
892                         queue_name, queue_kind_label)
893               .str();
894     } else {
895       thread_str = llvm::formatv("Thread {0}", thread.GetIndexID()).str();
896     }
897   }
898 
899   EmplaceSafeString(object, "name", thread_str);
900 
901   return llvm::json::Value(std::move(object));
902 }
903 
904 // "StoppedEvent": {
905 //   "allOf": [ { "$ref": "#/definitions/Event" }, {
906 //     "type": "object",
907 //     "description": "Event message for 'stopped' event type. The event
908 //                     indicates that the execution of the debuggee has stopped
909 //                     due to some condition. This can be caused by a break
910 //                     point previously set, a stepping action has completed,
911 //                     by executing a debugger statement etc.",
912 //     "properties": {
913 //       "event": {
914 //         "type": "string",
915 //         "enum": [ "stopped" ]
916 //       },
917 //       "body": {
918 //         "type": "object",
919 //         "properties": {
920 //           "reason": {
921 //             "type": "string",
922 //             "description": "The reason for the event. For backward
923 //                             compatibility this string is shown in the UI if
924 //                             the 'description' attribute is missing (but it
925 //                             must not be translated).",
926 //             "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ]
927 //           },
928 //           "description": {
929 //             "type": "string",
930 //             "description": "The full reason for the event, e.g. 'Paused
931 //                             on exception'. This string is shown in the UI
932 //                             as is."
933 //           },
934 //           "threadId": {
935 //             "type": "integer",
936 //             "description": "The thread which was stopped."
937 //           },
938 //           "text": {
939 //             "type": "string",
940 //             "description": "Additional information. E.g. if reason is
941 //                             'exception', text contains the exception name.
942 //                             This string is shown in the UI."
943 //           },
944 //           "allThreadsStopped": {
945 //             "type": "boolean",
946 //             "description": "If allThreadsStopped is true, a debug adapter
947 //                             can announce that all threads have stopped.
948 //                             The client should use this information to
949 //                             enable that all threads can be expanded to
950 //                             access their stacktraces. If the attribute
951 //                             is missing or false, only the thread with the
952 //                             given threadId can be expanded."
953 //           }
954 //         },
955 //         "required": [ "reason" ]
956 //       }
957 //     },
958 //     "required": [ "event", "body" ]
959 //   }]
960 // }
961 llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
962                                       uint32_t stop_id) {
963   llvm::json::Object event(CreateEventObject("stopped"));
964   llvm::json::Object body;
965   switch (thread.GetStopReason()) {
966   case lldb::eStopReasonTrace:
967   case lldb::eStopReasonPlanComplete:
968     body.try_emplace("reason", "step");
969     break;
970   case lldb::eStopReasonBreakpoint: {
971     ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
972     if (exc_bp) {
973       body.try_emplace("reason", "exception");
974       EmplaceSafeString(body, "description", exc_bp->label);
975     } else {
976       InstructionBreakpoint *inst_bp =
977           dap.GetInstructionBPFromStopReason(thread);
978       if (inst_bp) {
979         body.try_emplace("reason", "instruction breakpoint");
980       } else {
981         body.try_emplace("reason", "breakpoint");
982       }
983       lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0);
984       lldb::break_id_t bp_loc_id = thread.GetStopReasonDataAtIndex(1);
985       std::string desc_str =
986           llvm::formatv("breakpoint {0}.{1}", bp_id, bp_loc_id);
987       body.try_emplace("hitBreakpointIds",
988                        llvm::json::Array{llvm::json::Value(bp_id)});
989       EmplaceSafeString(body, "description", desc_str);
990     }
991   } break;
992   case lldb::eStopReasonWatchpoint:
993   case lldb::eStopReasonInstrumentation:
994     body.try_emplace("reason", "breakpoint");
995     break;
996   case lldb::eStopReasonProcessorTrace:
997     body.try_emplace("reason", "processor trace");
998     break;
999   case lldb::eStopReasonSignal:
1000   case lldb::eStopReasonException:
1001     body.try_emplace("reason", "exception");
1002     break;
1003   case lldb::eStopReasonExec:
1004     body.try_emplace("reason", "entry");
1005     break;
1006   case lldb::eStopReasonFork:
1007     body.try_emplace("reason", "fork");
1008     break;
1009   case lldb::eStopReasonVFork:
1010     body.try_emplace("reason", "vfork");
1011     break;
1012   case lldb::eStopReasonVForkDone:
1013     body.try_emplace("reason", "vforkdone");
1014     break;
1015   case lldb::eStopReasonInterrupt:
1016     body.try_emplace("reason", "async interrupt");
1017     break;
1018   case lldb::eStopReasonThreadExiting:
1019   case lldb::eStopReasonInvalid:
1020   case lldb::eStopReasonNone:
1021     break;
1022   }
1023   if (stop_id == 0)
1024     body.try_emplace("reason", "entry");
1025   const lldb::tid_t tid = thread.GetThreadID();
1026   body.try_emplace("threadId", (int64_t)tid);
1027   // If no description has been set, then set it to the default thread stopped
1028   // description. If we have breakpoints that get hit and shouldn't be reported
1029   // as breakpoints, then they will set the description above.
1030   if (!ObjectContainsKey(body, "description")) {
1031     char description[1024];
1032     if (thread.GetStopDescription(description, sizeof(description))) {
1033       EmplaceSafeString(body, "description", std::string(description));
1034     }
1035   }
1036   // "threadCausedFocus" is used in tests to validate breaking behavior.
1037   if (tid == dap.focus_tid) {
1038     body.try_emplace("threadCausedFocus", true);
1039   }
1040   body.try_emplace("preserveFocusHint", tid != dap.focus_tid);
1041   body.try_emplace("allThreadsStopped", true);
1042   event.try_emplace("body", std::move(body));
1043   return llvm::json::Value(std::move(event));
1044 }
1045 
1046 const char *GetNonNullVariableName(lldb::SBValue &v) {
1047   const char *name = v.GetName();
1048   return name ? name : "<null>";
1049 }
1050 
1051 std::string CreateUniqueVariableNameForDisplay(lldb::SBValue &v,
1052                                                bool is_name_duplicated) {
1053   lldb::SBStream name_builder;
1054   name_builder.Print(GetNonNullVariableName(v));
1055   if (is_name_duplicated) {
1056     lldb::SBDeclaration declaration = v.GetDeclaration();
1057     const char *file_name = declaration.GetFileSpec().GetFilename();
1058     const uint32_t line = declaration.GetLine();
1059 
1060     if (file_name != nullptr && line > 0)
1061       name_builder.Printf(" @ %s:%u", file_name, line);
1062     else if (const char *location = v.GetLocation())
1063       name_builder.Printf(" @ %s", location);
1064   }
1065   return name_builder.GetData();
1066 }
1067 
1068 VariableDescription::VariableDescription(lldb::SBValue v,
1069                                          bool auto_variable_summaries,
1070                                          bool format_hex,
1071                                          bool is_name_duplicated,
1072                                          std::optional<std::string> custom_name)
1073     : v(v) {
1074   name = custom_name
1075              ? *custom_name
1076              : CreateUniqueVariableNameForDisplay(v, is_name_duplicated);
1077 
1078   type_obj = v.GetType();
1079   std::string raw_display_type_name =
1080       llvm::StringRef(type_obj.GetDisplayTypeName()).str();
1081   display_type_name =
1082       !raw_display_type_name.empty() ? raw_display_type_name : NO_TYPENAME;
1083 
1084   // Only format hex/default if there is no existing special format.
1085   if (v.GetFormat() == lldb::eFormatDefault ||
1086       v.GetFormat() == lldb::eFormatHex) {
1087     if (format_hex)
1088       v.SetFormat(lldb::eFormatHex);
1089     else
1090       v.SetFormat(lldb::eFormatDefault);
1091   }
1092 
1093   llvm::raw_string_ostream os_display_value(display_value);
1094 
1095   if (lldb::SBError sb_error = v.GetError(); sb_error.Fail()) {
1096     error = sb_error.GetCString();
1097     os_display_value << "<error: " << error << ">";
1098   } else {
1099     value = llvm::StringRef(v.GetValue()).str();
1100     summary = llvm::StringRef(v.GetSummary()).str();
1101     if (summary.empty() && auto_variable_summaries)
1102       auto_summary = TryCreateAutoSummary(v);
1103 
1104     std::optional<std::string> effective_summary =
1105         !summary.empty() ? summary : auto_summary;
1106 
1107     if (!value.empty()) {
1108       os_display_value << value;
1109       if (effective_summary)
1110         os_display_value << " " << *effective_summary;
1111     } else if (effective_summary) {
1112       os_display_value << *effective_summary;
1113 
1114       // As last resort, we print its type and address if available.
1115     } else {
1116       if (!raw_display_type_name.empty()) {
1117         os_display_value << raw_display_type_name;
1118         lldb::addr_t address = v.GetLoadAddress();
1119         if (address != LLDB_INVALID_ADDRESS)
1120           os_display_value << " @ " << llvm::format_hex(address, 0);
1121       }
1122     }
1123   }
1124 
1125   lldb::SBStream evaluateStream;
1126   v.GetExpressionPath(evaluateStream);
1127   evaluate_name = llvm::StringRef(evaluateStream.GetData()).str();
1128 }
1129 
1130 llvm::json::Object VariableDescription::GetVariableExtensionsJSON() {
1131   llvm::json::Object extensions;
1132   if (error)
1133     EmplaceSafeString(extensions, "error", *error);
1134   if (!value.empty())
1135     EmplaceSafeString(extensions, "value", value);
1136   if (!summary.empty())
1137     EmplaceSafeString(extensions, "summary", summary);
1138   if (auto_summary)
1139     EmplaceSafeString(extensions, "autoSummary", *auto_summary);
1140 
1141   if (lldb::SBDeclaration decl = v.GetDeclaration(); decl.IsValid()) {
1142     llvm::json::Object decl_obj;
1143     if (lldb::SBFileSpec file = decl.GetFileSpec(); file.IsValid()) {
1144       char path[PATH_MAX] = "";
1145       if (file.GetPath(path, sizeof(path)) &&
1146           lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) {
1147         decl_obj.try_emplace("path", std::string(path));
1148       }
1149     }
1150 
1151     if (int line = decl.GetLine())
1152       decl_obj.try_emplace("line", line);
1153     if (int column = decl.GetColumn())
1154       decl_obj.try_emplace("column", column);
1155 
1156     if (!decl_obj.empty())
1157       extensions.try_emplace("declaration", std::move(decl_obj));
1158   }
1159   return extensions;
1160 }
1161 
1162 std::string VariableDescription::GetResult(llvm::StringRef context) {
1163   // In repl context, the results can be displayed as multiple lines so more
1164   // detailed descriptions can be returned.
1165   if (context != "repl")
1166     return display_value;
1167 
1168   if (!v.IsValid())
1169     return display_value;
1170 
1171   // Try the SBValue::GetDescription(), which may call into language runtime
1172   // specific formatters (see ValueObjectPrinter).
1173   lldb::SBStream stream;
1174   v.GetDescription(stream);
1175   llvm::StringRef description = stream.GetData();
1176   return description.trim().str();
1177 }
1178 
1179 bool ValuePointsToCode(lldb::SBValue v) {
1180   if (!v.GetType().GetPointeeType().IsFunctionType())
1181     return false;
1182 
1183   lldb::addr_t addr = v.GetValueAsAddress();
1184   lldb::SBLineEntry line_entry =
1185       v.GetTarget().ResolveLoadAddress(addr).GetLineEntry();
1186 
1187   return line_entry.IsValid();
1188 }
1189 
1190 int64_t PackLocation(int64_t var_ref, bool is_value_location) {
1191   return var_ref << 1 | is_value_location;
1192 }
1193 
1194 std::pair<int64_t, bool> UnpackLocation(int64_t location_id) {
1195   return std::pair{location_id >> 1, location_id & 1};
1196 }
1197 
1198 // "Variable": {
1199 //   "type": "object",
1200 //   "description": "A Variable is a name/value pair. Optionally a variable
1201 //                   can have a 'type' that is shown if space permits or when
1202 //                   hovering over the variable's name. An optional 'kind' is
1203 //                   used to render additional properties of the variable,
1204 //                   e.g. different icons can be used to indicate that a
1205 //                   variable is public or private. If the value is
1206 //                   structured (has children), a handle is provided to
1207 //                   retrieve the children with the VariablesRequest. If
1208 //                   the number of named or indexed children is large, the
1209 //                   numbers should be returned via the optional
1210 //                   'namedVariables' and 'indexedVariables' attributes. The
1211 //                   client can use this optional information to present the
1212 //                   children in a paged UI and fetch them in chunks.",
1213 //   "properties": {
1214 //     "name": {
1215 //       "type": "string",
1216 //       "description": "The variable's name."
1217 //     },
1218 //     "value": {
1219 //       "type": "string",
1220 //       "description": "The variable's value. This can be a multi-line text,
1221 //                       e.g. for a function the body of a function."
1222 //     },
1223 //     "type": {
1224 //       "type": "string",
1225 //       "description": "The type of the variable's value. Typically shown in
1226 //                       the UI when hovering over the value."
1227 //     },
1228 //     "presentationHint": {
1229 //       "$ref": "#/definitions/VariablePresentationHint",
1230 //       "description": "Properties of a variable that can be used to determine
1231 //                       how to render the variable in the UI."
1232 //     },
1233 //     "evaluateName": {
1234 //       "type": "string",
1235 //       "description": "Optional evaluatable name of this variable which can
1236 //                       be passed to the 'EvaluateRequest' to fetch the
1237 //                       variable's value."
1238 //     },
1239 //     "variablesReference": {
1240 //       "type": "integer",
1241 //       "description": "If variablesReference is > 0, the variable is
1242 //                       structured and its children can be retrieved by
1243 //                       passing variablesReference to the VariablesRequest."
1244 //     },
1245 //     "namedVariables": {
1246 //       "type": "integer",
1247 //       "description": "The number of named child variables. The client can
1248 //                       use this optional information to present the children
1249 //                       in a paged UI and fetch them in chunks."
1250 //     },
1251 //     "indexedVariables": {
1252 //       "type": "integer",
1253 //       "description": "The number of indexed child variables. The client
1254 //                       can use this optional information to present the
1255 //                       children in a paged UI and fetch them in chunks."
1256 //     },
1257 //     "memoryReference": {
1258 //        "type": "string",
1259 //        "description": "A memory reference associated with this variable.
1260 //                        For pointer type variables, this is generally a
1261 //                        reference to the memory address contained in the
1262 //                        pointer. For executable data, this reference may later
1263 //                        be used in a `disassemble` request. This attribute may
1264 //                        be returned by a debug adapter if corresponding
1265 //                        capability `supportsMemoryReferences` is true."
1266 //     },
1267 //     "declarationLocationReference": {
1268 //       "type": "integer",
1269 //       "description": "A reference that allows the client to request the
1270 //                       location where the variable is declared. This should be
1271 //                       present only if the adapter is likely to be able to
1272 //                       resolve the location.\n\nThis reference shares the same
1273 //                       lifetime as the `variablesReference`. See 'Lifetime of
1274 //                       Object References' in the Overview section for
1275 //                       details."
1276 //     },
1277 //     "valueLocationReference": {
1278 //       "type": "integer",
1279 //       "description": "A reference that allows the client to request the
1280 //                       location where the variable's value is declared. For
1281 //                       example, if the variable contains a function pointer,
1282 //                       the adapter may be able to look up the function's
1283 //                       location. This should be present only if the adapter
1284 //                       is likely to be able to resolve the location.\n\nThis
1285 //                       reference shares the same lifetime as the
1286 //                       `variablesReference`. See 'Lifetime of Object
1287 //                       References' in the Overview section for details."
1288 //     },
1289 //
1290 //     "$__lldb_extensions": {
1291 //       "description": "Unofficial extensions to the protocol",
1292 //       "properties": {
1293 //         "declaration": {
1294 //           "type": "object",
1295 //           "description": "The source location where the variable was
1296 //                           declared. This value won't be present if no
1297 //                           declaration is available.
1298 //                           Superseded by `declarationLocationReference`",
1299 //           "properties": {
1300 //             "path": {
1301 //               "type": "string",
1302 //               "description": "The source file path where the variable was
1303 //                              declared."
1304 //             },
1305 //             "line": {
1306 //               "type": "number",
1307 //               "description": "The 1-indexed source line where the variable
1308 //                               was declared."
1309 //             },
1310 //             "column": {
1311 //               "type": "number",
1312 //               "description": "The 1-indexed source column where the variable
1313 //                               was declared."
1314 //             }
1315 //           }
1316 //         },
1317 //         "value": {
1318 //           "type": "string",
1319 //           "description": "The internal value of the variable as returned by
1320 //                            This is effectively SBValue.GetValue(). The other
1321 //                            `value` entry in the top-level variable response
1322 //                            is, on the other hand, just a display string for
1323 //                            the variable."
1324 //         },
1325 //         "summary": {
1326 //           "type": "string",
1327 //           "description": "The summary string of the variable. This is
1328 //                           effectively SBValue.GetSummary()."
1329 //         },
1330 //         "autoSummary": {
1331 //           "type": "string",
1332 //           "description": "The auto generated summary if using
1333 //                           `enableAutoVariableSummaries`."
1334 //         },
1335 //         "error": {
1336 //           "type": "string",
1337 //           "description": "An error message generated if LLDB couldn't inspect
1338 //                           the variable."
1339 //         }
1340 //       }
1341 //     }
1342 //   },
1343 //   "required": [ "name", "value", "variablesReference" ]
1344 // }
1345 llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref,
1346                                  bool format_hex, bool auto_variable_summaries,
1347                                  bool synthetic_child_debugging,
1348                                  bool is_name_duplicated,
1349                                  std::optional<std::string> custom_name) {
1350   VariableDescription desc(v, auto_variable_summaries, format_hex,
1351                            is_name_duplicated, custom_name);
1352   llvm::json::Object object;
1353   EmplaceSafeString(object, "name", desc.name);
1354   EmplaceSafeString(object, "value", desc.display_value);
1355 
1356   if (!desc.evaluate_name.empty())
1357     EmplaceSafeString(object, "evaluateName", desc.evaluate_name);
1358 
1359   // If we have a type with many children, we would like to be able to
1360   // give a hint to the IDE that the type has indexed children so that the
1361   // request can be broken up in grabbing only a few children at a time. We
1362   // want to be careful and only call "v.GetNumChildren()" if we have an array
1363   // type or if we have a synthetic child provider producing indexed children.
1364   // We don't want to call "v.GetNumChildren()" on all objects as class, struct
1365   // and union types don't need to be completed if they are never expanded. So
1366   // we want to avoid calling this to only cases where we it makes sense to keep
1367   // performance high during normal debugging.
1368 
1369   // If we have an array type, say that it is indexed and provide the number
1370   // of children in case we have a huge array. If we don't do this, then we
1371   // might take a while to produce all children at onces which can delay your
1372   // debug session.
1373   if (desc.type_obj.IsArrayType()) {
1374     object.try_emplace("indexedVariables", v.GetNumChildren());
1375   } else if (v.IsSynthetic()) {
1376     // For a type with a synthetic child provider, the SBType of "v" won't tell
1377     // us anything about what might be displayed. Instead, we check if the first
1378     // child's name is "[0]" and then say it is indexed. We call
1379     // GetNumChildren() only if the child name matches to avoid a potentially
1380     // expensive operation.
1381     if (lldb::SBValue first_child = v.GetChildAtIndex(0)) {
1382       llvm::StringRef first_child_name = first_child.GetName();
1383       if (first_child_name == "[0]") {
1384         size_t num_children = v.GetNumChildren();
1385         // If we are creating a "[raw]" fake child for each synthetic type, we
1386         // have to account for it when returning indexed variables.
1387         if (synthetic_child_debugging)
1388           ++num_children;
1389         object.try_emplace("indexedVariables", num_children);
1390       }
1391     }
1392   }
1393   EmplaceSafeString(object, "type", desc.display_type_name);
1394 
1395   // A unique variable identifier to help in properly identifying variables with
1396   // the same name. This is an extension to the VS protocol.
1397   object.try_emplace("id", var_ref);
1398 
1399   if (v.MightHaveChildren())
1400     object.try_emplace("variablesReference", var_ref);
1401   else
1402     object.try_emplace("variablesReference", 0);
1403 
1404   if (v.GetDeclaration().IsValid())
1405     object.try_emplace("declarationLocationReference",
1406                        PackLocation(var_ref, false));
1407 
1408   if (ValuePointsToCode(v))
1409     object.try_emplace("valueLocationReference", PackLocation(var_ref, true));
1410 
1411   if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
1412     object.try_emplace("memoryReference", EncodeMemoryReference(addr));
1413 
1414   object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON());
1415   return llvm::json::Value(std::move(object));
1416 }
1417 
1418 llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
1419   llvm::json::Object object;
1420   char unit_path_arr[PATH_MAX];
1421   unit.GetFileSpec().GetPath(unit_path_arr, sizeof(unit_path_arr));
1422   std::string unit_path(unit_path_arr);
1423   object.try_emplace("compileUnitPath", unit_path);
1424   return llvm::json::Value(std::move(object));
1425 }
1426 
1427 /// See
1428 /// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
1429 llvm::json::Object
1430 CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request,
1431                                   llvm::StringRef debug_adaptor_path,
1432                                   llvm::StringRef comm_file,
1433                                   lldb::pid_t debugger_pid) {
1434   llvm::json::Object run_in_terminal_args;
1435   // This indicates the IDE to open an embedded terminal, instead of opening
1436   // the terminal in a new window.
1437   run_in_terminal_args.try_emplace("kind", "integrated");
1438 
1439   const auto *launch_request_arguments = launch_request.getObject("arguments");
1440   // The program path must be the first entry in the "args" field
1441   std::vector<std::string> args = {debug_adaptor_path.str(), "--comm-file",
1442                                    comm_file.str()};
1443   if (debugger_pid != LLDB_INVALID_PROCESS_ID) {
1444     args.push_back("--debugger-pid");
1445     args.push_back(std::to_string(debugger_pid));
1446   }
1447   args.push_back("--launch-target");
1448   args.push_back(GetString(launch_request_arguments, "program").str());
1449   std::vector<std::string> target_args =
1450       GetStrings(launch_request_arguments, "args");
1451   args.insert(args.end(), target_args.begin(), target_args.end());
1452   run_in_terminal_args.try_emplace("args", args);
1453 
1454   const auto cwd = GetString(launch_request_arguments, "cwd");
1455   if (!cwd.empty())
1456     run_in_terminal_args.try_emplace("cwd", cwd);
1457 
1458   auto envs = GetEnvironmentFromArguments(*launch_request_arguments);
1459   llvm::json::Object env_json;
1460   for (size_t index = 0, env_count = envs.GetNumValues(); index < env_count;
1461        index++) {
1462     llvm::StringRef key = envs.GetNameAtIndex(index);
1463     llvm::StringRef value = envs.GetValueAtIndex(index);
1464 
1465     if (!key.empty())
1466       env_json.try_emplace(key, value);
1467   }
1468   run_in_terminal_args.try_emplace("env",
1469                                    llvm::json::Value(std::move(env_json)));
1470 
1471   return run_in_terminal_args;
1472 }
1473 
1474 // Keep all the top level items from the statistics dump, except for the
1475 // "modules" array. It can be huge and cause delay
1476 // Array and dictionary value will return as <key, JSON string> pairs
1477 static void FilterAndGetValueForKey(const lldb::SBStructuredData data,
1478                                     const char *key, llvm::json::Object &out) {
1479   lldb::SBStructuredData value = data.GetValueForKey(key);
1480   std::string key_utf8 = llvm::json::fixUTF8(key);
1481   if (llvm::StringRef(key) == "modules")
1482     return;
1483   switch (value.GetType()) {
1484   case lldb::eStructuredDataTypeFloat:
1485     out.try_emplace(key_utf8, value.GetFloatValue());
1486     break;
1487   case lldb::eStructuredDataTypeUnsignedInteger:
1488     out.try_emplace(key_utf8, value.GetIntegerValue((uint64_t)0));
1489     break;
1490   case lldb::eStructuredDataTypeSignedInteger:
1491     out.try_emplace(key_utf8, value.GetIntegerValue((int64_t)0));
1492     break;
1493   case lldb::eStructuredDataTypeArray: {
1494     lldb::SBStream contents;
1495     value.GetAsJSON(contents);
1496     out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData()));
1497   } break;
1498   case lldb::eStructuredDataTypeBoolean:
1499     out.try_emplace(key_utf8, value.GetBooleanValue());
1500     break;
1501   case lldb::eStructuredDataTypeString: {
1502     // Get the string size before reading
1503     const size_t str_length = value.GetStringValue(nullptr, 0);
1504     std::string str(str_length + 1, 0);
1505     value.GetStringValue(&str[0], str_length);
1506     out.try_emplace(key_utf8, llvm::json::fixUTF8(str));
1507   } break;
1508   case lldb::eStructuredDataTypeDictionary: {
1509     lldb::SBStream contents;
1510     value.GetAsJSON(contents);
1511     out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData()));
1512   } break;
1513   case lldb::eStructuredDataTypeNull:
1514   case lldb::eStructuredDataTypeGeneric:
1515   case lldb::eStructuredDataTypeInvalid:
1516     break;
1517   }
1518 }
1519 
1520 static void addStatistic(lldb::SBTarget &target, llvm::json::Object &event) {
1521   lldb::SBStructuredData statistics = target.GetStatistics();
1522   bool is_dictionary =
1523       statistics.GetType() == lldb::eStructuredDataTypeDictionary;
1524   if (!is_dictionary)
1525     return;
1526   llvm::json::Object stats_body;
1527 
1528   lldb::SBStringList keys;
1529   if (!statistics.GetKeys(keys))
1530     return;
1531   for (size_t i = 0; i < keys.GetSize(); i++) {
1532     const char *key = keys.GetStringAtIndex(i);
1533     FilterAndGetValueForKey(statistics, key, stats_body);
1534   }
1535   event.try_emplace("statistics", std::move(stats_body));
1536 }
1537 
1538 llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target) {
1539   llvm::json::Object event(CreateEventObject("terminated"));
1540   addStatistic(target, event);
1541   return event;
1542 }
1543 
1544 std::string JSONToString(const llvm::json::Value &json) {
1545   std::string data;
1546   llvm::raw_string_ostream os(data);
1547   os << json;
1548   return data;
1549 }
1550 
1551 } // namespace lldb_dap
1552