xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 23349d83a98f23e67ff0321dad7c378b117ce6aa)
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 ? eLazyBoolYes : eLazyBoolNo;
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 = eLazyBoolCalculate;
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 != eLazyBoolCalculate)
206     options.SetSuppressPersistentResult(suppress_persistent_result ==
207                                         eLazyBoolYes);
208   else if (m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact)
209     options.SetSuppressPersistentResult(display_opts.use_objc);
210   options.SetUnwindOnError(unwind_on_error);
211   options.SetIgnoreBreakpoints(ignore_breakpoints);
212   options.SetKeepInMemory(true);
213   options.SetUseDynamic(display_opts.use_dynamic);
214   options.SetTryAllThreads(try_all_threads);
215   options.SetDebug(debug);
216   options.SetLanguage(language);
217   options.SetExecutionPolicy(
218       allow_jit ? EvaluateExpressionOptions::default_execution_policy
219                 : lldb_private::eExecutionPolicyNever);
220 
221   bool auto_apply_fixits;
222   if (this->auto_apply_fixits == eLazyBoolCalculate)
223     auto_apply_fixits = target.GetEnableAutoApplyFixIts();
224   else
225     auto_apply_fixits = this->auto_apply_fixits == eLazyBoolYes;
226 
227   options.SetAutoApplyFixIts(auto_apply_fixits);
228   options.SetRetriesWithFixIts(target.GetNumberOfRetriesWithFixits());
229 
230   if (top_level)
231     options.SetExecutionPolicy(eExecutionPolicyTopLevel);
232 
233   // If there is any chance we are going to stop and want to see what went
234   // wrong with our expression, we should generate debug info
235   if (!ignore_breakpoints || !unwind_on_error)
236     options.SetGenerateDebugInfo(true);
237 
238   if (timeout > 0)
239     options.SetTimeout(std::chrono::microseconds(timeout));
240   else
241     options.SetTimeout(std::nullopt);
242   return options;
243 }
244 
245 CommandObjectExpression::CommandObjectExpression(
246     CommandInterpreter &interpreter)
247     : CommandObjectRaw(interpreter, "expression",
248                        "Evaluate an expression on the current "
249                        "thread.  Displays any returned value "
250                        "with LLDB's default formatting.",
251                        "",
252                        eCommandProcessMustBePaused | eCommandTryTargetAPILock),
253       IOHandlerDelegate(IOHandlerDelegate::Completion::Expression),
254       m_format_options(eFormatDefault),
255       m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false,
256                     true),
257       m_expr_line_count(0) {
258   SetHelpLong(
259       R"(
260 Single and multi-line expressions:
261 
262 )"
263       "    The expression provided on the command line must be a complete expression \
264 with no newlines.  To evaluate a multi-line expression, \
265 hit a return after an empty expression, and lldb will enter the multi-line expression editor. \
266 Hit return on an empty line to end the multi-line expression."
267 
268       R"(
269 
270 Timeouts:
271 
272 )"
273       "    If the expression can be evaluated statically (without running code) then it will be.  \
274 Otherwise, by default the expression will run on the current thread with a short timeout: \
275 currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted \
276 and resumed with all threads running.  You can use the -a option to disable retrying on all \
277 threads.  You can use the -t option to set a shorter timeout."
278       R"(
279 
280 User defined variables:
281 
282 )"
283       "    You can define your own variables for convenience or to be used in subsequent expressions.  \
284 You define them the same way you would define variables in C.  If the first character of \
285 your user defined variable is a $, then the variable's value will be available in future \
286 expressions, otherwise it will just be available in the current expression."
287       R"(
288 
289 Continuing evaluation after a breakpoint:
290 
291 )"
292       "    If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
293 you are done with your investigation, you can either remove the expression execution frames \
294 from the stack with \"thread return -x\" or if you are still interested in the expression result \
295 you can issue the \"continue\" command and the expression evaluation will complete and the \
296 expression result will be available using the \"thread.completed-expression\" key in the thread \
297 format."
298 
299       R"(
300 
301 Examples:
302 
303     expr my_struct->a = my_array[3]
304     expr -f bin -- (index * 8) + 5
305     expr unsigned int $foo = 5
306     expr char c[] = \"foo\"; c[0])");
307 
308   CommandArgumentEntry arg;
309   CommandArgumentData expression_arg;
310 
311   // Define the first (and only) variant of this arg.
312   expression_arg.arg_type = eArgTypeExpression;
313   expression_arg.arg_repetition = eArgRepeatPlain;
314 
315   // There is only one variant this argument could be; put it into the argument
316   // entry.
317   arg.push_back(expression_arg);
318 
319   // Push the data for the first argument into the m_arguments vector.
320   m_arguments.push_back(arg);
321 
322   // Add the "--format" and "--gdb-format"
323   m_option_group.Append(&m_format_options,
324                         OptionGroupFormat::OPTION_GROUP_FORMAT |
325                             OptionGroupFormat::OPTION_GROUP_GDB_FMT,
326                         LLDB_OPT_SET_1);
327   m_option_group.Append(&m_command_options);
328   m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL,
329                         LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
330   m_option_group.Append(&m_repl_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
331   m_option_group.Finalize();
332 }
333 
334 CommandObjectExpression::~CommandObjectExpression() = default;
335 
336 Options *CommandObjectExpression::GetOptions() { return &m_option_group; }
337 
338 void CommandObjectExpression::HandleCompletion(CompletionRequest &request) {
339   EvaluateExpressionOptions options;
340   options.SetCoerceToId(m_varobj_options.use_objc);
341   options.SetLanguage(m_command_options.language);
342   options.SetExecutionPolicy(lldb_private::eExecutionPolicyNever);
343   options.SetAutoApplyFixIts(false);
344   options.SetGenerateDebugInfo(false);
345 
346   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
347 
348   // Get out before we start doing things that expect a valid frame pointer.
349   if (exe_ctx.GetFramePtr() == nullptr)
350     return;
351 
352   Target *exe_target = exe_ctx.GetTargetPtr();
353   Target &target = exe_target ? *exe_target : GetDummyTarget();
354 
355   unsigned cursor_pos = request.GetRawCursorPos();
356   // Get the full user input including the suffix. The suffix is necessary
357   // as OptionsWithRaw will use it to detect if the cursor is cursor is in the
358   // argument part of in the raw input part of the arguments. If we cut of
359   // of the suffix then "expr -arg[cursor] --" would interpret the "-arg" as
360   // the raw input (as the "--" is hidden in the suffix).
361   llvm::StringRef code = request.GetRawLineWithUnusedSuffix();
362 
363   const std::size_t original_code_size = code.size();
364 
365   // Remove the first token which is 'expr' or some alias/abbreviation of that.
366   code = llvm::getToken(code).second.ltrim();
367   OptionsWithRaw args(code);
368   code = args.GetRawPart();
369 
370   // The position where the expression starts in the command line.
371   assert(original_code_size >= code.size());
372   std::size_t raw_start = original_code_size - code.size();
373 
374   // Check if the cursor is actually in the expression string, and if not, we
375   // exit.
376   // FIXME: We should complete the options here.
377   if (cursor_pos < raw_start)
378     return;
379 
380   // Make the cursor_pos again relative to the start of the code string.
381   assert(cursor_pos >= raw_start);
382   cursor_pos -= raw_start;
383 
384   auto language = exe_ctx.GetFrameRef().GetLanguage();
385 
386   Status error;
387   lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage(
388       code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
389       options, nullptr, error));
390   if (error.Fail())
391     return;
392 
393   expr->Complete(exe_ctx, request, cursor_pos);
394 }
395 
396 static lldb_private::Status
397 CanBeUsedForElementCountPrinting(ValueObject &valobj) {
398   CompilerType type(valobj.GetCompilerType());
399   CompilerType pointee;
400   if (!type.IsPointerType(&pointee))
401     return Status("as it does not refer to a pointer");
402   if (pointee.IsVoidType())
403     return Status("as it refers to a pointer to void");
404   return Status();
405 }
406 
407 bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
408                                                  Stream &output_stream,
409                                                  Stream &error_stream,
410                                                  CommandReturnObject &result) {
411   // Don't use m_exe_ctx as this might be called asynchronously after the
412   // command object DoExecute has finished when doing multi-line expression
413   // that use an input reader...
414   ExecutionContext exe_ctx(m_interpreter.GetExecutionContext());
415   Target *exe_target = exe_ctx.GetTargetPtr();
416   Target &target = exe_target ? *exe_target : GetDummyTarget();
417 
418   lldb::ValueObjectSP result_valobj_sp;
419   StackFrame *frame = exe_ctx.GetFramePtr();
420 
421   if (m_command_options.top_level && !m_command_options.allow_jit) {
422     result.AppendErrorWithFormat(
423         "Can't disable JIT compilation for top-level expressions.\n");
424     return false;
425   }
426 
427   const EvaluateExpressionOptions eval_options =
428       m_command_options.GetEvaluateExpressionOptions(target, m_varobj_options);
429   ExpressionResults success = target.EvaluateExpression(
430       expr, frame, result_valobj_sp, eval_options, &m_fixed_expression);
431 
432   // We only tell you about the FixIt if we applied it.  The compiler errors
433   // will suggest the FixIt if it parsed.
434   if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
435     error_stream.Printf("  Fix-it applied, fixed expression was: \n    %s\n",
436                         m_fixed_expression.c_str());
437   }
438 
439   if (result_valobj_sp) {
440     Format format = m_format_options.GetFormat();
441 
442     if (result_valobj_sp->GetError().Success()) {
443       if (format != eFormatVoid) {
444         if (format != eFormatDefault)
445           result_valobj_sp->SetFormat(format);
446 
447         if (m_varobj_options.elem_count > 0) {
448           Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp));
449           if (error.Fail()) {
450             result.AppendErrorWithFormat(
451                 "expression cannot be used with --element-count %s\n",
452                 error.AsCString(""));
453             return false;
454           }
455         }
456 
457         DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
458             m_command_options.m_verbosity, format));
459         options.SetHideRootName(eval_options.GetSuppressPersistentResult());
460         options.SetVariableFormatDisplayLanguage(
461             result_valobj_sp->GetPreferredDisplayLanguage());
462 
463         result_valobj_sp->Dump(output_stream, options);
464 
465         result.SetStatus(eReturnStatusSuccessFinishResult);
466       }
467     } else {
468       if (result_valobj_sp->GetError().GetError() ==
469           UserExpression::kNoResult) {
470         if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) {
471           error_stream.PutCString("(void)\n");
472         }
473 
474         result.SetStatus(eReturnStatusSuccessFinishResult);
475       } else {
476         const char *error_cstr = result_valobj_sp->GetError().AsCString();
477         if (error_cstr && error_cstr[0]) {
478           const size_t error_cstr_len = strlen(error_cstr);
479           const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
480           if (strstr(error_cstr, "error:") != error_cstr)
481             error_stream.PutCString("error: ");
482           error_stream.Write(error_cstr, error_cstr_len);
483           if (!ends_with_newline)
484             error_stream.EOL();
485         } else {
486           error_stream.PutCString("error: unknown error\n");
487         }
488 
489         result.SetStatus(eReturnStatusFailed);
490       }
491     }
492   } else {
493     error_stream.Printf("error: unknown error\n");
494   }
495 
496   return (success != eExpressionSetupError &&
497           success != eExpressionParseError);
498 }
499 
500 void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
501                                                      std::string &line) {
502   io_handler.SetIsDone(true);
503   StreamFileSP output_sp = io_handler.GetOutputStreamFileSP();
504   StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
505 
506   CommandReturnObject return_obj(
507       GetCommandInterpreter().GetDebugger().GetUseColor());
508   EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj);
509   if (output_sp)
510     output_sp->Flush();
511   if (error_sp)
512     error_sp->Flush();
513 }
514 
515 bool CommandObjectExpression::IOHandlerIsInputComplete(IOHandler &io_handler,
516                                                        StringList &lines) {
517   // An empty lines is used to indicate the end of input
518   const size_t num_lines = lines.GetSize();
519   if (num_lines > 0 && lines[num_lines - 1].empty()) {
520     // Remove the last empty line from "lines" so it doesn't appear in our
521     // resulting input and return true to indicate we are done getting lines
522     lines.PopBack();
523     return true;
524   }
525   return false;
526 }
527 
528 void CommandObjectExpression::GetMultilineExpression() {
529   m_expr_lines.clear();
530   m_expr_line_count = 0;
531 
532   Debugger &debugger = GetCommandInterpreter().GetDebugger();
533   bool color_prompt = debugger.GetUseColor();
534   const bool multiple_lines = true; // Get multiple lines
535   IOHandlerSP io_handler_sp(
536       new IOHandlerEditline(debugger, IOHandler::Type::Expression,
537                             "lldb-expr", // Name of input reader for history
538                             llvm::StringRef(), // No prompt
539                             llvm::StringRef(), // Continuation prompt
540                             multiple_lines, color_prompt,
541                             1, // Show line numbers starting at 1
542                             *this));
543 
544   StreamFileSP output_sp = io_handler_sp->GetOutputStreamFileSP();
545   if (output_sp) {
546     output_sp->PutCString(
547         "Enter expressions, then terminate with an empty line to evaluate:\n");
548     output_sp->Flush();
549   }
550   debugger.RunIOHandlerAsync(io_handler_sp);
551 }
552 
553 static EvaluateExpressionOptions
554 GetExprOptions(ExecutionContext &ctx,
555                CommandObjectExpression::CommandOptions command_options) {
556   command_options.OptionParsingStarting(&ctx);
557 
558   // Default certain settings for REPL regardless of the global settings.
559   command_options.unwind_on_error = false;
560   command_options.ignore_breakpoints = false;
561   command_options.debug = false;
562 
563   EvaluateExpressionOptions expr_options;
564   expr_options.SetUnwindOnError(command_options.unwind_on_error);
565   expr_options.SetIgnoreBreakpoints(command_options.ignore_breakpoints);
566   expr_options.SetTryAllThreads(command_options.try_all_threads);
567 
568   if (command_options.timeout > 0)
569     expr_options.SetTimeout(std::chrono::microseconds(command_options.timeout));
570   else
571     expr_options.SetTimeout(std::nullopt);
572 
573   return expr_options;
574 }
575 
576 bool CommandObjectExpression::DoExecute(llvm::StringRef command,
577                                         CommandReturnObject &result) {
578   m_fixed_expression.clear();
579   auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
580   m_option_group.NotifyOptionParsingStarting(&exe_ctx);
581 
582   if (command.empty()) {
583     GetMultilineExpression();
584     return result.Succeeded();
585   }
586 
587   OptionsWithRaw args(command);
588   llvm::StringRef expr = args.GetRawPart();
589 
590   if (args.HasArgs()) {
591     if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group, exe_ctx))
592       return false;
593 
594     if (m_repl_option.GetOptionValue().GetCurrentValue()) {
595       Target &target = GetSelectedOrDummyTarget();
596       // Drop into REPL
597       m_expr_lines.clear();
598       m_expr_line_count = 0;
599 
600       Debugger &debugger = target.GetDebugger();
601 
602       // Check if the LLDB command interpreter is sitting on top of a REPL
603       // that launched it...
604       if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter,
605                                           IOHandler::Type::REPL)) {
606         // the LLDB command interpreter is sitting on top of a REPL that
607         // launched it, so just say the command interpreter is done and
608         // fall back to the existing REPL
609         m_interpreter.GetIOHandler(false)->SetIsDone(true);
610       } else {
611         // We are launching the REPL on top of the current LLDB command
612         // interpreter, so just push one
613         bool initialize = false;
614         Status repl_error;
615         REPLSP repl_sp(target.GetREPL(repl_error, m_command_options.language,
616                                        nullptr, false));
617 
618         if (!repl_sp) {
619           initialize = true;
620           repl_sp = target.GetREPL(repl_error, m_command_options.language,
621                                     nullptr, true);
622           if (!repl_error.Success()) {
623             result.SetError(repl_error);
624             return result.Succeeded();
625           }
626         }
627 
628         if (repl_sp) {
629           if (initialize) {
630             repl_sp->SetEvaluateOptions(
631                 GetExprOptions(exe_ctx, m_command_options));
632             repl_sp->SetFormatOptions(m_format_options);
633             repl_sp->SetValueObjectDisplayOptions(m_varobj_options);
634           }
635 
636           IOHandlerSP io_handler_sp(repl_sp->GetIOHandler());
637           io_handler_sp->SetIsDone(false);
638           debugger.RunIOHandlerAsync(io_handler_sp);
639         } else {
640           repl_error.SetErrorStringWithFormat(
641               "Couldn't create a REPL for %s",
642               Language::GetNameForLanguageType(m_command_options.language));
643           result.SetError(repl_error);
644           return result.Succeeded();
645         }
646       }
647     }
648     // No expression following options
649     else if (expr.empty()) {
650       GetMultilineExpression();
651       return result.Succeeded();
652     }
653   }
654 
655   Target &target = GetSelectedOrDummyTarget();
656   if (EvaluateExpression(expr, result.GetOutputStream(),
657                          result.GetErrorStream(), result)) {
658 
659     if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
660       CommandHistory &history = m_interpreter.GetCommandHistory();
661       // FIXME: Can we figure out what the user actually typed (e.g. some alias
662       // for expr???)
663       // If we can it would be nice to show that.
664       std::string fixed_command("expression ");
665       if (args.HasArgs()) {
666         // Add in any options that might have been in the original command:
667         fixed_command.append(std::string(args.GetArgStringWithDelimiter()));
668         fixed_command.append(m_fixed_expression);
669       } else
670         fixed_command.append(m_fixed_expression);
671       history.AppendString(fixed_command);
672     }
673     return true;
674   }
675   result.SetStatus(eReturnStatusFailed);
676   return false;
677 }
678