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