xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 93a64300f8b9620213055926b194b9c5bbb10bcf)
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/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 OptionDefinition
53 CommandObjectExpression::CommandOptions::g_option_table[] =
54 {
55     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",        'a', required_argument, NULL, 0, eArgTypeBoolean,    "Should we run all threads if the execution doesn't complete on one thread."},
56     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "dynamic-value",      'd', required_argument, NULL, 0, eArgTypeBoolean,    "Upcast the value resulting from the expression to its dynamic type if available."},
57     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value for running the expression."},
58     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",    'u', required_argument, NULL, 0, eArgTypeBoolean,    "Clean up program state if the expression causes a crash, breakpoint hit or signal."},
59     { LLDB_OPT_SET_2                 , false, "object-description", 'o', no_argument,       NULL, 0, eArgTypeNone,       "Print the object description of the value resulting from the expression."},
60 };
61 
62 
63 uint32_t
64 CommandObjectExpression::CommandOptions::GetNumDefinitions ()
65 {
66     return sizeof(g_option_table)/sizeof(OptionDefinition);
67 }
68 
69 Error
70 CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
71                                                          uint32_t option_idx,
72                                                          const char *option_arg)
73 {
74     Error error;
75 
76     const int short_option = g_option_table[option_idx].short_option;
77 
78     switch (short_option)
79     {
80       //case 'l':
81       //if (language.SetLanguageFromCString (option_arg) == false)
82       //{
83       //    error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
84       //}
85       //break;
86 
87     case 'a':
88         {
89             bool success;
90             bool result;
91             result = Args::StringToBoolean(option_arg, true, &success);
92             if (!success)
93                 error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
94             else
95                 try_all_threads = result;
96         }
97         break;
98 
99     case 'd':
100         {
101             bool success;
102             bool result;
103             result = Args::StringToBoolean(option_arg, true, &success);
104             if (!success)
105                 error.SetErrorStringWithFormat("invalid dynamic value setting: \"%s\"", option_arg);
106             else
107             {
108                 if (result)
109                     use_dynamic = eLazyBoolYes;
110                 else
111                     use_dynamic = eLazyBoolNo;
112             }
113         }
114         break;
115 
116     case 'o':
117         print_object = true;
118         break;
119 
120     case 't':
121         {
122             bool success;
123             uint32_t result;
124             result = Args::StringToUInt32(option_arg, 0, 0, &success);
125             if (success)
126                 timeout = result;
127             else
128                 error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
129         }
130         break;
131 
132     case 'u':
133         {
134             bool success;
135             unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
136             if (!success)
137                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
138             break;
139         }
140     default:
141         error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
142         break;
143     }
144 
145     return error;
146 }
147 
148 void
149 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
150 {
151     use_dynamic = eLazyBoolCalculate;
152     print_object = false;
153     unwind_on_error = true;
154     show_types = true;
155     show_summary = true;
156     try_all_threads = true;
157     timeout = 0;
158 }
159 
160 const OptionDefinition*
161 CommandObjectExpression::CommandOptions::GetDefinitions ()
162 {
163     return g_option_table;
164 }
165 
166 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
167     CommandObjectRaw (interpreter,
168                       "expression",
169                       "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
170                       NULL,
171                       eFlagProcessMustBePaused),
172     m_option_group (interpreter),
173     m_format_options (eFormatDefault),
174     m_command_options (),
175     m_expr_line_count (0),
176     m_expr_lines ()
177 {
178   SetHelpLong(
179 "Timeouts:\n\
180     If the expression can be evaluated statically (without runnning code) then it will be.\n\
181     Otherwise, by default the expression will run on the current thread with a short timeout:\n\
182     currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted\n\
183     and resumed with all threads running.  You can use the -a option to disable retrying on all\n\
184     threads.  You can use the -t option to set a shorter timeout.\n\
185 \n\
186 User defined variables:\n\
187     You can define your own variables for convenience or to be used in subsequent expressions.\n\
188     You define them the same way you would define variables in C.  If the first character of \n\
189     your user defined variable is a $, then the variable's value will be available in future\n\
190     expressions, otherwise it will just be available in the current expression.\n\
191 \n\
192 Examples: \n\
193 \n\
194    expr my_struct->a = my_array[3] \n\
195    expr -f bin -- (index * 8) + 5 \n\
196    expr unsigned int $foo = 5\n\
197    expr char c[] = \"foo\"; c[0]\n");
198 
199     CommandArgumentEntry arg;
200     CommandArgumentData expression_arg;
201 
202     // Define the first (and only) variant of this arg.
203     expression_arg.arg_type = eArgTypeExpression;
204     expression_arg.arg_repetition = eArgRepeatPlain;
205 
206     // There is only one variant this argument could be; put it into the argument entry.
207     arg.push_back (expression_arg);
208 
209     // Push the data for the first argument into the m_arguments vector.
210     m_arguments.push_back (arg);
211 
212     // Add the "--format" and "--gdb-format"
213     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
214     m_option_group.Append (&m_command_options);
215     m_option_group.Finalize();
216 }
217 
218 CommandObjectExpression::~CommandObjectExpression ()
219 {
220 }
221 
222 Options *
223 CommandObjectExpression::GetOptions ()
224 {
225     return &m_option_group;
226 }
227 
228 size_t
229 CommandObjectExpression::MultiLineExpressionCallback
230 (
231     void *baton,
232     InputReader &reader,
233     lldb::InputReaderAction notification,
234     const char *bytes,
235     size_t bytes_len
236 )
237 {
238     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
239     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
240 
241     switch (notification)
242     {
243     case eInputReaderActivate:
244         if (!batch_mode)
245         {
246             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
247             if (async_strm_sp)
248             {
249                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
250                 async_strm_sp->Flush();
251             }
252         }
253         // Fall through
254     case eInputReaderReactivate:
255         break;
256 
257     case eInputReaderDeactivate:
258         break;
259 
260     case eInputReaderAsynchronousOutputWritten:
261         break;
262 
263     case eInputReaderGotToken:
264         ++cmd_object_expr->m_expr_line_count;
265         if (bytes && bytes_len)
266         {
267             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
268         }
269 
270         if (bytes_len == 0)
271             reader.SetIsDone(true);
272         break;
273 
274     case eInputReaderInterrupt:
275         cmd_object_expr->m_expr_lines.clear();
276         reader.SetIsDone (true);
277         if (!batch_mode)
278         {
279             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
280             if (async_strm_sp)
281             {
282                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
283                 async_strm_sp->Flush();
284             }
285         }
286         break;
287 
288     case eInputReaderEndOfFile:
289         reader.SetIsDone (true);
290         break;
291 
292     case eInputReaderDone:
293 		if (cmd_object_expr->m_expr_lines.size() > 0)
294         {
295             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
296             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
297             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
298                                                  output_stream.get(),
299                                                  error_stream.get());
300             output_stream->Flush();
301             error_stream->Flush();
302         }
303         break;
304     }
305 
306     return bytes_len;
307 }
308 
309 bool
310 CommandObjectExpression::EvaluateExpression
311 (
312     const char *expr,
313     Stream *output_stream,
314     Stream *error_stream,
315     CommandReturnObject *result
316 )
317 {
318     Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
319 
320     if (!target)
321         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
322 
323     if (target)
324     {
325         lldb::ValueObjectSP result_valobj_sp;
326 
327         ExecutionResults exe_results;
328 
329         bool keep_in_memory = true;
330         lldb::DynamicValueType use_dynamic;
331         // If use dynamic is not set, get it from the target:
332         switch (m_command_options.use_dynamic)
333         {
334         case eLazyBoolCalculate:
335             use_dynamic = target->GetPreferDynamicValue();
336             break;
337         case eLazyBoolYes:
338             use_dynamic = lldb::eDynamicCanRunTarget;
339             break;
340         case eLazyBoolNo:
341             use_dynamic = lldb::eNoDynamicValues;
342             break;
343         }
344 
345         EvaluateExpressionOptions options;
346         options.SetCoerceToId(m_command_options.print_object)
347         .SetUnwindOnError(m_command_options.unwind_on_error)
348         .SetKeepInMemory(keep_in_memory)
349         .SetUseDynamic(use_dynamic)
350         .SetRunOthers(m_command_options.try_all_threads)
351         .SetTimeoutUsec(m_command_options.timeout);
352 
353         exe_results = target->EvaluateExpression (expr,
354                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
355                                                   result_valobj_sp,
356                                                   options);
357 
358         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
359         {
360             uint32_t start_frame = 0;
361             uint32_t num_frames = 1;
362             uint32_t num_frames_with_source = 0;
363             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
364             if (thread)
365             {
366                 thread->GetStatus (result->GetOutputStream(),
367                                    start_frame,
368                                    num_frames,
369                                    num_frames_with_source);
370             }
371             else
372             {
373                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
374                 if (process)
375                 {
376                     bool only_threads_with_stop_reason = true;
377                     process->GetThreadStatus (result->GetOutputStream(),
378                                               only_threads_with_stop_reason,
379                                               start_frame,
380                                               num_frames,
381                                               num_frames_with_source);
382                 }
383             }
384         }
385 
386         if (result_valobj_sp)
387         {
388             Format format = m_format_options.GetFormat();
389 
390             if (result_valobj_sp->GetError().Success())
391             {
392                 if (format != eFormatVoid)
393                 {
394                     if (format != eFormatDefault)
395                         result_valobj_sp->SetFormat (format);
396 
397                     ValueObject::DumpValueObjectOptions options;
398                     options.SetMaximumPointerDepth(0)
399                     .SetMaximumDepth(UINT32_MAX)
400                     .SetShowLocation(false)
401                     .SetShowTypes(m_command_options.show_types)
402                     .SetUseObjectiveC(m_command_options.print_object)
403                     .SetUseDynamicType(use_dynamic)
404                     .SetScopeChecked(true)
405                     .SetFlatOutput(false)
406                     .SetUseSyntheticValue(true)
407                     .SetIgnoreCap(false)
408                     .SetFormat(format)
409                     .SetSummary()
410                     .SetShowSummary(!m_command_options.print_object)
411                     .SetHideRootType(m_command_options.print_object);
412 
413                     ValueObject::DumpValueObject (*(output_stream),
414                                                   result_valobj_sp.get(),   // Variable object to dump
415                                                   options);
416                     if (result)
417                         result->SetStatus (eReturnStatusSuccessFinishResult);
418                 }
419             }
420             else
421             {
422                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
423                 {
424                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
425                     {
426                         error_stream->PutCString("(void)\n");
427                     }
428 
429                     if (result)
430                         result->SetStatus (eReturnStatusSuccessFinishResult);
431                 }
432                 else
433                 {
434                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
435                     if (error_cstr && error_cstr[0])
436                     {
437                         int error_cstr_len = strlen (error_cstr);
438                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
439                         if (strstr(error_cstr, "error:") != error_cstr)
440                             error_stream->PutCString ("error: ");
441                         error_stream->Write(error_cstr, error_cstr_len);
442                         if (!ends_with_newline)
443                             error_stream->EOL();
444                     }
445                     else
446                     {
447                         error_stream->PutCString ("error: unknown error\n");
448                     }
449 
450                     if (result)
451                         result->SetStatus (eReturnStatusFailed);
452                 }
453             }
454         }
455     }
456     else
457     {
458         error_stream->Printf ("error: invalid execution context for expression\n");
459         return false;
460     }
461 
462     return true;
463 }
464 
465 bool
466 CommandObjectExpression::DoExecute
467 (
468     const char *command,
469     CommandReturnObject &result
470 )
471 {
472     m_option_group.NotifyOptionParsingStarting();
473 
474     const char * expr = NULL;
475 
476     if (command[0] == '\0')
477     {
478         m_expr_lines.clear();
479         m_expr_line_count = 0;
480 
481         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
482         if (reader_sp)
483         {
484             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
485                                               this,                         // baton
486                                               eInputReaderGranularityLine,  // token size, to pass to callback function
487                                               NULL,                         // end token
488                                               NULL,                         // prompt
489                                               true));                       // echo input
490             if (err.Success())
491             {
492                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
493                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
494             }
495             else
496             {
497                 result.AppendError (err.AsCString());
498                 result.SetStatus (eReturnStatusFailed);
499             }
500         }
501         else
502         {
503             result.AppendError("out of memory");
504             result.SetStatus (eReturnStatusFailed);
505         }
506         return result.Succeeded();
507     }
508 
509     if (command[0] == '-')
510     {
511         // We have some options and these options MUST end with --.
512         const char *end_options = NULL;
513         const char *s = command;
514         while (s && s[0])
515         {
516             end_options = ::strstr (s, "--");
517             if (end_options)
518             {
519                 end_options += 2; // Get past the "--"
520                 if (::isspace (end_options[0]))
521                 {
522                     expr = end_options;
523                     while (::isspace (*expr))
524                         ++expr;
525                     break;
526                 }
527             }
528             s = end_options;
529         }
530 
531         if (end_options)
532         {
533             Args args (command, end_options - command);
534             if (!ParseOptions (args, result))
535                 return false;
536 
537             Error error (m_option_group.NotifyOptionParsingFinished());
538             if (error.Fail())
539             {
540                 result.AppendError (error.AsCString());
541                 result.SetStatus (eReturnStatusFailed);
542                 return false;
543             }
544         }
545     }
546 
547     if (expr == NULL)
548         expr = command;
549 
550     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
551         return true;
552 
553     result.SetStatus (eReturnStatusFailed);
554     return false;
555 }
556 
557