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