1 //===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
11 #include "BreakpointBase.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"
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());
64 obj
.try_emplace(key
, llvm::json::fixUTF8(str
));
67 llvm::StringRef
GetAsString(const llvm::json::Value
&value
) {
68 if (auto s
= value
.getAsString())
70 return llvm::StringRef();
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
))
81 llvm::StringRef
GetString(const llvm::json::Object
*obj
, llvm::StringRef key
,
82 llvm::StringRef defaultValue
) {
85 return GetString(*obj
, key
, defaultValue
);
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
;
97 uint64_t GetUnsigned(const llvm::json::Object
*obj
, llvm::StringRef key
,
98 uint64_t fail_value
) {
101 return GetUnsigned(*obj
, key
, fail_value
);
104 bool GetBoolean(const llvm::json::Object
&obj
, llvm::StringRef key
,
106 if (auto value
= obj
.getBoolean(key
))
108 if (auto value
= obj
.getInteger(key
))
113 bool GetBoolean(const llvm::json::Object
*obj
, llvm::StringRef key
,
117 return GetBoolean(*obj
, key
, fail_value
);
120 int64_t GetSigned(const llvm::json::Object
&obj
, llvm::StringRef key
,
121 int64_t fail_value
) {
122 if (auto value
= obj
.getInteger(key
))
127 int64_t GetSigned(const llvm::json::Object
*obj
, llvm::StringRef key
,
128 int64_t fail_value
) {
131 return GetSigned(*obj
, key
, fail_value
);
134 bool ObjectContainsKey(const llvm::json::Object
&obj
, llvm::StringRef key
) {
135 return obj
.find(key
) != obj
.end();
138 std::string
EncodeMemoryReference(lldb::addr_t addr
) {
139 return "0x" + llvm::utohexstr(addr
);
142 std::optional
<lldb::addr_t
>
143 DecodeMemoryReference(llvm::StringRef memoryReference
) {
144 if (!memoryReference
.starts_with("0x"))
148 if (memoryReference
.consumeInteger(0, addr
))
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
);
160 for (const auto &value
: *json_array
) {
161 switch (value
.kind()) {
162 case llvm::json::Value::String
:
163 strs
.push_back(value
.getAsString()->str());
165 case llvm::json::Value::Number
:
166 case llvm::json::Value::Boolean
:
167 strs
.push_back(llvm::to_string(value
));
169 case llvm::json::Value::Null
:
170 case llvm::json::Value::Object
:
171 case llvm::json::Value::Array
:
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
);
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());
190 case llvm::json::Value::Number
:
191 case llvm::json::Value::Boolean
:
192 strs
.emplace(key
.str(), llvm::to_string(value
));
194 case llvm::json::Value::Null
:
195 case llvm::json::Value::Object
:
196 case llvm::json::Value::Array
:
203 static bool IsClassStructOrUnionType(lldb::SBType t
) {
204 return (t
.GetTypeClass() & (lldb::eTypeClassUnion
| lldb::eTypeClassStruct
|
205 lldb::eTypeClassArray
)) != 0;
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
211 static std::optional
<std::string
>
212 TryCreateAutoSummaryForContainer(lldb::SBValue
&v
) {
213 if (!v
.MightHaveChildren())
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
220 const size_t max_length
= 32;
222 auto start
= std::chrono::steady_clock::now();
224 llvm::raw_string_ostream
os(summary
);
227 llvm::StringRef separator
= "";
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
<< "...";
237 lldb::SBValue child
= v
.GetChildAtIndex(i
);
239 if (llvm::StringRef name
= child
.GetName(); !name
.empty()) {
240 llvm::StringRef desc
;
241 if (llvm::StringRef summary
= child
.GetSummary(); !summary
.empty())
243 else if (llvm::StringRef value
= child
.GetValue(); !value
.empty())
245 else if (IsClassStructOrUnionType(child
.GetType()))
250 // If the child is an indexed entry, we don't show its index to save
252 if (name
.starts_with("["))
253 os
<< separator
<< desc
;
255 os
<< separator
<< name
<< ":" << desc
;
261 if (summary
== "{...}" || summary
== "{}")
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();
273 // We only support auto summaries for containers.
274 return TryCreateAutoSummaryForContainer(value
);
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);
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.",
296 // "description": "Name of the scope such as 'Arguments', 'Locals'."
298 // "presentationHint": {
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" ],
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."
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."
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."
324 // "type": "boolean",
325 // "description": "If true, the number of variables in this scope is
326 // large or expensive to retrieve."
329 // "$ref": "#/definitions/Source",
330 // "description": "Optional source for this scope."
333 // "type": "integer",
334 // "description": "Optional start line of the range covered by this
338 // "type": "integer",
339 // "description": "Optional start column of the range covered by this
343 // "type": "integer",
344 // "description": "Optional end line of the range covered by this scope."
347 // "type": "integer",
348 // "description": "Optional end column of the range covered by this
352 // "required": [ "name", "variablesReference", "expensive" ]
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());
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");
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
));
376 // "description": "Information about a Breakpoint created in setBreakpoints
377 // or setFunctionBreakpoints.",
380 // "type": "integer",
381 // "description": "An optional unique identifier for the breakpoint."
384 // "type": "boolean",
385 // "description": "If true breakpoint could be set (but not necessarily
386 // at the desired location)."
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."
395 // "$ref": "#/definitions/Source",
396 // "description": "The source where the breakpoint is located."
399 // "type": "integer",
400 // "description": "The start line of the actual range covered by the
404 // "type": "integer",
405 // "description": "An optional start column of the actual range covered
406 // by the breakpoint."
409 // "type": "integer",
410 // "description": "An optional end line of the actual range covered by
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."
420 // "required": [ "verified" ]
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
;
428 object
.try_emplace("source", CreateSource(*request_path
));
429 bp
->CreateJsonObject(object
);
430 // We try to add request_line as a fallback
432 object
.try_emplace("line", *request_line
);
434 object
.try_emplace("column", *request_column
);
435 return llvm::json::Value(std::move(object
));
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
++) {
448 GetDebugInfoSizeInSection(section
.GetSubSectionAtIndex(i
));
450 return debug_info_size
;
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
));
459 return debug_info_size
;
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;
470 } else if (debug_info
< 1024 * 1024 * 1024) {
471 double mb
= double(debug_info
) / (1024.0 * 1024.0);
474 double gb
= double(debug_info
) / (1024.0 * 1024.0 * 1024.0);
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
));
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
);
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
);
507 object
.try_emplace("symbolStatus", "Symbols not found.");
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())
519 version_str
+= std::to_string(version_nums
[i
]);
521 if (!version_str
.empty())
522 object
.try_emplace("version", version_str
);
523 return llvm::json::Value(std::move(object
));
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
));
533 // "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
535 // "description": "Server-initiated event.",
539 // "enum": [ "event" ]
543 // "description": "Type of event."
546 // "type": [ "array", "boolean", "integer", "null", "number" ,
547 // "object", "string" ],
548 // "description": "Event-specific information."
551 // "required": [ "type", "event" ]
554 // "ProtocolMessage": {
556 // "description": "Base class of requests, responses, and events.",
559 // "type": "integer",
560 // "description": "Sequence number."
564 // "description": "Message type.",
565 // "_enum": [ "request", "response", "event" ]
568 // "required": [ "seq", "type" ]
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
);
578 // "ExceptionBreakpointsFilter": {
580 // "description": "An ExceptionBreakpointsFilter is shown in the UI as an
581 // option for configuring how exceptions are dealt with.",
585 // "description": "The internal ID of the filter. This value is passed
586 // to the setExceptionBreakpoints request."
590 // "description": "The name of the filter. This will be shown in the UI."
593 // "type": "boolean",
594 // "description": "Initial value of the filter. If not specified a value
595 // 'false' is assumed."
598 // "required": [ "filter", "label" ]
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
));
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.",
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."
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
628 // "sourceReference": {
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."
635 // "presentationHint": {
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" ]
645 // "description": "The (optional) origin of this source: possible values
646 // 'internal module', 'inlined content from source map',
652 // "$ref": "#/definitions/Source"
654 // "description": "An optional list of sources that are related to this
655 // source. These may be the source that generated this
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."
668 // "$ref": "#/definitions/Checksum"
670 // "description": "The checksums associated with this file."
674 llvm::json::Value
CreateSource(const lldb::SBFileSpec
&file
) {
675 llvm::json::Object object
;
676 if (file
.IsValid()) {
677 const char *name
= file
.GetFilename();
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
));
686 return llvm::json::Value(std::move(object
));
689 llvm::json::Value
CreateSource(const lldb::SBLineEntry
&line_entry
) {
690 return CreateSource(line_entry
.GetFileSpec());
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
));
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
);
713 // "description": "A Stackframe contains the source location.",
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."
724 // "description": "The name of the stack frame, typically a method name."
727 // "$ref": "#/definitions/Source",
728 // "description": "The optional source of the frame."
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."
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."
741 // "type": "integer",
742 // "description": "An optional end line of the range covered by the
746 // "type": "integer",
747 // "description": "An optional end column of the range covered by the
750 // "instructionPointerReference": {
752 // "description": "A memory reference for the current instruction
753 // pointer in this frame."
756 // "type": ["integer", "string"],
757 // "description": "The module associated with this frame, if any."
759 // "presentationHint": {
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
770 // "required": [ "id", "name", "line", "column" ]
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
);
778 std::string frame_name
;
779 lldb::SBStream stream
;
780 if (format
&& frame
.GetDescriptionWithFormat(format
, stream
).Success()) {
781 frame_name
= stream
.GetData();
783 // `function_name` can be a nullptr, which throws an error when assigned to
785 } else if (const char *name
= frame
.GetDisplayFunctionName()) {
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);
796 // We only include `[opt]` if a custom frame format is not specified.
797 if (!format
&& frame
.GetFunction().GetIsOptimized())
798 frame_name
+= " [opt]";
800 EmplaceSafeString(object
, "name", frame_name
);
802 auto source
= CreateSource(frame
);
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
);
811 object
.try_emplace("line", 0);
812 auto column
= line_entry
.GetColumn();
813 object
.try_emplace("column", column
);
815 object
.try_emplace("line", 0);
816 object
.try_emplace("column", 0);
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
);
825 if (frame
.IsArtificial() || frame
.IsHidden())
826 object
.try_emplace("presentationHint", "subtle");
828 return llvm::json::Value(std::move(object
));
831 llvm::json::Value
CreateExtendedStackFrameLabel(lldb::SBThread
&thread
,
832 lldb::SBFormat
&format
) {
834 lldb::SBStream stream
;
835 if (format
&& thread
.GetDescriptionWithFormat(format
, stream
).Success()) {
836 name
= stream
.GetData();
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
,
844 name
= llvm::formatv("Thread {0}", thread_idx
);
848 return llvm::json::Value(llvm::json::Object
{{"id", thread
.GetThreadID() + 1},
850 {"presentationHint", "label"}});
855 // "description": "A Thread",
858 // "type": "integer",
859 // "description": "Unique identifier for the thread."
863 // "description": "A name of the thread."
866 // "required": [ "id", "name" ]
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();
876 const char *thread_name
= thread
.GetName();
877 const char *queue_name
= thread
.GetQueueName();
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)";
891 llvm::formatv("Thread {0} Queue: {1}{2}", thread
.GetIndexID(),
892 queue_name
, queue_kind_label
)
895 thread_str
= llvm::formatv("Thread {0}", thread
.GetIndexID()).str();
899 EmplaceSafeString(object
, "name", thread_str
);
901 return llvm::json::Value(std::move(object
));
905 // "allOf": [ { "$ref": "#/definitions/Event" }, {
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.",
915 // "enum": [ "stopped" ]
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" ]
930 // "description": "The full reason for the event, e.g. 'Paused
931 // on exception'. This string is shown in the UI
935 // "type": "integer",
936 // "description": "The thread which was stopped."
940 // "description": "Additional information. E.g. if reason is
941 // 'exception', text contains the exception name.
942 // This string is shown in the UI."
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."
955 // "required": [ "reason" ]
958 // "required": [ "event", "body" ]
961 llvm::json::Value
CreateThreadStopped(DAP
&dap
, lldb::SBThread
&thread
,
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");
970 case lldb::eStopReasonBreakpoint
: {
971 ExceptionBreakpoint
*exc_bp
= dap
.GetExceptionBPFromStopReason(thread
);
973 body
.try_emplace("reason", "exception");
974 EmplaceSafeString(body
, "description", exc_bp
->label
);
976 InstructionBreakpoint
*inst_bp
=
977 dap
.GetInstructionBPFromStopReason(thread
);
979 body
.try_emplace("reason", "instruction breakpoint");
981 body
.try_emplace("reason", "breakpoint");
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
);
992 case lldb::eStopReasonWatchpoint
:
993 case lldb::eStopReasonInstrumentation
:
994 body
.try_emplace("reason", "breakpoint");
996 case lldb::eStopReasonProcessorTrace
:
997 body
.try_emplace("reason", "processor trace");
999 case lldb::eStopReasonSignal
:
1000 case lldb::eStopReasonException
:
1001 body
.try_emplace("reason", "exception");
1003 case lldb::eStopReasonExec
:
1004 body
.try_emplace("reason", "entry");
1006 case lldb::eStopReasonFork
:
1007 body
.try_emplace("reason", "fork");
1009 case lldb::eStopReasonVFork
:
1010 body
.try_emplace("reason", "vfork");
1012 case lldb::eStopReasonVForkDone
:
1013 body
.try_emplace("reason", "vforkdone");
1015 case lldb::eStopReasonInterrupt
:
1016 body
.try_emplace("reason", "async interrupt");
1018 case lldb::eStopReasonThreadExiting
:
1019 case lldb::eStopReasonInvalid
:
1020 case lldb::eStopReasonNone
:
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
));
1036 // "threadCausedFocus" is used in tests to validate breaking behavior.
1037 if (tid
== dap
.focus_tid
) {
1038 body
.try_emplace("threadCausedFocus", true);
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
));
1046 const char *GetNonNullVariableName(lldb::SBValue
&v
) {
1047 const char *name
= v
.GetName();
1048 return name
? name
: "<null>";
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();
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
);
1065 return name_builder
.GetData();
1068 VariableDescription::VariableDescription(lldb::SBValue v
,
1069 bool auto_variable_summaries
,
1071 bool is_name_duplicated
,
1072 std::optional
<std::string
> custom_name
)
1076 : CreateUniqueVariableNameForDisplay(v
, is_name_duplicated
);
1078 type_obj
= v
.GetType();
1079 std::string raw_display_type_name
=
1080 llvm::StringRef(type_obj
.GetDisplayTypeName()).str();
1082 !raw_display_type_name
.empty() ? raw_display_type_name
: NO_TYPENAME
;
1084 // Only format hex/default if there is no existing special format.
1085 if (v
.GetFormat() == lldb::eFormatDefault
||
1086 v
.GetFormat() == lldb::eFormatHex
) {
1088 v
.SetFormat(lldb::eFormatHex
);
1090 v
.SetFormat(lldb::eFormatDefault
);
1093 llvm::raw_string_ostream
os_display_value(display_value
);
1095 if (lldb::SBError sb_error
= v
.GetError(); sb_error
.Fail()) {
1096 error
= sb_error
.GetCString();
1097 os_display_value
<< "<error: " << error
<< ">";
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
);
1104 std::optional
<std::string
> effective_summary
=
1105 !summary
.empty() ? summary
: auto_summary
;
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
;
1114 // As last resort, we print its type and address if available.
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);
1125 lldb::SBStream evaluateStream
;
1126 v
.GetExpressionPath(evaluateStream
);
1127 evaluate_name
= llvm::StringRef(evaluateStream
.GetData()).str();
1130 llvm::json::Object
VariableDescription::GetVariableExtensionsJSON() {
1131 llvm::json::Object extensions
;
1133 EmplaceSafeString(extensions
, "error", *error
);
1135 EmplaceSafeString(extensions
, "value", value
);
1136 if (!summary
.empty())
1137 EmplaceSafeString(extensions
, "summary", summary
);
1139 EmplaceSafeString(extensions
, "autoSummary", *auto_summary
);
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
));
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
);
1156 if (!decl_obj
.empty())
1157 extensions
.try_emplace("declaration", std::move(decl_obj
));
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
;
1169 return display_value
;
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();
1179 bool ValuePointsToCode(lldb::SBValue v
) {
1180 if (!v
.GetType().GetPointeeType().IsFunctionType())
1183 lldb::addr_t addr
= v
.GetValueAsAddress();
1184 lldb::SBLineEntry line_entry
=
1185 v
.GetTarget().ResolveLoadAddress(addr
).GetLineEntry();
1187 return line_entry
.IsValid();
1190 int64_t PackLocation(int64_t var_ref
, bool is_value_location
) {
1191 return var_ref
<< 1 | is_value_location
;
1194 std::pair
<int64_t, bool> UnpackLocation(int64_t location_id
) {
1195 return std::pair
{location_id
>> 1, location_id
& 1};
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.",
1215 // "type": "string",
1216 // "description": "The variable's name."
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."
1224 // "type": "string",
1225 // "description": "The type of the variable's value. Typically shown in
1226 // the UI when hovering over the value."
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."
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."
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."
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."
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."
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."
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
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."
1290 // "$__lldb_extensions": {
1291 // "description": "Unofficial extensions to the protocol",
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`",
1301 // "type": "string",
1302 // "description": "The source file path where the variable was
1306 // "type": "number",
1307 // "description": "The 1-indexed source line where the variable
1311 // "type": "number",
1312 // "description": "The 1-indexed source column where the variable
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
1326 // "type": "string",
1327 // "description": "The summary string of the variable. This is
1328 // effectively SBValue.GetSummary()."
1331 // "type": "string",
1332 // "description": "The auto generated summary if using
1333 // `enableAutoVariableSummaries`."
1336 // "type": "string",
1337 // "description": "An error message generated if LLDB couldn't inspect
1343 // "required": [ "name", "value", "variablesReference" ]
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
);
1356 if (!desc
.evaluate_name
.empty())
1357 EmplaceSafeString(object
, "evaluateName", desc
.evaluate_name
);
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.
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
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
)
1389 object
.try_emplace("indexedVariables", num_children
);
1393 EmplaceSafeString(object
, "type", desc
.display_type_name
);
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
);
1399 if (v
.MightHaveChildren())
1400 object
.try_emplace("variablesReference", var_ref
);
1402 object
.try_emplace("variablesReference", 0);
1404 if (v
.GetDeclaration().IsValid())
1405 object
.try_emplace("declarationLocationReference",
1406 PackLocation(var_ref
, false));
1408 if (ValuePointsToCode(v
))
1409 object
.try_emplace("valueLocationReference", PackLocation(var_ref
, true));
1411 if (lldb::addr_t addr
= v
.GetLoadAddress(); addr
!= LLDB_INVALID_ADDRESS
)
1412 object
.try_emplace("memoryReference", EncodeMemoryReference(addr
));
1414 object
.try_emplace("$__lldb_extensions", desc
.GetVariableExtensionsJSON());
1415 return llvm::json::Value(std::move(object
));
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
));
1428 /// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
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");
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",
1443 if (debugger_pid
!= LLDB_INVALID_PROCESS_ID
) {
1444 args
.push_back("--debugger-pid");
1445 args
.push_back(std::to_string(debugger_pid
));
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
);
1454 const auto cwd
= GetString(launch_request_arguments
, "cwd");
1456 run_in_terminal_args
.try_emplace("cwd", cwd
);
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
;
1462 llvm::StringRef key
= envs
.GetNameAtIndex(index
);
1463 llvm::StringRef value
= envs
.GetValueAtIndex(index
);
1466 env_json
.try_emplace(key
, value
);
1468 run_in_terminal_args
.try_emplace("env",
1469 llvm::json::Value(std::move(env_json
)));
1471 return run_in_terminal_args
;
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")
1483 switch (value
.GetType()) {
1484 case lldb::eStructuredDataTypeFloat
:
1485 out
.try_emplace(key_utf8
, value
.GetFloatValue());
1487 case lldb::eStructuredDataTypeUnsignedInteger
:
1488 out
.try_emplace(key_utf8
, value
.GetIntegerValue((uint64_t)0));
1490 case lldb::eStructuredDataTypeSignedInteger
:
1491 out
.try_emplace(key_utf8
, value
.GetIntegerValue((int64_t)0));
1493 case lldb::eStructuredDataTypeArray
: {
1494 lldb::SBStream contents
;
1495 value
.GetAsJSON(contents
);
1496 out
.try_emplace(key_utf8
, llvm::json::fixUTF8(contents
.GetData()));
1498 case lldb::eStructuredDataTypeBoolean
:
1499 out
.try_emplace(key_utf8
, value
.GetBooleanValue());
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
));
1508 case lldb::eStructuredDataTypeDictionary
: {
1509 lldb::SBStream contents
;
1510 value
.GetAsJSON(contents
);
1511 out
.try_emplace(key_utf8
, llvm::json::fixUTF8(contents
.GetData()));
1513 case lldb::eStructuredDataTypeNull
:
1514 case lldb::eStructuredDataTypeGeneric
:
1515 case lldb::eStructuredDataTypeInvalid
:
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
;
1526 llvm::json::Object stats_body
;
1528 lldb::SBStringList keys
;
1529 if (!statistics
.GetKeys(keys
))
1531 for (size_t i
= 0; i
< keys
.GetSize(); i
++) {
1532 const char *key
= keys
.GetStringAtIndex(i
);
1533 FilterAndGetValueForKey(statistics
, key
, stats_body
);
1535 event
.try_emplace("statistics", std::move(stats_body
));
1538 llvm::json::Object
CreateTerminatedEventObject(lldb::SBTarget
&target
) {
1539 llvm::json::Object
event(CreateEventObject("terminated"));
1540 addStatistic(target
, event
);
1544 std::string
JSONToString(const llvm::json::Value
&json
) {
1546 llvm::raw_string_ostream
os(data
);
1551 } // namespace lldb_dap