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