xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 5a988416736b906931cf6076d38f5b960110ed81)
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     CommandObjectRaw (interpreter,
138                       "expression",
139                       "Evaluate a C/ObjC/C++ expression in the current program context, using variables currently in scope.",
140                       NULL,
141                       eFlagProcessMustBePaused),
142     m_option_group (interpreter),
143     m_format_options (eFormatDefault),
144     m_command_options (),
145     m_expr_line_count (0),
146     m_expr_lines ()
147 {
148   SetHelpLong(
149 "Examples: \n\
150 \n\
151    expr my_struct->a = my_array[3] \n\
152    expr -f bin -- (index * 8) + 5 \n\
153    expr char c[] = \"foo\"; c[0]\n");
154 
155     CommandArgumentEntry arg;
156     CommandArgumentData expression_arg;
157 
158     // Define the first (and only) variant of this arg.
159     expression_arg.arg_type = eArgTypeExpression;
160     expression_arg.arg_repetition = eArgRepeatPlain;
161 
162     // There is only one variant this argument could be; put it into the argument entry.
163     arg.push_back (expression_arg);
164 
165     // Push the data for the first argument into the m_arguments vector.
166     m_arguments.push_back (arg);
167 
168     // Add the "--format" and "--gdb-format"
169     m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
170     m_option_group.Append (&m_command_options);
171     m_option_group.Finalize();
172 }
173 
174 CommandObjectExpression::~CommandObjectExpression ()
175 {
176 }
177 
178 Options *
179 CommandObjectExpression::GetOptions ()
180 {
181     return &m_option_group;
182 }
183 
184 size_t
185 CommandObjectExpression::MultiLineExpressionCallback
186 (
187     void *baton,
188     InputReader &reader,
189     lldb::InputReaderAction notification,
190     const char *bytes,
191     size_t bytes_len
192 )
193 {
194     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
195     bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
196 
197     switch (notification)
198     {
199     case eInputReaderActivate:
200         if (!batch_mode)
201         {
202             StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
203             if (async_strm_sp)
204             {
205                 async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
206                 async_strm_sp->Flush();
207             }
208         }
209         // Fall through
210     case eInputReaderReactivate:
211         break;
212 
213     case eInputReaderDeactivate:
214         break;
215 
216     case eInputReaderAsynchronousOutputWritten:
217         break;
218 
219     case eInputReaderGotToken:
220         ++cmd_object_expr->m_expr_line_count;
221         if (bytes && bytes_len)
222         {
223             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
224         }
225 
226         if (bytes_len == 0)
227             reader.SetIsDone(true);
228         break;
229 
230     case eInputReaderInterrupt:
231         cmd_object_expr->m_expr_lines.clear();
232         reader.SetIsDone (true);
233         if (!batch_mode)
234         {
235             StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
236             if (async_strm_sp)
237             {
238                 async_strm_sp->PutCString("Expression evaluation cancelled.\n");
239                 async_strm_sp->Flush();
240             }
241         }
242         break;
243 
244     case eInputReaderEndOfFile:
245         reader.SetIsDone (true);
246         break;
247 
248     case eInputReaderDone:
249 		if (cmd_object_expr->m_expr_lines.size() > 0)
250         {
251             StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
252             StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
253             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
254                                                  output_stream.get(),
255                                                  error_stream.get());
256             output_stream->Flush();
257             error_stream->Flush();
258         }
259         break;
260     }
261 
262     return bytes_len;
263 }
264 
265 bool
266 CommandObjectExpression::EvaluateExpression
267 (
268     const char *expr,
269     Stream *output_stream,
270     Stream *error_stream,
271     CommandReturnObject *result
272 )
273 {
274     Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
275 
276     if (!target)
277         target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
278 
279     if (target)
280     {
281         lldb::ValueObjectSP result_valobj_sp;
282 
283         ExecutionResults exe_results;
284 
285         bool keep_in_memory = true;
286         lldb::DynamicValueType use_dynamic;
287         // If use dynamic is not set, get it from the target:
288         switch (m_command_options.use_dynamic)
289         {
290         case eLazyBoolCalculate:
291             use_dynamic = target->GetPreferDynamicValue();
292             break;
293         case eLazyBoolYes:
294             use_dynamic = lldb::eDynamicCanRunTarget;
295             break;
296         case eLazyBoolNo:
297             use_dynamic = lldb::eNoDynamicValues;
298             break;
299         }
300 
301         exe_results = target->EvaluateExpression (expr,
302                                                   m_interpreter.GetExecutionContext().GetFramePtr(),
303                                                   eExecutionPolicyOnlyWhenNeeded,
304                                                   m_command_options.print_object,
305                                                   m_command_options.unwind_on_error,
306                                                   keep_in_memory,
307                                                   use_dynamic,
308                                                   result_valobj_sp);
309 
310         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
311         {
312             uint32_t start_frame = 0;
313             uint32_t num_frames = 1;
314             uint32_t num_frames_with_source = 0;
315             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
316             if (thread)
317             {
318                 thread->GetStatus (result->GetOutputStream(),
319                                    start_frame,
320                                    num_frames,
321                                    num_frames_with_source);
322             }
323             else
324             {
325                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
326                 if (process)
327                 {
328                     bool only_threads_with_stop_reason = true;
329                     process->GetThreadStatus (result->GetOutputStream(),
330                                               only_threads_with_stop_reason,
331                                               start_frame,
332                                               num_frames,
333                                               num_frames_with_source);
334                 }
335             }
336         }
337 
338         if (result_valobj_sp)
339         {
340             if (result_valobj_sp->GetError().Success())
341             {
342                 Format format = m_format_options.GetFormat();
343                 if (format != eFormatDefault)
344                     result_valobj_sp->SetFormat (format);
345 
346                 ValueObject::DumpValueObjectOptions options;
347                 options.SetMaximumPointerDepth(0)
348                 .SetMaximumDepth(UINT32_MAX)
349                 .SetShowLocation(false)
350                 .SetShowTypes(m_command_options.show_types)
351                 .SetUseObjectiveC(m_command_options.print_object)
352                 .SetUseDynamicType(use_dynamic)
353                 .SetScopeChecked(true)
354                 .SetFlatOutput(false)
355                 .SetUseSyntheticValue(true)
356                 .SetIgnoreCap(false)
357                 .SetFormat(format)
358                 .SetSummary()
359                 .SetShowSummary(!m_command_options.print_object);
360 
361                 ValueObject::DumpValueObject (*(output_stream),
362                                               result_valobj_sp.get(),   // Variable object to dump
363                                               options);
364                 if (result)
365                     result->SetStatus (eReturnStatusSuccessFinishResult);
366             }
367             else
368             {
369                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
370                 {
371                     error_stream->PutCString("<no result>\n");
372 
373                     if (result)
374                         result->SetStatus (eReturnStatusSuccessFinishResult);
375                 }
376                 else
377                 {
378                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
379                     if (error_cstr && error_cstr[0])
380                     {
381                         int error_cstr_len = strlen (error_cstr);
382                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
383                         if (strstr(error_cstr, "error:") != error_cstr)
384                             error_stream->PutCString ("error: ");
385                         error_stream->Write(error_cstr, error_cstr_len);
386                         if (!ends_with_newline)
387                             error_stream->EOL();
388                     }
389                     else
390                     {
391                         error_stream->PutCString ("error: unknown error\n");
392                     }
393 
394                     if (result)
395                         result->SetStatus (eReturnStatusFailed);
396                 }
397             }
398         }
399     }
400     else
401     {
402         error_stream->Printf ("error: invalid execution context for expression\n");
403         return false;
404     }
405 
406     return true;
407 }
408 
409 bool
410 CommandObjectExpression::DoExecute
411 (
412     const char *command,
413     CommandReturnObject &result
414 )
415 {
416     m_option_group.NotifyOptionParsingStarting();
417 
418     const char * expr = NULL;
419 
420     if (command[0] == '\0')
421     {
422         m_expr_lines.clear();
423         m_expr_line_count = 0;
424 
425         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
426         if (reader_sp)
427         {
428             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
429                                               this,                         // baton
430                                               eInputReaderGranularityLine,  // token size, to pass to callback function
431                                               NULL,                         // end token
432                                               NULL,                         // prompt
433                                               true));                       // echo input
434             if (err.Success())
435             {
436                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
437                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
438             }
439             else
440             {
441                 result.AppendError (err.AsCString());
442                 result.SetStatus (eReturnStatusFailed);
443             }
444         }
445         else
446         {
447             result.AppendError("out of memory");
448             result.SetStatus (eReturnStatusFailed);
449         }
450         return result.Succeeded();
451     }
452 
453     if (command[0] == '-')
454     {
455         // We have some options and these options MUST end with --.
456         const char *end_options = NULL;
457         const char *s = command;
458         while (s && s[0])
459         {
460             end_options = ::strstr (s, "--");
461             if (end_options)
462             {
463                 end_options += 2; // Get past the "--"
464                 if (::isspace (end_options[0]))
465                 {
466                     expr = end_options;
467                     while (::isspace (*expr))
468                         ++expr;
469                     break;
470                 }
471             }
472             s = end_options;
473         }
474 
475         if (end_options)
476         {
477             Args args (command, end_options - command);
478             if (!ParseOptions (args, result))
479                 return false;
480 
481             Error error (m_option_group.NotifyOptionParsingFinished());
482             if (error.Fail())
483             {
484                 result.AppendError (error.AsCString());
485                 result.SetStatus (eReturnStatusFailed);
486                 return false;
487             }
488         }
489     }
490 
491     if (expr == NULL)
492         expr = command;
493 
494     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
495         return true;
496 
497     result.SetStatus (eReturnStatusFailed);
498     return false;
499 }
500 
501