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