1dda28197Spatrick //===-- CommandObjectExpression.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "llvm/ADT/StringRef.h"
10061da546Spatrick
11061da546Spatrick #include "CommandObjectExpression.h"
12061da546Spatrick #include "lldb/Core/Debugger.h"
13061da546Spatrick #include "lldb/Expression/REPL.h"
14061da546Spatrick #include "lldb/Expression/UserExpression.h"
15061da546Spatrick #include "lldb/Host/OptionParser.h"
16061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
17*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
18061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
19061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
20061da546Spatrick #include "lldb/Target/Language.h"
21061da546Spatrick #include "lldb/Target/Process.h"
22061da546Spatrick #include "lldb/Target/StackFrame.h"
23061da546Spatrick #include "lldb/Target/Target.h"
24061da546Spatrick
25061da546Spatrick using namespace lldb;
26061da546Spatrick using namespace lldb_private;
27061da546Spatrick
28*f6aab3d8Srobert CommandObjectExpression::CommandOptions::CommandOptions() = default;
29061da546Spatrick
30061da546Spatrick CommandObjectExpression::CommandOptions::~CommandOptions() = default;
31061da546Spatrick
32061da546Spatrick #define LLDB_OPTIONS_expression
33061da546Spatrick #include "CommandOptions.inc"
34061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)35061da546Spatrick Status CommandObjectExpression::CommandOptions::SetOptionValue(
36061da546Spatrick uint32_t option_idx, llvm::StringRef option_arg,
37061da546Spatrick ExecutionContext *execution_context) {
38061da546Spatrick Status error;
39061da546Spatrick
40061da546Spatrick const int short_option = GetDefinitions()[option_idx].short_option;
41061da546Spatrick
42061da546Spatrick switch (short_option) {
43061da546Spatrick case 'l':
44061da546Spatrick language = Language::GetLanguageTypeFromString(option_arg);
45*f6aab3d8Srobert if (language == eLanguageTypeUnknown) {
46*f6aab3d8Srobert StreamString sstr;
47*f6aab3d8Srobert sstr.Printf("unknown language type: '%s' for expression. "
48*f6aab3d8Srobert "List of supported languages:\n",
49061da546Spatrick option_arg.str().c_str());
50*f6aab3d8Srobert
51*f6aab3d8Srobert Language::PrintSupportedLanguagesForExpressions(sstr, " ", "\n");
52*f6aab3d8Srobert error.SetErrorString(sstr.GetString());
53*f6aab3d8Srobert }
54061da546Spatrick break;
55061da546Spatrick
56061da546Spatrick case 'a': {
57061da546Spatrick bool success;
58061da546Spatrick bool result;
59061da546Spatrick result = OptionArgParser::ToBoolean(option_arg, true, &success);
60061da546Spatrick if (!success)
61061da546Spatrick error.SetErrorStringWithFormat(
62061da546Spatrick "invalid all-threads value setting: \"%s\"",
63061da546Spatrick option_arg.str().c_str());
64061da546Spatrick else
65061da546Spatrick try_all_threads = result;
66061da546Spatrick } break;
67061da546Spatrick
68061da546Spatrick case 'i': {
69061da546Spatrick bool success;
70061da546Spatrick bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
71061da546Spatrick if (success)
72061da546Spatrick ignore_breakpoints = tmp_value;
73061da546Spatrick else
74061da546Spatrick error.SetErrorStringWithFormat(
75061da546Spatrick "could not convert \"%s\" to a boolean value.",
76061da546Spatrick option_arg.str().c_str());
77061da546Spatrick break;
78061da546Spatrick }
79061da546Spatrick
80061da546Spatrick case 'j': {
81061da546Spatrick bool success;
82061da546Spatrick bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
83061da546Spatrick if (success)
84061da546Spatrick allow_jit = tmp_value;
85061da546Spatrick else
86061da546Spatrick error.SetErrorStringWithFormat(
87061da546Spatrick "could not convert \"%s\" to a boolean value.",
88061da546Spatrick option_arg.str().c_str());
89061da546Spatrick break;
90061da546Spatrick }
91061da546Spatrick
92061da546Spatrick case 't':
93061da546Spatrick if (option_arg.getAsInteger(0, timeout)) {
94061da546Spatrick timeout = 0;
95061da546Spatrick error.SetErrorStringWithFormat("invalid timeout setting \"%s\"",
96061da546Spatrick option_arg.str().c_str());
97061da546Spatrick }
98061da546Spatrick break;
99061da546Spatrick
100061da546Spatrick case 'u': {
101061da546Spatrick bool success;
102061da546Spatrick bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
103061da546Spatrick if (success)
104061da546Spatrick unwind_on_error = tmp_value;
105061da546Spatrick else
106061da546Spatrick error.SetErrorStringWithFormat(
107061da546Spatrick "could not convert \"%s\" to a boolean value.",
108061da546Spatrick option_arg.str().c_str());
109061da546Spatrick break;
110061da546Spatrick }
111061da546Spatrick
112061da546Spatrick case 'v':
113061da546Spatrick if (option_arg.empty()) {
114061da546Spatrick m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
115061da546Spatrick break;
116061da546Spatrick }
117061da546Spatrick m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity)
118061da546Spatrick OptionArgParser::ToOptionEnum(
119061da546Spatrick option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
120061da546Spatrick if (!error.Success())
121061da546Spatrick error.SetErrorStringWithFormat(
122061da546Spatrick "unrecognized value for description-verbosity '%s'",
123061da546Spatrick option_arg.str().c_str());
124061da546Spatrick break;
125061da546Spatrick
126061da546Spatrick case 'g':
127061da546Spatrick debug = true;
128061da546Spatrick unwind_on_error = false;
129061da546Spatrick ignore_breakpoints = false;
130061da546Spatrick break;
131061da546Spatrick
132061da546Spatrick case 'p':
133061da546Spatrick top_level = true;
134061da546Spatrick break;
135061da546Spatrick
136061da546Spatrick case 'X': {
137061da546Spatrick bool success;
138061da546Spatrick bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
139061da546Spatrick if (success)
140061da546Spatrick auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;
141061da546Spatrick else
142061da546Spatrick error.SetErrorStringWithFormat(
143061da546Spatrick "could not convert \"%s\" to a boolean value.",
144061da546Spatrick option_arg.str().c_str());
145061da546Spatrick break;
146061da546Spatrick }
147061da546Spatrick
148061da546Spatrick default:
149061da546Spatrick llvm_unreachable("Unimplemented option");
150061da546Spatrick }
151061da546Spatrick
152061da546Spatrick return error;
153061da546Spatrick }
154061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)155061da546Spatrick void CommandObjectExpression::CommandOptions::OptionParsingStarting(
156061da546Spatrick ExecutionContext *execution_context) {
157061da546Spatrick auto process_sp =
158061da546Spatrick execution_context ? execution_context->GetProcessSP() : ProcessSP();
159061da546Spatrick if (process_sp) {
160061da546Spatrick ignore_breakpoints = process_sp->GetIgnoreBreakpointsInExpressions();
161061da546Spatrick unwind_on_error = process_sp->GetUnwindOnErrorInExpressions();
162061da546Spatrick } else {
163061da546Spatrick ignore_breakpoints = true;
164061da546Spatrick unwind_on_error = true;
165061da546Spatrick }
166061da546Spatrick
167061da546Spatrick show_summary = true;
168061da546Spatrick try_all_threads = true;
169061da546Spatrick timeout = 0;
170061da546Spatrick debug = false;
171061da546Spatrick language = eLanguageTypeUnknown;
172061da546Spatrick m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
173061da546Spatrick auto_apply_fixits = eLazyBoolCalculate;
174061da546Spatrick top_level = false;
175061da546Spatrick allow_jit = true;
176061da546Spatrick }
177061da546Spatrick
178061da546Spatrick llvm::ArrayRef<OptionDefinition>
GetDefinitions()179061da546Spatrick CommandObjectExpression::CommandOptions::GetDefinitions() {
180*f6aab3d8Srobert return llvm::ArrayRef(g_expression_options);
181061da546Spatrick }
182061da546Spatrick
CommandObjectExpression(CommandInterpreter & interpreter)183061da546Spatrick CommandObjectExpression::CommandObjectExpression(
184061da546Spatrick CommandInterpreter &interpreter)
185061da546Spatrick : CommandObjectRaw(interpreter, "expression",
186061da546Spatrick "Evaluate an expression on the current "
187061da546Spatrick "thread. Displays any returned value "
188061da546Spatrick "with LLDB's default formatting.",
189061da546Spatrick "",
190061da546Spatrick eCommandProcessMustBePaused | eCommandTryTargetAPILock),
191061da546Spatrick IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
192*f6aab3d8Srobert m_format_options(eFormatDefault),
193061da546Spatrick m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
194061da546Spatrick true),
195*f6aab3d8Srobert m_expr_line_count(0) {
196061da546Spatrick SetHelpLong(
197061da546Spatrick R"(
198061da546Spatrick Single and multi-line expressions:
199061da546Spatrick
200061da546Spatrick )"
201061da546Spatrick " The expression provided on the command line must be a complete expression \
202061da546Spatrick with no newlines. To evaluate a multi-line expression, \
203061da546Spatrick hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
204061da546Spatrick Hit return on an empty line to end the multi-line expression."
205061da546Spatrick
206061da546Spatrick R"(
207061da546Spatrick
208061da546Spatrick Timeouts:
209061da546Spatrick
210061da546Spatrick )"
211061da546Spatrick " If the expression can be evaluated statically (without running code) then it will be. \
212061da546Spatrick Otherwise, by default the expression will run on the current thread with a short timeout: \
213061da546Spatrick currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted \
214061da546Spatrick and resumed with all threads running. You can use the -a option to disable retrying on all \
215061da546Spatrick threads. You can use the -t option to set a shorter timeout."
216061da546Spatrick R"(
217061da546Spatrick
218061da546Spatrick User defined variables:
219061da546Spatrick
220061da546Spatrick )"
221061da546Spatrick " You can define your own variables for convenience or to be used in subsequent expressions. \
222061da546Spatrick You define them the same way you would define variables in C. If the first character of \
223061da546Spatrick your user defined variable is a $, then the variable's value will be available in future \
224061da546Spatrick expressions, otherwise it will just be available in the current expression."
225061da546Spatrick R"(
226061da546Spatrick
227061da546Spatrick Continuing evaluation after a breakpoint:
228061da546Spatrick
229061da546Spatrick )"
230061da546Spatrick " If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
231061da546Spatrick you are done with your investigation, you can either remove the expression execution frames \
232061da546Spatrick from the stack with \"thread return -x\" or if you are still interested in the expression result \
233061da546Spatrick you can issue the \"continue\" command and the expression evaluation will complete and the \
234061da546Spatrick expression result will be available using the \"thread.completed-expression\" key in the thread \
235061da546Spatrick format."
236061da546Spatrick
237061da546Spatrick R"(
238061da546Spatrick
239061da546Spatrick Examples:
240061da546Spatrick
241061da546Spatrick expr my_struct->a = my_array[3]
242061da546Spatrick expr -f bin -- (index * 8) + 5
243061da546Spatrick expr unsigned int $foo = 5
244061da546Spatrick expr char c[] = \"foo\"; c[0])");
245061da546Spatrick
246061da546Spatrick CommandArgumentEntry arg;
247061da546Spatrick CommandArgumentData expression_arg;
248061da546Spatrick
249061da546Spatrick // Define the first (and only) variant of this arg.
250061da546Spatrick expression_arg.arg_type = eArgTypeExpression;
251061da546Spatrick expression_arg.arg_repetition = eArgRepeatPlain;
252061da546Spatrick
253061da546Spatrick // There is only one variant this argument could be; put it into the argument
254061da546Spatrick // entry.
255061da546Spatrick arg.push_back(expression_arg);
256061da546Spatrick
257061da546Spatrick // Push the data for the first argument into the m_arguments vector.
258061da546Spatrick m_arguments.push_back(arg);
259061da546Spatrick
260061da546Spatrick // Add the "--format" and "--gdb-format"
261061da546Spatrick m_option_group.Append(&m_format_options,
262061da546Spatrick OptionGroupFormat::OPTION_GROUP_FORMAT |
263061da546Spatrick OptionGroupFormat::OPTION_GROUP_GDB_FMT,
264061da546Spatrick LLDB_OPT_SET_1);
265061da546Spatrick m_option_group.Append(&m_command_options);
266061da546Spatrick m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
267061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
268061da546Spatrick m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
269061da546Spatrick m_option_group.Finalize();
270061da546Spatrick }
271061da546Spatrick
272061da546Spatrick CommandObjectExpression::~CommandObjectExpression() = default;
273061da546Spatrick
GetOptions()274061da546Spatrick Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
275061da546Spatrick
HandleCompletion(CompletionRequest & request)276061da546Spatrick void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
277061da546Spatrick EvaluateExpressionOptions options;
278061da546Spatrick options.SetCoerceToId(m_varobj_options.use_objc);
279061da546Spatrick options.SetLanguage(m_command_options.language);
280061da546Spatrick options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
281061da546Spatrick options.SetAutoApplyFixIts(false);
282061da546Spatrick options.SetGenerateDebugInfo(false);
283061da546Spatrick
284061da546Spatrick ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
285061da546Spatrick
286be691f3bSpatrick // Get out before we start doing things that expect a valid frame pointer.
287be691f3bSpatrick if (exe_ctx.GetFramePtr() == nullptr)
288be691f3bSpatrick return;
289061da546Spatrick
290be691f3bSpatrick Target *exe_target = exe_ctx.GetTargetPtr();
291be691f3bSpatrick Target &target = exe_target ? *exe_target : GetDummyTarget();
292061da546Spatrick
293061da546Spatrick unsigned cursor_pos = request.GetRawCursorPos();
294dda28197Spatrick // Get the full user input including the suffix. The suffix is necessary
295dda28197Spatrick // as OptionsWithRaw will use it to detect if the cursor is cursor is in the
296dda28197Spatrick // argument part of in the raw input part of the arguments. If we cut of
297dda28197Spatrick // of the suffix then "expr -arg[cursor] --" would interpret the "-arg" as
298dda28197Spatrick // the raw input (as the "--" is hidden in the suffix).
299dda28197Spatrick llvm::StringRef code = request.GetRawLineWithUnusedSuffix();
300061da546Spatrick
301061da546Spatrick const std::size_t original_code_size = code.size();
302061da546Spatrick
303061da546Spatrick // Remove the first token which is 'expr' or some alias/abbreviation of that.
304061da546Spatrick code = llvm::getToken(code).second.ltrim();
305061da546Spatrick OptionsWithRaw args(code);
306061da546Spatrick code = args.GetRawPart();
307061da546Spatrick
308061da546Spatrick // The position where the expression starts in the command line.
309061da546Spatrick assert(original_code_size >= code.size());
310061da546Spatrick std::size_t raw_start = original_code_size - code.size();
311061da546Spatrick
312061da546Spatrick // Check if the cursor is actually in the expression string, and if not, we
313061da546Spatrick // exit.
314061da546Spatrick // FIXME: We should complete the options here.
315061da546Spatrick if (cursor_pos < raw_start)
316061da546Spatrick return;
317061da546Spatrick
318061da546Spatrick // Make the cursor_pos again relative to the start of the code string.
319061da546Spatrick assert(cursor_pos >= raw_start);
320061da546Spatrick cursor_pos -= raw_start;
321061da546Spatrick
322061da546Spatrick auto language = exe_ctx.GetFrameRef().GetLanguage();
323061da546Spatrick
324061da546Spatrick Status error;
325be691f3bSpatrick lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage(
326061da546Spatrick code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
327061da546Spatrick options, nullptr, error));
328061da546Spatrick if (error.Fail())
329061da546Spatrick return;
330061da546Spatrick
331061da546Spatrick expr->Complete(exe_ctx, request, cursor_pos);
332061da546Spatrick }
333061da546Spatrick
334061da546Spatrick static lldb_private::Status
CanBeUsedForElementCountPrinting(ValueObject & valobj)335061da546Spatrick CanBeUsedForElementCountPrinting(ValueObject &valobj) {
336061da546Spatrick CompilerType type(valobj.GetCompilerType());
337061da546Spatrick CompilerType pointee;
338061da546Spatrick if (!type.IsPointerType(&pointee))
339061da546Spatrick return Status("as it does not refer to a pointer");
340061da546Spatrick if (pointee.IsVoidType())
341061da546Spatrick return Status("as it refers to a pointer to void");
342061da546Spatrick return Status();
343061da546Spatrick }
344061da546Spatrick
345dda28197Spatrick EvaluateExpressionOptions
GetEvalOptions(const Target & target)346dda28197Spatrick CommandObjectExpression::GetEvalOptions(const Target &target) {
347061da546Spatrick EvaluateExpressionOptions options;
348061da546Spatrick options.SetCoerceToId(m_varobj_options.use_objc);
349061da546Spatrick options.SetUnwindOnError(m_command_options.unwind_on_error);
350061da546Spatrick options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
351dda28197Spatrick options.SetKeepInMemory(true);
352061da546Spatrick options.SetUseDynamic(m_varobj_options.use_dynamic);
353061da546Spatrick options.SetTryAllThreads(m_command_options.try_all_threads);
354061da546Spatrick options.SetDebug(m_command_options.debug);
355061da546Spatrick options.SetLanguage(m_command_options.language);
356061da546Spatrick options.SetExecutionPolicy(
357061da546Spatrick m_command_options.allow_jit
358061da546Spatrick ? EvaluateExpressionOptions::default_execution_policy
359061da546Spatrick : lldb_private::eExecutionPolicyNever);
360061da546Spatrick
361061da546Spatrick bool auto_apply_fixits;
362061da546Spatrick if (m_command_options.auto_apply_fixits == eLazyBoolCalculate)
363dda28197Spatrick auto_apply_fixits = target.GetEnableAutoApplyFixIts();
364061da546Spatrick else
365061da546Spatrick auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes;
366061da546Spatrick
367061da546Spatrick options.SetAutoApplyFixIts(auto_apply_fixits);
368dda28197Spatrick options.SetRetriesWithFixIts(target.GetNumberOfRetriesWithFixits());
369061da546Spatrick
370061da546Spatrick if (m_command_options.top_level)
371061da546Spatrick options.SetExecutionPolicy(eExecutionPolicyTopLevel);
372061da546Spatrick
373061da546Spatrick // If there is any chance we are going to stop and want to see what went
374061da546Spatrick // wrong with our expression, we should generate debug info
375061da546Spatrick if (!m_command_options.ignore_breakpoints ||
376061da546Spatrick !m_command_options.unwind_on_error)
377061da546Spatrick options.SetGenerateDebugInfo(true);
378061da546Spatrick
379061da546Spatrick if (m_command_options.timeout > 0)
380061da546Spatrick options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
381061da546Spatrick else
382*f6aab3d8Srobert options.SetTimeout(std::nullopt);
383dda28197Spatrick return options;
384dda28197Spatrick }
385061da546Spatrick
EvaluateExpression(llvm::StringRef expr,Stream & output_stream,Stream & error_stream,CommandReturnObject & result)386dda28197Spatrick bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
387dda28197Spatrick Stream &output_stream,
388dda28197Spatrick Stream &error_stream,
389dda28197Spatrick CommandReturnObject &result) {
390dda28197Spatrick // Don't use m_exe_ctx as this might be called asynchronously after the
391dda28197Spatrick // command object DoExecute has finished when doing multi-line expression
392dda28197Spatrick // that use an input reader...
393dda28197Spatrick ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
394be691f3bSpatrick Target *exe_target = exe_ctx.GetTargetPtr();
395be691f3bSpatrick Target &target = exe_target ? *exe_target : GetDummyTarget();
396dda28197Spatrick
397dda28197Spatrick lldb::ValueObjectSP result_valobj_sp;
398dda28197Spatrick StackFrame *frame = exe_ctx.GetFramePtr();
399dda28197Spatrick
400be691f3bSpatrick if (m_command_options.top_level && !m_command_options.allow_jit) {
401be691f3bSpatrick result.AppendErrorWithFormat(
402be691f3bSpatrick "Can't disable JIT compilation for top-level expressions.\n");
403be691f3bSpatrick return false;
404be691f3bSpatrick }
405be691f3bSpatrick
406be691f3bSpatrick const EvaluateExpressionOptions options = GetEvalOptions(target);
407be691f3bSpatrick ExpressionResults success = target.EvaluateExpression(
408061da546Spatrick expr, frame, result_valobj_sp, options, &m_fixed_expression);
409061da546Spatrick
410061da546Spatrick // We only tell you about the FixIt if we applied it. The compiler errors
411061da546Spatrick // will suggest the FixIt if it parsed.
412be691f3bSpatrick if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
413dda28197Spatrick error_stream.Printf(" Fix-it applied, fixed expression was: \n %s\n",
414061da546Spatrick m_fixed_expression.c_str());
415061da546Spatrick }
416061da546Spatrick
417061da546Spatrick if (result_valobj_sp) {
418061da546Spatrick Format format = m_format_options.GetFormat();
419061da546Spatrick
420061da546Spatrick if (result_valobj_sp->GetError().Success()) {
421061da546Spatrick if (format != eFormatVoid) {
422061da546Spatrick if (format != eFormatDefault)
423061da546Spatrick result_valobj_sp->SetFormat(format);
424061da546Spatrick
425061da546Spatrick if (m_varobj_options.elem_count > 0) {
426061da546Spatrick Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
427061da546Spatrick if (error.Fail()) {
428dda28197Spatrick result.AppendErrorWithFormat(
429061da546Spatrick "expression cannot be used with --element-count %s\n",
430061da546Spatrick error.AsCString(""));
431061da546Spatrick return false;
432061da546Spatrick }
433061da546Spatrick }
434061da546Spatrick
435061da546Spatrick DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
436061da546Spatrick m_command_options.m_verbosity, format));
437061da546Spatrick options.SetVariableFormatDisplayLanguage(
438061da546Spatrick result_valobj_sp->GetPreferredDisplayLanguage());
439061da546Spatrick
440dda28197Spatrick result_valobj_sp->Dump(output_stream, options);
441061da546Spatrick
442dda28197Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
443061da546Spatrick }
444061da546Spatrick } else {
445061da546Spatrick if (result_valobj_sp->GetError().GetError() ==
446061da546Spatrick UserExpression::kNoResult) {
447061da546Spatrick if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) {
448dda28197Spatrick error_stream.PutCString("(void)\n");
449061da546Spatrick }
450061da546Spatrick
451dda28197Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
452061da546Spatrick } else {
453061da546Spatrick const char *error_cstr = result_valobj_sp->GetError().AsCString();
454061da546Spatrick if (error_cstr && error_cstr[0]) {
455061da546Spatrick const size_t error_cstr_len = strlen(error_cstr);
456061da546Spatrick const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
457061da546Spatrick if (strstr(error_cstr, "error:") != error_cstr)
458dda28197Spatrick error_stream.PutCString("error: ");
459dda28197Spatrick error_stream.Write(error_cstr, error_cstr_len);
460061da546Spatrick if (!ends_with_newline)
461dda28197Spatrick error_stream.EOL();
462061da546Spatrick } else {
463dda28197Spatrick error_stream.PutCString("error: unknown error\n");
464061da546Spatrick }
465061da546Spatrick
466dda28197Spatrick result.SetStatus(eReturnStatusFailed);
467061da546Spatrick }
468061da546Spatrick }
469*f6aab3d8Srobert } else {
470*f6aab3d8Srobert error_stream.Printf("error: unknown error\n");
471061da546Spatrick }
472061da546Spatrick
473dda28197Spatrick return (success != eExpressionSetupError &&
474dda28197Spatrick success != eExpressionParseError);
475061da546Spatrick }
476061da546Spatrick
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)477061da546Spatrick void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
478061da546Spatrick std::string &line) {
479061da546Spatrick io_handler.SetIsDone(true);
480061da546Spatrick StreamFileSP output_sp = io_handler.GetOutputStreamFileSP();
481061da546Spatrick StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
482061da546Spatrick
483dda28197Spatrick CommandReturnObject return_obj(
484dda28197Spatrick GetCommandInterpreter().GetDebugger().GetUseColor());
485dda28197Spatrick EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj);
486061da546Spatrick if (output_sp)
487061da546Spatrick output_sp->Flush();
488061da546Spatrick if (error_sp)
489061da546Spatrick error_sp->Flush();
490061da546Spatrick }
491061da546Spatrick
IOHandlerIsInputComplete(IOHandler & io_handler,StringList & lines)492061da546Spatrick bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
493061da546Spatrick StringList &lines) {
494061da546Spatrick // An empty lines is used to indicate the end of input
495061da546Spatrick const size_t num_lines = lines.GetSize();
496061da546Spatrick if (num_lines > 0 && lines[num_lines - 1].empty()) {
497061da546Spatrick // Remove the last empty line from "lines" so it doesn't appear in our
498061da546Spatrick // resulting input and return true to indicate we are done getting lines
499061da546Spatrick lines.PopBack();
500061da546Spatrick return true;
501061da546Spatrick }
502061da546Spatrick return false;
503061da546Spatrick }
504061da546Spatrick
GetMultilineExpression()505061da546Spatrick void CommandObjectExpression::GetMultilineExpression() {
506061da546Spatrick m_expr_lines.clear();
507061da546Spatrick m_expr_line_count = 0;
508061da546Spatrick
509061da546Spatrick Debugger &debugger = GetCommandInterpreter().GetDebugger();
510061da546Spatrick bool color_prompt = debugger.GetUseColor();
511061da546Spatrick const bool multiple_lines = true; // Get multiple lines
512061da546Spatrick IOHandlerSP io_handler_sp(
513061da546Spatrick new IOHandlerEditline(debugger, IOHandler::Type::Expression,
514061da546Spatrick "lldb-expr", // Name of input reader for history
515061da546Spatrick llvm::StringRef(), // No prompt
516061da546Spatrick llvm::StringRef(), // Continuation prompt
517061da546Spatrick multiple_lines, color_prompt,
518061da546Spatrick 1, // Show line numbers starting at 1
519*f6aab3d8Srobert *this));
520061da546Spatrick
521061da546Spatrick StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP();
522061da546Spatrick if (output_sp) {
523061da546Spatrick output_sp->PutCString(
524061da546Spatrick "Enter expressions, then terminate with an empty line to evaluate:\n");
525061da546Spatrick output_sp->Flush();
526061da546Spatrick }
527dda28197Spatrick debugger.RunIOHandlerAsync(io_handler_sp);
528061da546Spatrick }
529061da546Spatrick
530061da546Spatrick static EvaluateExpressionOptions
GetExprOptions(ExecutionContext & ctx,CommandObjectExpression::CommandOptions command_options)531061da546Spatrick GetExprOptions(ExecutionContext &ctx,
532061da546Spatrick CommandObjectExpression::CommandOptions command_options) {
533061da546Spatrick command_options.OptionParsingStarting(&ctx);
534061da546Spatrick
535061da546Spatrick // Default certain settings for REPL regardless of the global settings.
536061da546Spatrick command_options.unwind_on_error = false;
537061da546Spatrick command_options.ignore_breakpoints = false;
538061da546Spatrick command_options.debug = false;
539061da546Spatrick
540061da546Spatrick EvaluateExpressionOptions expr_options;
541061da546Spatrick expr_options.SetUnwindOnError(command_options.unwind_on_error);
542061da546Spatrick expr_options.SetIgnoreBreakpoints(command_options.ignore_breakpoints);
543061da546Spatrick expr_options.SetTryAllThreads(command_options.try_all_threads);
544061da546Spatrick
545061da546Spatrick if (command_options.timeout > 0)
546061da546Spatrick expr_options.SetTimeout(std::chrono::microseconds(command_options.timeout));
547061da546Spatrick else
548*f6aab3d8Srobert expr_options.SetTimeout(std::nullopt);
549061da546Spatrick
550061da546Spatrick return expr_options;
551061da546Spatrick }
552061da546Spatrick
DoExecute(llvm::StringRef command,CommandReturnObject & result)553061da546Spatrick bool CommandObjectExpression::DoExecute(llvm::StringRef command,
554061da546Spatrick CommandReturnObject &result) {
555061da546Spatrick m_fixed_expression.clear();
556061da546Spatrick auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
557061da546Spatrick m_option_group.NotifyOptionParsingStarting(&exe_ctx);
558061da546Spatrick
559061da546Spatrick if (command.empty()) {
560061da546Spatrick GetMultilineExpression();
561061da546Spatrick return result.Succeeded();
562061da546Spatrick }
563061da546Spatrick
564061da546Spatrick OptionsWithRaw args(command);
565061da546Spatrick llvm::StringRef expr = args.GetRawPart();
566061da546Spatrick
567061da546Spatrick if (args.HasArgs()) {
568061da546Spatrick if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
569061da546Spatrick return false;
570061da546Spatrick
571061da546Spatrick if (m_repl_option.GetOptionValue().GetCurrentValue()) {
572061da546Spatrick Target &target = GetSelectedOrDummyTarget();
573061da546Spatrick // Drop into REPL
574061da546Spatrick m_expr_lines.clear();
575061da546Spatrick m_expr_line_count = 0;
576061da546Spatrick
577061da546Spatrick Debugger &debugger = target.GetDebugger();
578061da546Spatrick
579061da546Spatrick // Check if the LLDB command interpreter is sitting on top of a REPL
580061da546Spatrick // that launched it...
581061da546Spatrick if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
582061da546Spatrick IOHandler::Type::REPL)) {
583061da546Spatrick // the LLDB command interpreter is sitting on top of a REPL that
584061da546Spatrick // launched it, so just say the command interpreter is done and
585061da546Spatrick // fall back to the existing REPL
586061da546Spatrick m_interpreter.GetIOHandler(false)->SetIsDone(true);
587061da546Spatrick } else {
588061da546Spatrick // We are launching the REPL on top of the current LLDB command
589061da546Spatrick // interpreter, so just push one
590061da546Spatrick bool initialize = false;
591061da546Spatrick Status repl_error;
592061da546Spatrick REPLSP repl_sp(target.GetREPL(repl_error, m_command_options.language,
593061da546Spatrick nullptr, false));
594061da546Spatrick
595061da546Spatrick if (!repl_sp) {
596061da546Spatrick initialize = true;
597061da546Spatrick repl_sp = target.GetREPL(repl_error, m_command_options.language,
598061da546Spatrick nullptr, true);
599061da546Spatrick if (!repl_error.Success()) {
600061da546Spatrick result.SetError(repl_error);
601061da546Spatrick return result.Succeeded();
602061da546Spatrick }
603061da546Spatrick }
604061da546Spatrick
605061da546Spatrick if (repl_sp) {
606061da546Spatrick if (initialize) {
607061da546Spatrick repl_sp->SetEvaluateOptions(
608061da546Spatrick GetExprOptions(exe_ctx, m_command_options));
609061da546Spatrick repl_sp->SetFormatOptions(m_format_options);
610061da546Spatrick repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
611061da546Spatrick }
612061da546Spatrick
613061da546Spatrick IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
614061da546Spatrick io_handler_sp->SetIsDone(false);
615dda28197Spatrick debugger.RunIOHandlerAsync(io_handler_sp);
616061da546Spatrick } else {
617061da546Spatrick repl_error.SetErrorStringWithFormat(
618061da546Spatrick "Couldn't create a REPL for %s",
619061da546Spatrick Language::GetNameForLanguageType(m_command_options.language));
620061da546Spatrick result.SetError(repl_error);
621061da546Spatrick return result.Succeeded();
622061da546Spatrick }
623061da546Spatrick }
624061da546Spatrick }
625061da546Spatrick // No expression following options
626061da546Spatrick else if (expr.empty()) {
627061da546Spatrick GetMultilineExpression();
628061da546Spatrick return result.Succeeded();
629061da546Spatrick }
630061da546Spatrick }
631061da546Spatrick
632061da546Spatrick Target &target = GetSelectedOrDummyTarget();
633dda28197Spatrick if (EvaluateExpression(expr, result.GetOutputStream(),
634dda28197Spatrick result.GetErrorStream(), result)) {
635061da546Spatrick
636061da546Spatrick if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
637061da546Spatrick CommandHistory &history = m_interpreter.GetCommandHistory();
638061da546Spatrick // FIXME: Can we figure out what the user actually typed (e.g. some alias
639061da546Spatrick // for expr???)
640061da546Spatrick // If we can it would be nice to show that.
641061da546Spatrick std::string fixed_command("expression ");
642061da546Spatrick if (args.HasArgs()) {
643061da546Spatrick // Add in any options that might have been in the original command:
644dda28197Spatrick fixed_command.append(std::string(args.GetArgStringWithDelimiter()));
645061da546Spatrick fixed_command.append(m_fixed_expression);
646061da546Spatrick } else
647061da546Spatrick fixed_command.append(m_fixed_expression);
648061da546Spatrick history.AppendString(fixed_command);
649061da546Spatrick }
650061da546Spatrick return true;
651061da546Spatrick }
652061da546Spatrick result.SetStatus(eReturnStatusFailed);
653061da546Spatrick return false;
654061da546Spatrick }
655