xref: /llvm-project/lldb/tools/lldb-dap/JSONUtils.h (revision faaf2dbf6d2c080d817c4dfe9f888e456418bc2e)
1 //===-- JSONUtils.h ---------------------------------------------*- 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 #ifndef LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
10 #define LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
11 
12 #include "DAPForward.h"
13 #include "lldb/API/SBCompileUnit.h"
14 #include "lldb/API/SBFileSpec.h"
15 #include "lldb/API/SBFormat.h"
16 #include "lldb/API/SBLineEntry.h"
17 #include "lldb/API/SBType.h"
18 #include "lldb/API/SBValue.h"
19 #include "lldb/lldb-types.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/JSON.h"
22 #include <cstdint>
23 #include <optional>
24 #include <string>
25 #include <unordered_map>
26 #include <utility>
27 #include <vector>
28 
29 namespace lldb_dap {
30 
31 /// Emplace a StringRef in a json::Object after enusring that the
32 /// string is valid UTF8. If not, first call llvm::json::fixUTF8
33 /// before emplacing.
34 ///
35 /// \param[in] obj
36 ///     A JSON object that we will attempt to emplace the value in
37 ///
38 /// \param[in] key
39 ///     The key to use when emplacing the value
40 ///
41 /// \param[in] str
42 ///     The string to emplace
43 void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key,
44                        llvm::StringRef str);
45 
46 /// Extract simple values as a string.
47 ///
48 /// \param[in] value
49 ///     A JSON value to extract the string from.
50 ///
51 /// \return
52 ///     A llvm::StringRef that contains the string value, or an empty
53 ///     string if \a value isn't a string.
54 llvm::StringRef GetAsString(const llvm::json::Value &value);
55 
56 /// Extract the string value for the specified key from the
57 /// specified object.
58 ///
59 /// \param[in] obj
60 ///     A JSON object that we will attempt to extract the value from
61 ///
62 /// \param[in] key
63 ///     The key to use when extracting the value
64 ///
65 /// \param[in] defaultValue
66 ///     The default value to return if the key is not present
67 ///
68 /// \return
69 ///     A llvm::StringRef that contains the string value for the
70 ///     specified \a key, or the default value if there is no key that
71 ///     matches or if the value is not a string.
72 llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key,
73                           llvm::StringRef defaultValue = {});
74 llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key,
75                           llvm::StringRef defaultValue = {});
76 
77 /// Extract the unsigned integer value for the specified key from
78 /// the specified object.
79 ///
80 /// \param[in] obj
81 ///     A JSON object that we will attempt to extract the value from
82 ///
83 /// \param[in] key
84 ///     The key to use when extracting the value
85 ///
86 /// \return
87 ///     The unsigned integer value for the specified \a key, or
88 ///     \a fail_value  if there is no key that matches or if the
89 ///     value is not an integer.
90 uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
91                      uint64_t fail_value);
92 uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
93                      uint64_t fail_value);
94 
95 /// Extract the boolean value for the specified key from the
96 /// specified object.
97 ///
98 /// \param[in] obj
99 ///     A JSON object that we will attempt to extract the value from
100 ///
101 /// \param[in] key
102 ///     The key to use when extracting the value
103 ///
104 /// \return
105 ///     The boolean value for the specified \a key, or \a fail_value
106 ///     if there is no key that matches or if the value is not a
107 ///     boolean value of an integer.
108 bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
109                 bool fail_value);
110 bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
111                 bool fail_value);
112 
113 /// Extract the signed integer for the specified key from the
114 /// specified object.
115 ///
116 /// \param[in] obj
117 ///     A JSON object that we will attempt to extract the value from
118 ///
119 /// \param[in] key
120 ///     The key to use when extracting the value
121 ///
122 /// \return
123 ///     The signed integer value for the specified \a key, or
124 ///     \a fail_value if there is no key that matches or if the
125 ///     value is not an integer.
126 int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
127                   int64_t fail_value);
128 int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
129                   int64_t fail_value);
130 
131 /// Check if the specified key exists in the specified object.
132 ///
133 /// \param[in] obj
134 ///     A JSON object that we will attempt to extract the value from
135 ///
136 /// \param[in] key
137 ///     The key to check for
138 ///
139 /// \return
140 ///     \b True if the key exists in the \a obj, \b False otherwise.
141 bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key);
142 
143 /// Encodes a memory reference
144 std::string EncodeMemoryReference(lldb::addr_t addr);
145 
146 /// Decodes a memory reference
147 std::optional<lldb::addr_t>
148 DecodeMemoryReference(llvm::StringRef memoryReference);
149 
150 /// Extract an array of strings for the specified key from an object.
151 ///
152 /// String values in the array will be extracted without any quotes
153 /// around them. Numbers and Booleans will be converted into
154 /// strings. Any NULL, array or objects values in the array will be
155 /// ignored.
156 ///
157 /// \param[in] obj
158 ///     A JSON object that we will attempt to extract the array from
159 ///
160 /// \param[in] key
161 ///     The key to use when extracting the value
162 ///
163 /// \return
164 ///     An array of string values for the specified \a key, or
165 ///     \a fail_value if there is no key that matches or if the
166 ///     value is not an array or all items in the array are not
167 ///     strings, numbers or booleans.
168 std::vector<std::string> GetStrings(const llvm::json::Object *obj,
169                                     llvm::StringRef key);
170 
171 /// Extract an object of key value strings for the specified key from an object.
172 ///
173 /// String values in the object will be extracted without any quotes
174 /// around them. Numbers and Booleans will be converted into
175 /// strings. Any NULL, array or objects values in the array will be
176 /// ignored.
177 ///
178 /// \param[in] obj
179 ///     A JSON object that we will attempt to extract the array from
180 ///
181 /// \param[in] key
182 ///     The key to use when extracting the value
183 ///
184 /// \return
185 ///     An object of key value strings for the specified \a key, or
186 ///     \a fail_value if there is no key that matches or if the
187 ///     value is not an object or key and values in the object are not
188 ///     strings, numbers or booleans.
189 std::unordered_map<std::string, std::string>
190 GetStringMap(const llvm::json::Object &obj, llvm::StringRef key);
191 
192 /// Fill a response object given the request object.
193 ///
194 /// The \a response object will get its "type" set to "response",
195 /// the "seq" set to zero, "response_seq" set to the "seq" value from
196 /// \a request, "command" set to the "command" from \a request,
197 /// and "success" set to true.
198 ///
199 /// \param[in] request
200 ///     The request object received from a call to DAP::ReadJSON().
201 ///
202 /// \param[in,out] response
203 ///     An empty llvm::json::Object object that will be filled
204 ///     in as noted in description.
205 void FillResponse(const llvm::json::Object &request,
206                   llvm::json::Object &response);
207 
208 /// Converts \a bp to a JSON value and appends the first valid location to the
209 /// \a breakpoints array.
210 ///
211 /// \param[in] bp
212 ///     A LLDB breakpoint object which will get the first valid location
213 ///     extracted and converted into a JSON object in the \a breakpoints array
214 ///
215 /// \param[in] breakpoints
216 ///     A JSON array that will get a llvm::json::Value for \a bp
217 ///     appended to it.
218 ///
219 /// \param[in] request_path
220 ///     An optional source path to use when creating the "Source" object of this
221 ///     breakpoint. If not specified, the "Source" object is created from the
222 ///     breakpoint's address' LineEntry. It is useful to ensure the same source
223 ///     paths provided by the setBreakpoints request are returned to the IDE.
224 ///
225 /// \param[in] request_line
226 ///     An optional line to use when creating the "Breakpoint" object to append.
227 ///     It is used if the breakpoint has no valid locations.
228 ///     It is useful to ensure the same line
229 ///     provided by the setBreakpoints request are returned to the IDE as a
230 ///     fallback.
231 void AppendBreakpoint(
232     BreakpointBase *bp, llvm::json::Array &breakpoints,
233     std::optional<llvm::StringRef> request_path = std::nullopt,
234     std::optional<uint32_t> request_line = std::nullopt);
235 
236 /// Converts breakpoint location to a debug adaptor protocol "Breakpoint".
237 ///
238 /// \param[in] bp
239 ///     A LLDB breakpoint object to convert into a JSON value
240 ///
241 /// \param[in] request_path
242 ///     An optional source path to use when creating the "Source" object of this
243 ///     breakpoint. If not specified, the "Source" object is created from the
244 ///     breakpoint's address' LineEntry. It is useful to ensure the same source
245 ///     paths provided by the setBreakpoints request are returned to the IDE.
246 ///
247 /// \param[in] request_line
248 ///     An optional line to use when creating the resulting "Breakpoint" object.
249 ///     It is used if the breakpoint has no valid locations.
250 ///     It is useful to ensure the same line
251 ///     provided by the setBreakpoints request are returned to the IDE as a
252 ///     fallback.
253 ///
254 /// \param[in] request_column
255 ///     An optional column to use when creating the resulting "Breakpoint"
256 ///     object. It is used if the breakpoint has no valid locations. It is
257 ///     useful to ensure the same column provided by the setBreakpoints request
258 ///     are returned to the IDE as a fallback.
259 ///
260 /// \return
261 ///     A "Breakpoint" JSON object with that follows the formal JSON
262 ///     definition outlined by Microsoft.
263 llvm::json::Value
264 CreateBreakpoint(BreakpointBase *bp,
265                  std::optional<llvm::StringRef> request_path = std::nullopt,
266                  std::optional<uint32_t> request_line = std::nullopt,
267                  std::optional<uint32_t> request_column = std::nullopt);
268 
269 /// Converts a LLDB module to a VS Code DAP module for use in "modules" events.
270 ///
271 /// \param[in] target
272 ///     A LLDB target object to convert into a JSON value.
273 ///
274 /// \param[in] module
275 ///     A LLDB module object to convert into a JSON value
276 ///
277 /// \return
278 ///     A "Module" JSON object with that follows the formal JSON
279 ///     definition outlined by Microsoft.
280 llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module);
281 
282 /// Create a "Event" JSON object using \a event_name as the event name
283 ///
284 /// \param[in] event_name
285 ///     The string value to use for the "event" key in the JSON object.
286 ///
287 /// \return
288 ///     A "Event" JSON object with that follows the formal JSON
289 ///     definition outlined by Microsoft.
290 llvm::json::Object CreateEventObject(const llvm::StringRef event_name);
291 
292 /// Create a "ExceptionBreakpointsFilter" JSON object as described in
293 /// the debug adaptor definition.
294 ///
295 /// \param[in] bp
296 ///     The exception breakpoint object to use
297 ///
298 /// \return
299 ///     A "ExceptionBreakpointsFilter" JSON object with that follows
300 ///     the formal JSON definition outlined by Microsoft.
301 llvm::json::Value
302 CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp);
303 
304 /// Create a "Scope" JSON object as described in the debug adaptor definition.
305 ///
306 /// \param[in] name
307 ///     The value to place into the "name" key
308 //
309 /// \param[in] variablesReference
310 ///     The value to place into the "variablesReference" key
311 //
312 /// \param[in] namedVariables
313 ///     The value to place into the "namedVariables" key
314 //
315 /// \param[in] expensive
316 ///     The value to place into the "expensive" key
317 ///
318 /// \return
319 ///     A "Scope" JSON object with that follows the formal JSON
320 ///     definition outlined by Microsoft.
321 llvm::json::Value CreateScope(const llvm::StringRef name,
322                               int64_t variablesReference,
323                               int64_t namedVariables, bool expensive);
324 
325 /// Create a "Source" JSON object as described in the debug adaptor definition.
326 ///
327 /// \param[in] file
328 ///     The SBFileSpec to use when populating out the "Source" object
329 ///
330 /// \return
331 ///     A "Source" JSON object that follows the formal JSON
332 ///     definition outlined by Microsoft.
333 llvm::json::Value CreateSource(const lldb::SBFileSpec &file);
334 
335 /// Create a "Source" JSON object as described in the debug adaptor definition.
336 ///
337 /// \param[in] line_entry
338 ///     The LLDB line table to use when populating out the "Source"
339 ///     object
340 ///
341 /// \return
342 ///     A "Source" JSON object that follows the formal JSON
343 ///     definition outlined by Microsoft.
344 llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry);
345 
346 /// Create a "Source" object for a given source path.
347 ///
348 /// \param[in] source_path
349 ///     The path to the source to use when creating the "Source" object.
350 ///
351 /// \return
352 ///     A "Source" JSON object that follows the formal JSON
353 ///     definition outlined by Microsoft.
354 llvm::json::Value CreateSource(llvm::StringRef source_path);
355 
356 /// Create a "StackFrame" object for a LLDB frame object.
357 ///
358 /// This function will fill in the following keys in the returned
359 /// object:
360 ///   "id" - the stack frame ID as an integer
361 ///   "name" - the function name as a string
362 ///   "source" - source file information as a "Source" DAP object
363 ///   "line" - the source file line number as an integer
364 ///   "column" - the source file column number as an integer
365 ///
366 /// \param[in] frame
367 ///     The LLDB stack frame to use when populating out the "StackFrame"
368 ///     object.
369 ///
370 /// \param[in] format
371 ///     The LLDB format to use when populating out the "StackFrame"
372 ///     object.
373 ///
374 /// \return
375 ///     A "StackFrame" JSON object with that follows the formal JSON
376 ///     definition outlined by Microsoft.
377 llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
378                                    lldb::SBFormat &format);
379 
380 /// Create a "StackFrame" label object for a LLDB thread.
381 ///
382 /// This function will fill in the following keys in the returned
383 /// object:
384 ///   "id" - the thread ID as an integer
385 ///   "name" - the thread name as a string which combines the LLDB
386 ///            thread index ID along with the string name of the thread
387 ///            from the OS if it has a name.
388 ///   "presentationHint" - "label"
389 ///
390 /// \param[in] thread
391 ///     The LLDB thread to use when populating out the "Thread"
392 ///     object.
393 ///
394 /// \param[in] format
395 ///     The configured formatter for the DAP session.
396 ///
397 /// \return
398 ///     A "StackFrame" JSON object with that follows the formal JSON
399 ///     definition outlined by Microsoft.
400 llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread,
401                                                 lldb::SBFormat &format);
402 
403 /// Create a "Thread" object for a LLDB thread object.
404 ///
405 /// This function will fill in the following keys in the returned
406 /// object:
407 ///   "id" - the thread ID as an integer
408 ///   "name" - the thread name as a string which combines the LLDB
409 ///            thread index ID along with the string name of the thread
410 ///            from the OS if it has a name.
411 ///
412 /// \param[in] thread
413 ///     The LLDB thread to use when populating out the "Thread"
414 ///     object.
415 ///
416 /// \param[in] format
417 ///     The LLDB format to use when populating out the "Thread"
418 ///     object.
419 ///
420 /// \return
421 ///     A "Thread" JSON object with that follows the formal JSON
422 ///     definition outlined by Microsoft.
423 llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format);
424 
425 /// Create a "StoppedEvent" object for a LLDB thread object.
426 ///
427 /// This function will fill in the following keys in the returned
428 /// object's "body" object:
429 ///   "reason" - With a valid stop reason enumeration string value
430 ///              that Microsoft specifies
431 ///   "threadId" - The thread ID as an integer
432 ///   "description" - a stop description (like "breakpoint 12.3") as a
433 ///                   string
434 ///   "preserveFocusHint" - a boolean value that states if this thread
435 ///                         should keep the focus in the GUI.
436 ///   "allThreadsStopped" - set to True to indicate that all threads
437 ///                         stop when any thread stops.
438 ///
439 /// \param[in] dap
440 ///     The DAP session associated with the stopped thread.
441 ///
442 /// \param[in] thread
443 ///     The LLDB thread to use when populating out the "StoppedEvent"
444 ///     object.
445 ///
446 /// \param[in] stop_id
447 ///     The stop id for this event.
448 ///
449 /// \return
450 ///     A "StoppedEvent" JSON object with that follows the formal JSON
451 ///     definition outlined by Microsoft.
452 llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
453                                       uint32_t stop_id);
454 
455 /// \return
456 ///     The variable name of \a value or a default placeholder.
457 const char *GetNonNullVariableName(lldb::SBValue &value);
458 
459 /// VSCode can't display two variables with the same name, so we need to
460 /// distinguish them by using a suffix.
461 ///
462 /// If the source and line information is present, we use it as the suffix.
463 /// Otherwise, we fallback to the variable address or register location.
464 std::string CreateUniqueVariableNameForDisplay(lldb::SBValue &v,
465                                                bool is_name_duplicated);
466 
467 /// Helper struct that parses the metadata of an \a lldb::SBValue and produces
468 /// a canonical set of properties that can be sent to DAP clients.
469 struct VariableDescription {
470   // The error message if SBValue.GetValue() fails.
471   std::optional<std::string> error;
472   // The display description to show on the IDE.
473   std::string display_value;
474   // The display name to show on the IDE.
475   std::string name;
476   // The variable path for this variable.
477   std::string evaluate_name;
478   // The output of SBValue.GetValue() if it doesn't fail. It might be empty.
479   std::string value;
480   // The summary string of this variable. It might be empty.
481   std::string summary;
482   // The auto summary if using `enableAutoVariableSummaries`.
483   std::optional<std::string> auto_summary;
484   // The type of this variable.
485   lldb::SBType type_obj;
486   // The display type name of this variable.
487   std::string display_type_name;
488   /// The SBValue for this variable.
489   lldb::SBValue v;
490 
491   VariableDescription(lldb::SBValue v, bool auto_variable_summaries,
492                       bool format_hex = false, bool is_name_duplicated = false,
493                       std::optional<std::string> custom_name = {});
494 
495   /// Create a JSON object that represents these extensions to the DAP variable
496   /// response.
497   llvm::json::Object GetVariableExtensionsJSON();
498 
499   /// Returns a description of the value appropriate for the specified context.
500   std::string GetResult(llvm::StringRef context);
501 };
502 
503 /// Does the given variable have an associated value location?
504 bool ValuePointsToCode(lldb::SBValue v);
505 
506 /// Pack a location into a single integer which we can send via
507 /// the debug adapter protocol.
508 int64_t PackLocation(int64_t var_ref, bool is_value_location);
509 
510 /// Reverse of `PackLocation`
511 std::pair<int64_t, bool> UnpackLocation(int64_t location_id);
512 
513 /// Create a "Variable" object for a LLDB thread object.
514 ///
515 /// This function will fill in the following keys in the returned
516 /// object:
517 ///   "name" - the name of the variable
518 ///   "value" - the value of the variable as a string
519 ///   "type" - the typename of the variable as a string
520 ///   "id" - a unique identifier for a value in case there are multiple
521 ///          variables with the same name. Other parts of the DAP
522 ///          protocol refer to values by name so this can help
523 ///          disambiguate such cases if a IDE passes this "id" value
524 ///          back down.
525 ///   "variablesReference" - Zero if the variable has no children,
526 ///          non-zero integer otherwise which can be used to expand
527 ///          the variable.
528 ///   "evaluateName" - The name of the variable to use in expressions
529 ///                    as a string.
530 ///
531 /// \param[in] v
532 ///     The LLDB value to use when populating out the "Variable"
533 ///     object.
534 ///
535 /// \param[in] var_ref
536 ///     The variable reference. Used to identify the value, e.g.
537 ///     in the `variablesReference` or `declarationLocationReference`
538 ///     properties.
539 ///
540 /// \param[in] format_hex
541 ///     If set to true the variable will be formatted as hex in
542 ///     the "value" key value pair for the value of the variable.
543 ///
544 /// \param[in] auto_variable_summaries
545 ///     IF set to true the variable will create an automatic variable summary.
546 ///
547 /// \param[in] is_name_duplicated
548 ///     Whether the same variable name appears multiple times within the same
549 ///     context (e.g. locals). This can happen due to shadowed variables in
550 ///     nested blocks.
551 ///
552 ///     As VSCode doesn't render two of more variables with the same name, we
553 ///     apply a suffix to distinguish duplicated variables.
554 ///
555 /// \param[in] custom_name
556 ///     A provided custom name that is used instead of the SBValue's when
557 ///     creating the JSON representation.
558 ///
559 /// \return
560 ///     A "Variable" JSON object with that follows the formal JSON
561 ///     definition outlined by Microsoft.
562 llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref,
563                                  bool format_hex, bool auto_variable_summaries,
564                                  bool synthetic_child_debugging,
565                                  bool is_name_duplicated = false,
566                                  std::optional<std::string> custom_name = {});
567 
568 llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
569 
570 /// Create a runInTerminal reverse request object
571 ///
572 /// \param[in] launch_request
573 ///     The original launch_request object whose fields are used to construct
574 ///     the reverse request object.
575 ///
576 /// \param[in] debug_adaptor_path
577 ///     Path to the current debug adaptor. It will be used to delegate the
578 ///     launch of the target.
579 ///
580 /// \param[in] comm_file
581 ///     The fifo file used to communicate the with the target launcher.
582 ///
583 /// \param[in] debugger_pid
584 ///     The PID of the lldb-dap instance that will attach to the target. The
585 ///     launcher uses it on Linux tell the kernel that it should allow the
586 ///     debugger process to attach.
587 ///
588 /// \return
589 ///     A "runInTerminal" JSON object that follows the specification outlined by
590 ///     Microsoft.
591 llvm::json::Object
592 CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request,
593                                   llvm::StringRef debug_adaptor_path,
594                                   llvm::StringRef comm_file,
595                                   lldb::pid_t debugger_pid);
596 
597 /// Create a "Terminated" JSON object that contains statistics
598 ///
599 /// \return
600 ///     A body JSON object with debug info and breakpoint info
601 llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target);
602 
603 /// Convert a given JSON object to a string.
604 std::string JSONToString(const llvm::json::Value &json);
605 
606 } // namespace lldb_dap
607 
608 #endif
609