xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 28606954bfe08ab4fb146cc85f2d4c0aff5cf1c2)
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, 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 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 runnning 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 Examples: \n\
222 \n\
223    expr my_struct->a = my_array[3] \n\
224    expr -f bin -- (index * 8) + 5 \n\
225    expr unsigned int $foo = 5\n\
226    expr char c[] = \"foo\"; c[0]\n");
227 
228     CommandArgumentEntry arg;
229     CommandArgumentData expression_arg;
230 
231     // Define the first (and only) variant of this arg.
232     expression_arg.arg_type = eArgTypeExpression;
233     expression_arg.arg_repetition = eArgRepeatPlain;
234 
235     // There is only one variant this argument could be; put it into the argument entry.
236     arg.push_back (expression_arg);
237 
238     // Push the data for the first argument into the m_arguments vector.
239     m_arguments.push_back (arg);
240 
241     // Add the "--format" and "--gdb-format"
242     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
243     m_option_group.Append (&m_command_options);
244     m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
245     m_option_group.Finalize();
246 }
247 
248 CommandObjectExpression::~CommandObjectExpression ()
249 {
250 }
251 
252 Options *
253 CommandObjectExpression::GetOptions ()
254 {
255     return &m_option_group;
256 }
257 
258 bool
259 CommandObjectExpression::EvaluateExpression
260 (
261     const char *expr,
262     Stream *output_stream,
263     Stream *error_stream,
264     CommandReturnObject *result
265 )
266 {
267     // Don't use m_exe_ctx as this might be called asynchronously
268     // after the command object DoExecute has finished when doing
269     // multi-line expression that use an input reader...
270     ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
271 
272     Target *target = exe_ctx.GetTargetPtr();
273 
274     if (!target)
275         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
276 
277     if (target)
278     {
279         lldb::ValueObjectSP result_valobj_sp;
280 
281         bool keep_in_memory = true;
282 
283         EvaluateExpressionOptions options;
284         options.SetCoerceToId(m_varobj_options.use_objc);
285         options.SetUnwindOnError(m_command_options.unwind_on_error);
286         options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
287         options.SetKeepInMemory(keep_in_memory);
288         options.SetUseDynamic(m_varobj_options.use_dynamic);
289         options.SetTryAllThreads(m_command_options.try_all_threads);
290         options.SetDebug(m_command_options.debug);
291 
292         // If there is any chance we are going to stop and want to see
293         // what went wrong with our expression, we should generate debug info
294         if (!m_command_options.ignore_breakpoints ||
295             !m_command_options.unwind_on_error)
296             options.SetGenerateDebugInfo(true);
297 
298         if (m_command_options.timeout > 0)
299             options.SetTimeoutUsec(m_command_options.timeout);
300         else
301             options.SetTimeoutUsec(0);
302 
303         target->EvaluateExpression(expr, exe_ctx.GetFramePtr(),
304                                    result_valobj_sp, options);
305 
306         if (result_valobj_sp)
307         {
308             Format format = m_format_options.GetFormat();
309 
310             if (result_valobj_sp->GetError().Success())
311             {
312                 if (format != eFormatVoid)
313                 {
314                     if (format != eFormatDefault)
315                         result_valobj_sp->SetFormat (format);
316 
317                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format));
318 
319                     result_valobj_sp->Dump(*output_stream,options);
320 
321                     if (result)
322                         result->SetStatus (eReturnStatusSuccessFinishResult);
323                 }
324             }
325             else
326             {
327                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
328                 {
329                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
330                     {
331                         error_stream->PutCString("(void)\n");
332                     }
333 
334                     if (result)
335                         result->SetStatus (eReturnStatusSuccessFinishResult);
336                 }
337                 else
338                 {
339                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
340                     if (error_cstr && error_cstr[0])
341                     {
342                         const size_t error_cstr_len = strlen (error_cstr);
343                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
344                         if (strstr(error_cstr, "error:") != error_cstr)
345                             error_stream->PutCString ("error: ");
346                         error_stream->Write(error_cstr, error_cstr_len);
347                         if (!ends_with_newline)
348                             error_stream->EOL();
349                     }
350                     else
351                     {
352                         error_stream->PutCString ("error: unknown error\n");
353                     }
354 
355                     if (result)
356                         result->SetStatus (eReturnStatusFailed);
357                 }
358             }
359         }
360     }
361     else
362     {
363         error_stream->Printf ("error: invalid execution context for expression\n");
364         return false;
365     }
366 
367     return true;
368 }
369 
370 void
371 CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
372 {
373     io_handler.SetIsDone(true);
374 //    StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream();
375 //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
376     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
377     StreamFileSP error_sp(io_handler.GetErrorStreamFile());
378 
379     EvaluateExpression (line.c_str(),
380                         output_sp.get(),
381                         error_sp.get());
382     if (output_sp)
383         output_sp->Flush();
384     if (error_sp)
385         error_sp->Flush();
386 }
387 
388 LineStatus
389 CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler,
390                                                 StringList &lines,
391                                                 uint32_t line_idx,
392                                                 Error &error)
393 {
394     if (line_idx == UINT32_MAX)
395     {
396         // Remove the last line from "lines" so it doesn't appear
397         // in our final expression
398         lines.PopBack();
399         error.Clear();
400         return LineStatus::Done;
401     }
402     else if (line_idx + 1 == lines.GetSize())
403     {
404         // The last line was edited, if this line is empty, then we are done
405         // getting our multiple lines.
406         if (lines[line_idx].empty())
407             return LineStatus::Done;
408     }
409     return LineStatus::Success;
410 }
411 
412 void
413 CommandObjectExpression::GetMultilineExpression ()
414 {
415     m_expr_lines.clear();
416     m_expr_line_count = 0;
417 
418     Debugger &debugger = GetCommandInterpreter().GetDebugger();
419     const bool multiple_lines = true; // Get multiple lines
420     IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
421                                                       "lldb-expr",      // Name of input reader for history
422                                                       NULL,             // No prompt
423                                                       multiple_lines,
424                                                       1,                // Show line numbers starting at 1
425                                                       *this));
426 
427     StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
428     if (output_sp)
429     {
430         output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
431         output_sp->Flush();
432     }
433     debugger.PushIOHandler(io_handler_sp);
434 }
435 
436 bool
437 CommandObjectExpression::DoExecute
438 (
439     const char *command,
440     CommandReturnObject &result
441 )
442 {
443     m_option_group.NotifyOptionParsingStarting();
444 
445     const char * expr = NULL;
446 
447     if (command[0] == '\0')
448     {
449         GetMultilineExpression ();
450         return result.Succeeded();
451     }
452 
453     if (command[0] == '-')
454     {
455         // We have some options and these options MUST end with --.
456         const char *end_options = NULL;
457         const char *s = command;
458         while (s && s[0])
459         {
460             end_options = ::strstr (s, "--");
461             if (end_options)
462             {
463                 end_options += 2; // Get past the "--"
464                 if (::isspace (end_options[0]))
465                 {
466                     expr = end_options;
467                     while (::isspace (*expr))
468                         ++expr;
469                     break;
470                 }
471             }
472             s = end_options;
473         }
474 
475         if (end_options)
476         {
477             Args args (command, end_options - command);
478             if (!ParseOptions (args, result))
479                 return false;
480 
481             Error error (m_option_group.NotifyOptionParsingFinished());
482             if (error.Fail())
483             {
484                 result.AppendError (error.AsCString());
485                 result.SetStatus (eReturnStatusFailed);
486                 return false;
487             }
488 
489             // No expression following options
490             if (expr == NULL || expr[0] == '\0')
491             {
492                 GetMultilineExpression ();
493                 return result.Succeeded();
494             }
495         }
496     }
497 
498     if (expr == NULL)
499         expr = command;
500 
501     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
502         return true;
503 
504     result.SetStatus (eReturnStatusFailed);
505     return false;
506 }
507 
508