xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 6f78f3869d46d5481026a1bc149a1b560e21f9b8)
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/InputReader.h"
21 #include "lldb/Core/ValueObjectVariable.h"
22 #include "lldb/DataFormatters/ValueObjectPrinter.h"
23 #include "lldb/Expression/ClangExpressionVariable.h"
24 #include "lldb/Expression/ClangUserExpression.h"
25 #include "lldb/Expression/ClangFunction.h"
26 #include "lldb/Expression/DWARFExpression.h"
27 #include "lldb/Host/Host.h"
28 #include "lldb/Core/Debugger.h"
29 #include "lldb/Interpreter/CommandInterpreter.h"
30 #include "lldb/Interpreter/CommandReturnObject.h"
31 #include "lldb/Target/ObjCLanguageRuntime.h"
32 #include "lldb/Symbol/ObjectFile.h"
33 #include "lldb/Symbol/Variable.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 #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, 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, 0, eArgTypeBoolean,    "Ignore breakpoint hits while running expressions"},
65     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', OptionParser::eRequiredArgument, 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, 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, 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, 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 sizeof(g_option_table)/sizeof(OptionDefinition);
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 = false;
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     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 size_t
258 CommandObjectExpression::MultiLineExpressionCallback
259 (
260     void *baton,
261     InputReader &reader,
262     lldb::InputReaderAction notification,
263     const char *bytes,
264     size_t bytes_len
265 )
266 {
267     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
268     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
269 
270     switch (notification)
271     {
272     case eInputReaderActivate:
273         if (!batch_mode)
274         {
275             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
276             if (async_strm_sp)
277             {
278                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
279                 async_strm_sp->Flush();
280             }
281         }
282         // Fall through
283     case eInputReaderReactivate:
284         break;
285 
286     case eInputReaderDeactivate:
287         break;
288 
289     case eInputReaderAsynchronousOutputWritten:
290         break;
291 
292     case eInputReaderGotToken:
293         ++cmd_object_expr->m_expr_line_count;
294         if (bytes && bytes_len)
295         {
296             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
297         }
298 
299         if (bytes_len == 0)
300             reader.SetIsDone(true);
301         break;
302 
303     case eInputReaderInterrupt:
304         cmd_object_expr->m_expr_lines.clear();
305         reader.SetIsDone (true);
306         if (!batch_mode)
307         {
308             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
309             if (async_strm_sp)
310             {
311                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
312                 async_strm_sp->Flush();
313             }
314         }
315         break;
316 
317     case eInputReaderEndOfFile:
318         reader.SetIsDone (true);
319         break;
320 
321     case eInputReaderDone:
322 		if (cmd_object_expr->m_expr_lines.size() > 0)
323         {
324             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
325             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
326             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
327                                                  output_stream.get(),
328                                                  error_stream.get());
329             output_stream->Flush();
330             error_stream->Flush();
331         }
332         break;
333     }
334 
335     return bytes_len;
336 }
337 
338 bool
339 CommandObjectExpression::EvaluateExpression
340 (
341     const char *expr,
342     Stream *output_stream,
343     Stream *error_stream,
344     CommandReturnObject *result
345 )
346 {
347     // Don't use m_exe_ctx as this might be called asynchronously
348     // after the command object DoExecute has finished when doing
349     // multi-line expression that use an input reader...
350     ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
351 
352     Target *target = exe_ctx.GetTargetPtr();
353 
354     if (!target)
355         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
356 
357     if (target)
358     {
359         lldb::ValueObjectSP result_valobj_sp;
360 
361         ExecutionResults exe_results;
362 
363         bool keep_in_memory = true;
364 
365         EvaluateExpressionOptions options;
366         options.SetCoerceToId(m_varobj_options.use_objc);
367         options.SetUnwindOnError(m_command_options.unwind_on_error);
368         options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
369         options.SetKeepInMemory(keep_in_memory);
370         options.SetUseDynamic(m_varobj_options.use_dynamic);
371         options.SetTryAllThreads(m_command_options.try_all_threads);
372         options.SetDebug(m_command_options.debug);
373 
374         if (m_command_options.timeout > 0)
375             options.SetTimeoutUsec(m_command_options.timeout);
376         else
377             options.SetTimeoutUsec(0);
378 
379         exe_results = target->EvaluateExpression (expr,
380                                                   exe_ctx.GetFramePtr(),
381                                                   result_valobj_sp,
382                                                   options);
383 
384         if (result_valobj_sp)
385         {
386             Format format = m_format_options.GetFormat();
387 
388             if (result_valobj_sp->GetError().Success())
389             {
390                 if (format != eFormatVoid)
391                 {
392                     if (format != eFormatDefault)
393                         result_valobj_sp->SetFormat (format);
394 
395                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format));
396 
397                     result_valobj_sp->Dump(*output_stream,options);
398 
399                     if (result)
400                         result->SetStatus (eReturnStatusSuccessFinishResult);
401                 }
402             }
403             else
404             {
405                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
406                 {
407                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
408                     {
409                         error_stream->PutCString("(void)\n");
410                     }
411 
412                     if (result)
413                         result->SetStatus (eReturnStatusSuccessFinishResult);
414                 }
415                 else
416                 {
417                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
418                     if (error_cstr && error_cstr[0])
419                     {
420                         const size_t error_cstr_len = strlen (error_cstr);
421                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
422                         if (strstr(error_cstr, "error:") != error_cstr)
423                             error_stream->PutCString ("error: ");
424                         error_stream->Write(error_cstr, error_cstr_len);
425                         if (!ends_with_newline)
426                             error_stream->EOL();
427                     }
428                     else
429                     {
430                         error_stream->PutCString ("error: unknown error\n");
431                     }
432 
433                     if (result)
434                         result->SetStatus (eReturnStatusFailed);
435                 }
436             }
437         }
438     }
439     else
440     {
441         error_stream->Printf ("error: invalid execution context for expression\n");
442         return false;
443     }
444 
445     return true;
446 }
447 
448 bool
449 CommandObjectExpression::DoExecute
450 (
451     const char *command,
452     CommandReturnObject &result
453 )
454 {
455     m_option_group.NotifyOptionParsingStarting();
456 
457     const char * expr = NULL;
458 
459     if (command[0] == '\0')
460     {
461         m_expr_lines.clear();
462         m_expr_line_count = 0;
463 
464         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
465         if (reader_sp)
466         {
467             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
468                                               this,                         // baton
469                                               eInputReaderGranularityLine,  // token size, to pass to callback function
470                                               NULL,                         // end token
471                                               NULL,                         // prompt
472                                               true));                       // echo input
473             if (err.Success())
474             {
475                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
476                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
477             }
478             else
479             {
480                 result.AppendError (err.AsCString());
481                 result.SetStatus (eReturnStatusFailed);
482             }
483         }
484         else
485         {
486             result.AppendError("out of memory");
487             result.SetStatus (eReturnStatusFailed);
488         }
489         return result.Succeeded();
490     }
491 
492     if (command[0] == '-')
493     {
494         // We have some options and these options MUST end with --.
495         const char *end_options = NULL;
496         const char *s = command;
497         while (s && s[0])
498         {
499             end_options = ::strstr (s, "--");
500             if (end_options)
501             {
502                 end_options += 2; // Get past the "--"
503                 if (::isspace (end_options[0]))
504                 {
505                     expr = end_options;
506                     while (::isspace (*expr))
507                         ++expr;
508                     break;
509                 }
510             }
511             s = end_options;
512         }
513 
514         if (end_options)
515         {
516             Args args (command, end_options - command);
517             if (!ParseOptions (args, result))
518                 return false;
519 
520             Error error (m_option_group.NotifyOptionParsingFinished());
521             if (error.Fail())
522             {
523                 result.AppendError (error.AsCString());
524                 result.SetStatus (eReturnStatusFailed);
525                 return false;
526             }
527         }
528     }
529 
530     if (expr == NULL)
531         expr = command;
532 
533     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
534         return true;
535 
536     result.SetStatus (eReturnStatusFailed);
537     return false;
538 }
539 
540