diff options
Diffstat (limited to 'tools/lldb-vscode/JSONUtils.cpp')
-rw-r--r-- | tools/lldb-vscode/JSONUtils.cpp | 892 |
1 files changed, 0 insertions, 892 deletions
diff --git a/tools/lldb-vscode/JSONUtils.cpp b/tools/lldb-vscode/JSONUtils.cpp deleted file mode 100644 index 76cd44cc72d1..000000000000 --- a/tools/lldb-vscode/JSONUtils.cpp +++ /dev/null @@ -1,892 +0,0 @@ -//===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <algorithm> - -#include "llvm/Support/FormatAdapters.h" - -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBBreakpointLocation.h" -#include "lldb/API/SBValue.h" -#include "lldb/Host/PosixApi.h" - -#include "ExceptionBreakpoint.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "VSCode.h" - -namespace lldb_vscode { - -void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, - llvm::StringRef str) { - if (LLVM_LIKELY(llvm::json::isUTF8(str))) - obj.try_emplace(key, str.str()); - else - obj.try_emplace(key, llvm::json::fixUTF8(str)); -} - -llvm::StringRef GetAsString(const llvm::json::Value &value) { - if (auto s = value.getAsString()) - return *s; - return llvm::StringRef(); -} - -// Gets a string from a JSON object using the key, or returns an empty string. -llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key) { - if (auto value = obj.getString(key)) - return GetAsString(*value); - return llvm::StringRef(); -} - -llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key) { - if (obj == nullptr) - return llvm::StringRef(); - return GetString(*obj, key); -} - -// Gets an unsigned integer from a JSON object using the key, or returns the -// specified fail value. -uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key, - uint64_t fail_value) { - if (auto value = obj.getInteger(key)) - return (uint64_t)*value; - return fail_value; -} - -uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key, - uint64_t fail_value) { - if (obj == nullptr) - return fail_value; - return GetUnsigned(*obj, key, fail_value); -} - -bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key, - bool fail_value) { - if (auto value = obj.getBoolean(key)) - return *value; - if (auto value = obj.getInteger(key)) - return *value != 0; - return fail_value; -} - -bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key, - bool fail_value) { - if (obj == nullptr) - return fail_value; - return GetBoolean(*obj, key, fail_value); -} - -int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key, - int64_t fail_value) { - if (auto value = obj.getInteger(key)) - return *value; - return fail_value; -} - -int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key, - int64_t fail_value) { - if (obj == nullptr) - return fail_value; - return GetSigned(*obj, key, fail_value); -} - -bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) { - return obj.find(key) != obj.end(); -} - -std::vector<std::string> GetStrings(const llvm::json::Object *obj, - llvm::StringRef key) { - std::vector<std::string> strs; - auto json_array = obj->getArray(key); - if (!json_array) - return strs; - for (const auto &value : *json_array) { - switch (value.kind()) { - case llvm::json::Value::String: - strs.push_back(value.getAsString()->str()); - break; - case llvm::json::Value::Number: - case llvm::json::Value::Boolean: { - std::string s; - llvm::raw_string_ostream strm(s); - strm << value; - strs.push_back(strm.str()); - break; - } - case llvm::json::Value::Null: - case llvm::json::Value::Object: - case llvm::json::Value::Array: - break; - } - } - return strs; -} - -void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object, - llvm::StringRef key) { - - llvm::StringRef value = v.GetValue(); - llvm::StringRef summary = v.GetSummary(); - llvm::StringRef type_name = v.GetType().GetDisplayTypeName(); - - std::string result; - llvm::raw_string_ostream strm(result); - if (!value.empty()) { - strm << value; - if (!summary.empty()) - strm << ' ' << summary; - } else if (!summary.empty()) { - strm << ' ' << summary; - } else if (!type_name.empty()) { - strm << type_name; - lldb::addr_t address = v.GetLoadAddress(); - if (address != LLDB_INVALID_ADDRESS) - strm << " @ " << llvm::format_hex(address, 0); - } - strm.flush(); - EmplaceSafeString(object, key, result); -} - -void FillResponse(const llvm::json::Object &request, - llvm::json::Object &response) { - // Fill in all of the needed response fields to a "request" and set "success" - // to true by default. - response.try_emplace("type", "response"); - response.try_emplace("seq", (int64_t)0); - EmplaceSafeString(response, "command", GetString(request, "command")); - const int64_t seq = GetSigned(request, "seq", 0); - response.try_emplace("request_seq", seq); - response.try_emplace("success", true); -} - -//---------------------------------------------------------------------- -// "Scope": { -// "type": "object", -// "description": "A Scope is a named container for variables. Optionally -// a scope can map to a source or a range within a source.", -// "properties": { -// "name": { -// "type": "string", -// "description": "Name of the scope such as 'Arguments', 'Locals'." -// }, -// "variablesReference": { -// "type": "integer", -// "description": "The variables of this scope can be retrieved by -// passing the value of variablesReference to the -// VariablesRequest." -// }, -// "namedVariables": { -// "type": "integer", -// "description": "The number of named variables in this scope. The -// client can use this optional information to present -// the variables in a paged UI and fetch them in chunks." -// }, -// "indexedVariables": { -// "type": "integer", -// "description": "The number of indexed variables in this scope. The -// client can use this optional information to present -// the variables in a paged UI and fetch them in chunks." -// }, -// "expensive": { -// "type": "boolean", -// "description": "If true, the number of variables in this scope is -// large or expensive to retrieve." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "Optional source for this scope." -// }, -// "line": { -// "type": "integer", -// "description": "Optional start line of the range covered by this -// scope." -// }, -// "column": { -// "type": "integer", -// "description": "Optional start column of the range covered by this -// scope." -// }, -// "endLine": { -// "type": "integer", -// "description": "Optional end line of the range covered by this scope." -// }, -// "endColumn": { -// "type": "integer", -// "description": "Optional end column of the range covered by this -// scope." -// } -// }, -// "required": [ "name", "variablesReference", "expensive" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive) { - llvm::json::Object object; - EmplaceSafeString(object, "name", name.str()); - object.try_emplace("variablesReference", variablesReference); - object.try_emplace("expensive", expensive); - object.try_emplace("namedVariables", namedVariables); - return llvm::json::Value(std::move(object)); -} - -//---------------------------------------------------------------------- -// "Breakpoint": { -// "type": "object", -// "description": "Information about a Breakpoint created in setBreakpoints -// or setFunctionBreakpoints.", -// "properties": { -// "id": { -// "type": "integer", -// "description": "An optional unique identifier for the breakpoint." -// }, -// "verified": { -// "type": "boolean", -// "description": "If true breakpoint could be set (but not necessarily -// at the desired location)." -// }, -// "message": { -// "type": "string", -// "description": "An optional message about the state of the breakpoint. -// This is shown to the user and can be used to explain -// why a breakpoint could not be verified." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "The source where the breakpoint is located." -// }, -// "line": { -// "type": "integer", -// "description": "The start line of the actual range covered by the -// breakpoint." -// }, -// "column": { -// "type": "integer", -// "description": "An optional start column of the actual range covered -// by the breakpoint." -// }, -// "endLine": { -// "type": "integer", -// "description": "An optional end line of the actual range covered by -// the breakpoint." -// }, -// "endColumn": { -// "type": "integer", -// "description": "An optional end column of the actual range covered by -// the breakpoint. If no end line is given, then the end -// column is assumed to be in the start line." -// } -// }, -// "required": [ "verified" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc) { - // Each breakpoint location is treated as a separate breakpoint for VS code. - // They don't have the notion of a single breakpoint with multiple locations. - llvm::json::Object object; - if (!bp_loc.IsValid()) - return llvm::json::Value(std::move(object)); - - object.try_emplace("verified", true); - const auto vs_id = MakeVSCodeBreakpointID(bp_loc); - object.try_emplace("id", vs_id); - auto bp_addr = bp_loc.GetAddress(); - if (bp_addr.IsValid()) { - auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != UINT32_MAX) - object.try_emplace("line", line); - object.try_emplace("source", CreateSource(line_entry)); - } - return llvm::json::Value(std::move(object)); -} - -void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints) { - if (!bp.IsValid()) - return; - const auto num_locations = bp.GetNumLocations(); - if (num_locations == 0) - return; - for (size_t i = 0; i < num_locations; ++i) { - auto bp_loc = bp.GetLocationAtIndex(i); - breakpoints.emplace_back(CreateBreakpoint(bp_loc)); - } -} - -//---------------------------------------------------------------------- -// "Event": { -// "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, { -// "type": "object", -// "description": "Server-initiated event.", -// "properties": { -// "type": { -// "type": "string", -// "enum": [ "event" ] -// }, -// "event": { -// "type": "string", -// "description": "Type of event." -// }, -// "body": { -// "type": [ "array", "boolean", "integer", "null", "number" , -// "object", "string" ], -// "description": "Event-specific information." -// } -// }, -// "required": [ "type", "event" ] -// }] -// }, -// "ProtocolMessage": { -// "type": "object", -// "description": "Base class of requests, responses, and events.", -// "properties": { -// "seq": { -// "type": "integer", -// "description": "Sequence number." -// }, -// "type": { -// "type": "string", -// "description": "Message type.", -// "_enum": [ "request", "response", "event" ] -// } -// }, -// "required": [ "seq", "type" ] -// } -//---------------------------------------------------------------------- -llvm::json::Object CreateEventObject(const llvm::StringRef event_name) { - llvm::json::Object event; - event.try_emplace("seq", 0); - event.try_emplace("type", "event"); - EmplaceSafeString(event, "event", event_name); - return event; -} - -//---------------------------------------------------------------------- -// "ExceptionBreakpointsFilter": { -// "type": "object", -// "description": "An ExceptionBreakpointsFilter is shown in the UI as an -// option for configuring how exceptions are dealt with.", -// "properties": { -// "filter": { -// "type": "string", -// "description": "The internal ID of the filter. This value is passed -// to the setExceptionBreakpoints request." -// }, -// "label": { -// "type": "string", -// "description": "The name of the filter. This will be shown in the UI." -// }, -// "default": { -// "type": "boolean", -// "description": "Initial value of the filter. If not specified a value -// 'false' is assumed." -// } -// }, -// "required": [ "filter", "label" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value -CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { - llvm::json::Object object; - EmplaceSafeString(object, "filter", bp.filter); - EmplaceSafeString(object, "label", bp.label); - object.try_emplace("default", bp.default_value); - return llvm::json::Value(std::move(object)); -} - -//---------------------------------------------------------------------- -// "Source": { -// "type": "object", -// "description": "A Source is a descriptor for source code. It is returned -// from the debug adapter as part of a StackFrame and it is -// used by clients when specifying breakpoints.", -// "properties": { -// "name": { -// "type": "string", -// "description": "The short name of the source. Every source returned -// from the debug adapter has a name. When sending a -// source to the debug adapter this name is optional." -// }, -// "path": { -// "type": "string", -// "description": "The path of the source to be shown in the UI. It is -// only used to locate and load the content of the -// source if no sourceReference is specified (or its -// value is 0)." -// }, -// "sourceReference": { -// "type": "number", -// "description": "If sourceReference > 0 the contents of the source must -// be retrieved through the SourceRequest (even if a path -// is specified). A sourceReference is only valid for a -// session, so it must not be used to persist a source." -// }, -// "presentationHint": { -// "type": "string", -// "description": "An optional hint for how to present the source in the -// UI. A value of 'deemphasize' can be used to indicate -// that the source is not available or that it is -// skipped on stepping.", -// "enum": [ "normal", "emphasize", "deemphasize" ] -// }, -// "origin": { -// "type": "string", -// "description": "The (optional) origin of this source: possible values -// 'internal module', 'inlined content from source map', -// etc." -// }, -// "sources": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Source" -// }, -// "description": "An optional list of sources that are related to this -// source. These may be the source that generated this -// source." -// }, -// "adapterData": { -// "type":["array","boolean","integer","null","number","object","string"], -// "description": "Optional data that a debug adapter might want to loop -// through the client. The client should leave the data -// intact and persist it across sessions. The client -// should not interpret the data." -// }, -// "checksums": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Checksum" -// }, -// "description": "The checksums associated with this file." -// } -// } -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) { - llvm::json::Object object; - lldb::SBFileSpec file = line_entry.GetFileSpec(); - if (file.IsValid()) { - const char *name = file.GetFilename(); - if (name) - EmplaceSafeString(object, "name", name); - char path[PATH_MAX] = ""; - file.GetPath(path, sizeof(path)); - if (path[0]) { - EmplaceSafeString(object, "path", std::string(path)); - } - } - return llvm::json::Value(std::move(object)); -} - -llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) { - disasm_line = 0; - auto line_entry = frame.GetLineEntry(); - if (line_entry.GetFileSpec().IsValid()) - return CreateSource(line_entry); - - llvm::json::Object object; - const auto pc = frame.GetPC(); - - lldb::SBInstructionList insts; - lldb::SBFunction function = frame.GetFunction(); - lldb::addr_t low_pc = LLDB_INVALID_ADDRESS; - if (function.IsValid()) { - low_pc = function.GetStartAddress().GetLoadAddress(g_vsc.target); - auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc); - if (addr_srcref != g_vsc.addr_to_source_ref.end()) { - // We have this disassembly cached already, return the existing - // sourceReference - object.try_emplace("sourceReference", addr_srcref->second); - disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc); - } else { - insts = function.GetInstructions(g_vsc.target); - } - } else { - lldb::SBSymbol symbol = frame.GetSymbol(); - if (symbol.IsValid()) { - low_pc = symbol.GetStartAddress().GetLoadAddress(g_vsc.target); - auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc); - if (addr_srcref != g_vsc.addr_to_source_ref.end()) { - // We have this disassembly cached already, return the existing - // sourceReference - object.try_emplace("sourceReference", addr_srcref->second); - disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc); - } else { - insts = symbol.GetInstructions(g_vsc.target); - } - } - } - const auto num_insts = insts.GetSize(); - if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) { - EmplaceSafeString(object, "name", frame.GetFunctionName()); - SourceReference source; - llvm::raw_string_ostream src_strm(source.content); - std::string line; - for (size_t i = 0; i < num_insts; ++i) { - lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); - const auto inst_addr = inst.GetAddress().GetLoadAddress(g_vsc.target); - const char *m = inst.GetMnemonic(g_vsc.target); - const char *o = inst.GetOperands(g_vsc.target); - const char *c = inst.GetComment(g_vsc.target); - if (pc == inst_addr) - disasm_line = i + 1; - const auto inst_offset = inst_addr - low_pc; - int spaces = 0; - if (inst_offset < 10) - spaces = 3; - else if (inst_offset < 100) - spaces = 2; - else if (inst_offset < 1000) - spaces = 1; - line.clear(); - llvm::raw_string_ostream line_strm(line); - line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr, - inst_offset, llvm::fmt_repeat(' ', spaces), m, - o); - - // If there is a comment append it starting at column 60 or after one - // space past the last char - const uint32_t comment_row = std::max(line_strm.str().size(), (size_t)60); - if (c && c[0]) { - if (line.size() < comment_row) - line_strm.indent(comment_row - line_strm.str().size()); - line_strm << " # " << c; - } - src_strm << line_strm.str() << "\n"; - source.addr_to_line[inst_addr] = i + 1; - } - // Flush the source stream - src_strm.str(); - auto sourceReference = VSCode::GetNextSourceReference(); - g_vsc.source_map[sourceReference] = std::move(source); - g_vsc.addr_to_source_ref[low_pc] = sourceReference; - object.try_emplace("sourceReference", sourceReference); - } - return llvm::json::Value(std::move(object)); -} - -//---------------------------------------------------------------------- -// "StackFrame": { -// "type": "object", -// "description": "A Stackframe contains the source location.", -// "properties": { -// "id": { -// "type": "integer", -// "description": "An identifier for the stack frame. It must be unique -// across all threads. This id can be used to retrieve -// the scopes of the frame with the 'scopesRequest' or -// to restart the execution of a stackframe." -// }, -// "name": { -// "type": "string", -// "description": "The name of the stack frame, typically a method name." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "The optional source of the frame." -// }, -// "line": { -// "type": "integer", -// "description": "The line within the file of the frame. If source is -// null or doesn't exist, line is 0 and must be ignored." -// }, -// "column": { -// "type": "integer", -// "description": "The column within the line. If source is null or -// doesn't exist, column is 0 and must be ignored." -// }, -// "endLine": { -// "type": "integer", -// "description": "An optional end line of the range covered by the -// stack frame." -// }, -// "endColumn": { -// "type": "integer", -// "description": "An optional end column of the range covered by the -// stack frame." -// }, -// "moduleId": { -// "type": ["integer", "string"], -// "description": "The module associated with this frame, if any." -// }, -// "presentationHint": { -// "type": "string", -// "enum": [ "normal", "label", "subtle" ], -// "description": "An optional hint for how to present this frame in -// the UI. A value of 'label' can be used to indicate -// that the frame is an artificial frame that is used -// as a visual label or separator. A value of 'subtle' -// can be used to change the appearance of a frame in -// a 'subtle' way." -// } -// }, -// "required": [ "id", "name", "line", "column" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) { - llvm::json::Object object; - int64_t frame_id = MakeVSCodeFrameID(frame); - object.try_emplace("id", frame_id); - EmplaceSafeString(object, "name", frame.GetFunctionName()); - int64_t disasm_line = 0; - object.try_emplace("source", CreateSource(frame, disasm_line)); - - auto line_entry = frame.GetLineEntry(); - if (disasm_line > 0) { - object.try_emplace("line", disasm_line); - } else { - auto line = line_entry.GetLine(); - if (line == UINT32_MAX) - line = 0; - object.try_emplace("line", line); - } - object.try_emplace("column", line_entry.GetColumn()); - return llvm::json::Value(std::move(object)); -} - -//---------------------------------------------------------------------- -// "Thread": { -// "type": "object", -// "description": "A Thread", -// "properties": { -// "id": { -// "type": "integer", -// "description": "Unique identifier for the thread." -// }, -// "name": { -// "type": "string", -// "description": "A name of the thread." -// } -// }, -// "required": [ "id", "name" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateThread(lldb::SBThread &thread) { - llvm::json::Object object; - object.try_emplace("id", (int64_t)thread.GetThreadID()); - char thread_str[64]; - snprintf(thread_str, sizeof(thread_str), "Thread #%u", thread.GetIndexID()); - const char *name = thread.GetName(); - if (name) { - std::string thread_with_name(thread_str); - thread_with_name += ' '; - thread_with_name += name; - EmplaceSafeString(object, "name", thread_with_name); - } else { - EmplaceSafeString(object, "name", std::string(thread_str)); - } - return llvm::json::Value(std::move(object)); -} - -//---------------------------------------------------------------------- -// "StoppedEvent": { -// "allOf": [ { "$ref": "#/definitions/Event" }, { -// "type": "object", -// "description": "Event message for 'stopped' event type. The event -// indicates that the execution of the debuggee has stopped -// due to some condition. This can be caused by a break -// point previously set, a stepping action has completed, -// by executing a debugger statement etc.", -// "properties": { -// "event": { -// "type": "string", -// "enum": [ "stopped" ] -// }, -// "body": { -// "type": "object", -// "properties": { -// "reason": { -// "type": "string", -// "description": "The reason for the event. For backward -// compatibility this string is shown in the UI if -// the 'description' attribute is missing (but it -// must not be translated).", -// "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ] -// }, -// "description": { -// "type": "string", -// "description": "The full reason for the event, e.g. 'Paused -// on exception'. This string is shown in the UI -// as is." -// }, -// "threadId": { -// "type": "integer", -// "description": "The thread which was stopped." -// }, -// "text": { -// "type": "string", -// "description": "Additional information. E.g. if reason is -// 'exception', text contains the exception name. -// This string is shown in the UI." -// }, -// "allThreadsStopped": { -// "type": "boolean", -// "description": "If allThreadsStopped is true, a debug adapter -// can announce that all threads have stopped. -// The client should use this information to -// enable that all threads can be expanded to -// access their stacktraces. If the attribute -// is missing or false, only the thread with the -// given threadId can be expanded." -// } -// }, -// "required": [ "reason" ] -// } -// }, -// "required": [ "event", "body" ] -// }] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, - uint32_t stop_id) { - llvm::json::Object event(CreateEventObject("stopped")); - llvm::json::Object body; - switch (thread.GetStopReason()) { - case lldb::eStopReasonTrace: - case lldb::eStopReasonPlanComplete: - body.try_emplace("reason", "step"); - break; - case lldb::eStopReasonBreakpoint: { - ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread); - if (exc_bp) { - body.try_emplace("reason", "exception"); - EmplaceSafeString(body, "description", exc_bp->label); - } else { - body.try_emplace("reason", "breakpoint"); - } - } break; - case lldb::eStopReasonWatchpoint: - case lldb::eStopReasonInstrumentation: - body.try_emplace("reason", "breakpoint"); - break; - case lldb::eStopReasonSignal: - body.try_emplace("reason", "exception"); - break; - case lldb::eStopReasonException: - body.try_emplace("reason", "exception"); - break; - case lldb::eStopReasonExec: - body.try_emplace("reason", "entry"); - break; - case lldb::eStopReasonThreadExiting: - case lldb::eStopReasonInvalid: - case lldb::eStopReasonNone: - break; - } - if (stop_id == 0) - body.try_emplace("reason", "entry"); - const lldb::tid_t tid = thread.GetThreadID(); - body.try_emplace("threadId", (int64_t)tid); - // If no description has been set, then set it to the default thread stopped - // description. If we have breakpoints that get hit and shouldn't be reported - // as breakpoints, then they will set the description above. - if (ObjectContainsKey(body, "description")) { - char description[1024]; - if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", std::string(description)); - } - } - if (tid == g_vsc.focus_tid) { - body.try_emplace("threadCausedFocus", true); - } - body.try_emplace("preserveFocusHint", tid != g_vsc.focus_tid); - body.try_emplace("allThreadsStopped", true); - event.try_emplace("body", std::move(body)); - return llvm::json::Value(std::move(event)); -} - -//---------------------------------------------------------------------- -// "Variable": { -// "type": "object", -// "description": "A Variable is a name/value pair. Optionally a variable -// can have a 'type' that is shown if space permits or when -// hovering over the variable's name. An optional 'kind' is -// used to render additional properties of the variable, -// e.g. different icons can be used to indicate that a -// variable is public or private. If the value is -// structured (has children), a handle is provided to -// retrieve the children with the VariablesRequest. If -// the number of named or indexed children is large, the -// numbers should be returned via the optional -// 'namedVariables' and 'indexedVariables' attributes. The -// client can use this optional information to present the -// children in a paged UI and fetch them in chunks.", -// "properties": { -// "name": { -// "type": "string", -// "description": "The variable's name." -// }, -// "value": { -// "type": "string", -// "description": "The variable's value. This can be a multi-line text, -// e.g. for a function the body of a function." -// }, -// "type": { -// "type": "string", -// "description": "The type of the variable's value. Typically shown in -// the UI when hovering over the value." -// }, -// "presentationHint": { -// "$ref": "#/definitions/VariablePresentationHint", -// "description": "Properties of a variable that can be used to determine -// how to render the variable in the UI." -// }, -// "evaluateName": { -// "type": "string", -// "description": "Optional evaluatable name of this variable which can -// be passed to the 'EvaluateRequest' to fetch the -// variable's value." -// }, -// "variablesReference": { -// "type": "integer", -// "description": "If variablesReference is > 0, the variable is -// structured and its children can be retrieved by -// passing variablesReference to the VariablesRequest." -// }, -// "namedVariables": { -// "type": "integer", -// "description": "The number of named child variables. The client can -// use this optional information to present the children -// in a paged UI and fetch them in chunks." -// }, -// "indexedVariables": { -// "type": "integer", -// "description": "The number of indexed child variables. The client -// can use this optional information to present the -// children in a paged UI and fetch them in chunks." -// } -// }, -// "required": [ "name", "value", "variablesReference" ] -// } -//---------------------------------------------------------------------- -llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, - int64_t varID, bool format_hex) { - llvm::json::Object object; - auto name = v.GetName(); - EmplaceSafeString(object, "name", name ? name : "<null>"); - if (format_hex) - v.SetFormat(lldb::eFormatHex); - SetValueForKey(v, object, "value"); - auto type_cstr = v.GetType().GetDisplayTypeName(); - EmplaceSafeString(object, "type", type_cstr ? type_cstr : NO_TYPENAME); - if (varID != INT64_MAX) - object.try_emplace("id", varID); - if (v.MightHaveChildren()) - object.try_emplace("variablesReference", variablesReference); - else - object.try_emplace("variablesReference", (int64_t)0); - lldb::SBStream evaluateStream; - v.GetExpressionPath(evaluateStream); - const char *evaluateName = evaluateStream.GetData(); - if (evaluateName && evaluateName[0]) - EmplaceSafeString(object, "evaluateName", std::string(evaluateName)); - return llvm::json::Value(std::move(object)); -} - -} // namespace lldb_vscode - |