xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectExpression.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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