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