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