xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 35e1bda6957bb7e5d26f6a50e473ca3aa22a1386)
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 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 Examples: \n\
184 \n\
185    expr my_struct->a = my_array[3] \n\
186    expr -f bin -- (index * 8) + 5 \n\
187    expr char c[] = \"foo\"; c[0]\n");
188 
189     CommandArgumentEntry arg;
190     CommandArgumentData expression_arg;
191 
192     // Define the first (and only) variant of this arg.
193     expression_arg.arg_type = eArgTypeExpression;
194     expression_arg.arg_repetition = eArgRepeatPlain;
195 
196     // There is only one variant this argument could be; put it into the argument entry.
197     arg.push_back (expression_arg);
198 
199     // Push the data for the first argument into the m_arguments vector.
200     m_arguments.push_back (arg);
201 
202     // Add the "--format" and "--gdb-format"
203     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
204     m_option_group.Append (&m_command_options);
205     m_option_group.Finalize();
206 }
207 
208 CommandObjectExpression::~CommandObjectExpression ()
209 {
210 }
211 
212 Options *
213 CommandObjectExpression::GetOptions ()
214 {
215     return &m_option_group;
216 }
217 
218 size_t
219 CommandObjectExpression::MultiLineExpressionCallback
220 (
221     void *baton,
222     InputReader &reader,
223     lldb::InputReaderAction notification,
224     const char *bytes,
225     size_t bytes_len
226 )
227 {
228     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
229     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
230 
231     switch (notification)
232     {
233     case eInputReaderActivate:
234         if (!batch_mode)
235         {
236             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
237             if (async_strm_sp)
238             {
239                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
240                 async_strm_sp->Flush();
241             }
242         }
243         // Fall through
244     case eInputReaderReactivate:
245         break;
246 
247     case eInputReaderDeactivate:
248         break;
249 
250     case eInputReaderAsynchronousOutputWritten:
251         break;
252 
253     case eInputReaderGotToken:
254         ++cmd_object_expr->m_expr_line_count;
255         if (bytes && bytes_len)
256         {
257             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
258         }
259 
260         if (bytes_len == 0)
261             reader.SetIsDone(true);
262         break;
263 
264     case eInputReaderInterrupt:
265         cmd_object_expr->m_expr_lines.clear();
266         reader.SetIsDone (true);
267         if (!batch_mode)
268         {
269             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
270             if (async_strm_sp)
271             {
272                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
273                 async_strm_sp->Flush();
274             }
275         }
276         break;
277 
278     case eInputReaderEndOfFile:
279         reader.SetIsDone (true);
280         break;
281 
282     case eInputReaderDone:
283 		if (cmd_object_expr->m_expr_lines.size() > 0)
284         {
285             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
286             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
287             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
288                                                  output_stream.get(),
289                                                  error_stream.get());
290             output_stream->Flush();
291             error_stream->Flush();
292         }
293         break;
294     }
295 
296     return bytes_len;
297 }
298 
299 bool
300 CommandObjectExpression::EvaluateExpression
301 (
302     const char *expr,
303     Stream *output_stream,
304     Stream *error_stream,
305     CommandReturnObject *result
306 )
307 {
308     Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
309 
310     if (!target)
311         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
312 
313     if (target)
314     {
315         lldb::ValueObjectSP result_valobj_sp;
316 
317         ExecutionResults exe_results;
318 
319         bool keep_in_memory = true;
320         lldb::DynamicValueType use_dynamic;
321         // If use dynamic is not set, get it from the target:
322         switch (m_command_options.use_dynamic)
323         {
324         case eLazyBoolCalculate:
325             use_dynamic = target->GetPreferDynamicValue();
326             break;
327         case eLazyBoolYes:
328             use_dynamic = lldb::eDynamicCanRunTarget;
329             break;
330         case eLazyBoolNo:
331             use_dynamic = lldb::eNoDynamicValues;
332             break;
333         }
334 
335         EvaluateExpressionOptions options;
336         options.SetCoerceToId(m_command_options.print_object)
337         .SetUnwindOnError(m_command_options.unwind_on_error)
338         .SetKeepInMemory(keep_in_memory)
339         .SetUseDynamic(use_dynamic)
340         .SetRunOthers(m_command_options.try_all_threads)
341         .SetTimeoutUsec(m_command_options.timeout);
342 
343         exe_results = target->EvaluateExpression (expr,
344                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
345                                                   result_valobj_sp,
346                                                   options);
347 
348         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
349         {
350             uint32_t start_frame = 0;
351             uint32_t num_frames = 1;
352             uint32_t num_frames_with_source = 0;
353             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
354             if (thread)
355             {
356                 thread->GetStatus (result->GetOutputStream(),
357                                    start_frame,
358                                    num_frames,
359                                    num_frames_with_source);
360             }
361             else
362             {
363                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
364                 if (process)
365                 {
366                     bool only_threads_with_stop_reason = true;
367                     process->GetThreadStatus (result->GetOutputStream(),
368                                               only_threads_with_stop_reason,
369                                               start_frame,
370                                               num_frames,
371                                               num_frames_with_source);
372                 }
373             }
374         }
375 
376         if (result_valobj_sp)
377         {
378             Format format = m_format_options.GetFormat();
379 
380             if (result_valobj_sp->GetError().Success())
381             {
382                 if (format != eFormatVoid)
383                 {
384                     if (format != eFormatDefault)
385                         result_valobj_sp->SetFormat (format);
386 
387                     ValueObject::DumpValueObjectOptions options;
388                     options.SetMaximumPointerDepth(0)
389                     .SetMaximumDepth(UINT32_MAX)
390                     .SetShowLocation(false)
391                     .SetShowTypes(m_command_options.show_types)
392                     .SetUseObjectiveC(m_command_options.print_object)
393                     .SetUseDynamicType(use_dynamic)
394                     .SetScopeChecked(true)
395                     .SetFlatOutput(false)
396                     .SetUseSyntheticValue(true)
397                     .SetIgnoreCap(false)
398                     .SetFormat(format)
399                     .SetSummary()
400                     .SetShowSummary(!m_command_options.print_object)
401                     .SetHideRootType(m_command_options.print_object);
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