xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 62e5f4de3d968e8f1c6b620a0dc6324562720c9d)
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 (m_command_options.timeout > 0)
292             options.SetTimeoutUsec(m_command_options.timeout);
293         else
294             options.SetTimeoutUsec(0);
295 
296         target->EvaluateExpression(expr, exe_ctx.GetFramePtr(),
297                                    result_valobj_sp, options);
298 
299         if (result_valobj_sp)
300         {
301             Format format = m_format_options.GetFormat();
302 
303             if (result_valobj_sp->GetError().Success())
304             {
305                 if (format != eFormatVoid)
306                 {
307                     if (format != eFormatDefault)
308                         result_valobj_sp->SetFormat (format);
309 
310                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format));
311 
312                     result_valobj_sp->Dump(*output_stream,options);
313 
314                     if (result)
315                         result->SetStatus (eReturnStatusSuccessFinishResult);
316                 }
317             }
318             else
319             {
320                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
321                 {
322                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
323                     {
324                         error_stream->PutCString("(void)\n");
325                     }
326 
327                     if (result)
328                         result->SetStatus (eReturnStatusSuccessFinishResult);
329                 }
330                 else
331                 {
332                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
333                     if (error_cstr && error_cstr[0])
334                     {
335                         const size_t error_cstr_len = strlen (error_cstr);
336                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
337                         if (strstr(error_cstr, "error:") != error_cstr)
338                             error_stream->PutCString ("error: ");
339                         error_stream->Write(error_cstr, error_cstr_len);
340                         if (!ends_with_newline)
341                             error_stream->EOL();
342                     }
343                     else
344                     {
345                         error_stream->PutCString ("error: unknown error\n");
346                     }
347 
348                     if (result)
349                         result->SetStatus (eReturnStatusFailed);
350                 }
351             }
352         }
353     }
354     else
355     {
356         error_stream->Printf ("error: invalid execution context for expression\n");
357         return false;
358     }
359 
360     return true;
361 }
362 
363 void
364 CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
365 {
366     io_handler.SetIsDone(true);
367 //    StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream();
368 //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
369     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
370     StreamFileSP error_sp(io_handler.GetErrorStreamFile());
371 
372     EvaluateExpression (line.c_str(),
373                         output_sp.get(),
374                         error_sp.get());
375     if (output_sp)
376         output_sp->Flush();
377     if (error_sp)
378         error_sp->Flush();
379 }
380 
381 LineStatus
382 CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler,
383                                                 StringList &lines,
384                                                 uint32_t line_idx,
385                                                 Error &error)
386 {
387     if (line_idx == UINT32_MAX)
388     {
389         // Remove the last line from "lines" so it doesn't appear
390         // in our final expression
391         lines.PopBack();
392         error.Clear();
393         return LineStatus::Done;
394     }
395     else if (line_idx + 1 == lines.GetSize())
396     {
397         // The last line was edited, if this line is empty, then we are done
398         // getting our multiple lines.
399         if (lines[line_idx].empty())
400             return LineStatus::Done;
401     }
402     return LineStatus::Success;
403 }
404 
405 void
406 CommandObjectExpression::GetMultilineExpression ()
407 {
408     m_expr_lines.clear();
409     m_expr_line_count = 0;
410 
411     Debugger &debugger = GetCommandInterpreter().GetDebugger();
412     const bool multiple_lines = true; // Get multiple lines
413     IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
414                                                       "lldb-expr",      // Name of input reader for history
415                                                       NULL,             // No prompt
416                                                       multiple_lines,
417                                                       1,                // Show line numbers starting at 1
418                                                       *this));
419 
420     StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
421     if (output_sp)
422     {
423         output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
424         output_sp->Flush();
425     }
426     debugger.PushIOHandler(io_handler_sp);
427 }
428 
429 bool
430 CommandObjectExpression::DoExecute
431 (
432     const char *command,
433     CommandReturnObject &result
434 )
435 {
436     m_option_group.NotifyOptionParsingStarting();
437 
438     const char * expr = NULL;
439 
440     if (command[0] == '\0')
441     {
442         GetMultilineExpression ();
443         return result.Succeeded();
444     }
445 
446     if (command[0] == '-')
447     {
448         // We have some options and these options MUST end with --.
449         const char *end_options = NULL;
450         const char *s = command;
451         while (s && s[0])
452         {
453             end_options = ::strstr (s, "--");
454             if (end_options)
455             {
456                 end_options += 2; // Get past the "--"
457                 if (::isspace (end_options[0]))
458                 {
459                     expr = end_options;
460                     while (::isspace (*expr))
461                         ++expr;
462                     break;
463                 }
464             }
465             s = end_options;
466         }
467 
468         if (end_options)
469         {
470             Args args (command, end_options - command);
471             if (!ParseOptions (args, result))
472                 return false;
473 
474             Error error (m_option_group.NotifyOptionParsingFinished());
475             if (error.Fail())
476             {
477                 result.AppendError (error.AsCString());
478                 result.SetStatus (eReturnStatusFailed);
479                 return false;
480             }
481 
482             // No expression following options
483             if (expr == NULL || expr[0] == '\0')
484             {
485                 GetMultilineExpression ();
486                 return result.Succeeded();
487             }
488         }
489     }
490 
491     if (expr == NULL)
492         expr = command;
493 
494     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
495         return true;
496 
497     result.SetStatus (eReturnStatusFailed);
498     return false;
499 }
500 
501