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
39using namespace lldb;
40using namespace lldb_private;
41
42CommandObjectExpression::CommandOptions::CommandOptions () :
43    OptionGroup()
44{
45}
46
47
48CommandObjectExpression::CommandOptions::~CommandOptions ()
49{
50}
51
52OptionDefinition
53CommandObjectExpression::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, "ignore-breakpoints", 'i', required_argument, NULL, 0, eArgTypeBoolean,    "Ignore breakpoint hits while running expressions"},
57    { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout",            't', required_argument, NULL, 0, eArgTypeUnsignedInteger,  "Timeout value (in microseconds) for running the expression."},
58    { 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, or raises a signal.  Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
59};
60
61
62uint32_t
63CommandObjectExpression::CommandOptions::GetNumDefinitions ()
64{
65    return sizeof(g_option_table)/sizeof(OptionDefinition);
66}
67
68Error
69CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
70                                                         uint32_t option_idx,
71                                                         const char *option_arg)
72{
73    Error error;
74
75    const int short_option = g_option_table[option_idx].short_option;
76
77    switch (short_option)
78    {
79      //case 'l':
80      //if (language.SetLanguageFromCString (option_arg) == false)
81      //{
82      //    error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
83      //}
84      //break;
85
86    case 'a':
87        {
88            bool success;
89            bool result;
90            result = Args::StringToBoolean(option_arg, true, &success);
91            if (!success)
92                error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
93            else
94                try_all_threads = result;
95        }
96        break;
97
98    case 'i':
99        {
100            bool success;
101            bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
102            if (success)
103                ignore_breakpoints = tmp_value;
104            else
105                error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
106            break;
107        }
108    case 't':
109        {
110            bool success;
111            uint32_t result;
112            result = Args::StringToUInt32(option_arg, 0, 0, &success);
113            if (success)
114                timeout = result;
115            else
116                error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
117        }
118        break;
119
120    case 'u':
121        {
122            bool success;
123            bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
124            if (success)
125                unwind_on_error = tmp_value;
126            else
127                error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
128            break;
129        }
130    default:
131        error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
132        break;
133    }
134
135    return error;
136}
137
138void
139CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
140{
141    Process *process = interpreter.GetExecutionContext().GetProcessPtr();
142    if (process != NULL)
143    {
144        ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
145        unwind_on_error    = process->GetUnwindOnErrorInExpressions();
146    }
147    else
148    {
149        ignore_breakpoints = false;
150        unwind_on_error = true;
151    }
152
153    show_summary = true;
154    try_all_threads = true;
155    timeout = 0;
156}
157
158const OptionDefinition*
159CommandObjectExpression::CommandOptions::GetDefinitions ()
160{
161    return g_option_table;
162}
163
164CommandObjectExpression::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 | eFlagTryTargetAPILock),
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\
184User 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\
190Examples: \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.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
214    m_option_group.Finalize();
215}
216
217CommandObjectExpression::~CommandObjectExpression ()
218{
219}
220
221Options *
222CommandObjectExpression::GetOptions ()
223{
224    return &m_option_group;
225}
226
227size_t
228CommandObjectExpression::MultiLineExpressionCallback
229(
230    void *baton,
231    InputReader &reader,
232    lldb::InputReaderAction notification,
233    const char *bytes,
234    size_t bytes_len
235)
236{
237    CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
238    bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
239
240    switch (notification)
241    {
242    case eInputReaderActivate:
243        if (!batch_mode)
244        {
245            StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
246            if (async_strm_sp)
247            {
248                async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
249                async_strm_sp->Flush();
250            }
251        }
252        // Fall through
253    case eInputReaderReactivate:
254        break;
255
256    case eInputReaderDeactivate:
257        break;
258
259    case eInputReaderAsynchronousOutputWritten:
260        break;
261
262    case eInputReaderGotToken:
263        ++cmd_object_expr->m_expr_line_count;
264        if (bytes && bytes_len)
265        {
266            cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
267        }
268
269        if (bytes_len == 0)
270            reader.SetIsDone(true);
271        break;
272
273    case eInputReaderInterrupt:
274        cmd_object_expr->m_expr_lines.clear();
275        reader.SetIsDone (true);
276        if (!batch_mode)
277        {
278            StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
279            if (async_strm_sp)
280            {
281                async_strm_sp->PutCString("Expression evaluation cancelled.\n");
282                async_strm_sp->Flush();
283            }
284        }
285        break;
286
287    case eInputReaderEndOfFile:
288        reader.SetIsDone (true);
289        break;
290
291    case eInputReaderDone:
292		if (cmd_object_expr->m_expr_lines.size() > 0)
293        {
294            StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
295            StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
296            cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
297                                                 output_stream.get(),
298                                                 error_stream.get());
299            output_stream->Flush();
300            error_stream->Flush();
301        }
302        break;
303    }
304
305    return bytes_len;
306}
307
308bool
309CommandObjectExpression::EvaluateExpression
310(
311    const char *expr,
312    Stream *output_stream,
313    Stream *error_stream,
314    CommandReturnObject *result
315)
316{
317    // Don't use m_exe_ctx as this might be called asynchronously
318    // after the command object DoExecute has finished when doing
319    // multi-line expression that use an input reader...
320    ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
321
322    Target *target = exe_ctx.GetTargetPtr();
323
324    if (!target)
325        target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
326
327    if (target)
328    {
329        lldb::ValueObjectSP result_valobj_sp;
330
331        ExecutionResults exe_results;
332
333        bool keep_in_memory = true;
334
335        EvaluateExpressionOptions options;
336        options.SetCoerceToId(m_varobj_options.use_objc)
337        .SetUnwindOnError(m_command_options.unwind_on_error)
338        .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints)
339        .SetKeepInMemory(keep_in_memory)
340        .SetUseDynamic(m_varobj_options.use_dynamic)
341        .SetRunOthers(m_command_options.try_all_threads)
342        .SetTimeoutUsec(m_command_options.timeout);
343
344        exe_results = target->EvaluateExpression (expr,
345                                                  exe_ctx.GetFramePtr(),
346                                                  result_valobj_sp,
347                                                  options);
348
349        if (result_valobj_sp)
350        {
351            Format format = m_format_options.GetFormat();
352
353            if (result_valobj_sp->GetError().Success())
354            {
355                if (format != eFormatVoid)
356                {
357                    if (format != eFormatDefault)
358                        result_valobj_sp->SetFormat (format);
359
360                    ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(true,format));
361
362                    ValueObject::DumpValueObject (*(output_stream),
363                                                  result_valobj_sp.get(),   // Variable object to dump
364                                                  options);
365                    if (result)
366                        result->SetStatus (eReturnStatusSuccessFinishResult);
367                }
368            }
369            else
370            {
371                if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
372                {
373                    if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
374                    {
375                        error_stream->PutCString("(void)\n");
376                    }
377
378                    if (result)
379                        result->SetStatus (eReturnStatusSuccessFinishResult);
380                }
381                else
382                {
383                    const char *error_cstr = result_valobj_sp->GetError().AsCString();
384                    if (error_cstr && error_cstr[0])
385                    {
386                        const size_t error_cstr_len = strlen (error_cstr);
387                        const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
388                        if (strstr(error_cstr, "error:") != error_cstr)
389                            error_stream->PutCString ("error: ");
390                        error_stream->Write(error_cstr, error_cstr_len);
391                        if (!ends_with_newline)
392                            error_stream->EOL();
393                    }
394                    else
395                    {
396                        error_stream->PutCString ("error: unknown error\n");
397                    }
398
399                    if (result)
400                        result->SetStatus (eReturnStatusFailed);
401                }
402            }
403        }
404    }
405    else
406    {
407        error_stream->Printf ("error: invalid execution context for expression\n");
408        return false;
409    }
410
411    return true;
412}
413
414bool
415CommandObjectExpression::DoExecute
416(
417    const char *command,
418    CommandReturnObject &result
419)
420{
421    m_option_group.NotifyOptionParsingStarting();
422
423    const char * expr = NULL;
424
425    if (command[0] == '\0')
426    {
427        m_expr_lines.clear();
428        m_expr_line_count = 0;
429
430        InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
431        if (reader_sp)
432        {
433            Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
434                                              this,                         // baton
435                                              eInputReaderGranularityLine,  // token size, to pass to callback function
436                                              NULL,                         // end token
437                                              NULL,                         // prompt
438                                              true));                       // echo input
439            if (err.Success())
440            {
441                m_interpreter.GetDebugger().PushInputReader (reader_sp);
442                result.SetStatus (eReturnStatusSuccessFinishNoResult);
443            }
444            else
445            {
446                result.AppendError (err.AsCString());
447                result.SetStatus (eReturnStatusFailed);
448            }
449        }
450        else
451        {
452            result.AppendError("out of memory");
453            result.SetStatus (eReturnStatusFailed);
454        }
455        return result.Succeeded();
456    }
457
458    if (command[0] == '-')
459    {
460        // We have some options and these options MUST end with --.
461        const char *end_options = NULL;
462        const char *s = command;
463        while (s && s[0])
464        {
465            end_options = ::strstr (s, "--");
466            if (end_options)
467            {
468                end_options += 2; // Get past the "--"
469                if (::isspace (end_options[0]))
470                {
471                    expr = end_options;
472                    while (::isspace (*expr))
473                        ++expr;
474                    break;
475                }
476            }
477            s = end_options;
478        }
479
480        if (end_options)
481        {
482            Args args (command, end_options - command);
483            if (!ParseOptions (args, result))
484                return false;
485
486            Error error (m_option_group.NotifyOptionParsingFinished());
487            if (error.Fail())
488            {
489                result.AppendError (error.AsCString());
490                result.SetStatus (eReturnStatusFailed);
491                return false;
492            }
493        }
494    }
495
496    if (expr == NULL)
497        expr = command;
498
499    if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
500        return true;
501
502    result.SetStatus (eReturnStatusFailed);
503    return false;
504}
505
506