101263c6cSJonas Devlieghere //===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===// 201263c6cSJonas Devlieghere // 301263c6cSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 401263c6cSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 501263c6cSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 601263c6cSJonas Devlieghere // 701263c6cSJonas Devlieghere //===----------------------------------------------------------------------===// 801263c6cSJonas Devlieghere 9b99d4112SJohn Harrison #include "JSONUtils.h" 1001263c6cSJonas Devlieghere 11b99d4112SJohn Harrison #include "BreakpointBase.h" 12b99d4112SJohn Harrison #include "DAP.h" 13b99d4112SJohn Harrison #include "ExceptionBreakpoint.h" 14b99d4112SJohn Harrison #include "LLDBUtils.h" 15b99d4112SJohn Harrison #include "lldb/API/SBAddress.h" 16b99d4112SJohn Harrison #include "lldb/API/SBCompileUnit.h" 1701263c6cSJonas Devlieghere #include "lldb/API/SBDeclaration.h" 18b99d4112SJohn Harrison #include "lldb/API/SBEnvironment.h" 19b99d4112SJohn Harrison #include "lldb/API/SBError.h" 20b99d4112SJohn Harrison #include "lldb/API/SBFileSpec.h" 21b99d4112SJohn Harrison #include "lldb/API/SBFrame.h" 22b99d4112SJohn Harrison #include "lldb/API/SBFunction.h" 23b99d4112SJohn Harrison #include "lldb/API/SBLineEntry.h" 24b99d4112SJohn Harrison #include "lldb/API/SBModule.h" 25b99d4112SJohn Harrison #include "lldb/API/SBQueue.h" 26b99d4112SJohn Harrison #include "lldb/API/SBSection.h" 2709c258efSAdrian Vogelsgesang #include "lldb/API/SBStream.h" 2801263c6cSJonas Devlieghere #include "lldb/API/SBStringList.h" 2901263c6cSJonas Devlieghere #include "lldb/API/SBStructuredData.h" 30b99d4112SJohn Harrison #include "lldb/API/SBTarget.h" 31b99d4112SJohn Harrison #include "lldb/API/SBThread.h" 32b99d4112SJohn Harrison #include "lldb/API/SBType.h" 3301263c6cSJonas Devlieghere #include "lldb/API/SBValue.h" 348d8d9f0eSJohn Harrison #include "lldb/Host/PosixApi.h" // IWYU pragma: keep 35b99d4112SJohn Harrison #include "lldb/lldb-defines.h" 36b99d4112SJohn Harrison #include "lldb/lldb-enumerations.h" 37b99d4112SJohn Harrison #include "lldb/lldb-types.h" 38b99d4112SJohn Harrison #include "llvm/ADT/DenseMap.h" 39b99d4112SJohn Harrison #include "llvm/ADT/StringExtras.h" 40b99d4112SJohn Harrison #include "llvm/ADT/StringRef.h" 41b99d4112SJohn Harrison #include "llvm/Support/Compiler.h" 42b99d4112SJohn Harrison #include "llvm/Support/Format.h" 43b99d4112SJohn Harrison #include "llvm/Support/FormatVariadic.h" 44b99d4112SJohn Harrison #include "llvm/Support/Path.h" 45b99d4112SJohn Harrison #include "llvm/Support/ScopedPrinter.h" 46b99d4112SJohn Harrison #include "llvm/Support/raw_ostream.h" 47b99d4112SJohn Harrison #include <chrono> 48b99d4112SJohn Harrison #include <climits> 49b99d4112SJohn Harrison #include <cstddef> 50b99d4112SJohn Harrison #include <iomanip> 51b99d4112SJohn Harrison #include <optional> 52b99d4112SJohn Harrison #include <sstream> 53b99d4112SJohn Harrison #include <string> 54b99d4112SJohn Harrison #include <utility> 55b99d4112SJohn Harrison #include <vector> 5601263c6cSJonas Devlieghere 5701263c6cSJonas Devlieghere namespace lldb_dap { 5801263c6cSJonas Devlieghere 5901263c6cSJonas Devlieghere void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, 6001263c6cSJonas Devlieghere llvm::StringRef str) { 6101263c6cSJonas Devlieghere if (LLVM_LIKELY(llvm::json::isUTF8(str))) 6201263c6cSJonas Devlieghere obj.try_emplace(key, str.str()); 6301263c6cSJonas Devlieghere else 6401263c6cSJonas Devlieghere obj.try_emplace(key, llvm::json::fixUTF8(str)); 6501263c6cSJonas Devlieghere } 6601263c6cSJonas Devlieghere 6701263c6cSJonas Devlieghere llvm::StringRef GetAsString(const llvm::json::Value &value) { 6801263c6cSJonas Devlieghere if (auto s = value.getAsString()) 6901263c6cSJonas Devlieghere return *s; 7001263c6cSJonas Devlieghere return llvm::StringRef(); 7101263c6cSJonas Devlieghere } 7201263c6cSJonas Devlieghere 7301263c6cSJonas Devlieghere // Gets a string from a JSON object using the key, or returns an empty string. 7410664813SWalter Erquinigo llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key, 7510664813SWalter Erquinigo llvm::StringRef defaultValue) { 7601263c6cSJonas Devlieghere if (std::optional<llvm::StringRef> value = obj.getString(key)) 7701263c6cSJonas Devlieghere return *value; 7810664813SWalter Erquinigo return defaultValue; 7901263c6cSJonas Devlieghere } 8001263c6cSJonas Devlieghere 8110664813SWalter Erquinigo llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key, 8210664813SWalter Erquinigo llvm::StringRef defaultValue) { 8301263c6cSJonas Devlieghere if (obj == nullptr) 8410664813SWalter Erquinigo return defaultValue; 8585ee3fc7Sjeffreytan81 return GetString(*obj, key, defaultValue); 8601263c6cSJonas Devlieghere } 8701263c6cSJonas Devlieghere 8801263c6cSJonas Devlieghere // Gets an unsigned integer from a JSON object using the key, or returns the 8901263c6cSJonas Devlieghere // specified fail value. 9001263c6cSJonas Devlieghere uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key, 9101263c6cSJonas Devlieghere uint64_t fail_value) { 9201263c6cSJonas Devlieghere if (auto value = obj.getInteger(key)) 9301263c6cSJonas Devlieghere return (uint64_t)*value; 9401263c6cSJonas Devlieghere return fail_value; 9501263c6cSJonas Devlieghere } 9601263c6cSJonas Devlieghere 9701263c6cSJonas Devlieghere uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key, 9801263c6cSJonas Devlieghere uint64_t fail_value) { 9901263c6cSJonas Devlieghere if (obj == nullptr) 10001263c6cSJonas Devlieghere return fail_value; 10101263c6cSJonas Devlieghere return GetUnsigned(*obj, key, fail_value); 10201263c6cSJonas Devlieghere } 10301263c6cSJonas Devlieghere 10401263c6cSJonas Devlieghere bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key, 10501263c6cSJonas Devlieghere bool fail_value) { 10601263c6cSJonas Devlieghere if (auto value = obj.getBoolean(key)) 10701263c6cSJonas Devlieghere return *value; 10801263c6cSJonas Devlieghere if (auto value = obj.getInteger(key)) 10901263c6cSJonas Devlieghere return *value != 0; 11001263c6cSJonas Devlieghere return fail_value; 11101263c6cSJonas Devlieghere } 11201263c6cSJonas Devlieghere 11301263c6cSJonas Devlieghere bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key, 11401263c6cSJonas Devlieghere bool fail_value) { 11501263c6cSJonas Devlieghere if (obj == nullptr) 11601263c6cSJonas Devlieghere return fail_value; 11701263c6cSJonas Devlieghere return GetBoolean(*obj, key, fail_value); 11801263c6cSJonas Devlieghere } 11901263c6cSJonas Devlieghere 12001263c6cSJonas Devlieghere int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key, 12101263c6cSJonas Devlieghere int64_t fail_value) { 12201263c6cSJonas Devlieghere if (auto value = obj.getInteger(key)) 12301263c6cSJonas Devlieghere return *value; 12401263c6cSJonas Devlieghere return fail_value; 12501263c6cSJonas Devlieghere } 12601263c6cSJonas Devlieghere 12701263c6cSJonas Devlieghere int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key, 12801263c6cSJonas Devlieghere int64_t fail_value) { 12901263c6cSJonas Devlieghere if (obj == nullptr) 13001263c6cSJonas Devlieghere return fail_value; 13101263c6cSJonas Devlieghere return GetSigned(*obj, key, fail_value); 13201263c6cSJonas Devlieghere } 13301263c6cSJonas Devlieghere 13401263c6cSJonas Devlieghere bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) { 13501263c6cSJonas Devlieghere return obj.find(key) != obj.end(); 13601263c6cSJonas Devlieghere } 13701263c6cSJonas Devlieghere 1383acb1eacSAdrian Vogelsgesang std::string EncodeMemoryReference(lldb::addr_t addr) { 1393acb1eacSAdrian Vogelsgesang return "0x" + llvm::utohexstr(addr); 1403acb1eacSAdrian Vogelsgesang } 1413acb1eacSAdrian Vogelsgesang 1423acb1eacSAdrian Vogelsgesang std::optional<lldb::addr_t> 1433acb1eacSAdrian Vogelsgesang DecodeMemoryReference(llvm::StringRef memoryReference) { 1443acb1eacSAdrian Vogelsgesang if (!memoryReference.starts_with("0x")) 1453acb1eacSAdrian Vogelsgesang return std::nullopt; 1463acb1eacSAdrian Vogelsgesang 1473acb1eacSAdrian Vogelsgesang lldb::addr_t addr; 1483acb1eacSAdrian Vogelsgesang if (memoryReference.consumeInteger(0, addr)) 1493acb1eacSAdrian Vogelsgesang return std::nullopt; 1503acb1eacSAdrian Vogelsgesang 1513acb1eacSAdrian Vogelsgesang return addr; 1523acb1eacSAdrian Vogelsgesang } 1533acb1eacSAdrian Vogelsgesang 15401263c6cSJonas Devlieghere std::vector<std::string> GetStrings(const llvm::json::Object *obj, 15501263c6cSJonas Devlieghere llvm::StringRef key) { 15601263c6cSJonas Devlieghere std::vector<std::string> strs; 157*faaf2dbfSJohn Harrison const auto *json_array = obj->getArray(key); 15801263c6cSJonas Devlieghere if (!json_array) 15901263c6cSJonas Devlieghere return strs; 16001263c6cSJonas Devlieghere for (const auto &value : *json_array) { 16101263c6cSJonas Devlieghere switch (value.kind()) { 16201263c6cSJonas Devlieghere case llvm::json::Value::String: 16301263c6cSJonas Devlieghere strs.push_back(value.getAsString()->str()); 16401263c6cSJonas Devlieghere break; 16501263c6cSJonas Devlieghere case llvm::json::Value::Number: 16601263c6cSJonas Devlieghere case llvm::json::Value::Boolean: 16701263c6cSJonas Devlieghere strs.push_back(llvm::to_string(value)); 16801263c6cSJonas Devlieghere break; 16901263c6cSJonas Devlieghere case llvm::json::Value::Null: 17001263c6cSJonas Devlieghere case llvm::json::Value::Object: 17101263c6cSJonas Devlieghere case llvm::json::Value::Array: 17201263c6cSJonas Devlieghere break; 17301263c6cSJonas Devlieghere } 17401263c6cSJonas Devlieghere } 17501263c6cSJonas Devlieghere return strs; 17601263c6cSJonas Devlieghere } 17701263c6cSJonas Devlieghere 178d4c17891SDa-Viper std::unordered_map<std::string, std::string> 179d4c17891SDa-Viper GetStringMap(const llvm::json::Object &obj, llvm::StringRef key) { 180d4c17891SDa-Viper std::unordered_map<std::string, std::string> strs; 181d4c17891SDa-Viper const auto *const json_object = obj.getObject(key); 182d4c17891SDa-Viper if (!json_object) 183d4c17891SDa-Viper return strs; 184d4c17891SDa-Viper 185d4c17891SDa-Viper for (const auto &[key, value] : *json_object) { 186d4c17891SDa-Viper switch (value.kind()) { 187d4c17891SDa-Viper case llvm::json::Value::String: 188d4c17891SDa-Viper strs.emplace(key.str(), value.getAsString()->str()); 189d4c17891SDa-Viper break; 190d4c17891SDa-Viper case llvm::json::Value::Number: 191d4c17891SDa-Viper case llvm::json::Value::Boolean: 192d4c17891SDa-Viper strs.emplace(key.str(), llvm::to_string(value)); 193d4c17891SDa-Viper break; 194d4c17891SDa-Viper case llvm::json::Value::Null: 195d4c17891SDa-Viper case llvm::json::Value::Object: 196d4c17891SDa-Viper case llvm::json::Value::Array: 197d4c17891SDa-Viper break; 198d4c17891SDa-Viper } 199d4c17891SDa-Viper } 200d4c17891SDa-Viper return strs; 201d4c17891SDa-Viper } 202d4c17891SDa-Viper 20340a361acSJohn Harrison static bool IsClassStructOrUnionType(lldb::SBType t) { 20440a361acSJohn Harrison return (t.GetTypeClass() & (lldb::eTypeClassUnion | lldb::eTypeClassStruct | 205ee63f287SZequan Wu lldb::eTypeClassArray)) != 0; 20640a361acSJohn Harrison } 20740a361acSJohn Harrison 20801263c6cSJonas Devlieghere /// Create a short summary for a container that contains the summary of its 20901263c6cSJonas Devlieghere /// first children, so that the user can get a glimpse of its contents at a 21001263c6cSJonas Devlieghere /// glance. 21101263c6cSJonas Devlieghere static std::optional<std::string> 21201263c6cSJonas Devlieghere TryCreateAutoSummaryForContainer(lldb::SBValue &v) { 21301263c6cSJonas Devlieghere if (!v.MightHaveChildren()) 21401263c6cSJonas Devlieghere return std::nullopt; 21501263c6cSJonas Devlieghere /// As this operation can be potentially slow, we limit the total time spent 21601263c6cSJonas Devlieghere /// fetching children to a few ms. 21701263c6cSJonas Devlieghere const auto max_evaluation_time = std::chrono::milliseconds(10); 21801263c6cSJonas Devlieghere /// We don't want to generate a extremely long summary string, so we limit its 21901263c6cSJonas Devlieghere /// length. 22001263c6cSJonas Devlieghere const size_t max_length = 32; 22101263c6cSJonas Devlieghere 22201263c6cSJonas Devlieghere auto start = std::chrono::steady_clock::now(); 22301263c6cSJonas Devlieghere std::string summary; 22401263c6cSJonas Devlieghere llvm::raw_string_ostream os(summary); 22501263c6cSJonas Devlieghere os << "{"; 22601263c6cSJonas Devlieghere 22701263c6cSJonas Devlieghere llvm::StringRef separator = ""; 22801263c6cSJonas Devlieghere 22901263c6cSJonas Devlieghere for (size_t i = 0, e = v.GetNumChildren(); i < e; ++i) { 23001263c6cSJonas Devlieghere // If we reached the time limit or exceeded the number of characters, we 23101263c6cSJonas Devlieghere // dump `...` to signal that there are more elements in the collection. 23201263c6cSJonas Devlieghere if (summary.size() > max_length || 23301263c6cSJonas Devlieghere (std::chrono::steady_clock::now() - start) > max_evaluation_time) { 23401263c6cSJonas Devlieghere os << separator << "..."; 23501263c6cSJonas Devlieghere break; 23601263c6cSJonas Devlieghere } 23701263c6cSJonas Devlieghere lldb::SBValue child = v.GetChildAtIndex(i); 23801263c6cSJonas Devlieghere 23901263c6cSJonas Devlieghere if (llvm::StringRef name = child.GetName(); !name.empty()) { 24040a361acSJohn Harrison llvm::StringRef desc; 24101263c6cSJonas Devlieghere if (llvm::StringRef summary = child.GetSummary(); !summary.empty()) 24240a361acSJohn Harrison desc = summary; 24340a361acSJohn Harrison else if (llvm::StringRef value = child.GetValue(); !value.empty()) 24440a361acSJohn Harrison desc = value; 24540a361acSJohn Harrison else if (IsClassStructOrUnionType(child.GetType())) 24640a361acSJohn Harrison desc = "{...}"; 24701263c6cSJonas Devlieghere else 24840a361acSJohn Harrison continue; 24901263c6cSJonas Devlieghere 25001263c6cSJonas Devlieghere // If the child is an indexed entry, we don't show its index to save 25101263c6cSJonas Devlieghere // characters. 25201263c6cSJonas Devlieghere if (name.starts_with("[")) 25340a361acSJohn Harrison os << separator << desc; 25401263c6cSJonas Devlieghere else 25540a361acSJohn Harrison os << separator << name << ":" << desc; 25601263c6cSJonas Devlieghere separator = ", "; 25701263c6cSJonas Devlieghere } 25801263c6cSJonas Devlieghere } 25901263c6cSJonas Devlieghere os << "}"; 26001263c6cSJonas Devlieghere 26101263c6cSJonas Devlieghere if (summary == "{...}" || summary == "{}") 26201263c6cSJonas Devlieghere return std::nullopt; 26301263c6cSJonas Devlieghere return summary; 26401263c6cSJonas Devlieghere } 26501263c6cSJonas Devlieghere 26601263c6cSJonas Devlieghere /// Try to create a summary string for the given value that doesn't have a 26701263c6cSJonas Devlieghere /// summary of its own. 268*faaf2dbfSJohn Harrison static std::optional<std::string> TryCreateAutoSummary(lldb::SBValue &value) { 26901263c6cSJonas Devlieghere // We use the dereferenced value for generating the summary. 27001263c6cSJonas Devlieghere if (value.GetType().IsPointerType() || value.GetType().IsReferenceType()) 27101263c6cSJonas Devlieghere value = value.Dereference(); 27201263c6cSJonas Devlieghere 27301263c6cSJonas Devlieghere // We only support auto summaries for containers. 27401263c6cSJonas Devlieghere return TryCreateAutoSummaryForContainer(value); 27501263c6cSJonas Devlieghere } 27601263c6cSJonas Devlieghere 27701263c6cSJonas Devlieghere void FillResponse(const llvm::json::Object &request, 27801263c6cSJonas Devlieghere llvm::json::Object &response) { 27901263c6cSJonas Devlieghere // Fill in all of the needed response fields to a "request" and set "success" 28001263c6cSJonas Devlieghere // to true by default. 28101263c6cSJonas Devlieghere response.try_emplace("type", "response"); 28201263c6cSJonas Devlieghere response.try_emplace("seq", (int64_t)0); 28301263c6cSJonas Devlieghere EmplaceSafeString(response, "command", GetString(request, "command")); 28401263c6cSJonas Devlieghere const int64_t seq = GetSigned(request, "seq", 0); 28501263c6cSJonas Devlieghere response.try_emplace("request_seq", seq); 28601263c6cSJonas Devlieghere response.try_emplace("success", true); 28701263c6cSJonas Devlieghere } 28801263c6cSJonas Devlieghere 28901263c6cSJonas Devlieghere // "Scope": { 29001263c6cSJonas Devlieghere // "type": "object", 29101263c6cSJonas Devlieghere // "description": "A Scope is a named container for variables. Optionally 29201263c6cSJonas Devlieghere // a scope can map to a source or a range within a source.", 29301263c6cSJonas Devlieghere // "properties": { 29401263c6cSJonas Devlieghere // "name": { 29501263c6cSJonas Devlieghere // "type": "string", 29601263c6cSJonas Devlieghere // "description": "Name of the scope such as 'Arguments', 'Locals'." 29701263c6cSJonas Devlieghere // }, 29801263c6cSJonas Devlieghere // "presentationHint": { 29901263c6cSJonas Devlieghere // "type": "string", 30001263c6cSJonas Devlieghere // "description": "An optional hint for how to present this scope in the 30101263c6cSJonas Devlieghere // UI. If this attribute is missing, the scope is shown 30201263c6cSJonas Devlieghere // with a generic UI.", 30301263c6cSJonas Devlieghere // "_enum": [ "arguments", "locals", "registers" ], 30401263c6cSJonas Devlieghere // }, 30501263c6cSJonas Devlieghere // "variablesReference": { 30601263c6cSJonas Devlieghere // "type": "integer", 30701263c6cSJonas Devlieghere // "description": "The variables of this scope can be retrieved by 30801263c6cSJonas Devlieghere // passing the value of variablesReference to the 30901263c6cSJonas Devlieghere // VariablesRequest." 31001263c6cSJonas Devlieghere // }, 31101263c6cSJonas Devlieghere // "namedVariables": { 31201263c6cSJonas Devlieghere // "type": "integer", 31301263c6cSJonas Devlieghere // "description": "The number of named variables in this scope. The 31401263c6cSJonas Devlieghere // client can use this optional information to present 31501263c6cSJonas Devlieghere // the variables in a paged UI and fetch them in chunks." 31601263c6cSJonas Devlieghere // }, 31701263c6cSJonas Devlieghere // "indexedVariables": { 31801263c6cSJonas Devlieghere // "type": "integer", 31901263c6cSJonas Devlieghere // "description": "The number of indexed variables in this scope. The 32001263c6cSJonas Devlieghere // client can use this optional information to present 32101263c6cSJonas Devlieghere // the variables in a paged UI and fetch them in chunks." 32201263c6cSJonas Devlieghere // }, 32301263c6cSJonas Devlieghere // "expensive": { 32401263c6cSJonas Devlieghere // "type": "boolean", 32501263c6cSJonas Devlieghere // "description": "If true, the number of variables in this scope is 32601263c6cSJonas Devlieghere // large or expensive to retrieve." 32701263c6cSJonas Devlieghere // }, 32801263c6cSJonas Devlieghere // "source": { 32901263c6cSJonas Devlieghere // "$ref": "#/definitions/Source", 33001263c6cSJonas Devlieghere // "description": "Optional source for this scope." 33101263c6cSJonas Devlieghere // }, 33201263c6cSJonas Devlieghere // "line": { 33301263c6cSJonas Devlieghere // "type": "integer", 33401263c6cSJonas Devlieghere // "description": "Optional start line of the range covered by this 33501263c6cSJonas Devlieghere // scope." 33601263c6cSJonas Devlieghere // }, 33701263c6cSJonas Devlieghere // "column": { 33801263c6cSJonas Devlieghere // "type": "integer", 33901263c6cSJonas Devlieghere // "description": "Optional start column of the range covered by this 34001263c6cSJonas Devlieghere // scope." 34101263c6cSJonas Devlieghere // }, 34201263c6cSJonas Devlieghere // "endLine": { 34301263c6cSJonas Devlieghere // "type": "integer", 34401263c6cSJonas Devlieghere // "description": "Optional end line of the range covered by this scope." 34501263c6cSJonas Devlieghere // }, 34601263c6cSJonas Devlieghere // "endColumn": { 34701263c6cSJonas Devlieghere // "type": "integer", 34801263c6cSJonas Devlieghere // "description": "Optional end column of the range covered by this 34901263c6cSJonas Devlieghere // scope." 35001263c6cSJonas Devlieghere // } 35101263c6cSJonas Devlieghere // }, 35201263c6cSJonas Devlieghere // "required": [ "name", "variablesReference", "expensive" ] 35301263c6cSJonas Devlieghere // } 35401263c6cSJonas Devlieghere llvm::json::Value CreateScope(const llvm::StringRef name, 35501263c6cSJonas Devlieghere int64_t variablesReference, 35601263c6cSJonas Devlieghere int64_t namedVariables, bool expensive) { 35701263c6cSJonas Devlieghere llvm::json::Object object; 35801263c6cSJonas Devlieghere EmplaceSafeString(object, "name", name.str()); 35901263c6cSJonas Devlieghere 36001263c6cSJonas Devlieghere // TODO: Support "arguments" scope. At the moment lldb-dap includes the 36101263c6cSJonas Devlieghere // arguments into the "locals" scope. 36201263c6cSJonas Devlieghere if (variablesReference == VARREF_LOCALS) { 36301263c6cSJonas Devlieghere object.try_emplace("presentationHint", "locals"); 36401263c6cSJonas Devlieghere } else if (variablesReference == VARREF_REGS) { 36501263c6cSJonas Devlieghere object.try_emplace("presentationHint", "registers"); 36601263c6cSJonas Devlieghere } 36701263c6cSJonas Devlieghere 36801263c6cSJonas Devlieghere object.try_emplace("variablesReference", variablesReference); 36901263c6cSJonas Devlieghere object.try_emplace("expensive", expensive); 37001263c6cSJonas Devlieghere object.try_emplace("namedVariables", namedVariables); 37101263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 37201263c6cSJonas Devlieghere } 37301263c6cSJonas Devlieghere 37401263c6cSJonas Devlieghere // "Breakpoint": { 37501263c6cSJonas Devlieghere // "type": "object", 37601263c6cSJonas Devlieghere // "description": "Information about a Breakpoint created in setBreakpoints 37701263c6cSJonas Devlieghere // or setFunctionBreakpoints.", 37801263c6cSJonas Devlieghere // "properties": { 37901263c6cSJonas Devlieghere // "id": { 38001263c6cSJonas Devlieghere // "type": "integer", 38101263c6cSJonas Devlieghere // "description": "An optional unique identifier for the breakpoint." 38201263c6cSJonas Devlieghere // }, 38301263c6cSJonas Devlieghere // "verified": { 38401263c6cSJonas Devlieghere // "type": "boolean", 38501263c6cSJonas Devlieghere // "description": "If true breakpoint could be set (but not necessarily 38601263c6cSJonas Devlieghere // at the desired location)." 38701263c6cSJonas Devlieghere // }, 38801263c6cSJonas Devlieghere // "message": { 38901263c6cSJonas Devlieghere // "type": "string", 39001263c6cSJonas Devlieghere // "description": "An optional message about the state of the breakpoint. 39101263c6cSJonas Devlieghere // This is shown to the user and can be used to explain 39201263c6cSJonas Devlieghere // why a breakpoint could not be verified." 39301263c6cSJonas Devlieghere // }, 39401263c6cSJonas Devlieghere // "source": { 39501263c6cSJonas Devlieghere // "$ref": "#/definitions/Source", 39601263c6cSJonas Devlieghere // "description": "The source where the breakpoint is located." 39701263c6cSJonas Devlieghere // }, 39801263c6cSJonas Devlieghere // "line": { 39901263c6cSJonas Devlieghere // "type": "integer", 40001263c6cSJonas Devlieghere // "description": "The start line of the actual range covered by the 40101263c6cSJonas Devlieghere // breakpoint." 40201263c6cSJonas Devlieghere // }, 40301263c6cSJonas Devlieghere // "column": { 40401263c6cSJonas Devlieghere // "type": "integer", 40501263c6cSJonas Devlieghere // "description": "An optional start column of the actual range covered 40601263c6cSJonas Devlieghere // by the breakpoint." 40701263c6cSJonas Devlieghere // }, 40801263c6cSJonas Devlieghere // "endLine": { 40901263c6cSJonas Devlieghere // "type": "integer", 41001263c6cSJonas Devlieghere // "description": "An optional end line of the actual range covered by 41101263c6cSJonas Devlieghere // the breakpoint." 41201263c6cSJonas Devlieghere // }, 41301263c6cSJonas Devlieghere // "endColumn": { 41401263c6cSJonas Devlieghere // "type": "integer", 41501263c6cSJonas Devlieghere // "description": "An optional end column of the actual range covered by 41601263c6cSJonas Devlieghere // the breakpoint. If no end line is given, then the end 41701263c6cSJonas Devlieghere // column is assumed to be in the start line." 41801263c6cSJonas Devlieghere // } 41901263c6cSJonas Devlieghere // }, 42001263c6cSJonas Devlieghere // "required": [ "verified" ] 42101263c6cSJonas Devlieghere // } 422d58c128bSZequan Wu llvm::json::Value CreateBreakpoint(BreakpointBase *bp, 42301263c6cSJonas Devlieghere std::optional<llvm::StringRef> request_path, 42401263c6cSJonas Devlieghere std::optional<uint32_t> request_line, 42501263c6cSJonas Devlieghere std::optional<uint32_t> request_column) { 42601263c6cSJonas Devlieghere llvm::json::Object object; 42701263c6cSJonas Devlieghere if (request_path) 42801263c6cSJonas Devlieghere object.try_emplace("source", CreateSource(*request_path)); 429d58c128bSZequan Wu bp->CreateJsonObject(object); 43001263c6cSJonas Devlieghere // We try to add request_line as a fallback 43101263c6cSJonas Devlieghere if (request_line) 43201263c6cSJonas Devlieghere object.try_emplace("line", *request_line); 43301263c6cSJonas Devlieghere if (request_column) 43401263c6cSJonas Devlieghere object.try_emplace("column", *request_column); 43501263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 43601263c6cSJonas Devlieghere } 43701263c6cSJonas Devlieghere 43801263c6cSJonas Devlieghere static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) { 43901263c6cSJonas Devlieghere uint64_t debug_info_size = 0; 44001263c6cSJonas Devlieghere llvm::StringRef section_name(section.GetName()); 441744f3891SKazu Hirata if (section_name.starts_with(".debug") || 442744f3891SKazu Hirata section_name.starts_with("__debug") || 443744f3891SKazu Hirata section_name.starts_with(".apple") || section_name.starts_with("__apple")) 44401263c6cSJonas Devlieghere debug_info_size += section.GetFileByteSize(); 44501263c6cSJonas Devlieghere size_t num_sub_sections = section.GetNumSubSections(); 44601263c6cSJonas Devlieghere for (size_t i = 0; i < num_sub_sections; i++) { 44701263c6cSJonas Devlieghere debug_info_size += 44801263c6cSJonas Devlieghere GetDebugInfoSizeInSection(section.GetSubSectionAtIndex(i)); 44901263c6cSJonas Devlieghere } 45001263c6cSJonas Devlieghere return debug_info_size; 45101263c6cSJonas Devlieghere } 45201263c6cSJonas Devlieghere 45301263c6cSJonas Devlieghere static uint64_t GetDebugInfoSize(lldb::SBModule module) { 45401263c6cSJonas Devlieghere uint64_t debug_info_size = 0; 45501263c6cSJonas Devlieghere size_t num_sections = module.GetNumSections(); 45601263c6cSJonas Devlieghere for (size_t i = 0; i < num_sections; i++) { 45701263c6cSJonas Devlieghere debug_info_size += GetDebugInfoSizeInSection(module.GetSectionAtIndex(i)); 45801263c6cSJonas Devlieghere } 45901263c6cSJonas Devlieghere return debug_info_size; 46001263c6cSJonas Devlieghere } 46101263c6cSJonas Devlieghere 46201263c6cSJonas Devlieghere static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) { 46301263c6cSJonas Devlieghere std::ostringstream oss; 46401263c6cSJonas Devlieghere oss << std::fixed << std::setprecision(1); 46501263c6cSJonas Devlieghere if (debug_info < 1024) { 46601263c6cSJonas Devlieghere oss << debug_info << "B"; 46701263c6cSJonas Devlieghere } else if (debug_info < 1024 * 1024) { 46801263c6cSJonas Devlieghere double kb = double(debug_info) / 1024.0; 46901263c6cSJonas Devlieghere oss << kb << "KB"; 47001263c6cSJonas Devlieghere } else if (debug_info < 1024 * 1024 * 1024) { 47101263c6cSJonas Devlieghere double mb = double(debug_info) / (1024.0 * 1024.0); 47201263c6cSJonas Devlieghere oss << mb << "MB"; 47301263c6cSJonas Devlieghere } else { 47401263c6cSJonas Devlieghere double gb = double(debug_info) / (1024.0 * 1024.0 * 1024.0); 47501263c6cSJonas Devlieghere oss << gb << "GB"; 47601263c6cSJonas Devlieghere } 47701263c6cSJonas Devlieghere return oss.str(); 47801263c6cSJonas Devlieghere } 479*faaf2dbfSJohn Harrison 480*faaf2dbfSJohn Harrison llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module) { 48101263c6cSJonas Devlieghere llvm::json::Object object; 482*faaf2dbfSJohn Harrison if (!target.IsValid() || !module.IsValid()) 48301263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 484*faaf2dbfSJohn Harrison 48501263c6cSJonas Devlieghere const char *uuid = module.GetUUIDString(); 48601263c6cSJonas Devlieghere object.try_emplace("id", uuid ? std::string(uuid) : std::string("")); 48701263c6cSJonas Devlieghere object.try_emplace("name", std::string(module.GetFileSpec().GetFilename())); 48801263c6cSJonas Devlieghere char module_path_arr[PATH_MAX]; 48901263c6cSJonas Devlieghere module.GetFileSpec().GetPath(module_path_arr, sizeof(module_path_arr)); 49001263c6cSJonas Devlieghere std::string module_path(module_path_arr); 49101263c6cSJonas Devlieghere object.try_emplace("path", module_path); 49201263c6cSJonas Devlieghere if (module.GetNumCompileUnits() > 0) { 49301263c6cSJonas Devlieghere std::string symbol_str = "Symbols loaded."; 49401263c6cSJonas Devlieghere std::string debug_info_size; 49501263c6cSJonas Devlieghere uint64_t debug_info = GetDebugInfoSize(module); 49601263c6cSJonas Devlieghere if (debug_info > 0) { 49701263c6cSJonas Devlieghere debug_info_size = ConvertDebugInfoSizeToString(debug_info); 49801263c6cSJonas Devlieghere } 49901263c6cSJonas Devlieghere object.try_emplace("symbolStatus", symbol_str); 50001263c6cSJonas Devlieghere object.try_emplace("debugInfoSize", debug_info_size); 50101263c6cSJonas Devlieghere char symbol_path_arr[PATH_MAX]; 50201263c6cSJonas Devlieghere module.GetSymbolFileSpec().GetPath(symbol_path_arr, 50301263c6cSJonas Devlieghere sizeof(symbol_path_arr)); 50401263c6cSJonas Devlieghere std::string symbol_path(symbol_path_arr); 50501263c6cSJonas Devlieghere object.try_emplace("symbolFilePath", symbol_path); 50601263c6cSJonas Devlieghere } else { 50701263c6cSJonas Devlieghere object.try_emplace("symbolStatus", "Symbols not found."); 50801263c6cSJonas Devlieghere } 50901263c6cSJonas Devlieghere std::string loaded_addr = std::to_string( 510*faaf2dbfSJohn Harrison module.GetObjectFileHeaderAddress().GetLoadAddress(target)); 51101263c6cSJonas Devlieghere object.try_emplace("addressRange", loaded_addr); 51201263c6cSJonas Devlieghere std::string version_str; 51301263c6cSJonas Devlieghere uint32_t version_nums[3]; 51401263c6cSJonas Devlieghere uint32_t num_versions = 51501263c6cSJonas Devlieghere module.GetVersion(version_nums, sizeof(version_nums) / sizeof(uint32_t)); 51601263c6cSJonas Devlieghere for (uint32_t i = 0; i < num_versions; ++i) { 51701263c6cSJonas Devlieghere if (!version_str.empty()) 51801263c6cSJonas Devlieghere version_str += "."; 51901263c6cSJonas Devlieghere version_str += std::to_string(version_nums[i]); 52001263c6cSJonas Devlieghere } 52101263c6cSJonas Devlieghere if (!version_str.empty()) 52201263c6cSJonas Devlieghere object.try_emplace("version", version_str); 52301263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 52401263c6cSJonas Devlieghere } 52501263c6cSJonas Devlieghere 526d58c128bSZequan Wu void AppendBreakpoint(BreakpointBase *bp, llvm::json::Array &breakpoints, 52701263c6cSJonas Devlieghere std::optional<llvm::StringRef> request_path, 52801263c6cSJonas Devlieghere std::optional<uint32_t> request_line) { 52901263c6cSJonas Devlieghere breakpoints.emplace_back(CreateBreakpoint(bp, request_path, request_line)); 53001263c6cSJonas Devlieghere } 53101263c6cSJonas Devlieghere 53201263c6cSJonas Devlieghere // "Event": { 53301263c6cSJonas Devlieghere // "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, { 53401263c6cSJonas Devlieghere // "type": "object", 53501263c6cSJonas Devlieghere // "description": "Server-initiated event.", 53601263c6cSJonas Devlieghere // "properties": { 53701263c6cSJonas Devlieghere // "type": { 53801263c6cSJonas Devlieghere // "type": "string", 53901263c6cSJonas Devlieghere // "enum": [ "event" ] 54001263c6cSJonas Devlieghere // }, 54101263c6cSJonas Devlieghere // "event": { 54201263c6cSJonas Devlieghere // "type": "string", 54301263c6cSJonas Devlieghere // "description": "Type of event." 54401263c6cSJonas Devlieghere // }, 54501263c6cSJonas Devlieghere // "body": { 54601263c6cSJonas Devlieghere // "type": [ "array", "boolean", "integer", "null", "number" , 54701263c6cSJonas Devlieghere // "object", "string" ], 54801263c6cSJonas Devlieghere // "description": "Event-specific information." 54901263c6cSJonas Devlieghere // } 55001263c6cSJonas Devlieghere // }, 55101263c6cSJonas Devlieghere // "required": [ "type", "event" ] 55201263c6cSJonas Devlieghere // }] 55301263c6cSJonas Devlieghere // }, 55401263c6cSJonas Devlieghere // "ProtocolMessage": { 55501263c6cSJonas Devlieghere // "type": "object", 55601263c6cSJonas Devlieghere // "description": "Base class of requests, responses, and events.", 55701263c6cSJonas Devlieghere // "properties": { 55801263c6cSJonas Devlieghere // "seq": { 55901263c6cSJonas Devlieghere // "type": "integer", 56001263c6cSJonas Devlieghere // "description": "Sequence number." 56101263c6cSJonas Devlieghere // }, 56201263c6cSJonas Devlieghere // "type": { 56301263c6cSJonas Devlieghere // "type": "string", 56401263c6cSJonas Devlieghere // "description": "Message type.", 56501263c6cSJonas Devlieghere // "_enum": [ "request", "response", "event" ] 56601263c6cSJonas Devlieghere // } 56701263c6cSJonas Devlieghere // }, 56801263c6cSJonas Devlieghere // "required": [ "seq", "type" ] 56901263c6cSJonas Devlieghere // } 57001263c6cSJonas Devlieghere llvm::json::Object CreateEventObject(const llvm::StringRef event_name) { 57101263c6cSJonas Devlieghere llvm::json::Object event; 57201263c6cSJonas Devlieghere event.try_emplace("seq", 0); 57301263c6cSJonas Devlieghere event.try_emplace("type", "event"); 57401263c6cSJonas Devlieghere EmplaceSafeString(event, "event", event_name); 57501263c6cSJonas Devlieghere return event; 57601263c6cSJonas Devlieghere } 57701263c6cSJonas Devlieghere 57801263c6cSJonas Devlieghere // "ExceptionBreakpointsFilter": { 57901263c6cSJonas Devlieghere // "type": "object", 58001263c6cSJonas Devlieghere // "description": "An ExceptionBreakpointsFilter is shown in the UI as an 58101263c6cSJonas Devlieghere // option for configuring how exceptions are dealt with.", 58201263c6cSJonas Devlieghere // "properties": { 58301263c6cSJonas Devlieghere // "filter": { 58401263c6cSJonas Devlieghere // "type": "string", 58501263c6cSJonas Devlieghere // "description": "The internal ID of the filter. This value is passed 58601263c6cSJonas Devlieghere // to the setExceptionBreakpoints request." 58701263c6cSJonas Devlieghere // }, 58801263c6cSJonas Devlieghere // "label": { 58901263c6cSJonas Devlieghere // "type": "string", 59001263c6cSJonas Devlieghere // "description": "The name of the filter. This will be shown in the UI." 59101263c6cSJonas Devlieghere // }, 59201263c6cSJonas Devlieghere // "default": { 59301263c6cSJonas Devlieghere // "type": "boolean", 59401263c6cSJonas Devlieghere // "description": "Initial value of the filter. If not specified a value 59501263c6cSJonas Devlieghere // 'false' is assumed." 59601263c6cSJonas Devlieghere // } 59701263c6cSJonas Devlieghere // }, 59801263c6cSJonas Devlieghere // "required": [ "filter", "label" ] 59901263c6cSJonas Devlieghere // } 60001263c6cSJonas Devlieghere llvm::json::Value 60101263c6cSJonas Devlieghere CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { 60201263c6cSJonas Devlieghere llvm::json::Object object; 60301263c6cSJonas Devlieghere EmplaceSafeString(object, "filter", bp.filter); 60401263c6cSJonas Devlieghere EmplaceSafeString(object, "label", bp.label); 60501263c6cSJonas Devlieghere object.try_emplace("default", bp.default_value); 60601263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 60701263c6cSJonas Devlieghere } 60801263c6cSJonas Devlieghere 60901263c6cSJonas Devlieghere // "Source": { 61001263c6cSJonas Devlieghere // "type": "object", 61101263c6cSJonas Devlieghere // "description": "A Source is a descriptor for source code. It is returned 61201263c6cSJonas Devlieghere // from the debug adapter as part of a StackFrame and it is 61301263c6cSJonas Devlieghere // used by clients when specifying breakpoints.", 61401263c6cSJonas Devlieghere // "properties": { 61501263c6cSJonas Devlieghere // "name": { 61601263c6cSJonas Devlieghere // "type": "string", 61701263c6cSJonas Devlieghere // "description": "The short name of the source. Every source returned 61801263c6cSJonas Devlieghere // from the debug adapter has a name. When sending a 61901263c6cSJonas Devlieghere // source to the debug adapter this name is optional." 62001263c6cSJonas Devlieghere // }, 62101263c6cSJonas Devlieghere // "path": { 62201263c6cSJonas Devlieghere // "type": "string", 62301263c6cSJonas Devlieghere // "description": "The path of the source to be shown in the UI. It is 62401263c6cSJonas Devlieghere // only used to locate and load the content of the 62501263c6cSJonas Devlieghere // source if no sourceReference is specified (or its 62601263c6cSJonas Devlieghere // value is 0)." 62701263c6cSJonas Devlieghere // }, 62801263c6cSJonas Devlieghere // "sourceReference": { 62901263c6cSJonas Devlieghere // "type": "number", 63001263c6cSJonas Devlieghere // "description": "If sourceReference > 0 the contents of the source must 63101263c6cSJonas Devlieghere // be retrieved through the SourceRequest (even if a path 63201263c6cSJonas Devlieghere // is specified). A sourceReference is only valid for a 63301263c6cSJonas Devlieghere // session, so it must not be used to persist a source." 63401263c6cSJonas Devlieghere // }, 63501263c6cSJonas Devlieghere // "presentationHint": { 63601263c6cSJonas Devlieghere // "type": "string", 63701263c6cSJonas Devlieghere // "description": "An optional hint for how to present the source in the 63801263c6cSJonas Devlieghere // UI. A value of 'deemphasize' can be used to indicate 63901263c6cSJonas Devlieghere // that the source is not available or that it is 64001263c6cSJonas Devlieghere // skipped on stepping.", 64101263c6cSJonas Devlieghere // "enum": [ "normal", "emphasize", "deemphasize" ] 64201263c6cSJonas Devlieghere // }, 64301263c6cSJonas Devlieghere // "origin": { 64401263c6cSJonas Devlieghere // "type": "string", 64501263c6cSJonas Devlieghere // "description": "The (optional) origin of this source: possible values 64601263c6cSJonas Devlieghere // 'internal module', 'inlined content from source map', 64701263c6cSJonas Devlieghere // etc." 64801263c6cSJonas Devlieghere // }, 64901263c6cSJonas Devlieghere // "sources": { 65001263c6cSJonas Devlieghere // "type": "array", 65101263c6cSJonas Devlieghere // "items": { 65201263c6cSJonas Devlieghere // "$ref": "#/definitions/Source" 65301263c6cSJonas Devlieghere // }, 65401263c6cSJonas Devlieghere // "description": "An optional list of sources that are related to this 65501263c6cSJonas Devlieghere // source. These may be the source that generated this 65601263c6cSJonas Devlieghere // source." 65701263c6cSJonas Devlieghere // }, 65801263c6cSJonas Devlieghere // "adapterData": { 65901263c6cSJonas Devlieghere // "type":["array","boolean","integer","null","number","object","string"], 66001263c6cSJonas Devlieghere // "description": "Optional data that a debug adapter might want to loop 66101263c6cSJonas Devlieghere // through the client. The client should leave the data 66201263c6cSJonas Devlieghere // intact and persist it across sessions. The client 66301263c6cSJonas Devlieghere // should not interpret the data." 66401263c6cSJonas Devlieghere // }, 66501263c6cSJonas Devlieghere // "checksums": { 66601263c6cSJonas Devlieghere // "type": "array", 66701263c6cSJonas Devlieghere // "items": { 66801263c6cSJonas Devlieghere // "$ref": "#/definitions/Checksum" 66901263c6cSJonas Devlieghere // }, 67001263c6cSJonas Devlieghere // "description": "The checksums associated with this file." 67101263c6cSJonas Devlieghere // } 67201263c6cSJonas Devlieghere // } 67301263c6cSJonas Devlieghere // } 6740cc2cd78SAdrian Vogelsgesang llvm::json::Value CreateSource(const lldb::SBFileSpec &file) { 67501263c6cSJonas Devlieghere llvm::json::Object object; 67601263c6cSJonas Devlieghere if (file.IsValid()) { 67701263c6cSJonas Devlieghere const char *name = file.GetFilename(); 67801263c6cSJonas Devlieghere if (name) 67901263c6cSJonas Devlieghere EmplaceSafeString(object, "name", name); 68001263c6cSJonas Devlieghere char path[PATH_MAX] = ""; 68101263c6cSJonas Devlieghere if (file.GetPath(path, sizeof(path)) && 68201263c6cSJonas Devlieghere lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) { 68301263c6cSJonas Devlieghere EmplaceSafeString(object, "path", std::string(path)); 68401263c6cSJonas Devlieghere } 68501263c6cSJonas Devlieghere } 68601263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 68701263c6cSJonas Devlieghere } 68801263c6cSJonas Devlieghere 6890cc2cd78SAdrian Vogelsgesang llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry) { 6900cc2cd78SAdrian Vogelsgesang return CreateSource(line_entry.GetFileSpec()); 6910cc2cd78SAdrian Vogelsgesang } 6920cc2cd78SAdrian Vogelsgesang 69301263c6cSJonas Devlieghere llvm::json::Value CreateSource(llvm::StringRef source_path) { 69401263c6cSJonas Devlieghere llvm::json::Object source; 69501263c6cSJonas Devlieghere llvm::StringRef name = llvm::sys::path::filename(source_path); 69601263c6cSJonas Devlieghere EmplaceSafeString(source, "name", name); 69701263c6cSJonas Devlieghere EmplaceSafeString(source, "path", source_path); 69801263c6cSJonas Devlieghere return llvm::json::Value(std::move(source)); 69901263c6cSJonas Devlieghere } 70001263c6cSJonas Devlieghere 701*faaf2dbfSJohn Harrison static std::optional<llvm::json::Value> CreateSource(lldb::SBFrame &frame) { 70201263c6cSJonas Devlieghere auto line_entry = frame.GetLineEntry(); 70301263c6cSJonas Devlieghere // A line entry of 0 indicates the line is compiler generated i.e. no source 70401263c6cSJonas Devlieghere // file is associated with the frame. 70501263c6cSJonas Devlieghere if (line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) 70601263c6cSJonas Devlieghere return CreateSource(line_entry); 70701263c6cSJonas Devlieghere 70801263c6cSJonas Devlieghere return {}; 70901263c6cSJonas Devlieghere } 71001263c6cSJonas Devlieghere 71101263c6cSJonas Devlieghere // "StackFrame": { 71201263c6cSJonas Devlieghere // "type": "object", 71301263c6cSJonas Devlieghere // "description": "A Stackframe contains the source location.", 71401263c6cSJonas Devlieghere // "properties": { 71501263c6cSJonas Devlieghere // "id": { 71601263c6cSJonas Devlieghere // "type": "integer", 71701263c6cSJonas Devlieghere // "description": "An identifier for the stack frame. It must be unique 71801263c6cSJonas Devlieghere // across all threads. This id can be used to retrieve 71901263c6cSJonas Devlieghere // the scopes of the frame with the 'scopesRequest' or 72001263c6cSJonas Devlieghere // to restart the execution of a stackframe." 72101263c6cSJonas Devlieghere // }, 72201263c6cSJonas Devlieghere // "name": { 72301263c6cSJonas Devlieghere // "type": "string", 72401263c6cSJonas Devlieghere // "description": "The name of the stack frame, typically a method name." 72501263c6cSJonas Devlieghere // }, 72601263c6cSJonas Devlieghere // "source": { 72701263c6cSJonas Devlieghere // "$ref": "#/definitions/Source", 72801263c6cSJonas Devlieghere // "description": "The optional source of the frame." 72901263c6cSJonas Devlieghere // }, 73001263c6cSJonas Devlieghere // "line": { 73101263c6cSJonas Devlieghere // "type": "integer", 73201263c6cSJonas Devlieghere // "description": "The line within the file of the frame. If source is 73301263c6cSJonas Devlieghere // null or doesn't exist, line is 0 and must be ignored." 73401263c6cSJonas Devlieghere // }, 73501263c6cSJonas Devlieghere // "column": { 73601263c6cSJonas Devlieghere // "type": "integer", 73701263c6cSJonas Devlieghere // "description": "The column within the line. If source is null or 73801263c6cSJonas Devlieghere // doesn't exist, column is 0 and must be ignored." 73901263c6cSJonas Devlieghere // }, 74001263c6cSJonas Devlieghere // "endLine": { 74101263c6cSJonas Devlieghere // "type": "integer", 74201263c6cSJonas Devlieghere // "description": "An optional end line of the range covered by the 74301263c6cSJonas Devlieghere // stack frame." 74401263c6cSJonas Devlieghere // }, 74501263c6cSJonas Devlieghere // "endColumn": { 74601263c6cSJonas Devlieghere // "type": "integer", 74701263c6cSJonas Devlieghere // "description": "An optional end column of the range covered by the 74801263c6cSJonas Devlieghere // stack frame." 74901263c6cSJonas Devlieghere // }, 75001263c6cSJonas Devlieghere // "instructionPointerReference": { 75101263c6cSJonas Devlieghere // "type": "string", 75201263c6cSJonas Devlieghere // "description": "A memory reference for the current instruction 7533acb1eacSAdrian Vogelsgesang // pointer in this frame." 75401263c6cSJonas Devlieghere // }, 75501263c6cSJonas Devlieghere // "moduleId": { 75601263c6cSJonas Devlieghere // "type": ["integer", "string"], 75701263c6cSJonas Devlieghere // "description": "The module associated with this frame, if any." 75801263c6cSJonas Devlieghere // }, 75901263c6cSJonas Devlieghere // "presentationHint": { 76001263c6cSJonas Devlieghere // "type": "string", 76101263c6cSJonas Devlieghere // "enum": [ "normal", "label", "subtle" ], 76201263c6cSJonas Devlieghere // "description": "An optional hint for how to present this frame in 76301263c6cSJonas Devlieghere // the UI. A value of 'label' can be used to indicate 76401263c6cSJonas Devlieghere // that the frame is an artificial frame that is used 76501263c6cSJonas Devlieghere // as a visual label or separator. A value of 'subtle' 76601263c6cSJonas Devlieghere // can be used to change the appearance of a frame in 76701263c6cSJonas Devlieghere // a 'subtle' way." 76801263c6cSJonas Devlieghere // } 76901263c6cSJonas Devlieghere // }, 77001263c6cSJonas Devlieghere // "required": [ "id", "name", "line", "column" ] 77101263c6cSJonas Devlieghere // } 772*faaf2dbfSJohn Harrison llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, 773*faaf2dbfSJohn Harrison lldb::SBFormat &format) { 77401263c6cSJonas Devlieghere llvm::json::Object object; 77501263c6cSJonas Devlieghere int64_t frame_id = MakeDAPFrameID(frame); 77601263c6cSJonas Devlieghere object.try_emplace("id", frame_id); 77701263c6cSJonas Devlieghere 778d9ec4b24SWalter Erquinigo std::string frame_name; 779d9ec4b24SWalter Erquinigo lldb::SBStream stream; 780*faaf2dbfSJohn Harrison if (format && frame.GetDescriptionWithFormat(format, stream).Success()) { 781d9ec4b24SWalter Erquinigo frame_name = stream.GetData(); 782d9ec4b24SWalter Erquinigo 783d9ec4b24SWalter Erquinigo // `function_name` can be a nullptr, which throws an error when assigned to 784d9ec4b24SWalter Erquinigo // an `std::string`. 785d9ec4b24SWalter Erquinigo } else if (const char *name = frame.GetDisplayFunctionName()) { 786d9ec4b24SWalter Erquinigo frame_name = name; 787d9ec4b24SWalter Erquinigo } 788d9ec4b24SWalter Erquinigo 78901263c6cSJonas Devlieghere if (frame_name.empty()) { 79001263c6cSJonas Devlieghere // If the function name is unavailable, display the pc address as a 16-digit 79101263c6cSJonas Devlieghere // hex string, e.g. "0x0000000000012345" 79201263c6cSJonas Devlieghere llvm::raw_string_ostream os(frame_name); 79301263c6cSJonas Devlieghere os << llvm::format_hex(frame.GetPC(), 18); 79401263c6cSJonas Devlieghere } 79507ed3258SWalter Erquinigo 79607ed3258SWalter Erquinigo // We only include `[opt]` if a custom frame format is not specified. 797*faaf2dbfSJohn Harrison if (!format && frame.GetFunction().GetIsOptimized()) 79801263c6cSJonas Devlieghere frame_name += " [opt]"; 79907ed3258SWalter Erquinigo 80001263c6cSJonas Devlieghere EmplaceSafeString(object, "name", frame_name); 80101263c6cSJonas Devlieghere 80201263c6cSJonas Devlieghere auto source = CreateSource(frame); 80301263c6cSJonas Devlieghere 80401263c6cSJonas Devlieghere if (source) { 80501263c6cSJonas Devlieghere object.try_emplace("source", *source); 80601263c6cSJonas Devlieghere auto line_entry = frame.GetLineEntry(); 80701263c6cSJonas Devlieghere auto line = line_entry.GetLine(); 80801263c6cSJonas Devlieghere if (line && line != LLDB_INVALID_LINE_NUMBER) 80901263c6cSJonas Devlieghere object.try_emplace("line", line); 81099f42e6bSXu Jun else 81199f42e6bSXu Jun object.try_emplace("line", 0); 81201263c6cSJonas Devlieghere auto column = line_entry.GetColumn(); 81301263c6cSJonas Devlieghere object.try_emplace("column", column); 81401263c6cSJonas Devlieghere } else { 81501263c6cSJonas Devlieghere object.try_emplace("line", 0); 81601263c6cSJonas Devlieghere object.try_emplace("column", 0); 81701263c6cSJonas Devlieghere } 81801263c6cSJonas Devlieghere 81901263c6cSJonas Devlieghere const auto pc = frame.GetPC(); 82001263c6cSJonas Devlieghere if (pc != LLDB_INVALID_ADDRESS) { 82101263c6cSJonas Devlieghere std::string formatted_addr = "0x" + llvm::utohexstr(pc); 82201263c6cSJonas Devlieghere object.try_emplace("instructionPointerReference", formatted_addr); 82301263c6cSJonas Devlieghere } 82401263c6cSJonas Devlieghere 8259e9e8238SAdrian Prantl if (frame.IsArtificial() || frame.IsHidden()) 8269e9e8238SAdrian Prantl object.try_emplace("presentationHint", "subtle"); 8279e9e8238SAdrian Prantl 82801263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 82901263c6cSJonas Devlieghere } 83001263c6cSJonas Devlieghere 831*faaf2dbfSJohn Harrison llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread, 832*faaf2dbfSJohn Harrison lldb::SBFormat &format) { 8335b4100ccSJohn Harrison std::string name; 8345b4100ccSJohn Harrison lldb::SBStream stream; 835*faaf2dbfSJohn Harrison if (format && thread.GetDescriptionWithFormat(format, stream).Success()) { 8365b4100ccSJohn Harrison name = stream.GetData(); 8375b4100ccSJohn Harrison } else { 8385b4100ccSJohn Harrison const uint32_t thread_idx = thread.GetExtendedBacktraceOriginatingIndexID(); 8395b4100ccSJohn Harrison const char *queue_name = thread.GetQueueName(); 8405b4100ccSJohn Harrison if (queue_name != nullptr) { 8415b4100ccSJohn Harrison name = llvm::formatv("Enqueued from {0} (Thread {1})", queue_name, 8425b4100ccSJohn Harrison thread_idx); 8435b4100ccSJohn Harrison } else { 8445b4100ccSJohn Harrison name = llvm::formatv("Thread {0}", thread_idx); 8455b4100ccSJohn Harrison } 8465b4100ccSJohn Harrison } 8475b4100ccSJohn Harrison 8485b4100ccSJohn Harrison return llvm::json::Value(llvm::json::Object{{"id", thread.GetThreadID() + 1}, 8495b4100ccSJohn Harrison {"name", name}, 8505b4100ccSJohn Harrison {"presentationHint", "label"}}); 8515b4100ccSJohn Harrison } 8525b4100ccSJohn Harrison 85301263c6cSJonas Devlieghere // "Thread": { 85401263c6cSJonas Devlieghere // "type": "object", 85501263c6cSJonas Devlieghere // "description": "A Thread", 85601263c6cSJonas Devlieghere // "properties": { 85701263c6cSJonas Devlieghere // "id": { 85801263c6cSJonas Devlieghere // "type": "integer", 85901263c6cSJonas Devlieghere // "description": "Unique identifier for the thread." 86001263c6cSJonas Devlieghere // }, 86101263c6cSJonas Devlieghere // "name": { 86201263c6cSJonas Devlieghere // "type": "string", 86301263c6cSJonas Devlieghere // "description": "A name of the thread." 86401263c6cSJonas Devlieghere // } 86501263c6cSJonas Devlieghere // }, 86601263c6cSJonas Devlieghere // "required": [ "id", "name" ] 86701263c6cSJonas Devlieghere // } 868*faaf2dbfSJohn Harrison llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format) { 86901263c6cSJonas Devlieghere llvm::json::Object object; 87001263c6cSJonas Devlieghere object.try_emplace("id", (int64_t)thread.GetThreadID()); 8711654d7dcSWalter Erquinigo std::string thread_str; 8721654d7dcSWalter Erquinigo lldb::SBStream stream; 873*faaf2dbfSJohn Harrison if (format && thread.GetDescriptionWithFormat(format, stream).Success()) { 8741654d7dcSWalter Erquinigo thread_str = stream.GetData(); 8751654d7dcSWalter Erquinigo } else { 87601263c6cSJonas Devlieghere const char *thread_name = thread.GetName(); 87701263c6cSJonas Devlieghere const char *queue_name = thread.GetQueueName(); 87801263c6cSJonas Devlieghere 87901263c6cSJonas Devlieghere if (thread_name) { 88001263c6cSJonas Devlieghere thread_str = std::string(thread_name); 88101263c6cSJonas Devlieghere } else if (queue_name) { 88201263c6cSJonas Devlieghere auto kind = thread.GetQueue().GetKind(); 88301263c6cSJonas Devlieghere std::string queue_kind_label = ""; 88401263c6cSJonas Devlieghere if (kind == lldb::eQueueKindSerial) { 88501263c6cSJonas Devlieghere queue_kind_label = " (serial)"; 88601263c6cSJonas Devlieghere } else if (kind == lldb::eQueueKindConcurrent) { 88701263c6cSJonas Devlieghere queue_kind_label = " (concurrent)"; 88801263c6cSJonas Devlieghere } 88901263c6cSJonas Devlieghere 8901654d7dcSWalter Erquinigo thread_str = 8911654d7dcSWalter Erquinigo llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(), 89201263c6cSJonas Devlieghere queue_name, queue_kind_label) 89301263c6cSJonas Devlieghere .str(); 89401263c6cSJonas Devlieghere } else { 89501263c6cSJonas Devlieghere thread_str = llvm::formatv("Thread {0}", thread.GetIndexID()).str(); 89601263c6cSJonas Devlieghere } 8971654d7dcSWalter Erquinigo } 89801263c6cSJonas Devlieghere 89901263c6cSJonas Devlieghere EmplaceSafeString(object, "name", thread_str); 90001263c6cSJonas Devlieghere 90101263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 90201263c6cSJonas Devlieghere } 90301263c6cSJonas Devlieghere 90401263c6cSJonas Devlieghere // "StoppedEvent": { 90501263c6cSJonas Devlieghere // "allOf": [ { "$ref": "#/definitions/Event" }, { 90601263c6cSJonas Devlieghere // "type": "object", 90701263c6cSJonas Devlieghere // "description": "Event message for 'stopped' event type. The event 90801263c6cSJonas Devlieghere // indicates that the execution of the debuggee has stopped 90901263c6cSJonas Devlieghere // due to some condition. This can be caused by a break 91001263c6cSJonas Devlieghere // point previously set, a stepping action has completed, 91101263c6cSJonas Devlieghere // by executing a debugger statement etc.", 91201263c6cSJonas Devlieghere // "properties": { 91301263c6cSJonas Devlieghere // "event": { 91401263c6cSJonas Devlieghere // "type": "string", 91501263c6cSJonas Devlieghere // "enum": [ "stopped" ] 91601263c6cSJonas Devlieghere // }, 91701263c6cSJonas Devlieghere // "body": { 91801263c6cSJonas Devlieghere // "type": "object", 91901263c6cSJonas Devlieghere // "properties": { 92001263c6cSJonas Devlieghere // "reason": { 92101263c6cSJonas Devlieghere // "type": "string", 92201263c6cSJonas Devlieghere // "description": "The reason for the event. For backward 92301263c6cSJonas Devlieghere // compatibility this string is shown in the UI if 92401263c6cSJonas Devlieghere // the 'description' attribute is missing (but it 92501263c6cSJonas Devlieghere // must not be translated).", 92601263c6cSJonas Devlieghere // "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ] 92701263c6cSJonas Devlieghere // }, 92801263c6cSJonas Devlieghere // "description": { 92901263c6cSJonas Devlieghere // "type": "string", 93001263c6cSJonas Devlieghere // "description": "The full reason for the event, e.g. 'Paused 93101263c6cSJonas Devlieghere // on exception'. This string is shown in the UI 93201263c6cSJonas Devlieghere // as is." 93301263c6cSJonas Devlieghere // }, 93401263c6cSJonas Devlieghere // "threadId": { 93501263c6cSJonas Devlieghere // "type": "integer", 93601263c6cSJonas Devlieghere // "description": "The thread which was stopped." 93701263c6cSJonas Devlieghere // }, 93801263c6cSJonas Devlieghere // "text": { 93901263c6cSJonas Devlieghere // "type": "string", 94001263c6cSJonas Devlieghere // "description": "Additional information. E.g. if reason is 94101263c6cSJonas Devlieghere // 'exception', text contains the exception name. 94201263c6cSJonas Devlieghere // This string is shown in the UI." 94301263c6cSJonas Devlieghere // }, 94401263c6cSJonas Devlieghere // "allThreadsStopped": { 94501263c6cSJonas Devlieghere // "type": "boolean", 94601263c6cSJonas Devlieghere // "description": "If allThreadsStopped is true, a debug adapter 94701263c6cSJonas Devlieghere // can announce that all threads have stopped. 94801263c6cSJonas Devlieghere // The client should use this information to 94901263c6cSJonas Devlieghere // enable that all threads can be expanded to 95001263c6cSJonas Devlieghere // access their stacktraces. If the attribute 95101263c6cSJonas Devlieghere // is missing or false, only the thread with the 95201263c6cSJonas Devlieghere // given threadId can be expanded." 95301263c6cSJonas Devlieghere // } 95401263c6cSJonas Devlieghere // }, 95501263c6cSJonas Devlieghere // "required": [ "reason" ] 95601263c6cSJonas Devlieghere // } 95701263c6cSJonas Devlieghere // }, 95801263c6cSJonas Devlieghere // "required": [ "event", "body" ] 95901263c6cSJonas Devlieghere // }] 96001263c6cSJonas Devlieghere // } 961*faaf2dbfSJohn Harrison llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, 96201263c6cSJonas Devlieghere uint32_t stop_id) { 96301263c6cSJonas Devlieghere llvm::json::Object event(CreateEventObject("stopped")); 96401263c6cSJonas Devlieghere llvm::json::Object body; 96501263c6cSJonas Devlieghere switch (thread.GetStopReason()) { 96601263c6cSJonas Devlieghere case lldb::eStopReasonTrace: 96701263c6cSJonas Devlieghere case lldb::eStopReasonPlanComplete: 96801263c6cSJonas Devlieghere body.try_emplace("reason", "step"); 96901263c6cSJonas Devlieghere break; 97001263c6cSJonas Devlieghere case lldb::eStopReasonBreakpoint: { 971*faaf2dbfSJohn Harrison ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); 97201263c6cSJonas Devlieghere if (exc_bp) { 97301263c6cSJonas Devlieghere body.try_emplace("reason", "exception"); 97401263c6cSJonas Devlieghere EmplaceSafeString(body, "description", exc_bp->label); 97501263c6cSJonas Devlieghere } else { 97689c27d6bSSanthosh Kumar Ellendula InstructionBreakpoint *inst_bp = 977*faaf2dbfSJohn Harrison dap.GetInstructionBPFromStopReason(thread); 97889c27d6bSSanthosh Kumar Ellendula if (inst_bp) { 97989c27d6bSSanthosh Kumar Ellendula body.try_emplace("reason", "instruction breakpoint"); 98089c27d6bSSanthosh Kumar Ellendula } else { 98101263c6cSJonas Devlieghere body.try_emplace("reason", "breakpoint"); 98289c27d6bSSanthosh Kumar Ellendula } 983c8f72856SJohn Harrison lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0); 984c8f72856SJohn Harrison lldb::break_id_t bp_loc_id = thread.GetStopReasonDataAtIndex(1); 985c8f72856SJohn Harrison std::string desc_str = 986c8f72856SJohn Harrison llvm::formatv("breakpoint {0}.{1}", bp_id, bp_loc_id); 98701263c6cSJonas Devlieghere body.try_emplace("hitBreakpointIds", 98801263c6cSJonas Devlieghere llvm::json::Array{llvm::json::Value(bp_id)}); 98901263c6cSJonas Devlieghere EmplaceSafeString(body, "description", desc_str); 99001263c6cSJonas Devlieghere } 99101263c6cSJonas Devlieghere } break; 99201263c6cSJonas Devlieghere case lldb::eStopReasonWatchpoint: 99301263c6cSJonas Devlieghere case lldb::eStopReasonInstrumentation: 99401263c6cSJonas Devlieghere body.try_emplace("reason", "breakpoint"); 99501263c6cSJonas Devlieghere break; 99601263c6cSJonas Devlieghere case lldb::eStopReasonProcessorTrace: 99701263c6cSJonas Devlieghere body.try_emplace("reason", "processor trace"); 99801263c6cSJonas Devlieghere break; 99901263c6cSJonas Devlieghere case lldb::eStopReasonSignal: 100001263c6cSJonas Devlieghere case lldb::eStopReasonException: 100101263c6cSJonas Devlieghere body.try_emplace("reason", "exception"); 100201263c6cSJonas Devlieghere break; 100301263c6cSJonas Devlieghere case lldb::eStopReasonExec: 100401263c6cSJonas Devlieghere body.try_emplace("reason", "entry"); 100501263c6cSJonas Devlieghere break; 100601263c6cSJonas Devlieghere case lldb::eStopReasonFork: 100701263c6cSJonas Devlieghere body.try_emplace("reason", "fork"); 100801263c6cSJonas Devlieghere break; 100901263c6cSJonas Devlieghere case lldb::eStopReasonVFork: 101001263c6cSJonas Devlieghere body.try_emplace("reason", "vfork"); 101101263c6cSJonas Devlieghere break; 101201263c6cSJonas Devlieghere case lldb::eStopReasonVForkDone: 101301263c6cSJonas Devlieghere body.try_emplace("reason", "vforkdone"); 101401263c6cSJonas Devlieghere break; 1015f838fa82Sjeffreytan81 case lldb::eStopReasonInterrupt: 1016f838fa82Sjeffreytan81 body.try_emplace("reason", "async interrupt"); 1017f838fa82Sjeffreytan81 break; 101801263c6cSJonas Devlieghere case lldb::eStopReasonThreadExiting: 101901263c6cSJonas Devlieghere case lldb::eStopReasonInvalid: 102001263c6cSJonas Devlieghere case lldb::eStopReasonNone: 102101263c6cSJonas Devlieghere break; 102201263c6cSJonas Devlieghere } 102301263c6cSJonas Devlieghere if (stop_id == 0) 102401263c6cSJonas Devlieghere body.try_emplace("reason", "entry"); 102501263c6cSJonas Devlieghere const lldb::tid_t tid = thread.GetThreadID(); 102601263c6cSJonas Devlieghere body.try_emplace("threadId", (int64_t)tid); 102701263c6cSJonas Devlieghere // If no description has been set, then set it to the default thread stopped 102801263c6cSJonas Devlieghere // description. If we have breakpoints that get hit and shouldn't be reported 102901263c6cSJonas Devlieghere // as breakpoints, then they will set the description above. 103001263c6cSJonas Devlieghere if (!ObjectContainsKey(body, "description")) { 103101263c6cSJonas Devlieghere char description[1024]; 103201263c6cSJonas Devlieghere if (thread.GetStopDescription(description, sizeof(description))) { 103301263c6cSJonas Devlieghere EmplaceSafeString(body, "description", std::string(description)); 103401263c6cSJonas Devlieghere } 103501263c6cSJonas Devlieghere } 103601263c6cSJonas Devlieghere // "threadCausedFocus" is used in tests to validate breaking behavior. 1037*faaf2dbfSJohn Harrison if (tid == dap.focus_tid) { 103801263c6cSJonas Devlieghere body.try_emplace("threadCausedFocus", true); 103901263c6cSJonas Devlieghere } 1040*faaf2dbfSJohn Harrison body.try_emplace("preserveFocusHint", tid != dap.focus_tid); 104101263c6cSJonas Devlieghere body.try_emplace("allThreadsStopped", true); 104201263c6cSJonas Devlieghere event.try_emplace("body", std::move(body)); 104301263c6cSJonas Devlieghere return llvm::json::Value(std::move(event)); 104401263c6cSJonas Devlieghere } 104501263c6cSJonas Devlieghere 1046*faaf2dbfSJohn Harrison const char *GetNonNullVariableName(lldb::SBValue &v) { 104701263c6cSJonas Devlieghere const char *name = v.GetName(); 104801263c6cSJonas Devlieghere return name ? name : "<null>"; 104901263c6cSJonas Devlieghere } 105001263c6cSJonas Devlieghere 1051*faaf2dbfSJohn Harrison std::string CreateUniqueVariableNameForDisplay(lldb::SBValue &v, 105201263c6cSJonas Devlieghere bool is_name_duplicated) { 105301263c6cSJonas Devlieghere lldb::SBStream name_builder; 105401263c6cSJonas Devlieghere name_builder.Print(GetNonNullVariableName(v)); 105501263c6cSJonas Devlieghere if (is_name_duplicated) { 105601263c6cSJonas Devlieghere lldb::SBDeclaration declaration = v.GetDeclaration(); 105701263c6cSJonas Devlieghere const char *file_name = declaration.GetFileSpec().GetFilename(); 105801263c6cSJonas Devlieghere const uint32_t line = declaration.GetLine(); 105901263c6cSJonas Devlieghere 106001263c6cSJonas Devlieghere if (file_name != nullptr && line > 0) 106101263c6cSJonas Devlieghere name_builder.Printf(" @ %s:%u", file_name, line); 106201263c6cSJonas Devlieghere else if (const char *location = v.GetLocation()) 106301263c6cSJonas Devlieghere name_builder.Printf(" @ %s", location); 106401263c6cSJonas Devlieghere } 106501263c6cSJonas Devlieghere return name_builder.GetData(); 106601263c6cSJonas Devlieghere } 106701263c6cSJonas Devlieghere 1068*faaf2dbfSJohn Harrison VariableDescription::VariableDescription(lldb::SBValue v, 1069*faaf2dbfSJohn Harrison bool auto_variable_summaries, 1070*faaf2dbfSJohn Harrison bool format_hex, 1071ffd173baSWalter Erquinigo bool is_name_duplicated, 1072ffd173baSWalter Erquinigo std::optional<std::string> custom_name) 1073ffd173baSWalter Erquinigo : v(v) { 1074ffd173baSWalter Erquinigo name = custom_name 1075ffd173baSWalter Erquinigo ? *custom_name 1076ffd173baSWalter Erquinigo : CreateUniqueVariableNameForDisplay(v, is_name_duplicated); 1077ffd173baSWalter Erquinigo 1078ffd173baSWalter Erquinigo type_obj = v.GetType(); 1079ffd173baSWalter Erquinigo std::string raw_display_type_name = 1080ffd173baSWalter Erquinigo llvm::StringRef(type_obj.GetDisplayTypeName()).str(); 1081ffd173baSWalter Erquinigo display_type_name = 1082ffd173baSWalter Erquinigo !raw_display_type_name.empty() ? raw_display_type_name : NO_TYPENAME; 1083ffd173baSWalter Erquinigo 1084b8d38bb5Sjeffreytan81 // Only format hex/default if there is no existing special format. 1085b8d38bb5Sjeffreytan81 if (v.GetFormat() == lldb::eFormatDefault || 1086b8d38bb5Sjeffreytan81 v.GetFormat() == lldb::eFormatHex) { 1087ffd173baSWalter Erquinigo if (format_hex) 1088ffd173baSWalter Erquinigo v.SetFormat(lldb::eFormatHex); 1089b8d38bb5Sjeffreytan81 else 1090b8d38bb5Sjeffreytan81 v.SetFormat(lldb::eFormatDefault); 1091b8d38bb5Sjeffreytan81 } 1092ffd173baSWalter Erquinigo 1093ffd173baSWalter Erquinigo llvm::raw_string_ostream os_display_value(display_value); 1094ffd173baSWalter Erquinigo 1095ffd173baSWalter Erquinigo if (lldb::SBError sb_error = v.GetError(); sb_error.Fail()) { 1096ffd173baSWalter Erquinigo error = sb_error.GetCString(); 1097ffd173baSWalter Erquinigo os_display_value << "<error: " << error << ">"; 1098ffd173baSWalter Erquinigo } else { 1099ffd173baSWalter Erquinigo value = llvm::StringRef(v.GetValue()).str(); 1100ffd173baSWalter Erquinigo summary = llvm::StringRef(v.GetSummary()).str(); 1101*faaf2dbfSJohn Harrison if (summary.empty() && auto_variable_summaries) 1102ffd173baSWalter Erquinigo auto_summary = TryCreateAutoSummary(v); 1103ffd173baSWalter Erquinigo 1104ffd173baSWalter Erquinigo std::optional<std::string> effective_summary = 1105ffd173baSWalter Erquinigo !summary.empty() ? summary : auto_summary; 1106ffd173baSWalter Erquinigo 1107ffd173baSWalter Erquinigo if (!value.empty()) { 1108ffd173baSWalter Erquinigo os_display_value << value; 1109ffd173baSWalter Erquinigo if (effective_summary) 1110ffd173baSWalter Erquinigo os_display_value << " " << *effective_summary; 1111ffd173baSWalter Erquinigo } else if (effective_summary) { 1112ffd173baSWalter Erquinigo os_display_value << *effective_summary; 1113ffd173baSWalter Erquinigo 1114ffd173baSWalter Erquinigo // As last resort, we print its type and address if available. 1115ffd173baSWalter Erquinigo } else { 1116ffd173baSWalter Erquinigo if (!raw_display_type_name.empty()) { 1117ffd173baSWalter Erquinigo os_display_value << raw_display_type_name; 1118ffd173baSWalter Erquinigo lldb::addr_t address = v.GetLoadAddress(); 1119ffd173baSWalter Erquinigo if (address != LLDB_INVALID_ADDRESS) 1120ffd173baSWalter Erquinigo os_display_value << " @ " << llvm::format_hex(address, 0); 1121ffd173baSWalter Erquinigo } 1122ffd173baSWalter Erquinigo } 1123ffd173baSWalter Erquinigo } 1124ffd173baSWalter Erquinigo 1125ffd173baSWalter Erquinigo lldb::SBStream evaluateStream; 1126ffd173baSWalter Erquinigo v.GetExpressionPath(evaluateStream); 1127ffd173baSWalter Erquinigo evaluate_name = llvm::StringRef(evaluateStream.GetData()).str(); 1128ffd173baSWalter Erquinigo } 1129ffd173baSWalter Erquinigo 1130ffd173baSWalter Erquinigo llvm::json::Object VariableDescription::GetVariableExtensionsJSON() { 1131ffd173baSWalter Erquinigo llvm::json::Object extensions; 1132ffd173baSWalter Erquinigo if (error) 1133ffd173baSWalter Erquinigo EmplaceSafeString(extensions, "error", *error); 1134ffd173baSWalter Erquinigo if (!value.empty()) 1135ffd173baSWalter Erquinigo EmplaceSafeString(extensions, "value", value); 1136ffd173baSWalter Erquinigo if (!summary.empty()) 1137ffd173baSWalter Erquinigo EmplaceSafeString(extensions, "summary", summary); 1138ffd173baSWalter Erquinigo if (auto_summary) 1139ffd173baSWalter Erquinigo EmplaceSafeString(extensions, "autoSummary", *auto_summary); 1140ffd173baSWalter Erquinigo 1141ffd173baSWalter Erquinigo if (lldb::SBDeclaration decl = v.GetDeclaration(); decl.IsValid()) { 1142ffd173baSWalter Erquinigo llvm::json::Object decl_obj; 1143ffd173baSWalter Erquinigo if (lldb::SBFileSpec file = decl.GetFileSpec(); file.IsValid()) { 1144ffd173baSWalter Erquinigo char path[PATH_MAX] = ""; 1145ffd173baSWalter Erquinigo if (file.GetPath(path, sizeof(path)) && 1146ffd173baSWalter Erquinigo lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) { 1147ffd173baSWalter Erquinigo decl_obj.try_emplace("path", std::string(path)); 1148ffd173baSWalter Erquinigo } 1149ffd173baSWalter Erquinigo } 1150ffd173baSWalter Erquinigo 1151ffd173baSWalter Erquinigo if (int line = decl.GetLine()) 1152ffd173baSWalter Erquinigo decl_obj.try_emplace("line", line); 1153ffd173baSWalter Erquinigo if (int column = decl.GetColumn()) 1154ffd173baSWalter Erquinigo decl_obj.try_emplace("column", column); 1155ffd173baSWalter Erquinigo 1156ffd173baSWalter Erquinigo if (!decl_obj.empty()) 1157ffd173baSWalter Erquinigo extensions.try_emplace("declaration", std::move(decl_obj)); 1158ffd173baSWalter Erquinigo } 1159ffd173baSWalter Erquinigo return extensions; 1160ffd173baSWalter Erquinigo } 1161ffd173baSWalter Erquinigo 116240a361acSJohn Harrison std::string VariableDescription::GetResult(llvm::StringRef context) { 1163af8f1554SPavel Labath // In repl context, the results can be displayed as multiple lines so more 1164af8f1554SPavel Labath // detailed descriptions can be returned. 1165af8f1554SPavel Labath if (context != "repl") 116640a361acSJohn Harrison return display_value; 116740a361acSJohn Harrison 116840a361acSJohn Harrison if (!v.IsValid()) 116940a361acSJohn Harrison return display_value; 117040a361acSJohn Harrison 117140a361acSJohn Harrison // Try the SBValue::GetDescription(), which may call into language runtime 117240a361acSJohn Harrison // specific formatters (see ValueObjectPrinter). 117340a361acSJohn Harrison lldb::SBStream stream; 117440a361acSJohn Harrison v.GetDescription(stream); 117540a361acSJohn Harrison llvm::StringRef description = stream.GetData(); 117640a361acSJohn Harrison return description.trim().str(); 117740a361acSJohn Harrison } 117840a361acSJohn Harrison 11799f8ae784SAdrian Vogelsgesang bool ValuePointsToCode(lldb::SBValue v) { 11809f8ae784SAdrian Vogelsgesang if (!v.GetType().GetPointeeType().IsFunctionType()) 11819f8ae784SAdrian Vogelsgesang return false; 11829f8ae784SAdrian Vogelsgesang 11839f8ae784SAdrian Vogelsgesang lldb::addr_t addr = v.GetValueAsAddress(); 11849f8ae784SAdrian Vogelsgesang lldb::SBLineEntry line_entry = 1185*faaf2dbfSJohn Harrison v.GetTarget().ResolveLoadAddress(addr).GetLineEntry(); 11869f8ae784SAdrian Vogelsgesang 11879f8ae784SAdrian Vogelsgesang return line_entry.IsValid(); 11889f8ae784SAdrian Vogelsgesang } 11899f8ae784SAdrian Vogelsgesang 11909f8ae784SAdrian Vogelsgesang int64_t PackLocation(int64_t var_ref, bool is_value_location) { 11919f8ae784SAdrian Vogelsgesang return var_ref << 1 | is_value_location; 11929f8ae784SAdrian Vogelsgesang } 11939f8ae784SAdrian Vogelsgesang 11949f8ae784SAdrian Vogelsgesang std::pair<int64_t, bool> UnpackLocation(int64_t location_id) { 11959f8ae784SAdrian Vogelsgesang return std::pair{location_id >> 1, location_id & 1}; 11969f8ae784SAdrian Vogelsgesang } 11979f8ae784SAdrian Vogelsgesang 119801263c6cSJonas Devlieghere // "Variable": { 119901263c6cSJonas Devlieghere // "type": "object", 120001263c6cSJonas Devlieghere // "description": "A Variable is a name/value pair. Optionally a variable 120101263c6cSJonas Devlieghere // can have a 'type' that is shown if space permits or when 120201263c6cSJonas Devlieghere // hovering over the variable's name. An optional 'kind' is 120301263c6cSJonas Devlieghere // used to render additional properties of the variable, 120401263c6cSJonas Devlieghere // e.g. different icons can be used to indicate that a 120501263c6cSJonas Devlieghere // variable is public or private. If the value is 120601263c6cSJonas Devlieghere // structured (has children), a handle is provided to 120701263c6cSJonas Devlieghere // retrieve the children with the VariablesRequest. If 120801263c6cSJonas Devlieghere // the number of named or indexed children is large, the 120901263c6cSJonas Devlieghere // numbers should be returned via the optional 121001263c6cSJonas Devlieghere // 'namedVariables' and 'indexedVariables' attributes. The 121101263c6cSJonas Devlieghere // client can use this optional information to present the 121201263c6cSJonas Devlieghere // children in a paged UI and fetch them in chunks.", 121301263c6cSJonas Devlieghere // "properties": { 121401263c6cSJonas Devlieghere // "name": { 121501263c6cSJonas Devlieghere // "type": "string", 121601263c6cSJonas Devlieghere // "description": "The variable's name." 121701263c6cSJonas Devlieghere // }, 121801263c6cSJonas Devlieghere // "value": { 121901263c6cSJonas Devlieghere // "type": "string", 122001263c6cSJonas Devlieghere // "description": "The variable's value. This can be a multi-line text, 122101263c6cSJonas Devlieghere // e.g. for a function the body of a function." 122201263c6cSJonas Devlieghere // }, 122301263c6cSJonas Devlieghere // "type": { 122401263c6cSJonas Devlieghere // "type": "string", 122501263c6cSJonas Devlieghere // "description": "The type of the variable's value. Typically shown in 122601263c6cSJonas Devlieghere // the UI when hovering over the value." 122701263c6cSJonas Devlieghere // }, 122801263c6cSJonas Devlieghere // "presentationHint": { 122901263c6cSJonas Devlieghere // "$ref": "#/definitions/VariablePresentationHint", 123001263c6cSJonas Devlieghere // "description": "Properties of a variable that can be used to determine 123101263c6cSJonas Devlieghere // how to render the variable in the UI." 123201263c6cSJonas Devlieghere // }, 123301263c6cSJonas Devlieghere // "evaluateName": { 123401263c6cSJonas Devlieghere // "type": "string", 123501263c6cSJonas Devlieghere // "description": "Optional evaluatable name of this variable which can 123601263c6cSJonas Devlieghere // be passed to the 'EvaluateRequest' to fetch the 123701263c6cSJonas Devlieghere // variable's value." 123801263c6cSJonas Devlieghere // }, 123901263c6cSJonas Devlieghere // "variablesReference": { 124001263c6cSJonas Devlieghere // "type": "integer", 124101263c6cSJonas Devlieghere // "description": "If variablesReference is > 0, the variable is 124201263c6cSJonas Devlieghere // structured and its children can be retrieved by 124301263c6cSJonas Devlieghere // passing variablesReference to the VariablesRequest." 124401263c6cSJonas Devlieghere // }, 124501263c6cSJonas Devlieghere // "namedVariables": { 124601263c6cSJonas Devlieghere // "type": "integer", 124701263c6cSJonas Devlieghere // "description": "The number of named child variables. The client can 124801263c6cSJonas Devlieghere // use this optional information to present the children 124901263c6cSJonas Devlieghere // in a paged UI and fetch them in chunks." 125001263c6cSJonas Devlieghere // }, 125101263c6cSJonas Devlieghere // "indexedVariables": { 125201263c6cSJonas Devlieghere // "type": "integer", 125301263c6cSJonas Devlieghere // "description": "The number of indexed child variables. The client 125401263c6cSJonas Devlieghere // can use this optional information to present the 125501263c6cSJonas Devlieghere // children in a paged UI and fetch them in chunks." 12560cc2cd78SAdrian Vogelsgesang // }, 12573acb1eacSAdrian Vogelsgesang // "memoryReference": { 12583acb1eacSAdrian Vogelsgesang // "type": "string", 12593acb1eacSAdrian Vogelsgesang // "description": "A memory reference associated with this variable. 12603acb1eacSAdrian Vogelsgesang // For pointer type variables, this is generally a 12613acb1eacSAdrian Vogelsgesang // reference to the memory address contained in the 12623acb1eacSAdrian Vogelsgesang // pointer. For executable data, this reference may later 12633acb1eacSAdrian Vogelsgesang // be used in a `disassemble` request. This attribute may 12643acb1eacSAdrian Vogelsgesang // be returned by a debug adapter if corresponding 12653acb1eacSAdrian Vogelsgesang // capability `supportsMemoryReferences` is true." 12663acb1eacSAdrian Vogelsgesang // }, 12670cc2cd78SAdrian Vogelsgesang // "declarationLocationReference": { 12680cc2cd78SAdrian Vogelsgesang // "type": "integer", 12690cc2cd78SAdrian Vogelsgesang // "description": "A reference that allows the client to request the 12700cc2cd78SAdrian Vogelsgesang // location where the variable is declared. This should be 12710cc2cd78SAdrian Vogelsgesang // present only if the adapter is likely to be able to 12720cc2cd78SAdrian Vogelsgesang // resolve the location.\n\nThis reference shares the same 12730cc2cd78SAdrian Vogelsgesang // lifetime as the `variablesReference`. See 'Lifetime of 12740cc2cd78SAdrian Vogelsgesang // Object References' in the Overview section for 12750cc2cd78SAdrian Vogelsgesang // details." 12760cc2cd78SAdrian Vogelsgesang // }, 12779f8ae784SAdrian Vogelsgesang // "valueLocationReference": { 12789f8ae784SAdrian Vogelsgesang // "type": "integer", 12799f8ae784SAdrian Vogelsgesang // "description": "A reference that allows the client to request the 12809f8ae784SAdrian Vogelsgesang // location where the variable's value is declared. For 12819f8ae784SAdrian Vogelsgesang // example, if the variable contains a function pointer, 12829f8ae784SAdrian Vogelsgesang // the adapter may be able to look up the function's 12839f8ae784SAdrian Vogelsgesang // location. This should be present only if the adapter 12849f8ae784SAdrian Vogelsgesang // is likely to be able to resolve the location.\n\nThis 12859f8ae784SAdrian Vogelsgesang // reference shares the same lifetime as the 12869f8ae784SAdrian Vogelsgesang // `variablesReference`. See 'Lifetime of Object 12879f8ae784SAdrian Vogelsgesang // References' in the Overview section for details." 12889f8ae784SAdrian Vogelsgesang // }, 12890cc2cd78SAdrian Vogelsgesang // 1290ffd173baSWalter Erquinigo // "$__lldb_extensions": { 1291ffd173baSWalter Erquinigo // "description": "Unofficial extensions to the protocol", 1292ffd173baSWalter Erquinigo // "properties": { 12930ea19bd3SWalter Erquinigo // "declaration": { 1294ffd173baSWalter Erquinigo // "type": "object", 12950cc2cd78SAdrian Vogelsgesang // "description": "The source location where the variable was 12960cc2cd78SAdrian Vogelsgesang // declared. This value won't be present if no 12970cc2cd78SAdrian Vogelsgesang // declaration is available. 12980cc2cd78SAdrian Vogelsgesang // Superseded by `declarationLocationReference`", 12990ea19bd3SWalter Erquinigo // "properties": { 13000ea19bd3SWalter Erquinigo // "path": { 1301ffd173baSWalter Erquinigo // "type": "string", 13020ea19bd3SWalter Erquinigo // "description": "The source file path where the variable was 13030ea19bd3SWalter Erquinigo // declared." 13040ea19bd3SWalter Erquinigo // }, 13050ea19bd3SWalter Erquinigo // "line": { 1306ffd173baSWalter Erquinigo // "type": "number", 13070cc2cd78SAdrian Vogelsgesang // "description": "The 1-indexed source line where the variable 13080cc2cd78SAdrian Vogelsgesang // was declared." 13090ea19bd3SWalter Erquinigo // }, 13100ea19bd3SWalter Erquinigo // "column": { 1311ffd173baSWalter Erquinigo // "type": "number", 1312ffd173baSWalter Erquinigo // "description": "The 1-indexed source column where the variable 1313ffd173baSWalter Erquinigo // was declared." 13140ea19bd3SWalter Erquinigo // } 13150ea19bd3SWalter Erquinigo // } 1316ffd173baSWalter Erquinigo // }, 13170cc2cd78SAdrian Vogelsgesang // "value": { 1318ffd173baSWalter Erquinigo // "type": "string", 1319ffd173baSWalter Erquinigo // "description": "The internal value of the variable as returned by 1320ffd173baSWalter Erquinigo // This is effectively SBValue.GetValue(). The other 13210cc2cd78SAdrian Vogelsgesang // `value` entry in the top-level variable response 13220cc2cd78SAdrian Vogelsgesang // is, on the other hand, just a display string for 13230cc2cd78SAdrian Vogelsgesang // the variable." 1324ffd173baSWalter Erquinigo // }, 13250cc2cd78SAdrian Vogelsgesang // "summary": { 1326ffd173baSWalter Erquinigo // "type": "string", 1327ffd173baSWalter Erquinigo // "description": "The summary string of the variable. This is 1328ffd173baSWalter Erquinigo // effectively SBValue.GetSummary()." 1329ffd173baSWalter Erquinigo // }, 13300cc2cd78SAdrian Vogelsgesang // "autoSummary": { 1331ffd173baSWalter Erquinigo // "type": "string", 1332ffd173baSWalter Erquinigo // "description": "The auto generated summary if using 1333ffd173baSWalter Erquinigo // `enableAutoVariableSummaries`." 1334ffd173baSWalter Erquinigo // }, 13350cc2cd78SAdrian Vogelsgesang // "error": { 1336ffd173baSWalter Erquinigo // "type": "string", 1337ffd173baSWalter Erquinigo // "description": "An error message generated if LLDB couldn't inspect 1338ffd173baSWalter Erquinigo // the variable." 1339ffd173baSWalter Erquinigo // } 13400ea19bd3SWalter Erquinigo // } 13410cc2cd78SAdrian Vogelsgesang // } 134201263c6cSJonas Devlieghere // }, 134301263c6cSJonas Devlieghere // "required": [ "name", "value", "variablesReference" ] 134401263c6cSJonas Devlieghere // } 13450cc2cd78SAdrian Vogelsgesang llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref, 1346*faaf2dbfSJohn Harrison bool format_hex, bool auto_variable_summaries, 1347*faaf2dbfSJohn Harrison bool synthetic_child_debugging, 1348*faaf2dbfSJohn Harrison bool is_name_duplicated, 134901263c6cSJonas Devlieghere std::optional<std::string> custom_name) { 1350*faaf2dbfSJohn Harrison VariableDescription desc(v, auto_variable_summaries, format_hex, 1351*faaf2dbfSJohn Harrison is_name_duplicated, custom_name); 135201263c6cSJonas Devlieghere llvm::json::Object object; 1353ffd173baSWalter Erquinigo EmplaceSafeString(object, "name", desc.name); 1354ffd173baSWalter Erquinigo EmplaceSafeString(object, "value", desc.display_value); 135501263c6cSJonas Devlieghere 1356ffd173baSWalter Erquinigo if (!desc.evaluate_name.empty()) 1357ffd173baSWalter Erquinigo EmplaceSafeString(object, "evaluateName", desc.evaluate_name); 1358ffd173baSWalter Erquinigo 135901263c6cSJonas Devlieghere // If we have a type with many children, we would like to be able to 136001263c6cSJonas Devlieghere // give a hint to the IDE that the type has indexed children so that the 1361ffd173baSWalter Erquinigo // request can be broken up in grabbing only a few children at a time. We 1362ffd173baSWalter Erquinigo // want to be careful and only call "v.GetNumChildren()" if we have an array 1363f38ebec7SPavel Labath // type or if we have a synthetic child provider producing indexed children. 1364f38ebec7SPavel Labath // We don't want to call "v.GetNumChildren()" on all objects as class, struct 1365f38ebec7SPavel Labath // and union types don't need to be completed if they are never expanded. So 1366f38ebec7SPavel Labath // we want to avoid calling this to only cases where we it makes sense to keep 1367ffd173baSWalter Erquinigo // performance high during normal debugging. 136801263c6cSJonas Devlieghere 1369ffd173baSWalter Erquinigo // If we have an array type, say that it is indexed and provide the number 1370ffd173baSWalter Erquinigo // of children in case we have a huge array. If we don't do this, then we 1371ffd173baSWalter Erquinigo // might take a while to produce all children at onces which can delay your 1372ffd173baSWalter Erquinigo // debug session. 1373f38ebec7SPavel Labath if (desc.type_obj.IsArrayType()) { 1374f38ebec7SPavel Labath object.try_emplace("indexedVariables", v.GetNumChildren()); 1375f38ebec7SPavel Labath } else if (v.IsSynthetic()) { 1376f38ebec7SPavel Labath // For a type with a synthetic child provider, the SBType of "v" won't tell 1377f38ebec7SPavel Labath // us anything about what might be displayed. Instead, we check if the first 1378f38ebec7SPavel Labath // child's name is "[0]" and then say it is indexed. We call 1379f38ebec7SPavel Labath // GetNumChildren() only if the child name matches to avoid a potentially 1380f38ebec7SPavel Labath // expensive operation. 1381f38ebec7SPavel Labath if (lldb::SBValue first_child = v.GetChildAtIndex(0)) { 1382f38ebec7SPavel Labath llvm::StringRef first_child_name = first_child.GetName(); 1383f38ebec7SPavel Labath if (first_child_name == "[0]") { 1384f38ebec7SPavel Labath size_t num_children = v.GetNumChildren(); 1385f38ebec7SPavel Labath // If we are creating a "[raw]" fake child for each synthetic type, we 1386f38ebec7SPavel Labath // have to account for it when returning indexed variables. 1387*faaf2dbfSJohn Harrison if (synthetic_child_debugging) 1388f38ebec7SPavel Labath ++num_children; 1389f38ebec7SPavel Labath object.try_emplace("indexedVariables", num_children); 1390f38ebec7SPavel Labath } 139101263c6cSJonas Devlieghere } 139201263c6cSJonas Devlieghere } 1393ffd173baSWalter Erquinigo EmplaceSafeString(object, "type", desc.display_type_name); 13940cc2cd78SAdrian Vogelsgesang 13950cc2cd78SAdrian Vogelsgesang // A unique variable identifier to help in properly identifying variables with 13960cc2cd78SAdrian Vogelsgesang // the same name. This is an extension to the VS protocol. 13970cc2cd78SAdrian Vogelsgesang object.try_emplace("id", var_ref); 13980cc2cd78SAdrian Vogelsgesang 139901263c6cSJonas Devlieghere if (v.MightHaveChildren()) 14000cc2cd78SAdrian Vogelsgesang object.try_emplace("variablesReference", var_ref); 140101263c6cSJonas Devlieghere else 14020cc2cd78SAdrian Vogelsgesang object.try_emplace("variablesReference", 0); 14030cc2cd78SAdrian Vogelsgesang 14040cc2cd78SAdrian Vogelsgesang if (v.GetDeclaration().IsValid()) 14059f8ae784SAdrian Vogelsgesang object.try_emplace("declarationLocationReference", 14069f8ae784SAdrian Vogelsgesang PackLocation(var_ref, false)); 14079f8ae784SAdrian Vogelsgesang 14089f8ae784SAdrian Vogelsgesang if (ValuePointsToCode(v)) 14099f8ae784SAdrian Vogelsgesang object.try_emplace("valueLocationReference", PackLocation(var_ref, true)); 14100ea19bd3SWalter Erquinigo 14113acb1eacSAdrian Vogelsgesang if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) 14123acb1eacSAdrian Vogelsgesang object.try_emplace("memoryReference", EncodeMemoryReference(addr)); 14133acb1eacSAdrian Vogelsgesang 1414ffd173baSWalter Erquinigo object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); 141501263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 141601263c6cSJonas Devlieghere } 141701263c6cSJonas Devlieghere 1418*faaf2dbfSJohn Harrison llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) { 141901263c6cSJonas Devlieghere llvm::json::Object object; 142001263c6cSJonas Devlieghere char unit_path_arr[PATH_MAX]; 142101263c6cSJonas Devlieghere unit.GetFileSpec().GetPath(unit_path_arr, sizeof(unit_path_arr)); 142201263c6cSJonas Devlieghere std::string unit_path(unit_path_arr); 142301263c6cSJonas Devlieghere object.try_emplace("compileUnitPath", unit_path); 142401263c6cSJonas Devlieghere return llvm::json::Value(std::move(object)); 142501263c6cSJonas Devlieghere } 142601263c6cSJonas Devlieghere 142701263c6cSJonas Devlieghere /// See 142801263c6cSJonas Devlieghere /// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal 142901263c6cSJonas Devlieghere llvm::json::Object 143001263c6cSJonas Devlieghere CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, 143101263c6cSJonas Devlieghere llvm::StringRef debug_adaptor_path, 143201263c6cSJonas Devlieghere llvm::StringRef comm_file, 143301263c6cSJonas Devlieghere lldb::pid_t debugger_pid) { 143401263c6cSJonas Devlieghere llvm::json::Object run_in_terminal_args; 14359f8ae784SAdrian Vogelsgesang // This indicates the IDE to open an embedded terminal, instead of opening 14369f8ae784SAdrian Vogelsgesang // the terminal in a new window. 143701263c6cSJonas Devlieghere run_in_terminal_args.try_emplace("kind", "integrated"); 143801263c6cSJonas Devlieghere 1439*faaf2dbfSJohn Harrison const auto *launch_request_arguments = launch_request.getObject("arguments"); 144001263c6cSJonas Devlieghere // The program path must be the first entry in the "args" field 144101263c6cSJonas Devlieghere std::vector<std::string> args = {debug_adaptor_path.str(), "--comm-file", 144201263c6cSJonas Devlieghere comm_file.str()}; 144301263c6cSJonas Devlieghere if (debugger_pid != LLDB_INVALID_PROCESS_ID) { 144401263c6cSJonas Devlieghere args.push_back("--debugger-pid"); 144501263c6cSJonas Devlieghere args.push_back(std::to_string(debugger_pid)); 144601263c6cSJonas Devlieghere } 144701263c6cSJonas Devlieghere args.push_back("--launch-target"); 144801263c6cSJonas Devlieghere args.push_back(GetString(launch_request_arguments, "program").str()); 144901263c6cSJonas Devlieghere std::vector<std::string> target_args = 145001263c6cSJonas Devlieghere GetStrings(launch_request_arguments, "args"); 145101263c6cSJonas Devlieghere args.insert(args.end(), target_args.begin(), target_args.end()); 145201263c6cSJonas Devlieghere run_in_terminal_args.try_emplace("args", args); 145301263c6cSJonas Devlieghere 145401263c6cSJonas Devlieghere const auto cwd = GetString(launch_request_arguments, "cwd"); 145501263c6cSJonas Devlieghere if (!cwd.empty()) 145601263c6cSJonas Devlieghere run_in_terminal_args.try_emplace("cwd", cwd); 145701263c6cSJonas Devlieghere 1458d4c17891SDa-Viper auto envs = GetEnvironmentFromArguments(*launch_request_arguments); 1459d4c17891SDa-Viper llvm::json::Object env_json; 1460d4c17891SDa-Viper for (size_t index = 0, env_count = envs.GetNumValues(); index < env_count; 1461d4c17891SDa-Viper index++) { 1462d4c17891SDa-Viper llvm::StringRef key = envs.GetNameAtIndex(index); 1463d4c17891SDa-Viper llvm::StringRef value = envs.GetValueAtIndex(index); 1464d4c17891SDa-Viper 1465*faaf2dbfSJohn Harrison if (!key.empty()) 1466d4c17891SDa-Viper env_json.try_emplace(key, value); 146701263c6cSJonas Devlieghere } 146801263c6cSJonas Devlieghere run_in_terminal_args.try_emplace("env", 1469d4c17891SDa-Viper llvm::json::Value(std::move(env_json))); 147001263c6cSJonas Devlieghere 147101263c6cSJonas Devlieghere return run_in_terminal_args; 147201263c6cSJonas Devlieghere } 147301263c6cSJonas Devlieghere 147401263c6cSJonas Devlieghere // Keep all the top level items from the statistics dump, except for the 147501263c6cSJonas Devlieghere // "modules" array. It can be huge and cause delay 147601263c6cSJonas Devlieghere // Array and dictionary value will return as <key, JSON string> pairs 1477*faaf2dbfSJohn Harrison static void FilterAndGetValueForKey(const lldb::SBStructuredData data, 1478*faaf2dbfSJohn Harrison const char *key, llvm::json::Object &out) { 147901263c6cSJonas Devlieghere lldb::SBStructuredData value = data.GetValueForKey(key); 148001263c6cSJonas Devlieghere std::string key_utf8 = llvm::json::fixUTF8(key); 1481b99d4112SJohn Harrison if (llvm::StringRef(key) == "modules") 148201263c6cSJonas Devlieghere return; 148301263c6cSJonas Devlieghere switch (value.GetType()) { 148401263c6cSJonas Devlieghere case lldb::eStructuredDataTypeFloat: 148501263c6cSJonas Devlieghere out.try_emplace(key_utf8, value.GetFloatValue()); 148601263c6cSJonas Devlieghere break; 148701263c6cSJonas Devlieghere case lldb::eStructuredDataTypeUnsignedInteger: 148801263c6cSJonas Devlieghere out.try_emplace(key_utf8, value.GetIntegerValue((uint64_t)0)); 148901263c6cSJonas Devlieghere break; 149001263c6cSJonas Devlieghere case lldb::eStructuredDataTypeSignedInteger: 149101263c6cSJonas Devlieghere out.try_emplace(key_utf8, value.GetIntegerValue((int64_t)0)); 149201263c6cSJonas Devlieghere break; 149301263c6cSJonas Devlieghere case lldb::eStructuredDataTypeArray: { 149401263c6cSJonas Devlieghere lldb::SBStream contents; 149501263c6cSJonas Devlieghere value.GetAsJSON(contents); 149601263c6cSJonas Devlieghere out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData())); 149701263c6cSJonas Devlieghere } break; 149801263c6cSJonas Devlieghere case lldb::eStructuredDataTypeBoolean: 149901263c6cSJonas Devlieghere out.try_emplace(key_utf8, value.GetBooleanValue()); 150001263c6cSJonas Devlieghere break; 150101263c6cSJonas Devlieghere case lldb::eStructuredDataTypeString: { 150201263c6cSJonas Devlieghere // Get the string size before reading 150301263c6cSJonas Devlieghere const size_t str_length = value.GetStringValue(nullptr, 0); 150401263c6cSJonas Devlieghere std::string str(str_length + 1, 0); 150501263c6cSJonas Devlieghere value.GetStringValue(&str[0], str_length); 150601263c6cSJonas Devlieghere out.try_emplace(key_utf8, llvm::json::fixUTF8(str)); 150701263c6cSJonas Devlieghere } break; 150801263c6cSJonas Devlieghere case lldb::eStructuredDataTypeDictionary: { 150901263c6cSJonas Devlieghere lldb::SBStream contents; 151001263c6cSJonas Devlieghere value.GetAsJSON(contents); 151101263c6cSJonas Devlieghere out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData())); 151201263c6cSJonas Devlieghere } break; 151301263c6cSJonas Devlieghere case lldb::eStructuredDataTypeNull: 151401263c6cSJonas Devlieghere case lldb::eStructuredDataTypeGeneric: 151501263c6cSJonas Devlieghere case lldb::eStructuredDataTypeInvalid: 151601263c6cSJonas Devlieghere break; 151701263c6cSJonas Devlieghere } 151801263c6cSJonas Devlieghere } 151901263c6cSJonas Devlieghere 1520*faaf2dbfSJohn Harrison static void addStatistic(lldb::SBTarget &target, llvm::json::Object &event) { 1521*faaf2dbfSJohn Harrison lldb::SBStructuredData statistics = target.GetStatistics(); 152201263c6cSJonas Devlieghere bool is_dictionary = 152301263c6cSJonas Devlieghere statistics.GetType() == lldb::eStructuredDataTypeDictionary; 152401263c6cSJonas Devlieghere if (!is_dictionary) 152501263c6cSJonas Devlieghere return; 152601263c6cSJonas Devlieghere llvm::json::Object stats_body; 152701263c6cSJonas Devlieghere 152801263c6cSJonas Devlieghere lldb::SBStringList keys; 152901263c6cSJonas Devlieghere if (!statistics.GetKeys(keys)) 153001263c6cSJonas Devlieghere return; 153101263c6cSJonas Devlieghere for (size_t i = 0; i < keys.GetSize(); i++) { 153201263c6cSJonas Devlieghere const char *key = keys.GetStringAtIndex(i); 153301263c6cSJonas Devlieghere FilterAndGetValueForKey(statistics, key, stats_body); 153401263c6cSJonas Devlieghere } 153501263c6cSJonas Devlieghere event.try_emplace("statistics", std::move(stats_body)); 153601263c6cSJonas Devlieghere } 153701263c6cSJonas Devlieghere 1538*faaf2dbfSJohn Harrison llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target) { 153901263c6cSJonas Devlieghere llvm::json::Object event(CreateEventObject("terminated")); 1540*faaf2dbfSJohn Harrison addStatistic(target, event); 154101263c6cSJonas Devlieghere return event; 154201263c6cSJonas Devlieghere } 154301263c6cSJonas Devlieghere 154401263c6cSJonas Devlieghere std::string JSONToString(const llvm::json::Value &json) { 154501263c6cSJonas Devlieghere std::string data; 154601263c6cSJonas Devlieghere llvm::raw_string_ostream os(data); 154701263c6cSJonas Devlieghere os << json; 154801263c6cSJonas Devlieghere return data; 154901263c6cSJonas Devlieghere } 155001263c6cSJonas Devlieghere 155101263c6cSJonas Devlieghere } // namespace lldb_dap 1552