1 //===-- CommandObjectExpression.cpp -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/STLExtras.h"
10 #include "llvm/ADT/StringRef.h"
11 
12 #include "CommandObjectExpression.h"
13 #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/Value.h"
16 #include "lldb/Core/ValueObjectVariable.h"
17 #include "lldb/DataFormatters/ValueObjectPrinter.h"
18 #include "lldb/Expression/DWARFExpression.h"
19 #include "lldb/Expression/REPL.h"
20 #include "lldb/Expression/UserExpression.h"
21 #include "lldb/Host/Host.h"
22 #include "lldb/Host/OptionParser.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/CommandReturnObject.h"
25 #include "lldb/Interpreter/OptionArgParser.h"
26 #include "lldb/Symbol/ObjectFile.h"
27 #include "lldb/Symbol/Variable.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/Process.h"
30 #include "lldb/Target/StackFrame.h"
31 #include "lldb/Target/Target.h"
32 #include "lldb/Target/Thread.h"
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 
37 CommandObjectExpression::CommandOptions::CommandOptions() : OptionGroup() {}
38 
39 CommandObjectExpression::CommandOptions::~CommandOptions() = default;
40 
41 static constexpr OptionEnumValueElement g_description_verbosity_type[] = {
42     {eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact",
43      "Only show the description string"},
44     {eLanguageRuntimeDescriptionDisplayVerbosityFull, "full",
45      "Show the full output, including persistent variable's name and type"} };
46 
47 static constexpr OptionEnumValues DescriptionVerbosityTypes() {
48   return OptionEnumValues(g_description_verbosity_type);
49 }
50 
51 static constexpr OptionDefinition g_expression_options[] = {
52     // clang-format off
53   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",           'a', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Should we run all threads if the execution doesn't complete on one thread."},
54   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints",    'i', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Ignore breakpoint hits while running expressions"},
55   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",               't', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeUnsignedInteger,      "Timeout value (in microseconds) for running the expression."},
56   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",       'u', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Clean up program state if the expression causes a crash, or raises a signal.  "
57                                                                                                                                                                                   "Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
58   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug",                 'g', OptionParser::eNoArgument,       nullptr, {},                          0, eArgTypeNone,                 "When specified, debug the JIT code by setting a breakpoint on the first instruction "
59                                                                                                                                                                                   "and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
60   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language",              'l', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeLanguage,             "Specifies the Language to use when parsing the expression.  If not set the target.language "
61                                                                                                                                                                                   "setting is used." },
62   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "apply-fixits",          'X', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeLanguage,             "If true, simple fix-it hints will be automatically applied to the expression." },
63   {LLDB_OPT_SET_1,                  false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, DescriptionVerbosityTypes(), 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."},
64   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "top-level",             'p', OptionParser::eNoArgument,       nullptr, {},                          0, eArgTypeNone,                 "Interpret the expression as a complete translation unit, without injecting it into the local "
65                                                                                                                                                                                   "context.  Allows declaration of persistent, top-level entities without a $ prefix."},
66   {LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "allow-jit",             'j', OptionParser::eRequiredArgument, nullptr, {},                          0, eArgTypeBoolean,              "Controls whether the expression can fall back to being JITted if it's not supported by "
67                                                                                                                                                                                   "the interpreter (defaults to true)."}
68     // clang-format on
69 };
70 
71 Status CommandObjectExpression::CommandOptions::SetOptionValue(
72     uint32_t option_idx, llvm::StringRef option_arg,
73     ExecutionContext *execution_context) {
74   Status error;
75 
76   const int short_option = GetDefinitions()[option_idx].short_option;
77 
78   switch (short_option) {
79   case 'l':
80     language = Language::GetLanguageTypeFromString(option_arg);
81     if (language == eLanguageTypeUnknown)
82       error.SetErrorStringWithFormat(
83           "unknown language type: '%s' for expression",
84           option_arg.str().c_str());
85     break;
86 
87   case 'a': {
88     bool success;
89     bool result;
90     result = OptionArgParser::ToBoolean(option_arg, true, &success);
91     if (!success)
92       error.SetErrorStringWithFormat(
93           "invalid all-threads value setting: \"%s\"",
94           option_arg.str().c_str());
95     else
96       try_all_threads = result;
97   } break;
98 
99   case 'i': {
100     bool success;
101     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
102     if (success)
103       ignore_breakpoints = tmp_value;
104     else
105       error.SetErrorStringWithFormat(
106           "could not convert \"%s\" to a boolean value.",
107           option_arg.str().c_str());
108     break;
109   }
110 
111   case 'j': {
112     bool success;
113     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
114     if (success)
115       allow_jit = tmp_value;
116     else
117       error.SetErrorStringWithFormat(
118           "could not convert \"%s\" to a boolean value.",
119           option_arg.str().c_str());
120     break;
121   }
122 
123   case 't':
124     if (option_arg.getAsInteger(0, timeout)) {
125       timeout = 0;
126       error.SetErrorStringWithFormat("invalid timeout setting \"%s\"",
127                                      option_arg.str().c_str());
128     }
129     break;
130 
131   case 'u': {
132     bool success;
133     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
134     if (success)
135       unwind_on_error = tmp_value;
136     else
137       error.SetErrorStringWithFormat(
138           "could not convert \"%s\" to a boolean value.",
139           option_arg.str().c_str());
140     break;
141   }
142 
143   case 'v':
144     if (option_arg.empty()) {
145       m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
146       break;
147     }
148     m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity)
149         OptionArgParser::ToOptionEnum(
150             option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
151     if (!error.Success())
152       error.SetErrorStringWithFormat(
153           "unrecognized value for description-verbosity '%s'",
154           option_arg.str().c_str());
155     break;
156 
157   case 'g':
158     debug = true;
159     unwind_on_error = false;
160     ignore_breakpoints = false;
161     break;
162 
163   case 'p':
164     top_level = true;
165     break;
166 
167   case 'X': {
168     bool success;
169     bool tmp_value = OptionArgParser::ToBoolean(option_arg, true, &success);
170     if (success)
171       auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo;
172     else
173       error.SetErrorStringWithFormat(
174           "could not convert \"%s\" to a boolean value.",
175           option_arg.str().c_str());
176     break;
177   }
178 
179   default:
180     error.SetErrorStringWithFormat("invalid short option character '%c'",
181                                    short_option);
182     break;
183   }
184 
185   return error;
186 }
187 
188 void CommandObjectExpression::CommandOptions::OptionParsingStarting(
189     ExecutionContext *execution_context) {
190   auto process_sp =
191       execution_context ? execution_context->GetProcessSP() : ProcessSP();
192   if (process_sp) {
193     ignore_breakpoints = process_sp->GetIgnoreBreakpointsInExpressions();
194     unwind_on_error = process_sp->GetUnwindOnErrorInExpressions();
195   } else {
196     ignore_breakpoints = true;
197     unwind_on_error = true;
198   }
199 
200   show_summary = true;
201   try_all_threads = true;
202   timeout = 0;
203   debug = false;
204   language = eLanguageTypeUnknown;
205   m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
206   auto_apply_fixits = eLazyBoolCalculate;
207   top_level = false;
208   allow_jit = true;
209 }
210 
211 llvm::ArrayRef<OptionDefinition>
212 CommandObjectExpression::CommandOptions::GetDefinitions() {
213   return llvm::makeArrayRef(g_expression_options);
214 }
215 
216 CommandObjectExpression::CommandObjectExpression(
217     CommandInterpreter &interpreter)
218     : CommandObjectRaw(
219           interpreter, "expression", "Evaluate an expression on the current "
220                                      "thread.  Displays any returned value "
221                                      "with LLDB's default formatting.",
222           "", eCommandProcessMustBePaused | eCommandTryTargetAPILock),
223       IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
224       m_option_group(), m_format_options(eFormatDefault),
225       m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
226                     true),
227       m_command_options(), m_expr_line_count(0), m_expr_lines() {
228   SetHelpLong(
229       R"(
230 Single and multi-line expressions:
231 
232 )"
233       "    The expression provided on the command line must be a complete expression \
234 with no newlines.  To evaluate a multi-line expression, \
235 hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
236 Hit return on an empty line to end the multi-line expression."
237 
238       R"(
239 
240 Timeouts:
241 
242 )"
243       "    If the expression can be evaluated statically (without running code) then it will be.  \
244 Otherwise, by default the expression will run on the current thread with a short timeout: \
245 currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted \
246 and resumed with all threads running.  You can use the -a option to disable retrying on all \
247 threads.  You can use the -t option to set a shorter timeout."
248       R"(
249 
250 User defined variables:
251 
252 )"
253       "    You can define your own variables for convenience or to be used in subsequent expressions.  \
254 You define them the same way you would define variables in C.  If the first character of \
255 your user defined variable is a $, then the variable's value will be available in future \
256 expressions, otherwise it will just be available in the current expression."
257       R"(
258 
259 Continuing evaluation after a breakpoint:
260 
261 )"
262       "    If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
263 you are done with your investigation, you can either remove the expression execution frames \
264 from the stack with \"thread return -x\" or if you are still interested in the expression result \
265 you can issue the \"continue\" command and the expression evaluation will complete and the \
266 expression result will be available using the \"thread.completed-expression\" key in the thread \
267 format."
268 
269       R"(
270 
271 Examples:
272 
273     expr my_struct->a = my_array[3]
274     expr -f bin -- (index * 8) + 5
275     expr unsigned int $foo = 5
276     expr char c[] = \"foo\"; c[0])");
277 
278   CommandArgumentEntry arg;
279   CommandArgumentData expression_arg;
280 
281   // Define the first (and only) variant of this arg.
282   expression_arg.arg_type = eArgTypeExpression;
283   expression_arg.arg_repetition = eArgRepeatPlain;
284 
285   // There is only one variant this argument could be; put it into the argument
286   // entry.
287   arg.push_back(expression_arg);
288 
289   // Push the data for the first argument into the m_arguments vector.
290   m_arguments.push_back(arg);
291 
292   // Add the "--format" and "--gdb-format"
293   m_option_group.Append(&m_format_options,
294                         OptionGroupFormat::OPTION_GROUP_FORMAT |
295                             OptionGroupFormat::OPTION_GROUP_GDB_FMT,
296                         LLDB_OPT_SET_1);
297   m_option_group.Append(&m_command_options);
298   m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
299                         LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
300   m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
301   m_option_group.Finalize();
302 }
303 
304 CommandObjectExpression::~CommandObjectExpression() = default;
305 
306 Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
307 
308 int CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
309   EvaluateExpressionOptions options;
310   options.SetCoerceToId(m_varobj_options.use_objc);
311   options.SetLanguage(m_command_options.language);
312   options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
313   options.SetAutoApplyFixIts(false);
314   options.SetGenerateDebugInfo(false);
315 
316   // We need a valid execution context with a frame pointer for this
317   // completion, so if we don't have one we should try to make a valid
318   // execution context.
319   if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
320     m_interpreter.UpdateExecutionContext(nullptr);
321 
322   // This didn't work, so let's get out before we start doing things that
323   // expect a valid frame pointer.
324   if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr)
325     return 0;
326 
327   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
328 
329   Target *target = exe_ctx.GetTargetPtr();
330 
331   if (!target)
332     target = GetDummyTarget();
333 
334   if (!target)
335     return 0;
336 
337   unsigned cursor_pos = request.GetRawCursorPos();
338   llvm::StringRef code = request.GetRawLine();
339 
340   const std::size_t original_code_size = code.size();
341 
342   // Remove the first token which is 'expr' or some alias/abbreviation of that.
343   code = llvm::getToken(code).second.ltrim();
344   OptionsWithRaw args(code);
345   code = args.GetRawPart();
346 
347   // The position where the expression starts in the command line.
348   assert(original_code_size >= code.size());
349   std::size_t raw_start = original_code_size - code.size();
350 
351   // Check if the cursor is actually in the expression string, and if not, we
352   // exit.
353   // FIXME: We should complete the options here.
354   if (cursor_pos < raw_start)
355     return 0;
356 
357   // Make the cursor_pos again relative to the start of the code string.
358   assert(cursor_pos >= raw_start);
359   cursor_pos -= raw_start;
360 
361   auto language = exe_ctx.GetFrameRef().GetLanguage();
362 
363   Status error;
364   lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage(
365       code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
366       options, nullptr, error));
367   if (error.Fail())
368     return 0;
369 
370   expr->Complete(exe_ctx, request, cursor_pos);
371   return request.GetNumberOfMatches();
372 }
373 
374 static lldb_private::Status
375 CanBeUsedForElementCountPrinting(ValueObject &valobj) {
376   CompilerType type(valobj.GetCompilerType());
377   CompilerType pointee;
378   if (!type.IsPointerType(&pointee))
379     return Status("as it does not refer to a pointer");
380   if (pointee.IsVoidType())
381     return Status("as it refers to a pointer to void");
382   return Status();
383 }
384 
385 bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
386                                                  Stream *output_stream,
387                                                  Stream *error_stream,
388                                                  CommandReturnObject *result) {
389   // Don't use m_exe_ctx as this might be called asynchronously after the
390   // command object DoExecute has finished when doing multi-line expression
391   // that use an input reader...
392   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
393 
394   Target *target = exe_ctx.GetTargetPtr();
395 
396   if (!target)
397     target = GetDummyTarget();
398 
399   if (target) {
400     lldb::ValueObjectSP result_valobj_sp;
401     bool keep_in_memory = true;
402     StackFrame *frame = exe_ctx.GetFramePtr();
403 
404     EvaluateExpressionOptions options;
405     options.SetCoerceToId(m_varobj_options.use_objc);
406     options.SetUnwindOnError(m_command_options.unwind_on_error);
407     options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints);
408     options.SetKeepInMemory(keep_in_memory);
409     options.SetUseDynamic(m_varobj_options.use_dynamic);
410     options.SetTryAllThreads(m_command_options.try_all_threads);
411     options.SetDebug(m_command_options.debug);
412     options.SetLanguage(m_command_options.language);
413     options.SetExecutionPolicy(
414         m_command_options.allow_jit
415             ? EvaluateExpressionOptions::default_execution_policy
416             : lldb_private::eExecutionPolicyNever);
417 
418     bool auto_apply_fixits;
419     if (m_command_options.auto_apply_fixits == eLazyBoolCalculate)
420       auto_apply_fixits = target->GetEnableAutoApplyFixIts();
421     else
422       auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes;
423 
424     options.SetAutoApplyFixIts(auto_apply_fixits);
425 
426     if (m_command_options.top_level)
427       options.SetExecutionPolicy(eExecutionPolicyTopLevel);
428 
429     // If there is any chance we are going to stop and want to see what went
430     // wrong with our expression, we should generate debug info
431     if (!m_command_options.ignore_breakpoints ||
432         !m_command_options.unwind_on_error)
433       options.SetGenerateDebugInfo(true);
434 
435     if (m_command_options.timeout > 0)
436       options.SetTimeout(std::chrono::microseconds(m_command_options.timeout));
437     else
438       options.SetTimeout(llvm::None);
439 
440     ExpressionResults success = target->EvaluateExpression(
441         expr, frame, result_valobj_sp, options, &m_fixed_expression);
442 
443     // We only tell you about the FixIt if we applied it.  The compiler errors
444     // will suggest the FixIt if it parsed.
445     if (error_stream && !m_fixed_expression.empty() &&
446         target->GetEnableNotifyAboutFixIts()) {
447       if (success == eExpressionCompleted)
448         error_stream->Printf(
449             "  Fix-it applied, fixed expression was: \n    %s\n",
450             m_fixed_expression.c_str());
451     }
452 
453     if (result_valobj_sp) {
454       Format format = m_format_options.GetFormat();
455 
456       if (result_valobj_sp->GetError().Success()) {
457         if (format != eFormatVoid) {
458           if (format != eFormatDefault)
459             result_valobj_sp->SetFormat(format);
460 
461           if (m_varobj_options.elem_count > 0) {
462             Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
463             if (error.Fail()) {
464               result->AppendErrorWithFormat(
465                   "expression cannot be used with --element-count %s\n",
466                   error.AsCString(""));
467               result->SetStatus(eReturnStatusFailed);
468               return false;
469             }
470           }
471 
472           DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
473               m_command_options.m_verbosity, format));
474           options.SetVariableFormatDisplayLanguage(
475               result_valobj_sp->GetPreferredDisplayLanguage());
476 
477           result_valobj_sp->Dump(*output_stream, options);
478 
479           if (result)
480             result->SetStatus(eReturnStatusSuccessFinishResult);
481         }
482       } else {
483         if (result_valobj_sp->GetError().GetError() ==
484             UserExpression::kNoResult) {
485           if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) {
486             error_stream->PutCString("(void)\n");
487           }
488 
489           if (result)
490             result->SetStatus(eReturnStatusSuccessFinishResult);
491         } else {
492           const char *error_cstr = result_valobj_sp->GetError().AsCString();
493           if (error_cstr && error_cstr[0]) {
494             const size_t error_cstr_len = strlen(error_cstr);
495             const bool ends_with_newline =
496                 error_cstr[error_cstr_len - 1] == '\n';
497             if (strstr(error_cstr, "error:") != error_cstr)
498               error_stream->PutCString("error: ");
499             error_stream->Write(error_cstr, error_cstr_len);
500             if (!ends_with_newline)
501               error_stream->EOL();
502           } else {
503             error_stream->PutCString("error: unknown error\n");
504           }
505 
506           if (result)
507             result->SetStatus(eReturnStatusFailed);
508         }
509       }
510     }
511   } else {
512     error_stream->Printf("error: invalid execution context for expression\n");
513     return false;
514   }
515 
516   return true;
517 }
518 
519 void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
520                                                      std::string &line) {
521   io_handler.SetIsDone(true);
522   //    StreamSP output_stream =
523   //    io_handler.GetDebugger().GetAsyncOutputStream();
524   //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
525   StreamFileSP output_sp(io_handler.GetOutputStreamFile());
526   StreamFileSP error_sp(io_handler.GetErrorStreamFile());
527 
528   EvaluateExpression(line.c_str(), output_sp.get(), error_sp.get());
529   if (output_sp)
530     output_sp->Flush();
531   if (error_sp)
532     error_sp->Flush();
533 }
534 
535 bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
536                                                        StringList &lines) {
537   // An empty lines is used to indicate the end of input
538   const size_t num_lines = lines.GetSize();
539   if (num_lines > 0 && lines[num_lines - 1].empty()) {
540     // Remove the last empty line from "lines" so it doesn't appear in our
541     // resulting input and return true to indicate we are done getting lines
542     lines.PopBack();
543     return true;
544   }
545   return false;
546 }
547 
548 void CommandObjectExpression::GetMultilineExpression() {
549   m_expr_lines.clear();
550   m_expr_line_count = 0;
551 
552   Debugger &debugger = GetCommandInterpreter().GetDebugger();
553   bool color_prompt = debugger.GetUseColor();
554   const bool multiple_lines = true; // Get multiple lines
555   IOHandlerSP io_handler_sp(
556       new IOHandlerEditline(debugger, IOHandler::Type::Expression,
557                             "lldb-expr", // Name of input reader for history
558                             llvm::StringRef(), // No prompt
559                             llvm::StringRef(), // Continuation prompt
560                             multiple_lines, color_prompt,
561                             1, // Show line numbers starting at 1
562                             *this, nullptr));
563 
564   StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
565   if (output_sp) {
566     output_sp->PutCString(
567         "Enter expressions, then terminate with an empty line to evaluate:\n");
568     output_sp->Flush();
569   }
570   debugger.PushIOHandler(io_handler_sp);
571 }
572 
573 static EvaluateExpressionOptions
574 GetExprOptions(ExecutionContext &ctx,
575                CommandObjectExpression::CommandOptions command_options) {
576   command_options.OptionParsingStarting(&ctx);
577 
578   // Default certain settings for REPL regardless of the global settings.
579   command_options.unwind_on_error = false;
580   command_options.ignore_breakpoints = false;
581   command_options.debug = false;
582 
583   EvaluateExpressionOptions expr_options;
584   expr_options.SetUnwindOnError(command_options.unwind_on_error);
585   expr_options.SetIgnoreBreakpoints(command_options.ignore_breakpoints);
586   expr_options.SetTryAllThreads(command_options.try_all_threads);
587 
588   if (command_options.timeout > 0)
589     expr_options.SetTimeout(std::chrono::microseconds(command_options.timeout));
590   else
591     expr_options.SetTimeout(llvm::None);
592 
593   return expr_options;
594 }
595 
596 bool CommandObjectExpression::DoExecute(llvm::StringRef command,
597                                         CommandReturnObject &result) {
598   m_fixed_expression.clear();
599   auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
600   m_option_group.NotifyOptionParsingStarting(&exe_ctx);
601 
602   if (command.empty()) {
603     GetMultilineExpression();
604     return result.Succeeded();
605   }
606 
607   OptionsWithRaw args(command);
608   llvm::StringRef expr = args.GetRawPart();
609 
610   if (args.HasArgs()) {
611     if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
612       return false;
613 
614     if (m_repl_option.GetOptionValue().GetCurrentValue()) {
615       Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
616       if (target) {
617         // Drop into REPL
618         m_expr_lines.clear();
619         m_expr_line_count = 0;
620 
621         Debugger &debugger = target->GetDebugger();
622 
623         // Check if the LLDB command interpreter is sitting on top of a REPL
624         // that launched it...
625         if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
626                                             IOHandler::Type::REPL)) {
627           // the LLDB command interpreter is sitting on top of a REPL that
628           // launched it, so just say the command interpreter is done and
629           // fall back to the existing REPL
630           m_interpreter.GetIOHandler(false)->SetIsDone(true);
631         } else {
632           // We are launching the REPL on top of the current LLDB command
633           // interpreter, so just push one
634           bool initialize = false;
635           Status repl_error;
636           REPLSP repl_sp(target->GetREPL(repl_error, m_command_options.language,
637                                          nullptr, false));
638 
639           if (!repl_sp) {
640             initialize = true;
641             repl_sp = target->GetREPL(repl_error, m_command_options.language,
642                                       nullptr, true);
643             if (!repl_error.Success()) {
644               result.SetError(repl_error);
645               return result.Succeeded();
646             }
647           }
648 
649           if (repl_sp) {
650             if (initialize) {
651               repl_sp->SetEvaluateOptions(
652                   GetExprOptions(exe_ctx, m_command_options));
653               repl_sp->SetFormatOptions(m_format_options);
654               repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
655             }
656 
657             IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
658 
659             io_handler_sp->SetIsDone(false);
660 
661             debugger.PushIOHandler(io_handler_sp);
662           } else {
663             repl_error.SetErrorStringWithFormat(
664                 "Couldn't create a REPL for %s",
665                 Language::GetNameForLanguageType(m_command_options.language));
666             result.SetError(repl_error);
667             return result.Succeeded();
668           }
669         }
670       }
671     }
672     // No expression following options
673     else if (expr.empty()) {
674       GetMultilineExpression();
675       return result.Succeeded();
676     }
677   }
678 
679   Target *target = GetSelectedOrDummyTarget();
680   if (EvaluateExpression(expr, &(result.GetOutputStream()),
681                          &(result.GetErrorStream()), &result)) {
682 
683     if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) {
684       CommandHistory &history = m_interpreter.GetCommandHistory();
685       // FIXME: Can we figure out what the user actually typed (e.g. some alias
686       // for expr???)
687       // If we can it would be nice to show that.
688       std::string fixed_command("expression ");
689       if (args.HasArgs()) {
690         // Add in any options that might have been in the original command:
691         fixed_command.append(args.GetArgStringWithDelimiter());
692         fixed_command.append(m_fixed_expression);
693       } else
694         fixed_command.append(m_fixed_expression);
695       history.AppendString(fixed_command);
696     }
697     // Increment statistics to record this expression evaluation success.
698     target->IncrementStats(StatisticKind::ExpressionSuccessful);
699     return true;
700   }
701 
702   // Increment statistics to record this expression evaluation failure.
703   target->IncrementStats(StatisticKind::ExpressionFailure);
704   result.SetStatus(eReturnStatusFailed);
705   return false;
706 }
707