1010#include " EventHelper.h"
1111#include " JSONUtils.h"
1212#include " LLDBUtils.h"
13+ #include " Protocol/ProtocolRequests.h"
14+ #include " Protocol/ProtocolTypes.h"
1315#include " RequestHandler.h"
16+ #include " lldb/API/SBCommandInterpreter.h"
17+ #include " lldb/API/SBCommandReturnObject.h"
18+ #include " lldb/lldb-enumerations.h"
19+ #include " llvm/ADT/StringRef.h"
20+ #include " llvm/Support/Error.h"
21+ #include < future>
22+ #include < optional>
23+ #include < unistd.h>
24+
25+ using namespace llvm ;
26+ using namespace lldb_dap ;
27+ using namespace lldb_dap ::protocol;
1428
1529namespace lldb_dap {
1630
17- // "EvaluateRequest": {
18- // "allOf": [ { "$ref": "#/definitions/Request" }, {
19- // "type": "object",
20- // "description": "Evaluate request; value of command field is 'evaluate'.
21- // Evaluates the given expression in the context of the
22- // top most stack frame. The expression has access to any
23- // variables and arguments that are in scope.",
24- // "properties": {
25- // "command": {
26- // "type": "string",
27- // "enum": [ "evaluate" ]
28- // },
29- // "arguments": {
30- // "$ref": "#/definitions/EvaluateArguments"
31- // }
32- // },
33- // "required": [ "command", "arguments" ]
34- // }]
35- // },
36- // "EvaluateArguments": {
37- // "type": "object",
38- // "description": "Arguments for 'evaluate' request.",
39- // "properties": {
40- // "expression": {
41- // "type": "string",
42- // "description": "The expression to evaluate."
43- // },
44- // "frameId": {
45- // "type": "integer",
46- // "description": "Evaluate the expression in the scope of this stack
47- // frame. If not specified, the expression is evaluated
48- // in the global scope."
49- // },
50- // "context": {
51- // "type": "string",
52- // "_enum": [ "watch", "repl", "hover" ],
53- // "enumDescriptions": [
54- // "evaluate is run in a watch.",
55- // "evaluate is run from REPL console.",
56- // "evaluate is run from a data hover."
57- // ],
58- // "description": "The context in which the evaluate request is run."
59- // },
60- // "format": {
61- // "$ref": "#/definitions/ValueFormat",
62- // "description": "Specifies details on how to format the Evaluate
63- // result."
64- // }
65- // },
66- // "required": [ "expression" ]
67- // },
68- // "EvaluateResponse": {
69- // "allOf": [ { "$ref": "#/definitions/Response" }, {
70- // "type": "object",
71- // "description": "Response to 'evaluate' request.",
72- // "properties": {
73- // "body": {
74- // "type": "object",
75- // "properties": {
76- // "result": {
77- // "type": "string",
78- // "description": "The result of the evaluate request."
79- // },
80- // "type": {
81- // "type": "string",
82- // "description": "The optional type of the evaluate result."
83- // },
84- // "presentationHint": {
85- // "$ref": "#/definitions/VariablePresentationHint",
86- // "description": "Properties of a evaluate result that can be
87- // used to determine how to render the result in
88- // the UI."
89- // },
90- // "variablesReference": {
91- // "type": "number",
92- // "description": "If variablesReference is > 0, the evaluate
93- // result is structured and its children can be
94- // retrieved by passing variablesReference to the
95- // VariablesRequest."
96- // },
97- // "namedVariables": {
98- // "type": "number",
99- // "description": "The number of named child variables. The
100- // client can use this optional information to
101- // present the variables in a paged UI and fetch
102- // them in chunks."
103- // },
104- // "indexedVariables": {
105- // "type": "number",
106- // "description": "The number of indexed child variables. The
107- // client can use this optional information to
108- // present the variables in a paged UI and fetch
109- // them in chunks."
110- // },
111- // "valueLocationReference": {
112- // "type": "integer",
113- // "description": "A reference that allows the client to request
114- // the location where the returned value is
115- // declared. For example, if a function pointer is
116- // returned, the adapter may be able to look up the
117- // function's location. This should be present only
118- // if the adapter is likely to be able to resolve
119- // the location.\n\nThis reference shares the same
120- // lifetime as the `variablesReference`. See
121- // 'Lifetime of Object References' in the
122- // Overview section for details."
123- // }
124- // "memoryReference": {
125- // "type": "string",
126- // "description": "A memory reference to a location appropriate
127- // for this result. For pointer type eval
128- // results, this is generally a reference to the
129- // memory address contained in the pointer. This
130- // attribute may be returned by a debug adapter
131- // if corresponding capability
132- // `supportsMemoryReferences` is true."
133- // },
134- // },
135- // "required": [ "result", "variablesReference" ]
136- // }
137- // },
138- // "required": [ "body" ]
139- // }]
140- // }
141- void EvaluateRequestHandler::operator ()(
142- const llvm::json::Object &request) const {
143- llvm::json::Object response;
144- FillResponse (request, response);
145- llvm::json::Object body;
146- const auto *arguments = request.getObject (" arguments" );
147- lldb::SBFrame frame = dap.GetLLDBFrame (*arguments);
148- std::string expression =
149- GetString (arguments, " expression" ).value_or (" " ).str ();
150- const llvm::StringRef context = GetString (arguments, " context" ).value_or (" " );
31+ // / Evaluates the given expression in the context of a stack frame.
32+ // /
33+ // / The expression has access to any variables and arguments that are in scope.
34+ Expected<EvaluateResponseBody>
35+ EvaluateRequestHandler::Run (const EvaluateArguments &arguments) const {
36+ EvaluateResponseBody body;
37+ lldb::SBFrame frame = dap.GetLLDBFrame (arguments.frameId );
38+ std::string expression = arguments.expression ;
15139 bool repeat_last_command =
15240 expression.empty () && dap.last_nonempty_var_expression .empty ();
15341
154- if (context == " repl " &&
42+ if (arguments. context == protocol::eEvaluateContextRepl &&
15543 (repeat_last_command ||
15644 (!expression.empty () &&
15745 dap.DetectReplMode (frame, expression, false ) == ReplMode::Command))) {
@@ -169,66 +57,61 @@ void EvaluateRequestHandler::operator()(
16957 dap.debugger , llvm::StringRef (), {expression}, required_command_failed,
17058 /* parse_command_directives=*/ false , /* echo_commands=*/ false );
17159
172- EmplaceSafeString (body, " result" , result);
173- body.try_emplace (" variablesReference" , (int64_t )0 );
174- } else {
175- if (context == " repl" ) {
176- // If the expression is empty and the last expression was for a
177- // variable, set the expression to the previous expression (repeat the
178- // evaluation); otherwise save the current non-empty expression for the
179- // next (possibly empty) variable expression.
180- if (expression.empty ())
181- expression = dap.last_nonempty_var_expression ;
182- else
183- dap.last_nonempty_var_expression = expression;
184- }
185- // Always try to get the answer from the local variables if possible. If
186- // this fails, then if the context is not "hover", actually evaluate an
187- // expression using the expression parser.
188- //
189- // "frame variable" is more reliable than the expression parser in
190- // many cases and it is faster.
191- lldb::SBValue value = frame.GetValueForVariablePath (
192- expression.data (), lldb::eDynamicDontRunTarget);
193-
194- // Freeze dry the value in case users expand it later in the debug console
195- if (value.GetError ().Success () && context == " repl" )
196- value = value.Persist ();
197-
198- if (value.GetError ().Fail () && context != " hover" )
199- value = frame.EvaluateExpression (expression.data ());
200-
201- if (value.GetError ().Fail ()) {
202- response[" success" ] = llvm::json::Value (false );
203- // This error object must live until we're done with the pointer returned
204- // by GetCString().
205- lldb::SBError error = value.GetError ();
206- const char *error_cstr = error.GetCString ();
207- if (error_cstr && error_cstr[0 ])
208- EmplaceSafeString (response, " message" , error_cstr);
209- else
210- EmplaceSafeString (response, " message" , " evaluate failed" );
211- } else {
212- VariableDescription desc (value,
213- dap.configuration .enableAutoVariableSummaries );
214- EmplaceSafeString (body, " result" , desc.GetResult (context));
215- EmplaceSafeString (body, " type" , desc.display_type_name );
216- int64_t var_ref = 0 ;
217- if (value.MightHaveChildren () || ValuePointsToCode (value))
218- var_ref = dap.variables .InsertVariable (
219- value, /* is_permanent=*/ context == " repl" );
220- if (value.MightHaveChildren ())
221- body.try_emplace (" variablesReference" , var_ref);
222- else
223- body.try_emplace (" variablesReference" , (int64_t )0 );
224- if (lldb::addr_t addr = value.GetLoadAddress ();
225- addr != LLDB_INVALID_ADDRESS)
226- body.try_emplace (" memoryReference" , EncodeMemoryReference (addr));
227- if (ValuePointsToCode (value))
228- body.try_emplace (" valueLocationReference" , var_ref);
229- }
60+ body.result = result;
61+ return body;
62+ }
63+
64+ if (arguments.context == eEvaluateContextRepl) {
65+ // If the expression is empty and the last expression was for a
66+ // variable, set the expression to the previous expression (repeat the
67+ // evaluation); otherwise save the current non-empty expression for the
68+ // next (possibly empty) variable expression.
69+ if (expression.empty ())
70+ expression = dap.last_nonempty_var_expression ;
71+ else
72+ dap.last_nonempty_var_expression = expression;
73+ }
74+
75+ // Always try to get the answer from the local variables if possible. If
76+ // this fails, then if the context is not "hover", actually evaluate an
77+ // expression using the expression parser.
78+ //
79+ // "frame variable" is more reliable than the expression parser in
80+ // many cases and it is faster.
81+ lldb::SBValue value = frame.GetValueForVariablePath (
82+ expression.data (), lldb::eDynamicDontRunTarget);
83+
84+ // Freeze dry the value in case users expand it later in the debug console
85+ if (value.GetError ().Success () && arguments.context == eEvaluateContextRepl)
86+ value = value.Persist ();
87+
88+ if (value.GetError ().Fail () && arguments.context != eEvaluateContextHover)
89+ value = frame.EvaluateExpression (expression.data ());
90+
91+ if (value.GetError ().Fail ()) {
92+ // This error object must live until we're done with the pointer returned
93+ // by GetCString().
94+ lldb::SBError error = value.GetError ();
95+ const char *error_cstr = error.GetCString ();
96+ return make_error<DAPError>(
97+ error_cstr && error_cstr[0 ] ? error_cstr : " evaluate failed" );
23098 }
231- response.try_emplace (" body" , std::move (body));
232- dap.SendJSON (llvm::json::Value (std::move (response)));
99+
100+ VariableDescription desc (value,
101+ dap.configuration .enableAutoVariableSummaries );
102+ body.result = desc.GetResult (arguments.context );
103+ body.type = desc.display_type_name ;
104+ if (value.MightHaveChildren () || ValuePointsToCode (value))
105+ body.variablesReference = dap.variables .InsertVariable (
106+ value, /* is_permanent=*/ arguments.context == eEvaluateContextRepl);
107+ if (lldb::addr_t addr = value.GetLoadAddress (); addr != LLDB_INVALID_ADDRESS)
108+ body.memoryReference = EncodeMemoryReference (addr);
109+
110+ if (ValuePointsToCode (value) &&
111+ body.variablesReference != LLDB_DAP_INVALID_VARRERF)
112+ body.valueLocationReference = body.variablesReference ;
113+
114+ return body;
233115}
116+
234117} // namespace lldb_dap
0 commit comments