xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision e30f11d9ee08309d545224091bad706b9a8d4eca)
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 #include "lldb/lldb-python.h"
11 
12 #include "CommandObjectExpression.h"
13 
14 // C Includes
15 // C++ Includes
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Interpreter/Args.h"
19 #include "lldb/Core/Value.h"
20 #include "lldb/Core/ValueObjectVariable.h"
21 #include "lldb/DataFormatters/ValueObjectPrinter.h"
22 #include "lldb/Expression/ClangExpressionVariable.h"
23 #include "lldb/Expression/ClangUserExpression.h"
24 #include "lldb/Expression/ClangFunction.h"
25 #include "lldb/Expression/DWARFExpression.h"
26 #include "lldb/Host/Host.h"
27 #include "lldb/Core/Debugger.h"
28 #include "lldb/Interpreter/CommandInterpreter.h"
29 #include "lldb/Interpreter/CommandReturnObject.h"
30 #include "lldb/Target/ObjCLanguageRuntime.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 #include "llvm/ADT/STLExtras.h"
38 #include "llvm/ADT/StringRef.h"
39 
40 using namespace lldb;
41 using namespace lldb_private;
42 
43 CommandObjectExpression::CommandOptions::CommandOptions () :
44     OptionGroup()
45 {
46 }
47 
48 
49 CommandObjectExpression::CommandOptions::~CommandOptions ()
50 {
51 }
52 
53 static OptionEnumValueElement g_description_verbosity_type[] =
54 {
55     { eLanguageRuntimeDescriptionDisplayVerbosityCompact,      "compact",       "Only show the description string"},
56     { eLanguageRuntimeDescriptionDisplayVerbosityFull,         "full",          "Show the full output, including persistent variable's name and type"},
57     { 0, NULL, NULL }
58 };
59 
60 OptionDefinition
61 CommandObjectExpression::CommandOptions::g_option_table[] =
62 {
63     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",        'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Should we run all threads if the execution doesn't complete on one thread."},
64     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Ignore breakpoint hits while running expressions"},
65     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value (in microseconds) for running the expression."},
66     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",    'u', OptionParser::eRequiredArgument, NULL, NULL, 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)."},
67     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug",              'g', OptionParser::eNoArgument      , NULL, NULL, 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)."},
68     { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, NULL, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity,        "How verbose should the output of this expression be, if the object description is asked for."},
69 };
70 
71 
72 uint32_t
73 CommandObjectExpression::CommandOptions::GetNumDefinitions ()
74 {
75     return llvm::array_lengthof(g_option_table);
76 }
77 
78 Error
79 CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
80                                                          uint32_t option_idx,
81                                                          const char *option_arg)
82 {
83     Error error;
84 
85     const int short_option = g_option_table[option_idx].short_option;
86 
87     switch (short_option)
88     {
89       //case 'l':
90       //if (language.SetLanguageFromCString (option_arg) == false)
91       //{
92       //    error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
93       //}
94       //break;
95 
96     case 'a':
97         {
98             bool success;
99             bool result;
100             result = Args::StringToBoolean(option_arg, true, &success);
101             if (!success)
102                 error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
103             else
104                 try_all_threads = result;
105         }
106         break;
107 
108     case 'i':
109         {
110             bool success;
111             bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
112             if (success)
113                 ignore_breakpoints = tmp_value;
114             else
115                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
116             break;
117         }
118     case 't':
119         {
120             bool success;
121             uint32_t result;
122             result = Args::StringToUInt32(option_arg, 0, 0, &success);
123             if (success)
124                 timeout = result;
125             else
126                 error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
127         }
128         break;
129 
130     case 'u':
131         {
132             bool success;
133             bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
134             if (success)
135                 unwind_on_error = tmp_value;
136             else
137                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
138             break;
139         }
140 
141     case 'v':
142         if (!option_arg)
143         {
144             m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
145             break;
146         }
147         m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
148         if (!error.Success())
149             error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg);
150         break;
151 
152     case 'g':
153         debug = true;
154         unwind_on_error = false;
155         ignore_breakpoints = false;
156         break;
157 
158     default:
159         error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
160         break;
161     }
162 
163     return error;
164 }
165 
166 void
167 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
168 {
169     Process *process = interpreter.GetExecutionContext().GetProcessPtr();
170     if (process != NULL)
171     {
172         ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
173         unwind_on_error    = process->GetUnwindOnErrorInExpressions();
174     }
175     else
176     {
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     m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
186 }
187 
188 const OptionDefinition*
189 CommandObjectExpression::CommandOptions::GetDefinitions ()
190 {
191     return g_option_table;
192 }
193 
194 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
195     CommandObjectRaw (interpreter,
196                       "expression",
197                       "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
198                       NULL,
199                       eFlagProcessMustBePaused | eFlagTryTargetAPILock),
200     IOHandlerDelegate (IOHandlerDelegate::Completion::Expression),
201     m_option_group (interpreter),
202     m_format_options (eFormatDefault),
203     m_command_options (),
204     m_expr_line_count (0),
205     m_expr_lines ()
206 {
207   SetHelpLong(
208 "Timeouts:\n\
209     If the expression can be evaluated statically (without running code) then it will be.\n\
210     Otherwise, by default the expression will run on the current thread with a short timeout:\n\
211     currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted\n\
212     and resumed with all threads running.  You can use the -a option to disable retrying on all\n\
213     threads.  You can use the -t option to set a shorter timeout.\n\
214 \n\
215 User defined variables:\n\
216     You can define your own variables for convenience or to be used in subsequent expressions.\n\
217     You define them the same way you would define variables in C.  If the first character of \n\
218     your user defined variable is a $, then the variable's value will be available in future\n\
219     expressions, otherwise it will just be available in the current expression.\n\
220 \n\
221 \n\
222 Continuing evaluation after a breakpoint:\n\
223     If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once\n\
224     you are done with your investigation, you can either remove the expression execution frames\n\
225     from the stack with \"thread return -x\" or if you are still interested in the expression result\n\
226     you can issue the \"continue\" command and the expression evaluation will complete and the\n\
227     expression result will be available using the \"thread.completed-expression\" key in the thread\n\
228     format.\n\
229 \n\
230 Examples: \n\
231 \n\
232    expr my_struct->a = my_array[3] \n\
233    expr -f bin -- (index * 8) + 5 \n\
234    expr unsigned int $foo = 5\n\
235    expr char c[] = \"foo\"; c[0]\n");
236 
237     CommandArgumentEntry arg;
238     CommandArgumentData expression_arg;
239 
240     // Define the first (and only) variant of this arg.
241     expression_arg.arg_type = eArgTypeExpression;
242     expression_arg.arg_repetition = eArgRepeatPlain;
243 
244     // There is only one variant this argument could be; put it into the argument entry.
245     arg.push_back (expression_arg);
246 
247     // Push the data for the first argument into the m_arguments vector.
248     m_arguments.push_back (arg);
249 
250     // Add the "--format" and "--gdb-format"
251     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
252     m_option_group.Append (&m_command_options);
253     m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
254     m_option_group.Finalize();
255 }
256 
257 CommandObjectExpression::~CommandObjectExpression ()
258 {
259 }
260 
261 Options *
262 CommandObjectExpression::GetOptions ()
263 {
264     return &m_option_group;
265 }
266 
267 bool
268 CommandObjectExpression::EvaluateExpression
269 (
270     const char *expr,
271     Stream *output_stream,
272     Stream *error_stream,
273     CommandReturnObject *result
274 )
275 {
276     // Don't use m_exe_ctx as this might be called asynchronously
277     // after the command object DoExecute has finished when doing
278     // multi-line expression that use an input reader...
279     ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
280 
281     Target *target = exe_ctx.GetTargetPtr();
282 
283     if (!target)
284         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
285 
286     if (target)
287     {
288         lldb::ValueObjectSP result_valobj_sp;
289 
290         bool keep_in_memory = true;
291 
292         EvaluateExpressionOptions options;
293         options.SetCoerceToId(m_varobj_options.use_objc);
294         options.SetUnwindOnError(m_command_options.unwind_on_error);
295         options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
296         options.SetKeepInMemory(keep_in_memory);
297         options.SetUseDynamic(m_varobj_options.use_dynamic);
298         options.SetTryAllThreads(m_command_options.try_all_threads);
299         options.SetDebug(m_command_options.debug);
300 
301         // If there is any chance we are going to stop and want to see
302         // what went wrong with our expression, we should generate debug info
303         if (!m_command_options.ignore_breakpoints ||
304             !m_command_options.unwind_on_error)
305             options.SetGenerateDebugInfo(true);
306 
307         if (m_command_options.timeout > 0)
308             options.SetTimeoutUsec(m_command_options.timeout);
309         else
310             options.SetTimeoutUsec(0);
311 
312         target->EvaluateExpression(expr, exe_ctx.GetFramePtr(),
313                                    result_valobj_sp, options);
314 
315         if (result_valobj_sp)
316         {
317             Format format = m_format_options.GetFormat();
318 
319             if (result_valobj_sp->GetError().Success())
320             {
321                 if (format != eFormatVoid)
322                 {
323                     if (format != eFormatDefault)
324                         result_valobj_sp->SetFormat (format);
325 
326                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format));
327 
328                     result_valobj_sp->Dump(*output_stream,options);
329 
330                     if (result)
331                         result->SetStatus (eReturnStatusSuccessFinishResult);
332                 }
333             }
334             else
335             {
336                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
337                 {
338                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
339                     {
340                         error_stream->PutCString("(void)\n");
341                     }
342 
343                     if (result)
344                         result->SetStatus (eReturnStatusSuccessFinishResult);
345                 }
346                 else
347                 {
348                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
349                     if (error_cstr && error_cstr[0])
350                     {
351                         const size_t error_cstr_len = strlen (error_cstr);
352                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
353                         if (strstr(error_cstr, "error:") != error_cstr)
354                             error_stream->PutCString ("error: ");
355                         error_stream->Write(error_cstr, error_cstr_len);
356                         if (!ends_with_newline)
357                             error_stream->EOL();
358                     }
359                     else
360                     {
361                         error_stream->PutCString ("error: unknown error\n");
362                     }
363 
364                     if (result)
365                         result->SetStatus (eReturnStatusFailed);
366                 }
367             }
368         }
369     }
370     else
371     {
372         error_stream->Printf ("error: invalid execution context for expression\n");
373         return false;
374     }
375 
376     return true;
377 }
378 
379 void
380 CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
381 {
382     io_handler.SetIsDone(true);
383 //    StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream();
384 //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
385     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
386     StreamFileSP error_sp(io_handler.GetErrorStreamFile());
387 
388     EvaluateExpression (line.c_str(),
389                         output_sp.get(),
390                         error_sp.get());
391     if (output_sp)
392         output_sp->Flush();
393     if (error_sp)
394         error_sp->Flush();
395 }
396 
397 LineStatus
398 CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler,
399                                                 StringList &lines,
400                                                 uint32_t line_idx,
401                                                 Error &error)
402 {
403     if (line_idx == UINT32_MAX)
404     {
405         // Remove the last line from "lines" so it doesn't appear
406         // in our final expression
407         lines.PopBack();
408         error.Clear();
409         return LineStatus::Done;
410     }
411     else if (line_idx + 1 == lines.GetSize())
412     {
413         // The last line was edited, if this line is empty, then we are done
414         // getting our multiple lines.
415         if (lines[line_idx].empty())
416             return LineStatus::Done;
417     }
418     return LineStatus::Success;
419 }
420 
421 void
422 CommandObjectExpression::GetMultilineExpression ()
423 {
424     m_expr_lines.clear();
425     m_expr_line_count = 0;
426 
427     Debugger &debugger = GetCommandInterpreter().GetDebugger();
428     bool color_prompt = debugger.GetUseColor();
429     const bool multiple_lines = true; // Get multiple lines
430     IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
431                                                       IOHandler::Type::Expression,
432                                                       "lldb-expr",      // Name of input reader for history
433                                                       NULL,             // No prompt
434                                                       NULL,             // Continuation prompt
435                                                       multiple_lines,
436                                                       color_prompt,
437                                                       1,                // Show line numbers starting at 1
438                                                       *this));
439 
440     StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
441     if (output_sp)
442     {
443         output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
444         output_sp->Flush();
445     }
446     debugger.PushIOHandler(io_handler_sp);
447 }
448 
449 bool
450 CommandObjectExpression::DoExecute
451 (
452     const char *command,
453     CommandReturnObject &result
454 )
455 {
456     m_option_group.NotifyOptionParsingStarting();
457 
458     const char * expr = NULL;
459 
460     if (command[0] == '\0')
461     {
462         GetMultilineExpression ();
463         return result.Succeeded();
464     }
465 
466     if (command[0] == '-')
467     {
468         // We have some options and these options MUST end with --.
469         const char *end_options = NULL;
470         const char *s = command;
471         while (s && s[0])
472         {
473             end_options = ::strstr (s, "--");
474             if (end_options)
475             {
476                 end_options += 2; // Get past the "--"
477                 if (::isspace (end_options[0]))
478                 {
479                     expr = end_options;
480                     while (::isspace (*expr))
481                         ++expr;
482                     break;
483                 }
484             }
485             s = end_options;
486         }
487 
488         if (end_options)
489         {
490             Args args (command, end_options - command);
491             if (!ParseOptions (args, result))
492                 return false;
493 
494             Error error (m_option_group.NotifyOptionParsingFinished());
495             if (error.Fail())
496             {
497                 result.AppendError (error.AsCString());
498                 result.SetStatus (eReturnStatusFailed);
499                 return false;
500             }
501 
502             // No expression following options
503             if (expr == NULL || expr[0] == '\0')
504             {
505                 GetMultilineExpression ();
506                 return result.Succeeded();
507             }
508         }
509     }
510 
511     if (expr == NULL)
512         expr = command;
513 
514     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
515         return true;
516 
517     result.SetStatus (eReturnStatusFailed);
518     return false;
519 }
520 
521