xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision d0ef0eff61eee004f08ef5add8a3f958d08698b7)
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                                              CommandReturnObject *result)
194 {
195     Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
196 
197     ////////////////////////////////////
198     // Set up the target and compiler
199     //
200 
201     Target *target = m_exe_ctx.target;
202 
203     if (!target)
204     {
205         error_stream.PutCString ("error: invalid target\n");
206         return false;
207     }
208 
209     ConstString target_triple;
210 
211     target->GetTargetTriple (target_triple);
212 
213     if (!target_triple)
214         target_triple = Host::GetTargetTriple ();
215 
216     if (!target_triple)
217     {
218         error_stream.PutCString ("error: invalid target triple\n");
219         return false;
220     }
221 
222     ClangExpressionDeclMap expr_decl_map (&m_exe_ctx);
223     ClangExpression clang_expr (target_triple.AsCString (), &expr_decl_map);
224 
225     //////////////////////////
226     // Parse the expression
227     //
228 
229     unsigned num_errors;
230 
231     if (bare)
232         num_errors = clang_expr.ParseBareExpression (llvm::StringRef (expr), error_stream);
233     else
234         num_errors = clang_expr.ParseExpression (expr, error_stream, true);
235 
236     if (num_errors)
237     {
238         error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
239         return false;
240     }
241 
242     ///////////////////////////////////////////////
243     // Convert the output of the parser to DWARF
244     //
245 
246     StreamString dwarf_opcodes;
247     dwarf_opcodes.SetByteOrder (eByteOrderHost);
248     dwarf_opcodes.GetFlags ().Set (Stream::eBinary);
249 
250     ClangExpressionVariableList expr_local_vars;
251 
252     bool success;
253     bool canInterpret = false;
254 
255     ClangExpressionVariable *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 ();
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 ())
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 ());
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);
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 rc = 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 (rc.Fail()) {
393             error_stream.Printf ("Couldn't print result : %s\n", rc.AsCString());
394             return false;
395         }
396 
397         output_stream.PutCString(ss.GetString().c_str());
398         if (result)
399             result->SetStatus (eReturnStatusSuccessFinishResult);
400     }
401     else
402     {
403         error_stream.Printf ("Expression produced no result\n");
404         if (result)
405             result->SetStatus (eReturnStatusSuccessFinishNoResult);
406     }
407 
408     return true;
409 }
410 
411 bool
412 CommandObjectExpression::ExecuteRawCommandString
413 (
414     CommandInterpreter &interpreter,
415     const char *command,
416     CommandReturnObject &result
417 )
418 {
419     m_exe_ctx = interpreter.GetDebugger().GetExecutionContext();
420 
421     m_options.ResetOptionValues();
422 
423     const char * expr = NULL;
424 
425     if (command[0] == '\0')
426     {
427         m_expr_lines.clear();
428         m_expr_line_count = 0;
429 
430         InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
431         if (reader_sp)
432         {
433             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
434                                               this,                         // baton
435                                               eInputReaderGranularityLine,  // token size, to pass to callback function
436                                               NULL,                         // end token
437                                               NULL,                         // prompt
438                                               true));                       // echo input
439             if (err.Success())
440             {
441                 interpreter.GetDebugger().PushInputReader (reader_sp);
442                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
443             }
444             else
445             {
446                 result.AppendError (err.AsCString());
447                 result.SetStatus (eReturnStatusFailed);
448             }
449         }
450         else
451         {
452             result.AppendError("out of memory");
453             result.SetStatus (eReturnStatusFailed);
454         }
455         return result.Succeeded();
456     }
457 
458     if (command[0] == '-')
459     {
460         // We have some options and these options MUST end with --.
461         const char *end_options = NULL;
462         const char *s = command;
463         while (s && s[0])
464         {
465             end_options = ::strstr (s, "--");
466             if (end_options)
467             {
468                 end_options += 2; // Get past the "--"
469                 if (::isspace (end_options[0]))
470                 {
471                     expr = end_options;
472                     while (::isspace (*expr))
473                         ++expr;
474                     break;
475                 }
476             }
477             s = end_options;
478         }
479 
480         if (end_options)
481         {
482             Args args (command, end_options - command);
483             if (!ParseOptions (interpreter, args, result))
484                 return false;
485         }
486     }
487 
488     if (expr == NULL)
489         expr = command;
490 
491     if (EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream(), &result))
492         return true;
493 
494     result.SetStatus (eReturnStatusFailed);
495     return false;
496 }
497 
498 lldb::OptionDefinition
499 CommandObjectExpression::CommandOptions::g_option_table[] =
500 {
501 { LLDB_OPT_SET_ALL, false, "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
502 { 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."},
503 { LLDB_OPT_SET_ALL, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
504 { LLDB_OPT_SET_ALL, false, "use-ir",     'i', no_argument,       NULL, 0, NULL,                           "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
505 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
506 };
507 
508