xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 5c48d5c53607b1aee018e9df0048ae23466c59db)
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 "CommandObjectExpression.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Interpreter/Args.h"
17 #include "lldb/Core/Value.h"
18 #include "lldb/Core/InputReader.h"
19 #include "lldb/Core/ValueObjectVariable.h"
20 #include "lldb/Expression/ClangExpressionVariable.h"
21 #include "lldb/Expression/ClangUserExpression.h"
22 #include "lldb/Expression/ClangFunction.h"
23 #include "lldb/Expression/DWARFExpression.h"
24 #include "lldb/Host/Host.h"
25 #include "lldb/Core/Debugger.h"
26 #include "lldb/Interpreter/CommandInterpreter.h"
27 #include "lldb/Interpreter/CommandReturnObject.h"
28 #include "lldb/Target/ObjCLanguageRuntime.h"
29 #include "lldb/Symbol/ObjectFile.h"
30 #include "lldb/Symbol/Variable.h"
31 #include "lldb/Target/Process.h"
32 #include "lldb/Target/StackFrame.h"
33 #include "lldb/Target/Target.h"
34 #include "lldb/Target/Thread.h"
35 #include "llvm/ADT/StringRef.h"
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 
40 CommandObjectExpression::CommandOptions::CommandOptions () :
41     OptionGroup()
42 {
43 }
44 
45 
46 CommandObjectExpression::CommandOptions::~CommandOptions ()
47 {
48 }
49 
50 OptionDefinition
51 CommandObjectExpression::CommandOptions::g_option_table[] =
52 {
53     { 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."},
54     { 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."},
55     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value for running the expression."},
56     { 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."},
57     { LLDB_OPT_SET_2                 , false, "object-description", 'o', no_argument,       NULL, 0, eArgTypeNone,       "Print the object description of the value resulting from the expression."},
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 char short_option = (char) 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 'd':
98         {
99             bool success;
100             bool result;
101             result = Args::StringToBoolean(option_arg, true, &success);
102             if (!success)
103                 error.SetErrorStringWithFormat("invalid dynamic value setting: \"%s\"", option_arg);
104             else
105             {
106                 if (result)
107                     use_dynamic = eLazyBoolYes;
108                 else
109                     use_dynamic = eLazyBoolNo;
110             }
111         }
112         break;
113 
114     case 'o':
115         print_object = true;
116         break;
117 
118     case 't':
119         {
120             bool success;
121             uint32_t result;
122             result = Args::StringToUInt32(option_arg, 0, 0, &success);
123             if (success)
124                 timeout = result;
125             else
126                 error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
127         }
128         break;
129 
130     case 'u':
131         {
132             bool success;
133             unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
134             if (!success)
135                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
136             break;
137         }
138     default:
139         error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
140         break;
141     }
142 
143     return error;
144 }
145 
146 void
147 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
148 {
149     use_dynamic = eLazyBoolCalculate;
150     print_object = false;
151     unwind_on_error = true;
152     show_types = true;
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),
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.Finalize();
214 }
215 
216 CommandObjectExpression::~CommandObjectExpression ()
217 {
218 }
219 
220 Options *
221 CommandObjectExpression::GetOptions ()
222 {
223     return &m_option_group;
224 }
225 
226 size_t
227 CommandObjectExpression::MultiLineExpressionCallback
228 (
229     void *baton,
230     InputReader &reader,
231     lldb::InputReaderAction notification,
232     const char *bytes,
233     size_t bytes_len
234 )
235 {
236     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
237     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
238 
239     switch (notification)
240     {
241     case eInputReaderActivate:
242         if (!batch_mode)
243         {
244             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
245             if (async_strm_sp)
246             {
247                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
248                 async_strm_sp->Flush();
249             }
250         }
251         // Fall through
252     case eInputReaderReactivate:
253         break;
254 
255     case eInputReaderDeactivate:
256         break;
257 
258     case eInputReaderAsynchronousOutputWritten:
259         break;
260 
261     case eInputReaderGotToken:
262         ++cmd_object_expr->m_expr_line_count;
263         if (bytes && bytes_len)
264         {
265             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
266         }
267 
268         if (bytes_len == 0)
269             reader.SetIsDone(true);
270         break;
271 
272     case eInputReaderInterrupt:
273         cmd_object_expr->m_expr_lines.clear();
274         reader.SetIsDone (true);
275         if (!batch_mode)
276         {
277             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
278             if (async_strm_sp)
279             {
280                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
281                 async_strm_sp->Flush();
282             }
283         }
284         break;
285 
286     case eInputReaderEndOfFile:
287         reader.SetIsDone (true);
288         break;
289 
290     case eInputReaderDone:
291 		if (cmd_object_expr->m_expr_lines.size() > 0)
292         {
293             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
294             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
295             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
296                                                  output_stream.get(),
297                                                  error_stream.get());
298             output_stream->Flush();
299             error_stream->Flush();
300         }
301         break;
302     }
303 
304     return bytes_len;
305 }
306 
307 bool
308 CommandObjectExpression::EvaluateExpression
309 (
310     const char *expr,
311     Stream *output_stream,
312     Stream *error_stream,
313     CommandReturnObject *result
314 )
315 {
316     Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
317 
318     if (!target)
319         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
320 
321     if (target)
322     {
323         lldb::ValueObjectSP result_valobj_sp;
324 
325         ExecutionResults exe_results;
326 
327         bool keep_in_memory = true;
328         lldb::DynamicValueType use_dynamic;
329         // If use dynamic is not set, get it from the target:
330         switch (m_command_options.use_dynamic)
331         {
332         case eLazyBoolCalculate:
333             use_dynamic = target->GetPreferDynamicValue();
334             break;
335         case eLazyBoolYes:
336             use_dynamic = lldb::eDynamicCanRunTarget;
337             break;
338         case eLazyBoolNo:
339             use_dynamic = lldb::eNoDynamicValues;
340             break;
341         }
342 
343         EvaluateExpressionOptions options;
344         options.SetCoerceToId(m_command_options.print_object)
345         .SetUnwindOnError(m_command_options.unwind_on_error)
346         .SetKeepInMemory(keep_in_memory)
347         .SetUseDynamic(use_dynamic)
348         .SetRunOthers(m_command_options.try_all_threads)
349         .SetTimeoutUsec(m_command_options.timeout);
350 
351         exe_results = target->EvaluateExpression (expr,
352                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
353                                                   result_valobj_sp,
354                                                   options);
355 
356         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
357         {
358             uint32_t start_frame = 0;
359             uint32_t num_frames = 1;
360             uint32_t num_frames_with_source = 0;
361             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
362             if (thread)
363             {
364                 thread->GetStatus (result->GetOutputStream(),
365                                    start_frame,
366                                    num_frames,
367                                    num_frames_with_source);
368             }
369             else
370             {
371                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
372                 if (process)
373                 {
374                     bool only_threads_with_stop_reason = true;
375                     process->GetThreadStatus (result->GetOutputStream(),
376                                               only_threads_with_stop_reason,
377                                               start_frame,
378                                               num_frames,
379                                               num_frames_with_source);
380                 }
381             }
382         }
383 
384         if (result_valobj_sp)
385         {
386             Format format = m_format_options.GetFormat();
387 
388             if (result_valobj_sp->GetError().Success())
389             {
390                 if (format != eFormatVoid)
391                 {
392                     if (format != eFormatDefault)
393                         result_valobj_sp->SetFormat (format);
394 
395                     ValueObject::DumpValueObjectOptions options;
396                     options.SetMaximumPointerDepth(0)
397                     .SetMaximumDepth(UINT32_MAX)
398                     .SetShowLocation(false)
399                     .SetShowTypes(m_command_options.show_types)
400                     .SetUseObjectiveC(m_command_options.print_object)
401                     .SetUseDynamicType(use_dynamic)
402                     .SetScopeChecked(true)
403                     .SetFlatOutput(false)
404                     .SetUseSyntheticValue(true)
405                     .SetIgnoreCap(false)
406                     .SetFormat(format)
407                     .SetSummary()
408                     .SetShowSummary(!m_command_options.print_object)
409                     .SetHideRootType(m_command_options.print_object);
410 
411                     ValueObject::DumpValueObject (*(output_stream),
412                                                   result_valobj_sp.get(),   // Variable object to dump
413                                                   options);
414                     if (result)
415                         result->SetStatus (eReturnStatusSuccessFinishResult);
416                 }
417             }
418             else
419             {
420                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
421                 {
422                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
423                     {
424                         error_stream->PutCString("(void)\n");
425                     }
426 
427                     if (result)
428                         result->SetStatus (eReturnStatusSuccessFinishResult);
429                 }
430                 else
431                 {
432                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
433                     if (error_cstr && error_cstr[0])
434                     {
435                         int error_cstr_len = strlen (error_cstr);
436                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
437                         if (strstr(error_cstr, "error:") != error_cstr)
438                             error_stream->PutCString ("error: ");
439                         error_stream->Write(error_cstr, error_cstr_len);
440                         if (!ends_with_newline)
441                             error_stream->EOL();
442                     }
443                     else
444                     {
445                         error_stream->PutCString ("error: unknown error\n");
446                     }
447 
448                     if (result)
449                         result->SetStatus (eReturnStatusFailed);
450                 }
451             }
452         }
453     }
454     else
455     {
456         error_stream->Printf ("error: invalid execution context for expression\n");
457         return false;
458     }
459 
460     return true;
461 }
462 
463 bool
464 CommandObjectExpression::DoExecute
465 (
466     const char *command,
467     CommandReturnObject &result
468 )
469 {
470     m_option_group.NotifyOptionParsingStarting();
471 
472     const char * expr = NULL;
473 
474     if (command[0] == '\0')
475     {
476         m_expr_lines.clear();
477         m_expr_line_count = 0;
478 
479         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
480         if (reader_sp)
481         {
482             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
483                                               this,                         // baton
484                                               eInputReaderGranularityLine,  // token size, to pass to callback function
485                                               NULL,                         // end token
486                                               NULL,                         // prompt
487                                               true));                       // echo input
488             if (err.Success())
489             {
490                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
491                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
492             }
493             else
494             {
495                 result.AppendError (err.AsCString());
496                 result.SetStatus (eReturnStatusFailed);
497             }
498         }
499         else
500         {
501             result.AppendError("out of memory");
502             result.SetStatus (eReturnStatusFailed);
503         }
504         return result.Succeeded();
505     }
506 
507     if (command[0] == '-')
508     {
509         // We have some options and these options MUST end with --.
510         const char *end_options = NULL;
511         const char *s = command;
512         while (s && s[0])
513         {
514             end_options = ::strstr (s, "--");
515             if (end_options)
516             {
517                 end_options += 2; // Get past the "--"
518                 if (::isspace (end_options[0]))
519                 {
520                     expr = end_options;
521                     while (::isspace (*expr))
522                         ++expr;
523                     break;
524                 }
525             }
526             s = end_options;
527         }
528 
529         if (end_options)
530         {
531             Args args (command, end_options - command);
532             if (!ParseOptions (args, result))
533                 return false;
534 
535             Error error (m_option_group.NotifyOptionParsingFinished());
536             if (error.Fail())
537             {
538                 result.AppendError (error.AsCString());
539                 result.SetStatus (eReturnStatusFailed);
540                 return false;
541             }
542         }
543     }
544 
545     if (expr == NULL)
546         expr = command;
547 
548     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
549         return true;
550 
551     result.SetStatus (eReturnStatusFailed);
552     return false;
553 }
554 
555