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