xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision d1e5b439c9a48255f1f88bf99f42547a81bef07e)
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/ClangPersistentVariables.h"
23 #include "lldb/Expression/ClangFunction.h"
24 #include "lldb/Expression/DWARFExpression.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Core/Debugger.h"
27 #include "lldb/Interpreter/CommandInterpreter.h"
28 #include "lldb/Interpreter/CommandReturnObject.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 "llvm/ADT/StringRef.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 
39 CommandObjectExpression::CommandOptions::CommandOptions () :
40     Options()
41 {
42     // Keep only one place to reset the values to their defaults
43     ResetOptionValues();
44 }
45 
46 
47 CommandObjectExpression::CommandOptions::~CommandOptions ()
48 {
49 }
50 
51 Error
52 CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
53 {
54     Error error;
55 
56     char short_option = (char) m_getopt_table[option_idx].val;
57 
58     switch (short_option)
59     {
60     case 'l':
61         if (language.SetLanguageFromCString (option_arg) == false)
62         {
63             error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg);
64         }
65         break;
66 
67     case 'g':
68         debug = true;
69         break;
70 
71     case 'f':
72         error = Args::StringToFormat(option_arg, format);
73         break;
74 
75     default:
76         error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
77         break;
78     }
79 
80     return error;
81 }
82 
83 void
84 CommandObjectExpression::CommandOptions::ResetOptionValues ()
85 {
86     Options::ResetOptionValues();
87     language.Clear();
88     debug = false;
89     format = eFormatDefault;
90     show_types = true;
91     show_summary = true;
92 }
93 
94 const lldb::OptionDefinition*
95 CommandObjectExpression::CommandOptions::GetDefinitions ()
96 {
97     return g_option_table;
98 }
99 
100 CommandObjectExpression::CommandObjectExpression () :
101     CommandObject (
102             "expression",
103             "Evaluate a C expression in the current program context, using variables currently in scope.",
104             "expression [<cmd-options>] <expr>"),
105     m_expr_line_count (0),
106     m_expr_lines ()
107 {
108   SetHelpLong(
109 "Examples: \n\
110 \n\
111    expr my_struct->a = my_array[3] \n\
112    expr -f bin -- (index * 8) + 5 \n\
113    expr char c[] = \"foo\"; c[0]\n");
114 }
115 
116 CommandObjectExpression::~CommandObjectExpression ()
117 {
118 }
119 
120 Options *
121 CommandObjectExpression::GetOptions ()
122 {
123     return &m_options;
124 }
125 
126 
127 bool
128 CommandObjectExpression::Execute
129 (
130     CommandInterpreter &interpreter,
131     Args& command,
132     CommandReturnObject &result
133 )
134 {
135     return false;
136 }
137 
138 
139 size_t
140 CommandObjectExpression::MultiLineExpressionCallback
141 (
142     void *baton,
143     InputReader &reader,
144     lldb::InputReaderAction notification,
145     const char *bytes,
146     size_t bytes_len
147 )
148 {
149     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
150 
151     switch (notification)
152     {
153     case eInputReaderActivate:
154         reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter expressions, then terminate with an empty line to evaluate:");
155         // Fall through
156     case eInputReaderReactivate:
157         //if (out_fh)
158         //    reader.GetDebugger().GetOutputStream().Printf ("%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             bool bare = false;
180             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
181                                                  bare,
182                                                  reader.GetDebugger().GetOutputStream(),
183                                                  reader.GetDebugger().GetErrorStream());
184         }
185         break;
186     }
187 
188     return bytes_len;
189 }
190 
191 bool
192 CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream)
193 {
194     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
195 
196     ////////////////////////////////////
197     // Set up the target and compiler
198     //
199 
200     Target *target = m_exe_ctx.target;
201 
202     if (!target)
203     {
204         error_stream.PutCString ("error: invalid target\n");
205         return false;
206     }
207 
208     ConstString target_triple;
209 
210     target->GetTargetTriple (target_triple);
211 
212     if (!target_triple)
213         target_triple = Host::GetTargetTriple ();
214 
215     if (!target_triple)
216     {
217         error_stream.PutCString ("error: invalid target triple\n");
218         return false;
219     }
220 
221     ClangExpressionDeclMap expr_decl_map (&m_exe_ctx);
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     ClangPersistentVariable *expr_result = 0;
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     if (expr_result)
382     {
383         StreamString ss;
384 
385         Error err = expr_result->Print (ss,
386                                         m_exe_ctx,
387                                         m_options.format,
388                                         m_options.show_types,
389                                         m_options.show_summary,
390                                         m_options.debug);
391 
392         if (err.Success())
393             output_stream.PutCString(ss.GetString().c_str());
394         else
395             error_stream.Printf ("Couldn't print result : %s\n", err.AsCString("unknown error"));
396     }
397     else
398     {
399         error_stream.Printf ("Expression produced no result\n");
400     }
401 
402     return true;
403 }
404 
405 bool
406 CommandObjectExpression::ExecuteRawCommandString
407 (
408     CommandInterpreter &interpreter,
409     const char *command,
410     CommandReturnObject &result
411 )
412 {
413     m_exe_ctx = interpreter.GetDebugger().GetExecutionContext();
414 
415     m_options.ResetOptionValues();
416 
417     const char * expr = NULL;
418 
419     if (command[0] == '\0')
420     {
421         m_expr_lines.clear();
422         m_expr_line_count = 0;
423 
424         InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
425         if (reader_sp)
426         {
427             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
428                                               this,                         // baton
429                                               eInputReaderGranularityLine,  // token size, to pass to callback function
430                                               NULL,                         // end token
431                                               NULL,                         // prompt
432                                               true));                       // echo input
433             if (err.Success())
434             {
435                 interpreter.GetDebugger().PushInputReader (reader_sp);
436                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
437             }
438             else
439             {
440                 result.AppendError (err.AsCString());
441                 result.SetStatus (eReturnStatusFailed);
442             }
443         }
444         else
445         {
446             result.AppendError("out of memory");
447             result.SetStatus (eReturnStatusFailed);
448         }
449         return result.Succeeded();
450     }
451 
452     if (command[0] == '-')
453     {
454         // We have some options and these options MUST end with --.
455         const char *end_options = NULL;
456         const char *s = command;
457         while (s && s[0])
458         {
459             end_options = ::strstr (s, "--");
460             if (end_options)
461             {
462                 end_options += 2; // Get past the "--"
463                 if (::isspace (end_options[0]))
464                 {
465                     expr = end_options;
466                     while (::isspace (*expr))
467                         ++expr;
468                     break;
469                 }
470             }
471             s = end_options;
472         }
473 
474         if (end_options)
475         {
476             Args args (command, end_options - command);
477             if (!ParseOptions (interpreter, args, result))
478                 return false;
479         }
480     }
481 
482     if (expr == NULL)
483         expr = command;
484 
485     return EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream());
486 }
487 
488 lldb::OptionDefinition
489 CommandObjectExpression::CommandOptions::g_option_table[] =
490 {
491 { LLDB_OPT_SET_ALL, false, "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
492 { 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."},
493 { LLDB_OPT_SET_ALL, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
494 { LLDB_OPT_SET_ALL, false, "use-ir",     'i', no_argument,       NULL, 0, NULL,                           "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
495 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
496 };
497 
498