xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 3372f581eb8bb97fddc316c79f48808ca3db245d)
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                                                   0 /* no timeout */);
310 
311         if (exe_results == eExecutionInterrupted && !m_command_options.unwind_on_error)
312         {
313             uint32_t start_frame = 0;
314             uint32_t num_frames = 1;
315             uint32_t num_frames_with_source = 0;
316             Thread *thread = m_interpreter.GetExecutionContext().GetThreadPtr();
317             if (thread)
318             {
319                 thread->GetStatus (result->GetOutputStream(),
320                                    start_frame,
321                                    num_frames,
322                                    num_frames_with_source);
323             }
324             else
325             {
326                 Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
327                 if (process)
328                 {
329                     bool only_threads_with_stop_reason = true;
330                     process->GetThreadStatus (result->GetOutputStream(),
331                                               only_threads_with_stop_reason,
332                                               start_frame,
333                                               num_frames,
334                                               num_frames_with_source);
335                 }
336             }
337         }
338 
339         if (result_valobj_sp)
340         {
341             if (result_valobj_sp->GetError().Success())
342             {
343                 Format format = m_format_options.GetFormat();
344                 if (format != eFormatDefault)
345                     result_valobj_sp->SetFormat (format);
346 
347                 ValueObject::DumpValueObjectOptions options;
348                 options.SetMaximumPointerDepth(0)
349                 .SetMaximumDepth(UINT32_MAX)
350                 .SetShowLocation(false)
351                 .SetShowTypes(m_command_options.show_types)
352                 .SetUseObjectiveC(m_command_options.print_object)
353                 .SetUseDynamicType(use_dynamic)
354                 .SetScopeChecked(true)
355                 .SetFlatOutput(false)
356                 .SetUseSyntheticValue(true)
357                 .SetIgnoreCap(false)
358                 .SetFormat(format)
359                 .SetSummary()
360                 .SetShowSummary(!m_command_options.print_object);
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             else
369             {
370                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
371                 {
372                     error_stream->PutCString("<no result>\n");
373 
374                     if (result)
375                         result->SetStatus (eReturnStatusSuccessFinishResult);
376                 }
377                 else
378                 {
379                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
380                     if (error_cstr && error_cstr[0])
381                     {
382                         int error_cstr_len = strlen (error_cstr);
383                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
384                         if (strstr(error_cstr, "error:") != error_cstr)
385                             error_stream->PutCString ("error: ");
386                         error_stream->Write(error_cstr, error_cstr_len);
387                         if (!ends_with_newline)
388                             error_stream->EOL();
389                     }
390                     else
391                     {
392                         error_stream->PutCString ("error: unknown error\n");
393                     }
394 
395                     if (result)
396                         result->SetStatus (eReturnStatusFailed);
397                 }
398             }
399         }
400     }
401     else
402     {
403         error_stream->Printf ("error: invalid execution context for expression\n");
404         return false;
405     }
406 
407     return true;
408 }
409 
410 bool
411 CommandObjectExpression::DoExecute
412 (
413     const char *command,
414     CommandReturnObject &result
415 )
416 {
417     m_option_group.NotifyOptionParsingStarting();
418 
419     const char * expr = NULL;
420 
421     if (command[0] == '\0')
422     {
423         m_expr_lines.clear();
424         m_expr_line_count = 0;
425 
426         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
427         if (reader_sp)
428         {
429             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
430                                               this,                         // baton
431                                               eInputReaderGranularityLine,  // token size, to pass to callback function
432                                               NULL,                         // end token
433                                               NULL,                         // prompt
434                                               true));                       // echo input
435             if (err.Success())
436             {
437                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
438                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
439             }
440             else
441             {
442                 result.AppendError (err.AsCString());
443                 result.SetStatus (eReturnStatusFailed);
444             }
445         }
446         else
447         {
448             result.AppendError("out of memory");
449             result.SetStatus (eReturnStatusFailed);
450         }
451         return result.Succeeded();
452     }
453 
454     if (command[0] == '-')
455     {
456         // We have some options and these options MUST end with --.
457         const char *end_options = NULL;
458         const char *s = command;
459         while (s && s[0])
460         {
461             end_options = ::strstr (s, "--");
462             if (end_options)
463             {
464                 end_options += 2; // Get past the "--"
465                 if (::isspace (end_options[0]))
466                 {
467                     expr = end_options;
468                     while (::isspace (*expr))
469                         ++expr;
470                     break;
471                 }
472             }
473             s = end_options;
474         }
475 
476         if (end_options)
477         {
478             Args args (command, end_options - command);
479             if (!ParseOptions (args, result))
480                 return false;
481 
482             Error error (m_option_group.NotifyOptionParsingFinished());
483             if (error.Fail())
484             {
485                 result.AppendError (error.AsCString());
486                 result.SetStatus (eReturnStatusFailed);
487                 return false;
488             }
489         }
490     }
491 
492     if (expr == NULL)
493         expr = command;
494 
495     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
496         return true;
497 
498     result.SetStatus (eReturnStatusFailed);
499     return false;
500 }
501 
502