xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 86edbf41d1ad98b057f0e4e14bbd47eb3b6014f9)
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, "dynamic-value",      'd', required_argument, NULL, 0, eArgTypeBoolean,    "Upcast the value resulting from the expression to its dynamic type if available."},
54     { 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."},
55     { LLDB_OPT_SET_2                 , false, "object-description", 'o', no_argument,       NULL, 0, eArgTypeNone,       "Print the object description of the value resulting from the expression."},
56 };
57 
58 
59 uint32_t
60 CommandObjectExpression::CommandOptions::GetNumDefinitions ()
61 {
62     return sizeof(g_option_table)/sizeof(OptionDefinition);
63 }
64 
65 Error
66 CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
67                                                          uint32_t option_idx,
68                                                          const char *option_arg)
69 {
70     Error error;
71 
72     const char short_option = (char) g_option_table[option_idx].short_option;
73 
74     switch (short_option)
75     {
76       //case 'l':
77       //if (language.SetLanguageFromCString (option_arg) == false)
78       //{
79       //    error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
80       //}
81       //break;
82 
83     case 'o':
84         print_object = true;
85         break;
86 
87     case 'd':
88         {
89             bool success;
90             bool result;
91             result = Args::StringToBoolean(option_arg, true, &success);
92             if (!success)
93                 error.SetErrorStringWithFormat("invalid dynamic value setting: \"%s\"", option_arg);
94             else
95             {
96                 if (result)
97                     use_dynamic = eLazyBoolYes;
98                 else
99                     use_dynamic = eLazyBoolNo;
100             }
101         }
102         break;
103 
104     case 'u':
105         {
106             bool success;
107             unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
108             if (!success)
109                 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
110             break;
111         }
112     default:
113         error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
114         break;
115     }
116 
117     return error;
118 }
119 
120 void
121 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
122 {
123     use_dynamic = eLazyBoolCalculate;
124     print_object = false;
125     unwind_on_error = true;
126     show_types = true;
127     show_summary = true;
128 }
129 
130 const OptionDefinition*
131 CommandObjectExpression::CommandOptions::GetDefinitions ()
132 {
133     return g_option_table;
134 }
135 
136 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
137     CommandObject (interpreter,
138                    "expression",
139                    "Evaluate a C/ObjC/C++ expression in the current program context, using variables currently in scope.",
140                    NULL),
141     m_option_group (interpreter),
142     m_format_options (eFormatDefault),
143     m_command_options (),
144     m_expr_line_count (0),
145     m_expr_lines ()
146 {
147   SetHelpLong(
148 "Examples: \n\
149 \n\
150    expr my_struct->a = my_array[3] \n\
151    expr -f bin -- (index * 8) + 5 \n\
152    expr char c[] = \"foo\"; c[0]\n");
153 
154     CommandArgumentEntry arg;
155     CommandArgumentData expression_arg;
156 
157     // Define the first (and only) variant of this arg.
158     expression_arg.arg_type = eArgTypeExpression;
159     expression_arg.arg_repetition = eArgRepeatPlain;
160 
161     // There is only one variant this argument could be; put it into the argument entry.
162     arg.push_back (expression_arg);
163 
164     // Push the data for the first argument into the m_arguments vector.
165     m_arguments.push_back (arg);
166 
167     // Add the "--format" and "--count" options to group 1 and 3
168     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
169     m_option_group.Append (&m_command_options);
170     m_option_group.Finalize();
171 }
172 
173 CommandObjectExpression::~CommandObjectExpression ()
174 {
175 }
176 
177 Options *
178 CommandObjectExpression::GetOptions ()
179 {
180     return &m_option_group;
181 }
182 
183 
184 bool
185 CommandObjectExpression::Execute
186 (
187     Args& command,
188     CommandReturnObject &result
189 )
190 {
191     return false;
192 }
193 
194 
195 size_t
196 CommandObjectExpression::MultiLineExpressionCallback
197 (
198     void *baton,
199     InputReader &reader,
200     lldb::InputReaderAction notification,
201     const char *bytes,
202     size_t bytes_len
203 )
204 {
205     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
206     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
207 
208     switch (notification)
209     {
210     case eInputReaderActivate:
211         if (!batch_mode)
212         {
213             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
214             if (async_strm_sp)
215             {
216                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
217                 async_strm_sp->Flush();
218             }
219         }
220         // Fall through
221     case eInputReaderReactivate:
222         break;
223 
224     case eInputReaderDeactivate:
225         break;
226 
227     case eInputReaderAsynchronousOutputWritten:
228         break;
229 
230     case eInputReaderGotToken:
231         ++cmd_object_expr->m_expr_line_count;
232         if (bytes && bytes_len)
233         {
234             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
235         }
236 
237         if (bytes_len == 0)
238             reader.SetIsDone(true);
239         break;
240 
241     case eInputReaderInterrupt:
242         cmd_object_expr->m_expr_lines.clear();
243         reader.SetIsDone (true);
244         if (!batch_mode)
245         {
246             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
247             if (async_strm_sp)
248             {
249                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
250                 async_strm_sp->Flush();
251             }
252         }
253         break;
254 
255     case eInputReaderEndOfFile:
256         reader.SetIsDone (true);
257         break;
258 
259     case eInputReaderDone:
260 		if (cmd_object_expr->m_expr_lines.size() > 0)
261         {
262             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
263             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
264             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
265                                                  output_stream.get(),
266                                                  error_stream.get());
267             output_stream->Flush();
268             error_stream->Flush();
269         }
270         break;
271     }
272 
273     return bytes_len;
274 }
275 
276 bool
277 CommandObjectExpression::EvaluateExpression
278 (
279     const char *expr,
280     Stream *output_stream,
281     Stream *error_stream,
282     CommandReturnObject *result
283 )
284 {
285     Target *target = m_exe_ctx.GetTargetPtr();
286     if (target)
287     {
288         lldb::ValueObjectSP result_valobj_sp;
289 
290         ExecutionResults exe_results;
291 
292         bool keep_in_memory = true;
293         lldb::DynamicValueType use_dynamic;
294         // If use dynamic is not set, get it from the target:
295         switch (m_command_options.use_dynamic)
296         {
297         case eLazyBoolCalculate:
298             use_dynamic = target->GetPreferDynamicValue();
299             break;
300         case eLazyBoolYes:
301             use_dynamic = lldb::eDynamicCanRunTarget;
302             break;
303         case eLazyBoolNo:
304             use_dynamic = lldb::eNoDynamicValues;
305             break;
306         }
307 
308         exe_results = target->EvaluateExpression (expr,
309                                                   m_exe_ctx.GetFramePtr(),
310                                                   eExecutionPolicyOnlyWhenNeeded,
311                                                   m_command_options.unwind_on_error,
312                                                   keep_in_memory,
313                                                   use_dynamic,
314                                                   result_valobj_sp);
315 
316         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
317         {
318             uint32_t start_frame = 0;
319             uint32_t num_frames = 1;
320             uint32_t num_frames_with_source = 0;
321             Thread *thread = m_exe_ctx.GetThreadPtr();
322             if (thread)
323             {
324                 thread->GetStatus (result->GetOutputStream(),
325                                    start_frame,
326                                    num_frames,
327                                    num_frames_with_source);
328             }
329             else
330             {
331                 Process *process = m_exe_ctx.GetProcessPtr();
332                 if (process)
333                 {
334                     bool only_threads_with_stop_reason = true;
335                     process->GetThreadStatus (result->GetOutputStream(),
336                                               only_threads_with_stop_reason,
337                                               start_frame,
338                                               num_frames,
339                                               num_frames_with_source);
340                 }
341             }
342         }
343 
344         if (result_valobj_sp)
345         {
346             if (result_valobj_sp->GetError().Success())
347             {
348                 Format format = m_format_options.GetFormat();
349                 if (format != eFormatDefault)
350                     result_valobj_sp->SetFormat (format);
351 
352                 ValueObject::DumpValueObject (*(output_stream),
353                                               result_valobj_sp.get(),   // Variable object to dump
354                                               result_valobj_sp->GetName().GetCString(),// Root object name
355                                               0,                        // Pointer depth to traverse (zero means stop at pointers)
356                                               0,                        // Current depth, this is the top most, so zero...
357                                               UINT32_MAX,               // Max depth to go when dumping concrete types, dump everything...
358                                               m_command_options.show_types,     // Show types when dumping?
359                                               false,                    // Show locations of variables, no since this is a host address which we don't care to see
360                                               m_command_options.print_object,   // Print the objective C object?
361                                               use_dynamic,
362                                               true,                     // Use synthetic children if available
363                                               true,                     // Scope is already checked. Const results are always in scope.
364                                               false,                    // Don't flatten output
365                                               0,                        // Always use summaries (you might want an option --no-summary like there is for frame variable)
366                                               false);                   // Do not show more children than settings allow
367                 if (result)
368                     result->SetStatus (eReturnStatusSuccessFinishResult);
369             }
370             else
371             {
372                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
373                 {
374                     error_stream->PutCString("<no result>\n");
375 
376                     if (result)
377                         result->SetStatus (eReturnStatusSuccessFinishResult);
378                 }
379                 else
380                 {
381                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
382                     if (error_cstr && error_cstr[0])
383                     {
384                         int error_cstr_len = strlen (error_cstr);
385                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
386                         if (strstr(error_cstr, "error:") != error_cstr)
387                             error_stream->PutCString ("error: ");
388                         error_stream->Write(error_cstr, error_cstr_len);
389                         if (!ends_with_newline)
390                             error_stream->EOL();
391                     }
392                     else
393                     {
394                         error_stream->PutCString ("error: unknown error\n");
395                     }
396 
397                     if (result)
398                         result->SetStatus (eReturnStatusFailed);
399                 }
400             }
401         }
402     }
403     else
404     {
405         error_stream->Printf ("error: invalid execution context for expression\n");
406         return false;
407     }
408 
409     return true;
410 }
411 
412 bool
413 CommandObjectExpression::ExecuteRawCommandString
414 (
415     const char *command,
416     CommandReturnObject &result
417 )
418 {
419     m_exe_ctx = m_interpreter.GetExecutionContext();
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