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