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