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/Core/Value.h"
17 #include "lldb/Core/ValueObjectVariable.h"
18 #include "lldb/DataFormatters/ValueObjectPrinter.h"
19 #include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h"
20 #include "lldb/Expression/ClangUserExpression.h"
21 #include "lldb/Expression/ClangFunction.h"
22 #include "lldb/Expression/DWARFExpression.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Host/StringConvert.h"
25 #include "lldb/Core/Debugger.h"
26 #include "lldb/Interpreter/CommandInterpreter.h"
27 #include "lldb/Interpreter/CommandReturnObject.h"
28 #include "lldb/Target/Language.h"
29 #include "lldb/Target/ObjCLanguageRuntime.h"
30 #include "lldb/Symbol/ObjectFile.h"
31 #include "lldb/Symbol/Variable.h"
32 #include "lldb/Target/Process.h"
33 #include "lldb/Target/StackFrame.h"
34 #include "lldb/Target/Target.h"
35 #include "lldb/Target/Thread.h"
36 #include "llvm/ADT/STLExtras.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 static OptionEnumValueElement g_description_verbosity_type[] =
53 {
54     { eLanguageRuntimeDescriptionDisplayVerbosityCompact,      "compact",       "Only show the description string"},
55     { eLanguageRuntimeDescriptionDisplayVerbosityFull,         "full",          "Show the full output, including persistent variable's name and type"},
56     { 0, NULL, NULL }
57 };
58 
59 OptionDefinition
60 CommandObjectExpression::CommandOptions::g_option_table[] =
61 {
62     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads",        'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Should we run all threads if the execution doesn't complete on one thread."},
63     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Ignore breakpoint hits while running expressions"},
64     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value (in microseconds) for running the expression."},
65     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error",    'u', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean,    "Clean up program state if the expression causes a crash, or raises a signal.  Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
66     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug",              'g', OptionParser::eNoArgument      , NULL, NULL, 0, eArgTypeNone,       "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."},
67     { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "language",           'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage,   "Specifies the Language to use when parsing the expression.  If not set the target.language setting is used." },
68     { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, NULL, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity,        "How verbose should the output of this expression be, if the object description is asked for."},
69 };
70 
71 
72 uint32_t
73 CommandObjectExpression::CommandOptions::GetNumDefinitions ()
74 {
75     return llvm::array_lengthof(g_option_table);
76 }
77 
78 Error
79 CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
80                                                          uint32_t option_idx,
81                                                          const char *option_arg)
82 {
83     Error error;
84 
85     const int short_option = g_option_table[option_idx].short_option;
86 
87     switch (short_option)
88     {
89     case 'l':
90         language = Language::GetLanguageTypeFromString (option_arg);
91         if (language == eLanguageTypeUnknown)
92             error.SetErrorStringWithFormat ("unknown language type: '%s' for expression", option_arg);
93         break;
94 
95     case 'a':
96         {
97             bool success;
98             bool result;
99             result = Args::StringToBoolean(option_arg, true, &success);
100             if (!success)
101                 error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
102             else
103                 try_all_threads = result;
104         }
105         break;
106 
107     case 'i':
108         {
109             bool success;
110             bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
111             if (success)
112                 ignore_breakpoints = tmp_value;
113             else
114                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
115             break;
116         }
117     case 't':
118         {
119             bool success;
120             uint32_t result;
121             result = StringConvert::ToUInt32(option_arg, 0, 0, &success);
122             if (success)
123                 timeout = result;
124             else
125                 error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
126         }
127         break;
128 
129     case 'u':
130         {
131             bool success;
132             bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
133             if (success)
134                 unwind_on_error = tmp_value;
135             else
136                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
137             break;
138         }
139 
140     case 'v':
141         if (!option_arg)
142         {
143             m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull;
144             break;
145         }
146         m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
147         if (!error.Success())
148             error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg);
149         break;
150 
151     case 'g':
152         debug = true;
153         unwind_on_error = false;
154         ignore_breakpoints = false;
155         break;
156 
157     default:
158         error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
159         break;
160     }
161 
162     return error;
163 }
164 
165 void
166 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
167 {
168     Process *process = interpreter.GetExecutionContext().GetProcessPtr();
169     if (process != NULL)
170     {
171         ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
172         unwind_on_error    = process->GetUnwindOnErrorInExpressions();
173     }
174     else
175     {
176         ignore_breakpoints = true;
177         unwind_on_error = true;
178     }
179 
180     show_summary = true;
181     try_all_threads = true;
182     timeout = 0;
183     debug = false;
184     language = eLanguageTypeUnknown;
185     m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact;
186 }
187 
188 const OptionDefinition*
189 CommandObjectExpression::CommandOptions::GetDefinitions ()
190 {
191     return g_option_table;
192 }
193 
194 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
195     CommandObjectRaw (interpreter,
196                       "expression",
197                       "Evaluate an expression in the current program context, using user defined variables and variables currently in scope.",
198                       NULL,
199                       eCommandProcessMustBePaused | eCommandTryTargetAPILock),
200     IOHandlerDelegate (IOHandlerDelegate::Completion::Expression),
201     m_option_group (interpreter),
202     m_format_options (eFormatDefault),
203     m_command_options (),
204     m_expr_line_count (0),
205     m_expr_lines ()
206 {
207     SetHelpLong(
208 R"(
209 Timeouts:
210 
211 )" "    If the expression can be evaluated statically (without running code) then it will be.  \
212 Otherwise, by default the expression will run on the current thread with a short timeout: \
213 currently .25 seconds.  If it doesn't return in that time, the evaluation will be interrupted \
214 and resumed with all threads running.  You can use the -a option to disable retrying on all \
215 threads.  You can use the -t option to set a shorter timeout." R"(
216 
217 User defined variables:
218 
219 )" "    You can define your own variables for convenience or to be used in subsequent expressions.  \
220 You define them the same way you would define variables in C.  If the first character of \
221 your user defined variable is a $, then the variable's value will be available in future \
222 expressions, otherwise it will just be available in the current expression." R"(
223 
224 Continuing evaluation after a breakpoint:
225 
226 )" "    If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once \
227 you are done with your investigation, you can either remove the expression execution frames \
228 from the stack with \"thread return -x\" or if you are still interested in the expression result \
229 you can issue the \"continue\" command and the expression evaluation will complete and the \
230 expression result will be available using the \"thread.completed-expression\" key in the thread \
231 format." R"(
232 
233 Examples:
234 
235     expr my_struct->a = my_array[3]
236     expr -f bin -- (index * 8) + 5
237     expr unsigned int $foo = 5
238     expr char c[] = \"foo\"; c[0])"
239     );
240 
241     CommandArgumentEntry arg;
242     CommandArgumentData expression_arg;
243 
244     // Define the first (and only) variant of this arg.
245     expression_arg.arg_type = eArgTypeExpression;
246     expression_arg.arg_repetition = eArgRepeatPlain;
247 
248     // There is only one variant this argument could be; put it into the argument entry.
249     arg.push_back (expression_arg);
250 
251     // Push the data for the first argument into the m_arguments vector.
252     m_arguments.push_back (arg);
253 
254     // Add the "--format" and "--gdb-format"
255     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
256     m_option_group.Append (&m_command_options);
257     m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
258     m_option_group.Finalize();
259 }
260 
261 CommandObjectExpression::~CommandObjectExpression ()
262 {
263 }
264 
265 Options *
266 CommandObjectExpression::GetOptions ()
267 {
268     return &m_option_group;
269 }
270 
271 bool
272 CommandObjectExpression::EvaluateExpression
273 (
274     const char *expr,
275     Stream *output_stream,
276     Stream *error_stream,
277     CommandReturnObject *result
278 )
279 {
280     // Don't use m_exe_ctx as this might be called asynchronously
281     // after the command object DoExecute has finished when doing
282     // multi-line expression that use an input reader...
283     ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
284 
285     Target *target = exe_ctx.GetTargetPtr();
286 
287     if (!target)
288         target = GetDummyTarget();
289 
290     if (target)
291     {
292         lldb::ValueObjectSP result_valobj_sp;
293 
294         bool keep_in_memory = true;
295 
296         EvaluateExpressionOptions options;
297         options.SetCoerceToId(m_varobj_options.use_objc);
298         options.SetUnwindOnError(m_command_options.unwind_on_error);
299         options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
300         options.SetKeepInMemory(keep_in_memory);
301         options.SetUseDynamic(m_varobj_options.use_dynamic);
302         options.SetTryAllThreads(m_command_options.try_all_threads);
303         options.SetDebug(m_command_options.debug);
304 
305         // If the language was not specified, set it from target's properties
306         if (m_command_options.language != eLanguageTypeUnknown)
307             options.SetLanguage(m_command_options.language);
308         else
309             options.SetLanguage(target->GetLanguage());
310 
311         // If there is any chance we are going to stop and want to see
312         // what went wrong with our expression, we should generate debug info
313         if (!m_command_options.ignore_breakpoints ||
314             !m_command_options.unwind_on_error)
315             options.SetGenerateDebugInfo(true);
316 
317         if (m_command_options.timeout > 0)
318             options.SetTimeoutUsec(m_command_options.timeout);
319         else
320             options.SetTimeoutUsec(0);
321 
322         target->EvaluateExpression(expr, exe_ctx.GetFramePtr(),
323                                    result_valobj_sp, options);
324 
325         if (result_valobj_sp)
326         {
327             Format format = m_format_options.GetFormat();
328 
329             if (result_valobj_sp->GetError().Success())
330             {
331                 if (format != eFormatVoid)
332                 {
333                     if (format != eFormatDefault)
334                         result_valobj_sp->SetFormat (format);
335 
336                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format));
337 
338                     result_valobj_sp->Dump(*output_stream,options);
339 
340                     if (result)
341                         result->SetStatus (eReturnStatusSuccessFinishResult);
342                 }
343             }
344             else
345             {
346                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
347                 {
348                     if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
349                     {
350                         error_stream->PutCString("(void)\n");
351                     }
352 
353                     if (result)
354                         result->SetStatus (eReturnStatusSuccessFinishResult);
355                 }
356                 else
357                 {
358                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
359                     if (error_cstr && error_cstr[0])
360                     {
361                         const size_t error_cstr_len = strlen (error_cstr);
362                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
363                         if (strstr(error_cstr, "error:") != error_cstr)
364                             error_stream->PutCString ("error: ");
365                         error_stream->Write(error_cstr, error_cstr_len);
366                         if (!ends_with_newline)
367                             error_stream->EOL();
368                     }
369                     else
370                     {
371                         error_stream->PutCString ("error: unknown error\n");
372                     }
373 
374                     if (result)
375                         result->SetStatus (eReturnStatusFailed);
376                 }
377             }
378         }
379     }
380     else
381     {
382         error_stream->Printf ("error: invalid execution context for expression\n");
383         return false;
384     }
385 
386     return true;
387 }
388 
389 void
390 CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
391 {
392     io_handler.SetIsDone(true);
393 //    StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream();
394 //    StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream();
395     StreamFileSP output_sp(io_handler.GetOutputStreamFile());
396     StreamFileSP error_sp(io_handler.GetErrorStreamFile());
397 
398     EvaluateExpression (line.c_str(),
399                         output_sp.get(),
400                         error_sp.get());
401     if (output_sp)
402         output_sp->Flush();
403     if (error_sp)
404         error_sp->Flush();
405 }
406 
407 LineStatus
408 CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler,
409                                                 StringList &lines,
410                                                 uint32_t line_idx,
411                                                 Error &error)
412 {
413     if (line_idx == UINT32_MAX)
414     {
415         // Remove the last line from "lines" so it doesn't appear
416         // in our final expression
417         lines.PopBack();
418         error.Clear();
419         return LineStatus::Done;
420     }
421     else if (line_idx + 1 == lines.GetSize())
422     {
423         // The last line was edited, if this line is empty, then we are done
424         // getting our multiple lines.
425         if (lines[line_idx].empty())
426             return LineStatus::Done;
427     }
428     return LineStatus::Success;
429 }
430 
431 void
432 CommandObjectExpression::GetMultilineExpression ()
433 {
434     m_expr_lines.clear();
435     m_expr_line_count = 0;
436 
437     Debugger &debugger = GetCommandInterpreter().GetDebugger();
438     bool color_prompt = debugger.GetUseColor();
439     const bool multiple_lines = true; // Get multiple lines
440     IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
441                                                       IOHandler::Type::Expression,
442                                                       "lldb-expr",      // Name of input reader for history
443                                                       NULL,             // No prompt
444                                                       NULL,             // Continuation prompt
445                                                       multiple_lines,
446                                                       color_prompt,
447                                                       1,                // Show line numbers starting at 1
448                                                       *this));
449 
450     StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile());
451     if (output_sp)
452     {
453         output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
454         output_sp->Flush();
455     }
456     debugger.PushIOHandler(io_handler_sp);
457 }
458 
459 bool
460 CommandObjectExpression::DoExecute
461 (
462     const char *command,
463     CommandReturnObject &result
464 )
465 {
466     m_option_group.NotifyOptionParsingStarting();
467 
468     const char * expr = NULL;
469 
470     if (command[0] == '\0')
471     {
472         GetMultilineExpression ();
473         return result.Succeeded();
474     }
475 
476     if (command[0] == '-')
477     {
478         // We have some options and these options MUST end with --.
479         const char *end_options = NULL;
480         const char *s = command;
481         while (s && s[0])
482         {
483             end_options = ::strstr (s, "--");
484             if (end_options)
485             {
486                 end_options += 2; // Get past the "--"
487                 if (::isspace (end_options[0]))
488                 {
489                     expr = end_options;
490                     while (::isspace (*expr))
491                         ++expr;
492                     break;
493                 }
494             }
495             s = end_options;
496         }
497 
498         if (end_options)
499         {
500             Args args (llvm::StringRef(command, end_options - command));
501             if (!ParseOptions (args, result))
502                 return false;
503 
504             Error error (m_option_group.NotifyOptionParsingFinished());
505             if (error.Fail())
506             {
507                 result.AppendError (error.AsCString());
508                 result.SetStatus (eReturnStatusFailed);
509                 return false;
510             }
511 
512             // No expression following options
513             if (expr == NULL || expr[0] == '\0')
514             {
515                 GetMultilineExpression ();
516                 return result.Succeeded();
517             }
518         }
519     }
520 
521     if (expr == NULL)
522         expr = command;
523 
524     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
525         return true;
526 
527     result.SetStatus (eReturnStatusFailed);
528     return false;
529 }
530 
531