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