xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 0c489f58cd948e2493bbb6ffac74a4465d91dba2)
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::DumpValueObjectOptions options;
358                 options.SetMaximumPointerDepth(0)
359                 .SetMaximumDepth(UINT32_MAX)
360                 .SetShowLocation(false)
361                 .SetShowTypes(m_command_options.show_types)
362                 .SetUseObjectiveC(m_command_options.print_object)
363                 .SetUseDynamicType(use_dynamic)
364                 .SetScopeChecked(true)
365                 .SetFlatOutput(false)
366                 .SetUseSyntheticValue(lldb::eUseSyntheticFilter)
367                 .SetOmitSummaryDepth(0)
368                 .SetIgnoreCap(false)
369                 .SetFormat(format)
370                 .SetSummary();
371                 ValueObject::DumpValueObject (*(output_stream),
372                                               result_valobj_sp.get(),   // Variable object to dump
373                                               options);
374                 if (result)
375                     result->SetStatus (eReturnStatusSuccessFinishResult);
376             }
377             else
378             {
379                 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
380                 {
381                     error_stream->PutCString("<no result>\n");
382 
383                     if (result)
384                         result->SetStatus (eReturnStatusSuccessFinishResult);
385                 }
386                 else
387                 {
388                     const char *error_cstr = result_valobj_sp->GetError().AsCString();
389                     if (error_cstr && error_cstr[0])
390                     {
391                         int error_cstr_len = strlen (error_cstr);
392                         const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
393                         if (strstr(error_cstr, "error:") != error_cstr)
394                             error_stream->PutCString ("error: ");
395                         error_stream->Write(error_cstr, error_cstr_len);
396                         if (!ends_with_newline)
397                             error_stream->EOL();
398                     }
399                     else
400                     {
401                         error_stream->PutCString ("error: unknown error\n");
402                     }
403 
404                     if (result)
405                         result->SetStatus (eReturnStatusFailed);
406                 }
407             }
408         }
409     }
410     else
411     {
412         error_stream->Printf ("error: invalid execution context for expression\n");
413         return false;
414     }
415 
416     return true;
417 }
418 
419 bool
420 CommandObjectExpression::ExecuteRawCommandString
421 (
422     const char *command,
423     CommandReturnObject &result
424 )
425 {
426     m_option_group.NotifyOptionParsingStarting();
427 
428     const char * expr = NULL;
429 
430     if (command[0] == '\0')
431     {
432         m_expr_lines.clear();
433         m_expr_line_count = 0;
434 
435         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
436         if (reader_sp)
437         {
438             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
439                                               this,                         // baton
440                                               eInputReaderGranularityLine,  // token size, to pass to callback function
441                                               NULL,                         // end token
442                                               NULL,                         // prompt
443                                               true));                       // echo input
444             if (err.Success())
445             {
446                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
447                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
448             }
449             else
450             {
451                 result.AppendError (err.AsCString());
452                 result.SetStatus (eReturnStatusFailed);
453             }
454         }
455         else
456         {
457             result.AppendError("out of memory");
458             result.SetStatus (eReturnStatusFailed);
459         }
460         return result.Succeeded();
461     }
462 
463     if (command[0] == '-')
464     {
465         // We have some options and these options MUST end with --.
466         const char *end_options = NULL;
467         const char *s = command;
468         while (s && s[0])
469         {
470             end_options = ::strstr (s, "--");
471             if (end_options)
472             {
473                 end_options += 2; // Get past the "--"
474                 if (::isspace (end_options[0]))
475                 {
476                     expr = end_options;
477                     while (::isspace (*expr))
478                         ++expr;
479                     break;
480                 }
481             }
482             s = end_options;
483         }
484 
485         if (end_options)
486         {
487             Args args (command, end_options - command);
488             if (!ParseOptions (args, result))
489                 return false;
490 
491             Error error (m_option_group.NotifyOptionParsingFinished());
492             if (error.Fail())
493             {
494                 result.AppendError (error.AsCString());
495                 result.SetStatus (eReturnStatusFailed);
496                 return false;
497             }
498         }
499     }
500 
501     if (expr == NULL)
502         expr = command;
503 
504     if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
505         return true;
506 
507     result.SetStatus (eReturnStatusFailed);
508     return false;
509 }
510 
511