xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c)
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/Core/Args.h"
17 #include "lldb/Core/Value.h"
18 #include "lldb/Core/InputReader.h"
19 #include "lldb/Expression/ClangExpression.h"
20 #include "lldb/Expression/ClangExpressionDeclMap.h"
21 #include "lldb/Expression/ClangExpressionVariable.h"
22 #include "lldb/Expression/DWARFExpression.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Interpreter/CommandContext.h"
25 #include "lldb/Interpreter/CommandReturnObject.h"
26 #include "lldb/Symbol/ObjectFile.h"
27 #include "lldb/Symbol/Variable.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/StackFrame.h"
30 #include "lldb/Target/Target.h"
31 #include "llvm/ADT/StringRef.h"
32 
33 using namespace lldb;
34 using namespace lldb_private;
35 
36 CommandObjectExpression::CommandOptions::CommandOptions () :
37     Options()
38 {
39     // Keep only one place to reset the values to their defaults
40     ResetOptionValues();
41 }
42 
43 
44 CommandObjectExpression::CommandOptions::~CommandOptions ()
45 {
46 }
47 
48 Error
49 CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
50 {
51     Error error;
52 
53     char short_option = (char) m_getopt_table[option_idx].val;
54 
55     switch (short_option)
56     {
57     case 'l':
58         if (language.SetLanguageFromCString (option_arg) == false)
59         {
60             error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg);
61         }
62         break;
63 
64     case 'g':
65         debug = true;
66         break;
67 
68     case 'f':
69         error = Args::StringToFormat(option_arg, format);
70         break;
71 
72     default:
73         error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
74         break;
75     }
76 
77     return error;
78 }
79 
80 void
81 CommandObjectExpression::CommandOptions::ResetOptionValues ()
82 {
83     Options::ResetOptionValues();
84     language.Clear();
85     debug = false;
86     format = eFormatDefault;
87     show_types = true;
88     show_summary = true;
89 }
90 
91 const lldb::OptionDefinition*
92 CommandObjectExpression::CommandOptions::GetDefinitions ()
93 {
94     return g_option_table;
95 }
96 
97 CommandObjectExpression::CommandObjectExpression () :
98     CommandObject (
99             "expression",
100             "Evaluate a C expression in the current program context, using variables currently in scope.",
101             "expression [<cmd-options>] <expr>"),
102     m_expr_line_count (0),
103     m_expr_lines ()
104 {
105   SetHelpLong(
106 "Examples: \n\
107 \n\
108    expr my_struct->a = my_array[3] \n\
109    expr -f bin -- (index * 8) + 5 \n\
110    expr char c[] = \"foo\"; c[0]\n");
111 }
112 
113 CommandObjectExpression::~CommandObjectExpression ()
114 {
115 }
116 
117 Options *
118 CommandObjectExpression::GetOptions ()
119 {
120     return &m_options;
121 }
122 
123 
124 bool
125 CommandObjectExpression::Execute
126 (
127     Args& command,
128     CommandContext *context,
129     CommandInterpreter *interpreter,
130     CommandReturnObject &result
131 )
132 {
133     return false;
134 }
135 
136 
137 size_t
138 CommandObjectExpression::MultiLineExpressionCallback
139 (
140     void *baton,
141     InputReader *reader,
142     lldb::InputReaderAction notification,
143     const char *bytes,
144     size_t bytes_len
145 )
146 {
147     FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle();
148     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
149 
150     switch (notification)
151     {
152     case eInputReaderActivate:
153         if (out_fh)
154             ::fprintf (out_fh, "%s\n", "Enter expressions, then terminate with an empty line to evaluate:");
155         // Fall through
156     case eInputReaderReactivate:
157         //if (out_fh)
158         //    ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
159         break;
160 
161     case eInputReaderDeactivate:
162         break;
163 
164     case eInputReaderGotToken:
165         ++cmd_object_expr->m_expr_line_count;
166         if (bytes && bytes_len)
167         {
168             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
169         }
170 
171         if (bytes_len == 0)
172             reader->SetIsDone(true);
173         //else if (out_fh && !reader->IsDone())
174         //    ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
175         break;
176 
177     case eInputReaderDone:
178         {
179             StreamFile out_stream(Debugger::GetSharedInstance().GetOutputFileHandle());
180             StreamFile err_stream(Debugger::GetSharedInstance().GetErrorFileHandle());
181             bool bare = false;
182             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
183                                                  bare,
184                                                  out_stream,
185                                                  err_stream);
186         }
187         break;
188     }
189 
190     return bytes_len;
191 }
192 
193 bool
194 CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream)
195 {
196     bool success = false;
197     ConstString target_triple;
198     Target *target = m_exe_ctx.target;
199     if (target)
200         target->GetTargetTriple(target_triple);
201 
202     if (!target_triple)
203         target_triple = Host::GetTargetTriple ();
204 
205 
206     if (target_triple)
207     {
208         const bool show_types = m_options.show_types;
209         const bool show_summary = m_options.show_summary;
210         const bool debug = m_options.debug;
211 
212         ClangExpressionDeclMap expr_decl_map(&m_exe_ctx);
213         ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map);
214 
215         unsigned num_errors = 0;
216 
217         if (bare)
218             num_errors = clang_expr.ParseBareExpression (llvm::StringRef(expr), error_stream);
219         else
220             num_errors = clang_expr.ParseExpression (expr, error_stream);
221 
222         if (num_errors == 0)
223         {
224             StreamString dwarf_opcodes;
225             dwarf_opcodes.SetByteOrder(eByteOrderHost);
226             dwarf_opcodes.GetFlags().Set(Stream::eBinary);
227             ClangExpressionVariableList expr_local_vars;
228             clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes);
229 
230             success = true;
231 
232             DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8);
233             DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL);
234             expr.SetExpressionLocalVariableList(&expr_local_vars);
235             if (debug)
236             {
237                 output_stream << "Expression parsed ok, dwarf opcodes:";
238                 output_stream.IndentMore();
239                 expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose);
240                 output_stream.IndentLess();
241                 output_stream.EOL();
242             }
243 
244             clang::ASTContext *ast_context = clang_expr.GetASTContext();
245             Value expr_result;
246             Error expr_error;
247             bool expr_success = expr.Evaluate (&m_exe_ctx, ast_context, NULL, expr_result, &expr_error);
248             if (expr_success)
249             {
250                 lldb::Format format = m_options.format;
251 
252                 // Resolve any values that are possible
253                 expr_result.ResolveValue(&m_exe_ctx, ast_context);
254 
255                 if (expr_result.GetContextType() == Value::eContextTypeInvalid &&
256                     expr_result.GetValueType() == Value::eValueTypeScalar &&
257                     format == eFormatDefault)
258                 {
259                     // The expression result is just a scalar with no special formatting
260                     expr_result.GetScalar().GetValue (&output_stream, show_types);
261                     output_stream.EOL();
262                 }
263                 else
264                 {
265                     DataExtractor data;
266                     expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0);
267                     if (expr_error.Success())
268                     {
269                         if (format == eFormatDefault)
270                             format = expr_result.GetValueDefaultFormat ();
271 
272                         void *clang_type = expr_result.GetValueOpaqueClangQualType();
273                         if (clang_type)
274                         {
275                             if (show_types)
276                                 Type::DumpClangTypeName(&output_stream, clang_type);
277 
278                             Type::DumpValue (
279                                 &m_exe_ctx,                 // The execution context for memory and variable access
280                                 ast_context,                // The ASTContext that the clang type belongs to
281                                 clang_type,                 // The opaque clang type we want to dump that value of
282                                 &output_stream,             // Stream to dump to
283                                 format,                     // Format to use when dumping
284                                 data,                       // A buffer containing the bytes for the clang type
285                                 0,                          // Byte offset within "data" where value is
286                                 data.GetByteSize(),         // Size in bytes of the value we are dumping
287                                 0,                          // Bitfield bit size
288                                 0,                          // Bitfield bit offset
289                                 show_types,                 // Show types?
290                                 show_summary,               // Show summary?
291                                 debug,                      // Debug logging output?
292                                 UINT32_MAX);                // Depth to dump in case this is an aggregate type
293                         }
294                         else
295                         {
296                             data.Dump(&output_stream,       // Stream to dump to
297                                       0,                    // Byte offset within "data"
298                                       format,               // Format to use when dumping
299                                       data.GetByteSize(),   // Size in bytes of each item we are dumping
300                                       1,                    // Number of items to dump
301                                       UINT32_MAX,           // Number of items per line
302                                       LLDB_INVALID_ADDRESS,   // Invalid address, don't show any offset/address context
303                                       0,                    // Bitfield bit size
304                                       0);                   // Bitfield bit offset
305                         }
306                         output_stream.EOL();
307                     }
308                     else
309                     {
310                         error_stream.Printf ("error: %s\n", expr_error.AsCString());
311                         success = false;
312                     }
313                 }
314             }
315             else
316             {
317                 error_stream.Printf ("error: %s\n", expr_error.AsCString());
318             }
319         }
320     }
321     else
322     {
323         error_stream.PutCString ("error: invalid target triple\n");
324     }
325 
326     return success;
327 }
328 
329 bool
330 CommandObjectExpression::ExecuteRawCommandString
331 (
332     const char *command,
333     CommandContext *context,
334     CommandInterpreter *interpreter,
335     CommandReturnObject &result
336 )
337 {
338     ConstString target_triple;
339     Target *target = context->GetTarget ();
340     if (target)
341         target->GetTargetTriple(target_triple);
342 
343     if (!target_triple)
344         target_triple = Host::GetTargetTriple ();
345 
346     ExecutionContext exe_ctx(context->GetExecutionContext());
347 
348     Stream &output_stream = result.GetOutputStream();
349 
350     m_options.ResetOptionValues();
351 
352     const char * expr = NULL;
353 
354     if (command[0] == '\0')
355     {
356         m_expr_lines.clear();
357         m_expr_line_count = 0;
358 
359         InputReaderSP reader_sp (new InputReader());
360         if (reader_sp)
361         {
362             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
363                                               this,                         // baton
364                                               eInputReaderGranularityLine,  // token size, to pass to callback function
365                                               NULL,                       // end token
366                                               NULL,                         // prompt
367                                               true));                       // echo input
368             if (err.Success())
369             {
370                 Debugger::GetSharedInstance().PushInputReader (reader_sp);
371                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
372             }
373             else
374             {
375                 result.AppendError (err.AsCString());
376                 result.SetStatus (eReturnStatusFailed);
377             }
378         }
379         else
380         {
381             result.AppendError("out of memory");
382             result.SetStatus (eReturnStatusFailed);
383         }
384         return result.Succeeded();
385     }
386 
387     if (command[0] == '-')
388     {
389         // We have some options and these options MUST end with --.
390         const char *end_options = NULL;
391         const char *s = command;
392         while (s && s[0])
393         {
394             end_options = ::strstr (s, "--");
395             if (end_options)
396             {
397                 end_options += 2; // Get past the "--"
398                 if (::isspace (end_options[0]))
399                 {
400                     expr = end_options;
401                     while (::isspace (*expr))
402                         ++expr;
403                     break;
404                 }
405             }
406             s = end_options;
407         }
408 
409         if (end_options)
410         {
411             Args args(command, end_options - command);
412             if (!ParseOptions(args, interpreter, result))
413                 return false;
414         }
415     }
416 
417     const bool show_types = m_options.show_types;
418     const bool show_summary = m_options.show_summary;
419     const bool debug = m_options.debug;
420 
421 
422     if (expr == NULL)
423         expr = command;
424 
425     if (target_triple)
426     {
427         ClangExpressionDeclMap expr_decl_map(&exe_ctx);
428 
429         ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map);
430 
431         unsigned num_errors = clang_expr.ParseExpression (expr, result.GetErrorStream());
432 
433         if (num_errors == 0)
434         {
435             StreamString dwarf_opcodes;
436             dwarf_opcodes.SetByteOrder(eByteOrderHost);
437             dwarf_opcodes.GetFlags().Set(Stream::eBinary);
438             ClangExpressionVariableList expr_local_vars;
439             clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes);
440 
441             result.SetStatus (eReturnStatusSuccessFinishResult);
442 
443             DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8);
444             DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL);
445             expr.SetExpressionLocalVariableList(&expr_local_vars);
446             expr.SetExpressionDeclMap(&expr_decl_map);
447             if (debug)
448             {
449                 output_stream << "Expression parsed ok, dwarf opcodes:";
450                 output_stream.IndentMore();
451                 expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose);
452                 output_stream.IndentLess();
453                 output_stream.EOL();
454             }
455 
456             clang::ASTContext *ast_context = clang_expr.GetASTContext();
457             Value expr_result;
458             Error expr_error;
459             bool expr_success = expr.Evaluate (&exe_ctx, ast_context, NULL, expr_result, &expr_error);
460             if (expr_success)
461             {
462                 lldb::Format format = m_options.format;
463 
464                 // Resolve any values that are possible
465                 expr_result.ResolveValue(&exe_ctx, ast_context);
466 
467                 if (expr_result.GetContextType() == Value::eContextTypeInvalid &&
468                     expr_result.GetValueType() == Value::eValueTypeScalar &&
469                     format == eFormatDefault)
470                 {
471                     // The expression result is just a scalar with no special formatting
472                     expr_result.GetScalar().GetValue (&output_stream, show_types);
473                     output_stream.EOL();
474                 }
475                 else
476                 {
477                     DataExtractor data;
478                     expr_error = expr_result.GetValueAsData (&exe_ctx, ast_context, data, 0);
479                     if (expr_error.Success())
480                     {
481                         if (format == eFormatDefault)
482                             format = expr_result.GetValueDefaultFormat ();
483 
484                         void *clang_type = expr_result.GetValueOpaqueClangQualType();
485                         if (clang_type)
486                         {
487                             if (show_types)
488                                 Type::DumpClangTypeName(&output_stream, clang_type);
489 
490                             Type::DumpValue (
491                                 &exe_ctx,                   // The execution context for memory and variable access
492                                 ast_context,                // The ASTContext that the clang type belongs to
493                                 clang_type,                 // The opaque clang type we want to dump that value of
494                                 &output_stream,             // Stream to dump to
495                                 format,                     // Format to use when dumping
496                                 data,                       // A buffer containing the bytes for the clang type
497                                 0,                          // Byte offset within "data" where value is
498                                 data.GetByteSize(),         // Size in bytes of the value we are dumping
499                                 0,                          // Bitfield bit size
500                                 0,                          // Bitfield bit offset
501                                 show_types,                 // Show types?
502                                 show_summary,               // Show summary?
503                                 debug,                      // Debug logging output?
504                                 UINT32_MAX);                // Depth to dump in case this is an aggregate type
505                         }
506                         else
507                         {
508                             data.Dump(&output_stream,       // Stream to dump to
509                                       0,                    // Byte offset within "data"
510                                       format,               // Format to use when dumping
511                                       data.GetByteSize(),   // Size in bytes of each item we are dumping
512                                       1,                    // Number of items to dump
513                                       UINT32_MAX,           // Number of items per line
514                                       LLDB_INVALID_ADDRESS,   // Invalid address, don't show any offset/address context
515                                       0,                    // Bitfield bit size
516                                       0);                   // Bitfield bit offset
517                         }
518                         output_stream.EOL();
519                     }
520                     else
521                     {
522                         result.AppendError(expr_error.AsCString());
523                         result.SetStatus (eReturnStatusFailed);
524                     }
525                 }
526             }
527             else
528             {
529                 result.AppendError (expr_error.AsCString());
530                 result.SetStatus (eReturnStatusFailed);
531             }
532         }
533         else
534         {
535             result.SetStatus (eReturnStatusFailed);
536         }
537     }
538     else
539     {
540         result.AppendError ("invalid target triple");
541         result.SetStatus (eReturnStatusFailed);
542     }
543     return result.Succeeded();
544 }
545 
546 lldb::OptionDefinition
547 CommandObjectExpression::CommandOptions::g_option_table[] =
548 {
549 { 0, true,  "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
550 { 0, false, "format",     'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]",  "Specify the format that the expression output should use."},
551 { 0, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
552 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
553 };
554 
555