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