1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "llvm/ADT/STLExtras.h" |
14 | #include "llvm/ADT/StringRef.h" |
15 | |
16 | |
17 | #include "CommandObjectExpression.h" |
18 | #include "lldb/Core/Value.h" |
19 | #include "lldb/Core/ValueObjectVariable.h" |
20 | #include "lldb/DataFormatters/ValueObjectPrinter.h" |
21 | #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" |
22 | #include "lldb/Expression/UserExpression.h" |
23 | #include "lldb/Expression/DWARFExpression.h" |
24 | #include "lldb/Expression/REPL.h" |
25 | #include "lldb/Host/Host.h" |
26 | #include "lldb/Host/StringConvert.h" |
27 | #include "lldb/Core/Debugger.h" |
28 | #include "lldb/Interpreter/CommandInterpreter.h" |
29 | #include "lldb/Interpreter/CommandReturnObject.h" |
30 | #include "lldb/Target/Language.h" |
31 | #include "lldb/Symbol/ObjectFile.h" |
32 | #include "lldb/Symbol/Variable.h" |
33 | #include "lldb/Target/Process.h" |
34 | #include "lldb/Target/StackFrame.h" |
35 | #include "lldb/Target/Target.h" |
36 | #include "lldb/Target/Thread.h" |
37 | |
38 | using namespace lldb; |
39 | using namespace lldb_private; |
40 | |
41 | CommandObjectExpression::CommandOptions::CommandOptions () : |
42 | OptionGroup() |
43 | { |
44 | } |
45 | |
46 | CommandObjectExpression::CommandOptions::~CommandOptions() = default; |
47 | |
48 | static OptionEnumValueElement g_description_verbosity_type[] = |
49 | { |
50 | { eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact", "Only show the description string"}, |
51 | { eLanguageRuntimeDescriptionDisplayVerbosityFull, "full", "Show the full output, including persistent variable's name and type"}, |
52 | { 0, nullptr, nullptr } |
53 | }; |
54 | |
55 | OptionDefinition |
56 | CommandObjectExpression::CommandOptions::g_option_table[] = |
57 | { |
58 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "all-threads", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."}, |
59 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"}, |
60 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "timeout", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."}, |
61 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."}, |
62 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "debug", 'g', OptionParser::eNoArgument , nullptr, nullptr, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."}, |
63 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "language", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specifies the Language to use when parsing the expression. If not set the target.language setting is used." }, |
64 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "apply-fixits", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "If true, simple FixIt hints will be automatically applied to the expression." }, |
65 | { LLDB_OPT_SET_1(1U << 0), false, "description-verbosity", 'v', OptionParser::eOptionalArgument, nullptr, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, |
66 | { LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1), false, "top-level", 'p', OptionParser::eNoArgument , NULL__null, NULL__null, 0, eArgTypeNone, "Interpret the expression as top-level definitions rather than code to be immediately executed."} |
67 | }; |
68 | |
69 | uint32_t |
70 | CommandObjectExpression::CommandOptions::GetNumDefinitions () |
71 | { |
72 | return llvm::array_lengthof(g_option_table); |
73 | } |
74 | |
75 | Error |
76 | CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter, |
77 | uint32_t option_idx, |
78 | const char *option_arg) |
79 | { |
80 | Error error; |
81 | |
82 | const int short_option = g_option_table[option_idx].short_option; |
83 | |
84 | switch (short_option) |
85 | { |
86 | case 'l': |
87 | language = Language::GetLanguageTypeFromString (option_arg); |
88 | if (language == eLanguageTypeUnknown) |
89 | error.SetErrorStringWithFormat ("unknown language type: '%s' for expression", option_arg); |
90 | break; |
91 | |
92 | case 'a': |
93 | { |
94 | bool success; |
95 | bool result; |
96 | result = Args::StringToBoolean(option_arg, true, &success); |
97 | if (!success) |
98 | error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg); |
99 | else |
100 | try_all_threads = result; |
101 | } |
102 | break; |
103 | |
104 | case 'i': |
105 | { |
106 | bool success; |
107 | bool tmp_value = Args::StringToBoolean(option_arg, true, &success); |
108 | if (success) |
109 | ignore_breakpoints = tmp_value; |
110 | else |
111 | error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); |
112 | break; |
113 | } |
114 | case 't': |
115 | { |
116 | bool success; |
117 | uint32_t result; |
118 | result = StringConvert::ToUInt32(option_arg, 0, 0, &success); |
119 | if (success) |
120 | timeout = result; |
121 | else |
122 | error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg); |
123 | } |
124 | break; |
125 | |
126 | case 'u': |
127 | { |
128 | bool success; |
129 | bool tmp_value = Args::StringToBoolean(option_arg, true, &success); |
130 | if (success) |
131 | unwind_on_error = tmp_value; |
132 | else |
133 | error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); |
134 | break; |
135 | } |
136 | |
137 | case 'v': |
138 | if (!option_arg) |
139 | { |
140 | m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull; |
141 | break; |
142 | } |
143 | m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); |
144 | if (!error.Success()) |
145 | error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg); |
146 | break; |
147 | |
148 | case 'g': |
149 | debug = true; |
150 | unwind_on_error = false; |
151 | ignore_breakpoints = false; |
152 | break; |
153 | |
154 | case 'p': |
155 | top_level = true; |
156 | break; |
157 | |
158 | case 'X': |
159 | { |
160 | bool success; |
161 | bool tmp_value = Args::StringToBoolean(option_arg, true, &success); |
162 | if (success) |
163 | auto_apply_fixits = tmp_value ? eLazyBoolYes : eLazyBoolNo; |
164 | else |
165 | error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); |
166 | break; |
167 | } |
168 | |
169 | default: |
170 | error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); |
171 | break; |
172 | } |
173 | |
174 | return error; |
175 | } |
176 | |
177 | void |
178 | CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter) |
179 | { |
180 | Process *process = interpreter.GetExecutionContext().GetProcessPtr(); |
181 | if (process != nullptr) |
182 | { |
183 | ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions(); |
184 | unwind_on_error = process->GetUnwindOnErrorInExpressions(); |
185 | } |
186 | else |
187 | { |
188 | ignore_breakpoints = true; |
189 | unwind_on_error = true; |
190 | } |
191 | |
192 | show_summary = true; |
193 | try_all_threads = true; |
194 | timeout = 0; |
195 | debug = false; |
196 | language = eLanguageTypeUnknown; |
197 | m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; |
198 | auto_apply_fixits = eLazyBoolCalculate; |
199 | top_level = false; |
200 | } |
201 | |
202 | const OptionDefinition* |
203 | CommandObjectExpression::CommandOptions::GetDefinitions () |
204 | { |
205 | return g_option_table; |
206 | } |
207 | |
208 | CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) : |
209 | CommandObjectRaw(interpreter, |
210 | "expression", |
211 | "Evaluate an expression in the current program context, using user defined variables and variables currently in scope.", |
212 | nullptr, |
213 | eCommandProcessMustBePaused | eCommandTryTargetAPILock), |
214 | IOHandlerDelegate (IOHandlerDelegate::Completion::Expression), |
215 | m_option_group (interpreter), |
216 | m_format_options (eFormatDefault), |
217 | m_repl_option (LLDB_OPT_SET_1(1U << 0), false, "repl", 'r', "Drop into REPL", false, true), |
218 | m_command_options (), |
219 | m_expr_line_count (0), |
220 | m_expr_lines () |
221 | { |
222 | SetHelpLong( |
223 | R"( |
224 | Timeouts: |
225 | |
226 | )" " If the expression can be evaluated statically (without running code) then it will be. \ |
227 | Otherwise, by default the expression will run on the current thread with a short timeout: \ |
228 | currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted \ |
229 | and resumed with all threads running. You can use the -a option to disable retrying on all \ |
230 | threads. You can use the -t option to set a shorter timeout." R"( |
231 | |
232 | User defined variables: |
233 | |
234 | )" " You can define your own variables for convenience or to be used in subsequent expressions. \ |
235 | You define them the same way you would define variables in C. If the first character of \ |
236 | your user defined variable is a $, then the variable's value will be available in future \ |
237 | expressions, otherwise it will just be available in the current expression." R"( |
238 | |
239 | Continuing evaluation after a breakpoint: |
240 | |
241 | )" " If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \ |
242 | you are done with your investigation, you can either remove the expression execution frames \ |
243 | from the stack with \"thread return -x\" or if you are still interested in the expression result \ |
244 | you can issue the \"continue\" command and the expression evaluation will complete and the \ |
245 | expression result will be available using the \"thread.completed-expression\" key in the thread \ |
246 | format." R"( |
247 | |
248 | Examples: |
249 | |
250 | expr my_struct->a = my_array[3] |
251 | expr -f bin -- (index * 8) + 5 |
252 | expr unsigned int $foo = 5 |
253 | expr char c[] = \"foo\"; c[0])" |
254 | ); |
255 | |
256 | CommandArgumentEntry arg; |
257 | CommandArgumentData expression_arg; |
258 | |
259 | |
260 | expression_arg.arg_type = eArgTypeExpression; |
261 | expression_arg.arg_repetition = eArgRepeatPlain; |
262 | |
263 | |
264 | arg.push_back (expression_arg); |
265 | |
266 | |
267 | m_arguments.push_back (arg); |
268 | |
269 | |
270 | m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1(1U << 0)); |
271 | m_option_group.Append (&m_command_options); |
272 | m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL0xFFFFFFFFU, LLDB_OPT_SET_1(1U << 0) | LLDB_OPT_SET_2(1U << 1)); |
273 | m_option_group.Append (&m_repl_option, LLDB_OPT_SET_ALL0xFFFFFFFFU, LLDB_OPT_SET_3(1U << 2)); |
274 | m_option_group.Finalize(); |
275 | } |
276 | |
277 | CommandObjectExpression::~CommandObjectExpression() = default; |
278 | |
279 | Options * |
280 | CommandObjectExpression::GetOptions () |
281 | { |
282 | return &m_option_group; |
283 | } |
284 | |
285 | static lldb_private::Error |
286 | CanBeUsedForElementCountPrinting (ValueObject& valobj) |
287 | { |
288 | CompilerType type(valobj.GetCompilerType()); |
289 | CompilerType pointee; |
290 | if (!type.IsPointerType(&pointee)) |
291 | return Error("as it does not refer to a pointer"); |
292 | if (pointee.IsVoidType()) |
293 | return Error("as it refers to a pointer to void"); |
294 | return Error(); |
295 | } |
296 | |
297 | bool |
298 | CommandObjectExpression::EvaluateExpression(const char *expr, |
299 | Stream *output_stream, |
300 | Stream *error_stream, |
301 | CommandReturnObject *result) |
302 | { |
303 | |
304 | |
305 | |
306 | ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); |
307 | |
308 | Target *target = exe_ctx.GetTargetPtr(); |
309 | |
310 | if (!target) |
| 1 | Assuming 'target' is non-null | |
|
| |
311 | target = GetDummyTarget(); |
312 | |
313 | if (target) |
| |
314 | { |
315 | lldb::ValueObjectSP result_valobj_sp; |
316 | bool keep_in_memory = true; |
317 | StackFrame *frame = exe_ctx.GetFramePtr(); |
318 | |
319 | EvaluateExpressionOptions options; |
320 | options.SetCoerceToId(m_varobj_options.use_objc); |
321 | options.SetUnwindOnError(m_command_options.unwind_on_error); |
322 | options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints); |
323 | options.SetKeepInMemory(keep_in_memory); |
324 | options.SetUseDynamic(m_varobj_options.use_dynamic); |
325 | options.SetTryAllThreads(m_command_options.try_all_threads); |
326 | options.SetDebug(m_command_options.debug); |
327 | options.SetLanguage(m_command_options.language); |
328 | |
329 | bool auto_apply_fixits; |
330 | if (m_command_options.auto_apply_fixits == eLazyBoolCalculate) |
| |
331 | auto_apply_fixits = target->GetEnableAutoApplyFixIts(); |
332 | else |
333 | auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes ? true : false; |
| |
334 | |
335 | options.SetAutoApplyFixIts(auto_apply_fixits); |
336 | |
337 | if (m_command_options.top_level) |
| |
338 | options.SetExecutionPolicy(eExecutionPolicyTopLevel); |
339 | |
340 | |
341 | |
342 | if (!m_command_options.ignore_breakpoints || |
| |
343 | !m_command_options.unwind_on_error) |
344 | options.SetGenerateDebugInfo(true); |
345 | |
346 | if (m_command_options.timeout > 0) |
| |
347 | options.SetTimeoutUsec(m_command_options.timeout); |
348 | else |
349 | options.SetTimeoutUsec(0); |
350 | |
351 | ExpressionResults success = target->EvaluateExpression(expr, frame, result_valobj_sp, options, &m_fixed_expression); |
352 | |
353 | |
354 | if (error_stream && !m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) |
| 9 | | Assuming pointer value is null | |
|
355 | { |
356 | if (success == eExpressionCompleted) |
357 | error_stream->Printf (" Fixit applied, fixed expression was: \n %s\n", m_fixed_expression.c_str()); |
358 | } |
359 | |
360 | if (result_valobj_sp) |
| |
361 | { |
362 | Format format = m_format_options.GetFormat(); |
363 | |
364 | if (result_valobj_sp->GetError().Success()) |
| |
365 | { |
366 | if (format != eFormatVoid) |
367 | { |
368 | if (format != eFormatDefault) |
369 | result_valobj_sp->SetFormat (format); |
370 | |
371 | if (m_varobj_options.elem_count > 0) |
372 | { |
373 | Error error(CanBeUsedForElementCountPrinting(*result_valobj_sp)); |
374 | if (error.Fail()) |
375 | { |
376 | result->AppendErrorWithFormat("expression cannot be used with --element-count %s\n", error.AsCString("")); |
377 | result->SetStatus(eReturnStatusFailed); |
378 | return false; |
379 | } |
380 | } |
381 | |
382 | DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format)); |
383 | options.SetVariableFormatDisplayLanguage(result_valobj_sp->GetPreferredDisplayLanguage()); |
384 | |
385 | result_valobj_sp->Dump(*output_stream,options); |
386 | |
387 | if (result) |
388 | result->SetStatus (eReturnStatusSuccessFinishResult); |
389 | } |
390 | } |
391 | else |
392 | { |
393 | if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) |
| |
394 | { |
395 | if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid()) |
396 | { |
397 | error_stream->PutCString("(void)\n"); |
398 | } |
399 | |
400 | if (result) |
401 | result->SetStatus (eReturnStatusSuccessFinishResult); |
402 | } |
403 | else |
404 | { |
405 | const char *error_cstr = result_valobj_sp->GetError().AsCString(); |
406 | if (error_cstr && error_cstr[0]) |
| |
407 | { |
408 | const size_t error_cstr_len = strlen (error_cstr); |
409 | const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n'; |
410 | if (strstr(error_cstr, "error:") != error_cstr) |
| |
411 | error_stream->PutCString ("error: "); |
412 | error_stream->Write(error_cstr, error_cstr_len); |
| 15 | | Called C++ object pointer is null |
|
413 | if (!ends_with_newline) |
414 | error_stream->EOL(); |
415 | } |
416 | else |
417 | { |
418 | error_stream->PutCString ("error: unknown error\n"); |
419 | } |
420 | |
421 | if (result) |
422 | result->SetStatus (eReturnStatusFailed); |
423 | } |
424 | } |
425 | } |
426 | } |
427 | else |
428 | { |
429 | error_stream->Printf ("error: invalid execution context for expression\n"); |
430 | return false; |
431 | } |
432 | |
433 | return true; |
434 | } |
435 | |
436 | void |
437 | CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) |
438 | { |
439 | io_handler.SetIsDone(true); |
440 | |
441 | |
442 | StreamFileSP output_sp(io_handler.GetOutputStreamFile()); |
443 | StreamFileSP error_sp(io_handler.GetErrorStreamFile()); |
444 | |
445 | EvaluateExpression (line.c_str(), |
446 | output_sp.get(), |
447 | error_sp.get()); |
448 | if (output_sp) |
449 | output_sp->Flush(); |
450 | if (error_sp) |
451 | error_sp->Flush(); |
452 | } |
453 | |
454 | LineStatus |
455 | CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler, |
456 | StringList &lines, |
457 | uint32_t line_idx, |
458 | Error &error) |
459 | { |
460 | if (line_idx == UINT32_MAX(4294967295U)) |
461 | { |
462 | |
463 | |
464 | lines.PopBack(); |
465 | error.Clear(); |
466 | return LineStatus::Done; |
467 | } |
468 | else if (line_idx + 1 == lines.GetSize()) |
469 | { |
470 | |
471 | |
472 | if (lines[line_idx].empty()) |
473 | return LineStatus::Done; |
474 | } |
475 | return LineStatus::Success; |
476 | } |
477 | |
478 | void |
479 | CommandObjectExpression::GetMultilineExpression () |
480 | { |
481 | m_expr_lines.clear(); |
482 | m_expr_line_count = 0; |
483 | |
484 | Debugger &debugger = GetCommandInterpreter().GetDebugger(); |
485 | bool color_prompt = debugger.GetUseColor(); |
486 | const bool multiple_lines = true; |
487 | IOHandlerSP io_handler_sp(new IOHandlerEditline(debugger, |
488 | IOHandler::Type::Expression, |
489 | "lldb-expr", |
490 | nullptr, |
491 | nullptr, |
492 | multiple_lines, |
493 | color_prompt, |
494 | 1, |
495 | *this)); |
496 | |
497 | StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile()); |
498 | if (output_sp) |
499 | { |
500 | output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n"); |
501 | output_sp->Flush(); |
502 | } |
503 | debugger.PushIOHandler(io_handler_sp); |
504 | } |
505 | |
506 | bool |
507 | CommandObjectExpression::DoExecute(const char *command, |
508 | CommandReturnObject &result) |
509 | { |
510 | m_fixed_expression.clear(); |
511 | m_option_group.NotifyOptionParsingStarting(); |
512 | |
513 | const char * expr = nullptr; |
514 | |
515 | if (command[0] == '\0') |
516 | { |
517 | GetMultilineExpression (); |
518 | return result.Succeeded(); |
519 | } |
520 | |
521 | if (command[0] == '-') |
522 | { |
523 | |
524 | const char *end_options = nullptr; |
525 | const char *s = command; |
526 | while (s && s[0]) |
527 | { |
528 | end_options = ::strstr (s, "--"); |
529 | if (end_options) |
530 | { |
531 | end_options += 2; |
532 | if (::isspace (end_options[0])) |
533 | { |
534 | expr = end_options; |
535 | while (::isspace (*expr)) |
536 | ++expr; |
537 | break; |
538 | } |
539 | } |
540 | s = end_options; |
541 | } |
542 | |
543 | if (end_options) |
544 | { |
545 | Args args (llvm::StringRef(command, end_options - command)); |
546 | if (!ParseOptions (args, result)) |
547 | return false; |
548 | |
549 | Error error (m_option_group.NotifyOptionParsingFinished()); |
550 | if (error.Fail()) |
551 | { |
552 | result.AppendError (error.AsCString()); |
553 | result.SetStatus (eReturnStatusFailed); |
554 | return false; |
555 | } |
556 | |
557 | if (m_repl_option.GetOptionValue().GetCurrentValue()) |
558 | { |
559 | Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); |
560 | if (target) |
561 | { |
562 | |
563 | m_expr_lines.clear(); |
564 | m_expr_line_count = 0; |
565 | |
566 | Debugger &debugger = target->GetDebugger(); |
567 | |
568 | |
569 | |
570 | if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::CommandInterpreter, IOHandler::Type::REPL)) |
571 | { |
572 | |
573 | |
574 | m_interpreter.GetIOHandler(false)->SetIsDone(true); |
575 | } |
576 | else |
577 | { |
578 | |
579 | |
580 | bool initialize = false; |
581 | Error repl_error; |
582 | REPLSP repl_sp (target->GetREPL(repl_error, m_command_options.language, nullptr, false)); |
583 | |
584 | if (!repl_sp) |
585 | { |
586 | initialize = true; |
587 | repl_sp = target->GetREPL(repl_error, m_command_options.language, nullptr, true); |
588 | if (!repl_error.Success()) |
589 | { |
590 | result.SetError(repl_error); |
591 | return result.Succeeded(); |
592 | } |
593 | } |
594 | |
595 | if (repl_sp) |
596 | { |
597 | if (initialize) |
598 | { |
599 | repl_sp->SetCommandOptions(m_command_options); |
600 | repl_sp->SetFormatOptions(m_format_options); |
601 | repl_sp->SetValueObjectDisplayOptions(m_varobj_options); |
602 | } |
603 | |
604 | IOHandlerSP io_handler_sp (repl_sp->GetIOHandler()); |
605 | |
606 | io_handler_sp->SetIsDone(false); |
607 | |
608 | debugger.PushIOHandler(io_handler_sp); |
609 | } |
610 | else |
611 | { |
612 | repl_error.SetErrorStringWithFormat("Couldn't create a REPL for %s", Language::GetNameForLanguageType(m_command_options.language)); |
613 | result.SetError(repl_error); |
614 | return result.Succeeded(); |
615 | } |
616 | } |
617 | } |
618 | } |
619 | |
620 | else if (expr == nullptr || expr[0] == '\0') |
621 | { |
622 | GetMultilineExpression (); |
623 | return result.Succeeded(); |
624 | } |
625 | } |
626 | } |
627 | |
628 | if (expr == nullptr) |
629 | expr = command; |
630 | |
631 | if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result)) |
632 | { |
633 | Target *target = m_interpreter.GetExecutionContext().GetTargetPtr(); |
634 | if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) |
635 | { |
636 | CommandHistory &history = m_interpreter.GetCommandHistory(); |
637 | |
638 | |
639 | std::string fixed_command("expression "); |
640 | if (expr == command) |
641 | fixed_command.append(m_fixed_expression); |
642 | else |
643 | { |
644 | |
645 | fixed_command.append(command, expr - command); |
646 | fixed_command.append(m_fixed_expression); |
647 | } |
648 | history.AppendString(fixed_command); |
649 | } |
650 | return true; |
651 | } |
652 | |
653 | result.SetStatus (eReturnStatusFailed); |
654 | return false; |
655 | } |