| //===-- EvaluateRequestHandler.cpp ----------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "DAP.h" |
| #include "EventHelper.h" |
| #include "JSONUtils.h" |
| #include "LLDBUtils.h" |
| #include "Protocol/ProtocolRequests.h" |
| #include "Protocol/ProtocolTypes.h" |
| #include "RequestHandler.h" |
| #include "lldb/lldb-enumerations.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/Support/Error.h" |
| |
| using namespace llvm; |
| using namespace lldb_dap; |
| using namespace lldb_dap::protocol; |
| |
| namespace lldb_dap { |
| |
| /// Evaluates the given expression in the context of a stack frame. |
| /// |
| /// The expression has access to any variables and arguments that are in scope. |
| Expected<EvaluateResponseBody> |
| EvaluateRequestHandler::Run(const EvaluateArguments &arguments) const { |
| EvaluateResponseBody body; |
| lldb::SBFrame frame = dap.GetLLDBFrame(arguments.frameId); |
| std::string expression = arguments.expression; |
| bool repeat_last_command = |
| expression.empty() && dap.last_nonempty_var_expression.empty(); |
| |
| if (arguments.context == protocol::eEvaluateContextRepl && |
| (repeat_last_command || |
| (!expression.empty() && |
| dap.DetectReplMode(frame, expression, false) == ReplMode::Command))) { |
| // Since the current expression is not for a variable, clear the |
| // last_nonempty_var_expression field. |
| dap.last_nonempty_var_expression.clear(); |
| // If we're evaluating a command relative to the current frame, set the |
| // focus_tid to the current frame for any thread related events. |
| if (frame.IsValid()) { |
| dap.focus_tid = frame.GetThread().GetThreadID(); |
| } |
| |
| bool required_command_failed = false; |
| body.result = RunLLDBCommands( |
| dap.debugger, llvm::StringRef(), {expression}, required_command_failed, |
| /*parse_command_directives=*/false, /*echo_commands=*/false); |
| return body; |
| } |
| |
| if (arguments.context == eEvaluateContextRepl) { |
| // If the expression is empty and the last expression was for a |
| // variable, set the expression to the previous expression (repeat the |
| // evaluation); otherwise save the current non-empty expression for the |
| // next (possibly empty) variable expression. |
| if (expression.empty()) |
| expression = dap.last_nonempty_var_expression; |
| else |
| dap.last_nonempty_var_expression = expression; |
| } |
| |
| // Always try to get the answer from the local variables if possible. If |
| // this fails, then if the context is not "hover", actually evaluate an |
| // expression using the expression parser. |
| // |
| // "frame variable" is more reliable than the expression parser in |
| // many cases and it is faster. |
| lldb::SBValue value = frame.GetValueForVariablePath( |
| expression.data(), lldb::eDynamicDontRunTarget); |
| |
| // Freeze dry the value in case users expand it later in the debug console |
| if (value.GetError().Success() && arguments.context == eEvaluateContextRepl) |
| value = value.Persist(); |
| |
| if (value.GetError().Fail() && arguments.context != eEvaluateContextHover) |
| value = frame.EvaluateExpression(expression.data()); |
| |
| if (value.GetError().Fail()) |
| return ToError(value.GetError(), /*show_user=*/false); |
| |
| const bool hex = arguments.format ? arguments.format->hex : false; |
| |
| VariableDescription desc(value, dap.configuration.enableAutoVariableSummaries, |
| hex); |
| |
| body.result = desc.GetResult(arguments.context); |
| body.type = desc.display_type_name; |
| |
| if (value.MightHaveChildren() || ValuePointsToCode(value)) |
| body.variablesReference = dap.variables.InsertVariable( |
| value, /*is_permanent=*/arguments.context == eEvaluateContextRepl); |
| |
| if (lldb::addr_t addr = value.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) |
| body.memoryReference = EncodeMemoryReference(addr); |
| |
| if (ValuePointsToCode(value) && |
| body.variablesReference != LLDB_DAP_INVALID_VAR_REF) |
| body.valueLocationReference = PackLocation(body.variablesReference, true); |
| |
| return body; |
| } |
| |
| } // namespace lldb_dap |