1cfca06d7SDimitry Andric //===-- CommandObjectExpression.cpp ---------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f3fbd1c0SDimitry Andric #include "llvm/ADT/StringRef.h"
10f3fbd1c0SDimitry Andric
11f3fbd1c0SDimitry Andric #include "CommandObjectExpression.h"
1214f1b3e8SDimitry Andric #include "lldb/Core/Debugger.h"
137fa27ce4SDimitry Andric #include "lldb/Expression/ExpressionVariable.h"
14e81d9d49SDimitry Andric #include "lldb/Expression/REPL.h"
1514f1b3e8SDimitry Andric #include "lldb/Expression/UserExpression.h"
1674a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
17f034231aSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
184b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
19f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
20f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
2114f1b3e8SDimitry Andric #include "lldb/Target/Language.h"
22f034231aSEd Maste #include "lldb/Target/Process.h"
23f034231aSEd Maste #include "lldb/Target/StackFrame.h"
24f034231aSEd Maste #include "lldb/Target/Target.h"
257fa27ce4SDimitry Andric #include "lldb/lldb-enumerations.h"
267fa27ce4SDimitry Andric #include "lldb/lldb-private-enumerations.h"
27f034231aSEd Maste
28f034231aSEd Maste using namespace lldb;
29f034231aSEd Maste using namespace lldb_private;
30f034231aSEd Maste
31145449b1SDimitry Andric CommandObjectExpression::CommandOptions::CommandOptions() = default;
32f034231aSEd Maste
33f3fbd1c0SDimitry Andric CommandObjectExpression::CommandOptions::~CommandOptions() = default;
34f034231aSEd Maste
35ead24645SDimitry Andric #define LLDB_OPTIONS_expression
36ead24645SDimitry Andric #include "CommandOptions.inc"
37f034231aSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)38b76161e4SDimitry Andric Status CommandObjectExpression::CommandOptions::SetOptionValue(
3914f1b3e8SDimitry Andric uint32_t option_idx, llvm::StringRef option_arg,
4014f1b3e8SDimitry Andric ExecutionContext *execution_context) {
41b76161e4SDimitry Andric Status error;
42f034231aSEd Maste
4314f1b3e8SDimitry Andric const int short_option = GetDefinitions()[option_idx].short_option;
44f034231aSEd Maste
4514f1b3e8SDimitry Andric switch (short_option) {
46e81d9d49SDimitry Andric case 'l':
47e81d9d49SDimitry Andric language = Language::GetLanguageTypeFromString(option_arg);
48e3b55780SDimitry Andric if (language == eLanguageTypeUnknown) {
49e3b55780SDimitry Andric StreamString sstr;
50e3b55780SDimitry Andric sstr.Printf("unknown language type: '%s' for expression. "
51e3b55780SDimitry Andric "List of supported languages:\n",
5214f1b3e8SDimitry Andric option_arg.str().c_str());
53e3b55780SDimitry Andric
54e3b55780SDimitry Andric Language::PrintSupportedLanguagesForExpressions(sstr, " ", "\n");
55e3b55780SDimitry Andric error.SetErrorString(sstr.GetString());
56e3b55780SDimitry Andric }
57e81d9d49SDimitry Andric break;
58f034231aSEd Maste
5914f1b3e8SDimitry Andric case 'a': {
60f034231aSEd Maste bool success;
61f034231aSEd Maste bool result;
62f73363f1SDimitry Andric result = OptionArgParser::ToBoolean(option_arg, true, &success);
63f034231aSEd Maste if (!success)
6414f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
6514f1b3e8SDimitry Andric "invalid all-threads value setting: \"%s\"",
6614f1b3e8SDimitry Andric option_arg.str().c_str());
67f034231aSEd Maste else
68f034231aSEd Maste try_all_threads = result;
6914f1b3e8SDimitry Andric } break;
70f034231aSEd Maste
7114f1b3e8SDimitry Andric case 'i': {
72f034231aSEd Maste bool success;
73f73363f1SDimitry Andric bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
74f034231aSEd Maste if (success)
75f034231aSEd Maste ignore_breakpoints = tmp_value;
76f034231aSEd Maste else
7714f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
7814f1b3e8SDimitry Andric "could not convert \"%s\" to a boolean value.",
7914f1b3e8SDimitry Andric option_arg.str().c_str());
80f034231aSEd Maste break;
81f034231aSEd Maste }
82f3fbd1c0SDimitry Andric
8314f1b3e8SDimitry Andric case 'j': {
84f3fbd1c0SDimitry Andric bool success;
85f73363f1SDimitry Andric bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
86f3fbd1c0SDimitry Andric if (success)
87f3fbd1c0SDimitry Andric allow_jit = tmp_value;
88f3fbd1c0SDimitry Andric else
8914f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
9014f1b3e8SDimitry Andric "could not convert \"%s\" to a boolean value.",
9114f1b3e8SDimitry Andric option_arg.str().c_str());
92f3fbd1c0SDimitry Andric break;
93f3fbd1c0SDimitry Andric }
94f3fbd1c0SDimitry Andric
95f034231aSEd Maste case 't':
9614f1b3e8SDimitry Andric if (option_arg.getAsInteger(0, timeout)) {
9714f1b3e8SDimitry Andric timeout = 0;
9814f1b3e8SDimitry Andric error.SetErrorStringWithFormat("invalid timeout setting \"%s\"",
9914f1b3e8SDimitry Andric option_arg.str().c_str());
100f034231aSEd Maste }
101f034231aSEd Maste break;
102f034231aSEd Maste
10314f1b3e8SDimitry Andric case 'u': {
104f034231aSEd Maste bool success;
105f73363f1SDimitry Andric bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
106f034231aSEd Maste if (success)
107f034231aSEd Maste unwind_on_error = tmp_value;
108f034231aSEd Maste else
10914f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
11014f1b3e8SDimitry Andric "could not convert \"%s\" to a boolean value.",
11114f1b3e8SDimitry Andric option_arg.str().c_str());
112f034231aSEd Maste break;
113f034231aSEd Maste }
114f21a844fSEd Maste
115f21a844fSEd Maste case 'v':
11614f1b3e8SDimitry Andric if (option_arg.empty()) {
117f21a844fSEd Maste m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
118f21a844fSEd Maste break;
119f21a844fSEd Maste }
120f73363f1SDimitry Andric m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity)
121f73363f1SDimitry Andric OptionArgParser::ToOptionEnum(
12214f1b3e8SDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
123f21a844fSEd Maste if (!error.Success())
12414f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
12514f1b3e8SDimitry Andric "unrecognized value for description-verbosity '%s'",
12614f1b3e8SDimitry Andric option_arg.str().c_str());
127f21a844fSEd Maste break;
128f21a844fSEd Maste
129f21a844fSEd Maste case 'g':
130f21a844fSEd Maste debug = true;
131f21a844fSEd Maste unwind_on_error = false;
132f21a844fSEd Maste ignore_breakpoints = false;
133f21a844fSEd Maste break;
134f21a844fSEd Maste
135f3fbd1c0SDimitry Andric case 'p':
136f3fbd1c0SDimitry Andric top_level = true;
137f3fbd1c0SDimitry Andric break;
138f3fbd1c0SDimitry Andric
13914f1b3e8SDimitry Andric case 'X': {
140f3fbd1c0SDimitry Andric bool success;
141f73363f1SDimitry Andric bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
142f3fbd1c0SDimitry Andric if (success)
143f3fbd1c0SDimitry Andric auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;
144f3fbd1c0SDimitry Andric else
14514f1b3e8SDimitry Andric error.SetErrorStringWithFormat(
14614f1b3e8SDimitry Andric "could not convert \"%s\" to a boolean value.",
14714f1b3e8SDimitry Andric option_arg.str().c_str());
148f3fbd1c0SDimitry Andric break;
149f3fbd1c0SDimitry Andric }
150f3fbd1c0SDimitry Andric
1517fa27ce4SDimitry Andric case '\x01': {
1527fa27ce4SDimitry Andric bool success;
1537fa27ce4SDimitry Andric bool persist_result =
1547fa27ce4SDimitry Andric OptionArgParser::ToBoolean(option_arg, true, &success);
1557fa27ce4SDimitry Andric if (success)
1567fa27ce4SDimitry Andric suppress_persistent_result = !persist_result ? eLazyBoolYes : eLazyBoolNo;
1577fa27ce4SDimitry Andric else
1587fa27ce4SDimitry Andric error.SetErrorStringWithFormat(
1597fa27ce4SDimitry Andric "could not convert \"%s\" to a boolean value.",
1607fa27ce4SDimitry Andric option_arg.str().c_str());
1617fa27ce4SDimitry Andric break;
1627fa27ce4SDimitry Andric }
1637fa27ce4SDimitry Andric
164f034231aSEd Maste default:
165ead24645SDimitry Andric llvm_unreachable("Unimplemented option");
166f034231aSEd Maste }
167f034231aSEd Maste
168f034231aSEd Maste return error;
169f034231aSEd Maste }
170f034231aSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)17114f1b3e8SDimitry Andric void CommandObjectExpression::CommandOptions::OptionParsingStarting(
17214f1b3e8SDimitry Andric ExecutionContext *execution_context) {
17314f1b3e8SDimitry Andric auto process_sp =
17414f1b3e8SDimitry Andric execution_context ? execution_context->GetProcessSP() : ProcessSP();
17514f1b3e8SDimitry Andric if (process_sp) {
17614f1b3e8SDimitry Andric ignore_breakpoints = process_sp->GetIgnoreBreakpointsInExpressions();
17714f1b3e8SDimitry Andric unwind_on_error = process_sp->GetUnwindOnErrorInExpressions();
17814f1b3e8SDimitry Andric } else {
1790cac4ca3SEd Maste ignore_breakpoints = true;
180f034231aSEd Maste unwind_on_error = true;
181f034231aSEd Maste }
182f034231aSEd Maste
183f034231aSEd Maste show_summary = true;
184f034231aSEd Maste try_all_threads = true;
185f034231aSEd Maste timeout = 0;
186f21a844fSEd Maste debug = false;
187e81d9d49SDimitry Andric language = eLanguageTypeUnknown;
188f21a844fSEd Maste m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
189f3fbd1c0SDimitry Andric auto_apply_fixits = eLazyBoolCalculate;
190f3fbd1c0SDimitry Andric top_level = false;
191f3fbd1c0SDimitry Andric allow_jit = true;
1927fa27ce4SDimitry Andric suppress_persistent_result = eLazyBoolCalculate;
193f034231aSEd Maste }
194f034231aSEd Maste
19514f1b3e8SDimitry Andric llvm::ArrayRef<OptionDefinition>
GetDefinitions()19614f1b3e8SDimitry Andric CommandObjectExpression::CommandOptions::GetDefinitions() {
197e3b55780SDimitry Andric return llvm::ArrayRef(g_expression_options);
198f034231aSEd Maste }
199f034231aSEd Maste
2007fa27ce4SDimitry Andric EvaluateExpressionOptions
GetEvaluateExpressionOptions(const Target & target,const OptionGroupValueObjectDisplay & display_opts)2017fa27ce4SDimitry Andric CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
2027fa27ce4SDimitry Andric const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
2037fa27ce4SDimitry Andric EvaluateExpressionOptions options;
2047fa27ce4SDimitry Andric options.SetCoerceToId(display_opts.use_objc);
2057fa27ce4SDimitry Andric options.SetUnwindOnError(unwind_on_error);
2067fa27ce4SDimitry Andric options.SetIgnoreBreakpoints(ignore_breakpoints);
2077fa27ce4SDimitry Andric options.SetKeepInMemory(true);
2087fa27ce4SDimitry Andric options.SetUseDynamic(display_opts.use_dynamic);
2097fa27ce4SDimitry Andric options.SetTryAllThreads(try_all_threads);
2107fa27ce4SDimitry Andric options.SetDebug(debug);
2117fa27ce4SDimitry Andric options.SetLanguage(language);
2127fa27ce4SDimitry Andric options.SetExecutionPolicy(
2137fa27ce4SDimitry Andric allow_jit ? EvaluateExpressionOptions::default_execution_policy
2147fa27ce4SDimitry Andric : lldb_private::eExecutionPolicyNever);
2157fa27ce4SDimitry Andric
2167fa27ce4SDimitry Andric bool auto_apply_fixits;
2177fa27ce4SDimitry Andric if (this->auto_apply_fixits == eLazyBoolCalculate)
2187fa27ce4SDimitry Andric auto_apply_fixits = target.GetEnableAutoApplyFixIts();
2197fa27ce4SDimitry Andric else
2207fa27ce4SDimitry Andric auto_apply_fixits = this->auto_apply_fixits == eLazyBoolYes;
2217fa27ce4SDimitry Andric
2227fa27ce4SDimitry Andric options.SetAutoApplyFixIts(auto_apply_fixits);
2237fa27ce4SDimitry Andric options.SetRetriesWithFixIts(target.GetNumberOfRetriesWithFixits());
2247fa27ce4SDimitry Andric
2257fa27ce4SDimitry Andric if (top_level)
2267fa27ce4SDimitry Andric options.SetExecutionPolicy(eExecutionPolicyTopLevel);
2277fa27ce4SDimitry Andric
2287fa27ce4SDimitry Andric // If there is any chance we are going to stop and want to see what went
2297fa27ce4SDimitry Andric // wrong with our expression, we should generate debug info
2307fa27ce4SDimitry Andric if (!ignore_breakpoints || !unwind_on_error)
2317fa27ce4SDimitry Andric options.SetGenerateDebugInfo(true);
2327fa27ce4SDimitry Andric
2337fa27ce4SDimitry Andric if (timeout > 0)
2347fa27ce4SDimitry Andric options.SetTimeout(std::chrono::microseconds(timeout));
2357fa27ce4SDimitry Andric else
2367fa27ce4SDimitry Andric options.SetTimeout(std::nullopt);
2377fa27ce4SDimitry Andric return options;
2387fa27ce4SDimitry Andric }
2397fa27ce4SDimitry Andric
ShouldSuppressResult(const OptionGroupValueObjectDisplay & display_opts) const2407fa27ce4SDimitry Andric bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
2417fa27ce4SDimitry Andric const OptionGroupValueObjectDisplay &display_opts) const {
2427fa27ce4SDimitry Andric // Explicitly disabling persistent results takes precedence over the
2437fa27ce4SDimitry Andric // m_verbosity/use_objc logic.
2447fa27ce4SDimitry Andric if (suppress_persistent_result != eLazyBoolCalculate)
2457fa27ce4SDimitry Andric return suppress_persistent_result == eLazyBoolYes;
2467fa27ce4SDimitry Andric
2477fa27ce4SDimitry Andric return display_opts.use_objc &&
2487fa27ce4SDimitry Andric m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
2497fa27ce4SDimitry Andric }
2507fa27ce4SDimitry Andric
CommandObjectExpression(CommandInterpreter & interpreter)25114f1b3e8SDimitry Andric CommandObjectExpression::CommandObjectExpression(
25214f1b3e8SDimitry Andric CommandInterpreter &interpreter)
253706b4fc4SDimitry Andric : CommandObjectRaw(interpreter, "expression",
254706b4fc4SDimitry Andric "Evaluate an expression on the current "
25514f1b3e8SDimitry Andric "thread. Displays any returned value "
25614f1b3e8SDimitry Andric "with LLDB's default formatting.",
257706b4fc4SDimitry Andric "",
258706b4fc4SDimitry Andric eCommandProcessMustBePaused | eCommandTryTargetAPILock),
259866dcdacSEd Maste IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
2606f8fc217SDimitry Andric m_format_options(eFormatDefault),
26114f1b3e8SDimitry Andric m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
26214f1b3e8SDimitry Andric true),
26308e8dd7bSDimitry Andric m_expr_line_count(0) {
264f034231aSEd Maste SetHelpLong(
265027f1c96SDimitry Andric R"(
266ef5d0b5eSDimitry Andric Single and multi-line expressions:
267ef5d0b5eSDimitry Andric
268ef5d0b5eSDimitry Andric )"
269ef5d0b5eSDimitry Andric " The expression provided on the command line must be a complete expression \
270ef5d0b5eSDimitry Andric with no newlines. To evaluate a multi-line expression, \
271ef5d0b5eSDimitry Andric hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
272ef5d0b5eSDimitry Andric Hit return on an empty line to end the multi-line expression."
273ef5d0b5eSDimitry Andric
274ef5d0b5eSDimitry Andric R"(
275ef5d0b5eSDimitry Andric
276027f1c96SDimitry Andric Timeouts:
277027f1c96SDimitry Andric
27814f1b3e8SDimitry Andric )"
27914f1b3e8SDimitry Andric " If the expression can be evaluated statically (without running code) then it will be. \
280027f1c96SDimitry Andric Otherwise, by default the expression will run on the current thread with a short timeout: \
281027f1c96SDimitry Andric currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted \
282027f1c96SDimitry Andric and resumed with all threads running. You can use the -a option to disable retrying on all \
28314f1b3e8SDimitry Andric threads. You can use the -t option to set a shorter timeout."
28414f1b3e8SDimitry Andric R"(
285027f1c96SDimitry Andric
286027f1c96SDimitry Andric User defined variables:
287027f1c96SDimitry Andric
28814f1b3e8SDimitry Andric )"
28914f1b3e8SDimitry Andric " You can define your own variables for convenience or to be used in subsequent expressions. \
290027f1c96SDimitry Andric You define them the same way you would define variables in C. If the first character of \
291027f1c96SDimitry Andric your user defined variable is a $, then the variable's value will be available in future \
29214f1b3e8SDimitry Andric expressions, otherwise it will just be available in the current expression."
29314f1b3e8SDimitry Andric R"(
294027f1c96SDimitry Andric
295027f1c96SDimitry Andric Continuing evaluation after a breakpoint:
296027f1c96SDimitry Andric
29714f1b3e8SDimitry Andric )"
29814f1b3e8SDimitry Andric " If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
299027f1c96SDimitry Andric you are done with your investigation, you can either remove the expression execution frames \
300027f1c96SDimitry Andric from the stack with \"thread return -x\" or if you are still interested in the expression result \
301027f1c96SDimitry Andric you can issue the \"continue\" command and the expression evaluation will complete and the \
302027f1c96SDimitry Andric expression result will be available using the \"thread.completed-expression\" key in the thread \
30314f1b3e8SDimitry Andric format."
304ef5d0b5eSDimitry Andric
30514f1b3e8SDimitry Andric R"(
306027f1c96SDimitry Andric
307027f1c96SDimitry Andric Examples:
308027f1c96SDimitry Andric
309027f1c96SDimitry Andric expr my_struct->a = my_array[3]
310027f1c96SDimitry Andric expr -f bin -- (index * 8) + 5
311027f1c96SDimitry Andric expr unsigned int $foo = 5
31214f1b3e8SDimitry Andric expr char c[] = \"foo\"; c[0])");
313f034231aSEd Maste
314ac9a064cSDimitry Andric AddSimpleArgumentList(eArgTypeExpression);
315f034231aSEd Maste
316f034231aSEd Maste // Add the "--format" and "--gdb-format"
31714f1b3e8SDimitry Andric m_option_group.Append(&m_format_options,
31814f1b3e8SDimitry Andric OptionGroupFormat::OPTION_GROUP_FORMAT |
31914f1b3e8SDimitry Andric OptionGroupFormat::OPTION_GROUP_GDB_FMT,
32014f1b3e8SDimitry Andric LLDB_OPT_SET_1);
321f034231aSEd Maste m_option_group.Append(&m_command_options);
32214f1b3e8SDimitry Andric m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
32314f1b3e8SDimitry Andric LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
324e81d9d49SDimitry Andric m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
325f034231aSEd Maste m_option_group.Finalize();
326f034231aSEd Maste }
327f034231aSEd Maste
328f3fbd1c0SDimitry Andric CommandObjectExpression::~CommandObjectExpression() = default;
329f034231aSEd Maste
GetOptions()33014f1b3e8SDimitry Andric Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
331f034231aSEd Maste
HandleCompletion(CompletionRequest & request)332ead24645SDimitry Andric void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
33394994d37SDimitry Andric EvaluateExpressionOptions options;
33494994d37SDimitry Andric options.SetCoerceToId(m_varobj_options.use_objc);
33594994d37SDimitry Andric options.SetLanguage(m_command_options.language);
33694994d37SDimitry Andric options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
33794994d37SDimitry Andric options.SetAutoApplyFixIts(false);
33894994d37SDimitry Andric options.SetGenerateDebugInfo(false);
33994994d37SDimitry Andric
340344a3780SDimitry Andric ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
34194994d37SDimitry Andric
342344a3780SDimitry Andric // Get out before we start doing things that expect a valid frame pointer.
343344a3780SDimitry Andric if (exe_ctx.GetFramePtr() == nullptr)
344ead24645SDimitry Andric return;
34594994d37SDimitry Andric
346b60736ecSDimitry Andric Target *exe_target = exe_ctx.GetTargetPtr();
347b60736ecSDimitry Andric Target &target = exe_target ? *exe_target : GetDummyTarget();
34894994d37SDimitry Andric
34994994d37SDimitry Andric unsigned cursor_pos = request.GetRawCursorPos();
350cfca06d7SDimitry Andric // Get the full user input including the suffix. The suffix is necessary
351cfca06d7SDimitry Andric // as OptionsWithRaw will use it to detect if the cursor is cursor is in the
352cfca06d7SDimitry Andric // argument part of in the raw input part of the arguments. If we cut of
353cfca06d7SDimitry Andric // of the suffix then "expr -arg[cursor] --" would interpret the "-arg" as
354cfca06d7SDimitry Andric // the raw input (as the "--" is hidden in the suffix).
355cfca06d7SDimitry Andric llvm::StringRef code = request.GetRawLineWithUnusedSuffix();
35694994d37SDimitry Andric
35794994d37SDimitry Andric const std::size_t original_code_size = code.size();
35894994d37SDimitry Andric
35994994d37SDimitry Andric // Remove the first token which is 'expr' or some alias/abbreviation of that.
36094994d37SDimitry Andric code = llvm::getToken(code).second.ltrim();
36194994d37SDimitry Andric OptionsWithRaw args(code);
36294994d37SDimitry Andric code = args.GetRawPart();
36394994d37SDimitry Andric
36494994d37SDimitry Andric // The position where the expression starts in the command line.
36594994d37SDimitry Andric assert(original_code_size >= code.size());
36694994d37SDimitry Andric std::size_t raw_start = original_code_size - code.size();
36794994d37SDimitry Andric
36894994d37SDimitry Andric // Check if the cursor is actually in the expression string, and if not, we
36994994d37SDimitry Andric // exit.
37094994d37SDimitry Andric // FIXME: We should complete the options here.
37194994d37SDimitry Andric if (cursor_pos < raw_start)
372ead24645SDimitry Andric return;
37394994d37SDimitry Andric
37494994d37SDimitry Andric // Make the cursor_pos again relative to the start of the code string.
37594994d37SDimitry Andric assert(cursor_pos >= raw_start);
37694994d37SDimitry Andric cursor_pos -= raw_start;
37794994d37SDimitry Andric
37894994d37SDimitry Andric auto language = exe_ctx.GetFrameRef().GetLanguage();
37994994d37SDimitry Andric
38094994d37SDimitry Andric Status error;
381b60736ecSDimitry Andric lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage(
38294994d37SDimitry Andric code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
3835f29bb8aSDimitry Andric options, nullptr, error));
38494994d37SDimitry Andric if (error.Fail())
385ead24645SDimitry Andric return;
38694994d37SDimitry Andric
38794994d37SDimitry Andric expr->Complete(exe_ctx, request, cursor_pos);
38894994d37SDimitry Andric }
38994994d37SDimitry Andric
390b76161e4SDimitry Andric static lldb_private::Status
CanBeUsedForElementCountPrinting(ValueObject & valobj)39114f1b3e8SDimitry Andric CanBeUsedForElementCountPrinting(ValueObject &valobj) {
392f3fbd1c0SDimitry Andric CompilerType type(valobj.GetCompilerType());
393f3fbd1c0SDimitry Andric CompilerType pointee;
394f3fbd1c0SDimitry Andric if (!type.IsPointerType(&pointee))
395b76161e4SDimitry Andric return Status("as it does not refer to a pointer");
396f3fbd1c0SDimitry Andric if (pointee.IsVoidType())
397b76161e4SDimitry Andric return Status("as it refers to a pointer to void");
398b76161e4SDimitry Andric return Status();
399f3fbd1c0SDimitry Andric }
400f3fbd1c0SDimitry Andric
EvaluateExpression(llvm::StringRef expr,Stream & output_stream,Stream & error_stream,CommandReturnObject & result)401cfca06d7SDimitry Andric bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
402cfca06d7SDimitry Andric Stream &output_stream,
403cfca06d7SDimitry Andric Stream &error_stream,
404cfca06d7SDimitry Andric CommandReturnObject &result) {
405cfca06d7SDimitry Andric // Don't use m_exe_ctx as this might be called asynchronously after the
406cfca06d7SDimitry Andric // command object DoExecute has finished when doing multi-line expression
407cfca06d7SDimitry Andric // that use an input reader...
408cfca06d7SDimitry Andric ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
409b60736ecSDimitry Andric Target *exe_target = exe_ctx.GetTargetPtr();
410b60736ecSDimitry Andric Target &target = exe_target ? *exe_target : GetDummyTarget();
411cfca06d7SDimitry Andric
412cfca06d7SDimitry Andric lldb::ValueObjectSP result_valobj_sp;
413cfca06d7SDimitry Andric StackFrame *frame = exe_ctx.GetFramePtr();
414cfca06d7SDimitry Andric
415344a3780SDimitry Andric if (m_command_options.top_level && !m_command_options.allow_jit) {
416344a3780SDimitry Andric result.AppendErrorWithFormat(
417344a3780SDimitry Andric "Can't disable JIT compilation for top-level expressions.\n");
418344a3780SDimitry Andric return false;
419344a3780SDimitry Andric }
420344a3780SDimitry Andric
4217fa27ce4SDimitry Andric EvaluateExpressionOptions eval_options =
4227fa27ce4SDimitry Andric m_command_options.GetEvaluateExpressionOptions(target, m_varobj_options);
4237fa27ce4SDimitry Andric // This command manually removes the result variable, make sure expression
4247fa27ce4SDimitry Andric // evaluation doesn't do it first.
4257fa27ce4SDimitry Andric eval_options.SetSuppressPersistentResult(false);
4267fa27ce4SDimitry Andric
427b60736ecSDimitry Andric ExpressionResults success = target.EvaluateExpression(
4287fa27ce4SDimitry Andric expr, frame, result_valobj_sp, eval_options, &m_fixed_expression);
429f3fbd1c0SDimitry Andric
430b1c73532SDimitry Andric // Only mention Fix-Its if the expression evaluator applied them.
431b1c73532SDimitry Andric // Compiler errors refer to the final expression after applying Fix-It(s).
432b60736ecSDimitry Andric if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
433b1c73532SDimitry Andric error_stream << " Evaluated this expression after applying Fix-It(s):\n";
434b1c73532SDimitry Andric error_stream << " " << m_fixed_expression << "\n";
435f3fbd1c0SDimitry Andric }
436f034231aSEd Maste
43714f1b3e8SDimitry Andric if (result_valobj_sp) {
438f034231aSEd Maste Format format = m_format_options.GetFormat();
439f034231aSEd Maste
44014f1b3e8SDimitry Andric if (result_valobj_sp->GetError().Success()) {
44114f1b3e8SDimitry Andric if (format != eFormatVoid) {
442f034231aSEd Maste if (format != eFormatDefault)
443f034231aSEd Maste result_valobj_sp->SetFormat(format);
444f034231aSEd Maste
44514f1b3e8SDimitry Andric if (m_varobj_options.elem_count > 0) {
446b76161e4SDimitry Andric Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
44714f1b3e8SDimitry Andric if (error.Fail()) {
448cfca06d7SDimitry Andric result.AppendErrorWithFormat(
44914f1b3e8SDimitry Andric "expression cannot be used with --element-count %s\n",
45014f1b3e8SDimitry Andric error.AsCString(""));
451f3fbd1c0SDimitry Andric return false;
452f3fbd1c0SDimitry Andric }
453f3fbd1c0SDimitry Andric }
454f3fbd1c0SDimitry Andric
4557fa27ce4SDimitry Andric bool suppress_result =
4567fa27ce4SDimitry Andric m_command_options.ShouldSuppressResult(m_varobj_options);
4577fa27ce4SDimitry Andric
45814f1b3e8SDimitry Andric DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
45914f1b3e8SDimitry Andric m_command_options.m_verbosity, format));
4607fa27ce4SDimitry Andric options.SetHideRootName(suppress_result);
46114f1b3e8SDimitry Andric options.SetVariableFormatDisplayLanguage(
46214f1b3e8SDimitry Andric result_valobj_sp->GetPreferredDisplayLanguage());
463f034231aSEd Maste
464ac9a064cSDimitry Andric if (llvm::Error error =
465ac9a064cSDimitry Andric result_valobj_sp->Dump(output_stream, options)) {
466ac9a064cSDimitry Andric result.AppendError(toString(std::move(error)));
467ac9a064cSDimitry Andric return false;
468ac9a064cSDimitry Andric }
469f21a844fSEd Maste
4707fa27ce4SDimitry Andric if (suppress_result)
4717fa27ce4SDimitry Andric if (auto result_var_sp =
4727fa27ce4SDimitry Andric target.GetPersistentVariable(result_valobj_sp->GetName())) {
4737fa27ce4SDimitry Andric auto language = result_valobj_sp->GetPreferredDisplayLanguage();
4747fa27ce4SDimitry Andric if (auto *persistent_state =
4757fa27ce4SDimitry Andric target.GetPersistentExpressionStateForLanguage(language))
4767fa27ce4SDimitry Andric persistent_state->RemovePersistentVariable(result_var_sp);
4777fa27ce4SDimitry Andric }
478cfca06d7SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
479f034231aSEd Maste }
48014f1b3e8SDimitry Andric } else {
48114f1b3e8SDimitry Andric if (result_valobj_sp->GetError().GetError() ==
48214f1b3e8SDimitry Andric UserExpression::kNoResult) {
4835f29bb8aSDimitry Andric if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) {
484cfca06d7SDimitry Andric error_stream.PutCString("(void)\n");
485f034231aSEd Maste }
486f034231aSEd Maste
487cfca06d7SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
48814f1b3e8SDimitry Andric } else {
489f034231aSEd Maste const char *error_cstr = result_valobj_sp->GetError().AsCString();
49014f1b3e8SDimitry Andric if (error_cstr && error_cstr[0]) {
491f034231aSEd Maste const size_t error_cstr_len = strlen(error_cstr);
492ead24645SDimitry Andric const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
493f034231aSEd Maste if (strstr(error_cstr, "error:") != error_cstr)
494cfca06d7SDimitry Andric error_stream.PutCString("error: ");
495cfca06d7SDimitry Andric error_stream.Write(error_cstr, error_cstr_len);
496f034231aSEd Maste if (!ends_with_newline)
497cfca06d7SDimitry Andric error_stream.EOL();
49814f1b3e8SDimitry Andric } else {
499cfca06d7SDimitry Andric error_stream.PutCString("error: unknown error\n");
500f034231aSEd Maste }
501f034231aSEd Maste
502cfca06d7SDimitry Andric result.SetStatus(eReturnStatusFailed);
503f034231aSEd Maste }
504f034231aSEd Maste }
505e3b55780SDimitry Andric } else {
506e3b55780SDimitry Andric error_stream.Printf("error: unknown error\n");
507f034231aSEd Maste }
508f034231aSEd Maste
509cfca06d7SDimitry Andric return (success != eExpressionSetupError &&
510cfca06d7SDimitry Andric success != eExpressionParseError);
511f034231aSEd Maste }
512f034231aSEd Maste
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)51314f1b3e8SDimitry Andric void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
51414f1b3e8SDimitry Andric std::string &line) {
515866dcdacSEd Maste io_handler.SetIsDone(true);
516ead24645SDimitry Andric StreamFileSP output_sp = io_handler.GetOutputStreamFileSP();
517ead24645SDimitry Andric StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
518866dcdacSEd Maste
519cfca06d7SDimitry Andric CommandReturnObject return_obj(
520cfca06d7SDimitry Andric GetCommandInterpreter().GetDebugger().GetUseColor());
521cfca06d7SDimitry Andric EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj);
522866dcdacSEd Maste if (output_sp)
523866dcdacSEd Maste output_sp->Flush();
524866dcdacSEd Maste if (error_sp)
525866dcdacSEd Maste error_sp->Flush();
526866dcdacSEd Maste }
527866dcdacSEd Maste
IOHandlerIsInputComplete(IOHandler & io_handler,StringList & lines)52814f1b3e8SDimitry Andric bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
52914f1b3e8SDimitry Andric StringList &lines) {
530f3fbd1c0SDimitry Andric // An empty lines is used to indicate the end of input
531f3fbd1c0SDimitry Andric const size_t num_lines = lines.GetSize();
53214f1b3e8SDimitry Andric if (num_lines > 0 && lines[num_lines - 1].empty()) {
533f73363f1SDimitry Andric // Remove the last empty line from "lines" so it doesn't appear in our
534f73363f1SDimitry Andric // resulting input and return true to indicate we are done getting lines
535866dcdacSEd Maste lines.PopBack();
536f3fbd1c0SDimitry Andric return true;
537866dcdacSEd Maste }
538f3fbd1c0SDimitry Andric return false;
539866dcdacSEd Maste }
540866dcdacSEd Maste
GetMultilineExpression()54114f1b3e8SDimitry Andric void CommandObjectExpression::GetMultilineExpression() {
5420cac4ca3SEd Maste m_expr_lines.clear();
5430cac4ca3SEd Maste m_expr_line_count = 0;
5440cac4ca3SEd Maste
5450cac4ca3SEd Maste Debugger &debugger = GetCommandInterpreter().GetDebugger();
546205afe67SEd Maste bool color_prompt = debugger.GetUseColor();
5470cac4ca3SEd Maste const bool multiple_lines = true; // Get multiple lines
54814f1b3e8SDimitry Andric IOHandlerSP io_handler_sp(
54914f1b3e8SDimitry Andric new IOHandlerEditline(debugger, IOHandler::Type::Expression,
5500cac4ca3SEd Maste "lldb-expr", // Name of input reader for history
55114f1b3e8SDimitry Andric llvm::StringRef(), // No prompt
55214f1b3e8SDimitry Andric llvm::StringRef(), // Continuation prompt
55314f1b3e8SDimitry Andric multiple_lines, color_prompt,
5540cac4ca3SEd Maste 1, // Show line numbers starting at 1
555e3b55780SDimitry Andric *this));
5560cac4ca3SEd Maste
557ead24645SDimitry Andric StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP();
55814f1b3e8SDimitry Andric if (output_sp) {
55914f1b3e8SDimitry Andric output_sp->PutCString(
56014f1b3e8SDimitry Andric "Enter expressions, then terminate with an empty line to evaluate:\n");
5610cac4ca3SEd Maste output_sp->Flush();
5620cac4ca3SEd Maste }
563cfca06d7SDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp);
5640cac4ca3SEd Maste }
5650cac4ca3SEd Maste
5665f29bb8aSDimitry Andric static EvaluateExpressionOptions
GetExprOptions(ExecutionContext & ctx,CommandObjectExpression::CommandOptions command_options)5675f29bb8aSDimitry Andric GetExprOptions(ExecutionContext &ctx,
5685f29bb8aSDimitry Andric CommandObjectExpression::CommandOptions command_options) {
5695f29bb8aSDimitry Andric command_options.OptionParsingStarting(&ctx);
5705f29bb8aSDimitry Andric
5715f29bb8aSDimitry Andric // Default certain settings for REPL regardless of the global settings.
5725f29bb8aSDimitry Andric command_options.unwind_on_error = false;
5735f29bb8aSDimitry Andric command_options.ignore_breakpoints = false;
5745f29bb8aSDimitry Andric command_options.debug = false;
5755f29bb8aSDimitry Andric
5765f29bb8aSDimitry Andric EvaluateExpressionOptions expr_options;
5775f29bb8aSDimitry Andric expr_options.SetUnwindOnError(command_options.unwind_on_error);
5785f29bb8aSDimitry Andric expr_options.SetIgnoreBreakpoints(command_options.ignore_breakpoints);
5795f29bb8aSDimitry Andric expr_options.SetTryAllThreads(command_options.try_all_threads);
5805f29bb8aSDimitry Andric
5815f29bb8aSDimitry Andric if (command_options.timeout > 0)
5825f29bb8aSDimitry Andric expr_options.SetTimeout(std::chrono::microseconds(command_options.timeout));
5835f29bb8aSDimitry Andric else
584e3b55780SDimitry Andric expr_options.SetTimeout(std::nullopt);
5855f29bb8aSDimitry Andric
5865f29bb8aSDimitry Andric return expr_options;
5875f29bb8aSDimitry Andric }
5885f29bb8aSDimitry Andric
DoExecute(llvm::StringRef command,CommandReturnObject & result)589b1c73532SDimitry Andric void CommandObjectExpression::DoExecute(llvm::StringRef command,
59014f1b3e8SDimitry Andric CommandReturnObject &result) {
591f3fbd1c0SDimitry Andric m_fixed_expression.clear();
59214f1b3e8SDimitry Andric auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
59314f1b3e8SDimitry Andric m_option_group.NotifyOptionParsingStarting(&exe_ctx);
594f034231aSEd Maste
595f73363f1SDimitry Andric if (command.empty()) {
5960cac4ca3SEd Maste GetMultilineExpression();
597b1c73532SDimitry Andric return;
598f034231aSEd Maste }
599f034231aSEd Maste
600f73363f1SDimitry Andric OptionsWithRaw args(command);
601f73363f1SDimitry Andric llvm::StringRef expr = args.GetRawPart();
602f034231aSEd Maste
603f73363f1SDimitry Andric if (args.HasArgs()) {
604f73363f1SDimitry Andric if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
605b1c73532SDimitry Andric return;
606f034231aSEd Maste
60714f1b3e8SDimitry Andric if (m_repl_option.GetOptionValue().GetCurrentValue()) {
608706b4fc4SDimitry Andric Target &target = GetSelectedOrDummyTarget();
609e81d9d49SDimitry Andric // Drop into REPL
610e81d9d49SDimitry Andric m_expr_lines.clear();
611e81d9d49SDimitry Andric m_expr_line_count = 0;
612e81d9d49SDimitry Andric
613706b4fc4SDimitry Andric Debugger &debugger = target.GetDebugger();
614e81d9d49SDimitry Andric
61514f1b3e8SDimitry Andric // Check if the LLDB command interpreter is sitting on top of a REPL
616f73363f1SDimitry Andric // that launched it...
617f73363f1SDimitry Andric if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
618f73363f1SDimitry Andric IOHandler::Type::REPL)) {
61914f1b3e8SDimitry Andric // the LLDB command interpreter is sitting on top of a REPL that
620f73363f1SDimitry Andric // launched it, so just say the command interpreter is done and
621f73363f1SDimitry Andric // fall back to the existing REPL
622e81d9d49SDimitry Andric m_interpreter.GetIOHandler(false)->SetIsDone(true);
62314f1b3e8SDimitry Andric } else {
62414f1b3e8SDimitry Andric // We are launching the REPL on top of the current LLDB command
625f73363f1SDimitry Andric // interpreter, so just push one
626e81d9d49SDimitry Andric bool initialize = false;
627b76161e4SDimitry Andric Status repl_error;
628706b4fc4SDimitry Andric REPLSP repl_sp(target.GetREPL(repl_error, m_command_options.language,
629f73363f1SDimitry Andric nullptr, false));
630e81d9d49SDimitry Andric
63114f1b3e8SDimitry Andric if (!repl_sp) {
632e81d9d49SDimitry Andric initialize = true;
633706b4fc4SDimitry Andric repl_sp = target.GetREPL(repl_error, m_command_options.language,
63414f1b3e8SDimitry Andric nullptr, true);
63514f1b3e8SDimitry Andric if (!repl_error.Success()) {
636e81d9d49SDimitry Andric result.SetError(repl_error);
637b1c73532SDimitry Andric return;
638e81d9d49SDimitry Andric }
639e81d9d49SDimitry Andric }
640e81d9d49SDimitry Andric
64114f1b3e8SDimitry Andric if (repl_sp) {
64214f1b3e8SDimitry Andric if (initialize) {
6435f29bb8aSDimitry Andric repl_sp->SetEvaluateOptions(
6445f29bb8aSDimitry Andric GetExprOptions(exe_ctx, m_command_options));
645e81d9d49SDimitry Andric repl_sp->SetFormatOptions(m_format_options);
646e81d9d49SDimitry Andric repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
647e81d9d49SDimitry Andric }
648e81d9d49SDimitry Andric
649e81d9d49SDimitry Andric IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
650e81d9d49SDimitry Andric io_handler_sp->SetIsDone(false);
651cfca06d7SDimitry Andric debugger.RunIOHandlerAsync(io_handler_sp);
65214f1b3e8SDimitry Andric } else {
65314f1b3e8SDimitry Andric repl_error.SetErrorStringWithFormat(
65414f1b3e8SDimitry Andric "Couldn't create a REPL for %s",
65514f1b3e8SDimitry Andric Language::GetNameForLanguageType(m_command_options.language));
656e81d9d49SDimitry Andric result.SetError(repl_error);
657b1c73532SDimitry Andric return;
658e81d9d49SDimitry Andric }
659e81d9d49SDimitry Andric }
660e81d9d49SDimitry Andric }
6610cac4ca3SEd Maste // No expression following options
662f73363f1SDimitry Andric else if (expr.empty()) {
6630cac4ca3SEd Maste GetMultilineExpression();
664b1c73532SDimitry Andric return;
6650cac4ca3SEd Maste }
666f034231aSEd Maste }
667f034231aSEd Maste
668ead24645SDimitry Andric Target &target = GetSelectedOrDummyTarget();
669cfca06d7SDimitry Andric if (EvaluateExpression(expr, result.GetOutputStream(),
670cfca06d7SDimitry Andric result.GetErrorStream(), result)) {
67114f1b3e8SDimitry Andric
672ead24645SDimitry Andric if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
673f3fbd1c0SDimitry Andric CommandHistory &history = m_interpreter.GetCommandHistory();
67414f1b3e8SDimitry Andric // FIXME: Can we figure out what the user actually typed (e.g. some alias
67514f1b3e8SDimitry Andric // for expr???)
676f3fbd1c0SDimitry Andric // If we can it would be nice to show that.
677f3fbd1c0SDimitry Andric std::string fixed_command("expression ");
678f73363f1SDimitry Andric if (args.HasArgs()) {
679f3fbd1c0SDimitry Andric // Add in any options that might have been in the original command:
680cfca06d7SDimitry Andric fixed_command.append(std::string(args.GetArgStringWithDelimiter()));
681f3fbd1c0SDimitry Andric fixed_command.append(m_fixed_expression);
682f73363f1SDimitry Andric } else
683f73363f1SDimitry Andric fixed_command.append(m_fixed_expression);
684f3fbd1c0SDimitry Andric history.AppendString(fixed_command);
685f3fbd1c0SDimitry Andric }
686b1c73532SDimitry Andric return;
687f3fbd1c0SDimitry Andric }
688f034231aSEd Maste result.SetStatus(eReturnStatusFailed);
689f034231aSEd Maste }
690