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