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