xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision a73d26929449a8cb7a67e2914c34c74cd6e00188)
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 "--gdb-format"
168     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, 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_interpreter.GetExecutionContext().GetTargetPtr();
286 
287     if (!target)
288         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
289 
290     if (target)
291     {
292         lldb::ValueObjectSP result_valobj_sp;
293 
294         ExecutionResults exe_results;
295 
296         bool keep_in_memory = true;
297         lldb::DynamicValueType use_dynamic;
298         // If use dynamic is not set, get it from the target:
299         switch (m_command_options.use_dynamic)
300         {
301         case eLazyBoolCalculate:
302             use_dynamic = target->GetPreferDynamicValue();
303             break;
304         case eLazyBoolYes:
305             use_dynamic = lldb::eDynamicCanRunTarget;
306             break;
307         case eLazyBoolNo:
308             use_dynamic = lldb::eNoDynamicValues;
309             break;
310         }
311 
312         exe_results = target->EvaluateExpression (expr,
313                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
314                                                   eExecutionPolicyOnlyWhenNeeded,
315                                                   m_command_options.print_object,
316                                                   m_command_options.unwind_on_error,
317                                                   keep_in_memory,
318                                                   use_dynamic,
319                                                   result_valobj_sp);
320 
321         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
322         {
323             uint32_t start_frame = 0;
324             uint32_t num_frames = 1;
325             uint32_t num_frames_with_source = 0;
326             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
327             if (thread)
328             {
329                 thread->GetStatus (result->GetOutputStream(),
330                                    start_frame,
331                                    num_frames,
332                                    num_frames_with_source);
333             }
334             else
335             {
336                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
337                 if (process)
338                 {
339                     bool only_threads_with_stop_reason = true;
340                     process->GetThreadStatus (result->GetOutputStream(),
341                                               only_threads_with_stop_reason,
342                                               start_frame,
343                                               num_frames,
344                                               num_frames_with_source);
345                 }
346             }
347         }
348 
349         if (result_valobj_sp)
350         {
351             if (result_valobj_sp->GetError().Success())
352             {
353                 Format format = m_format_options.GetFormat();
354                 if (format != eFormatDefault)
355                     result_valobj_sp->SetFormat (format);
356 
357                 ValueObject::DumpValueObject (*(output_stream),
358                                               result_valobj_sp.get(),   // Variable object to dump
359                                               result_valobj_sp->GetName().GetCString(),// Root object name
360                                               0,                        // Pointer depth to traverse (zero means stop at pointers)
361                                               0,                        // Current depth, this is the top most, so zero...
362                                               UINT32_MAX,               // Max depth to go when dumping concrete types, dump everything...
363                                               m_command_options.show_types,     // Show types when dumping?
364                                               false,                    // Show locations of variables, no since this is a host address which we don't care to see
365                                               m_command_options.print_object,   // Print the objective C object?
366                                               use_dynamic,
367                                               true,                     // Use synthetic children if available
368                                               true,                     // Scope is already checked. Const results are always in scope.
369                                               false,                    // Don't flatten output
370                                               0,                        // Always use summaries (you might want an option --no-summary like there is for frame variable)
371                                               false,                    // Do not show more children than settings allow
372                                               format);                  // Format override
373                 if (result)
374                     result->SetStatus (eReturnStatusSuccessFinishResult);
375             }
376             else
377             {
378                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
379                 {
380                     error_stream->PutCString("<no result>\n");
381 
382                     if (result)
383                         result->SetStatus (eReturnStatusSuccessFinishResult);
384                 }
385                 else
386                 {
387                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
388                     if (error_cstr && error_cstr[0])
389                     {
390                         int error_cstr_len = strlen (error_cstr);
391                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
392                         if (strstr(error_cstr, "error:") != error_cstr)
393                             error_stream->PutCString ("error: ");
394                         error_stream->Write(error_cstr, error_cstr_len);
395                         if (!ends_with_newline)
396                             error_stream->EOL();
397                     }
398                     else
399                     {
400                         error_stream->PutCString ("error: unknown error\n");
401                     }
402 
403                     if (result)
404                         result->SetStatus (eReturnStatusFailed);
405                 }
406             }
407         }
408     }
409     else
410     {
411         error_stream->Printf ("error: invalid execution context for expression\n");
412         return false;
413     }
414 
415     return true;
416 }
417 
418 bool
419 CommandObjectExpression::ExecuteRawCommandString
420 (
421     const char *command,
422     CommandReturnObject &result
423 )
424 {
425     m_option_group.NotifyOptionParsingStarting();
426 
427     const char * expr = NULL;
428 
429     if (command[0] == '\0')
430     {
431         m_expr_lines.clear();
432         m_expr_line_count = 0;
433 
434         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
435         if (reader_sp)
436         {
437             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
438                                               this,                         // baton
439                                               eInputReaderGranularityLine,  // token size, to pass to callback function
440                                               NULL,                         // end token
441                                               NULL,                         // prompt
442                                               true));                       // echo input
443             if (err.Success())
444             {
445                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
446                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
447             }
448             else
449             {
450                 result.AppendError (err.AsCString());
451                 result.SetStatus (eReturnStatusFailed);
452             }
453         }
454         else
455         {
456             result.AppendError("out of memory");
457             result.SetStatus (eReturnStatusFailed);
458         }
459         return result.Succeeded();
460     }
461 
462     if (command[0] == '-')
463     {
464         // We have some options and these options MUST end with --.
465         const char *end_options = NULL;
466         const char *s = command;
467         while (s && s[0])
468         {
469             end_options = ::strstr (s, "--");
470             if (end_options)
471             {
472                 end_options += 2; // Get past the "--"
473                 if (::isspace (end_options[0]))
474                 {
475                     expr = end_options;
476                     while (::isspace (*expr))
477                         ++expr;
478                     break;
479                 }
480             }
481             s = end_options;
482         }
483 
484         if (end_options)
485         {
486             Args args (command, end_options - command);
487             if (!ParseOptions (args, result))
488                 return false;
489 
490             Error error (m_option_group.NotifyOptionParsingFinished());
491             if (error.Fail())
492             {
493                 result.AppendError (error.AsCString());
494                 result.SetStatus (eReturnStatusFailed);
495                 return false;
496             }
497         }
498     }
499 
500     if (expr == NULL)
501         expr = command;
502 
503     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
504         return true;
505 
506     result.SetStatus (eReturnStatusFailed);
507     return false;
508 }
509 
510