xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 6961e87847cd39a65ecde0342ec5c7d1dee9622c)
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/ClangExpressionVariable.h"
20 #include "lldb/Expression/ClangUserExpression.h"
21 #include "lldb/Expression/ClangFunction.h"
22 #include "lldb/Expression/DWARFExpression.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Core/Debugger.h"
25 #include "lldb/Interpreter/CommandInterpreter.h"
26 #include "lldb/Interpreter/CommandReturnObject.h"
27 #include "lldb/Symbol/ObjectFile.h"
28 #include "lldb/Symbol/Variable.h"
29 #include "lldb/Target/Process.h"
30 #include "lldb/Target/StackFrame.h"
31 #include "lldb/Target/Target.h"
32 #include "llvm/ADT/StringRef.h"
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 
37 CommandObjectExpression::CommandOptions::CommandOptions () :
38     Options()
39 {
40     // Keep only one place to reset the values to their defaults
41     ResetOptionValues();
42 }
43 
44 
45 CommandObjectExpression::CommandOptions::~CommandOptions ()
46 {
47 }
48 
49 Error
50 CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
51 {
52     Error error;
53 
54     char short_option = (char) m_getopt_table[option_idx].val;
55 
56     switch (short_option)
57     {
58     case 'l':
59         if (language.SetLanguageFromCString (option_arg) == false)
60         {
61             error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg);
62         }
63         break;
64 
65     case 'g':
66         debug = true;
67         break;
68 
69     case 'f':
70         error = Args::StringToFormat(option_arg, format);
71         break;
72 
73     default:
74         error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
75         break;
76     }
77 
78     return error;
79 }
80 
81 void
82 CommandObjectExpression::CommandOptions::ResetOptionValues ()
83 {
84     Options::ResetOptionValues();
85     language.Clear();
86     debug = false;
87     format = eFormatDefault;
88     show_types = true;
89     show_summary = true;
90 }
91 
92 const lldb::OptionDefinition*
93 CommandObjectExpression::CommandOptions::GetDefinitions ()
94 {
95     return g_option_table;
96 }
97 
98 CommandObjectExpression::CommandObjectExpression () :
99     CommandObject (
100             "expression",
101             "Evaluate a C expression in the current program context, using variables currently in scope.",
102             "expression [<cmd-options>] <expr>"),
103     m_expr_line_count (0),
104     m_expr_lines ()
105 {
106   SetHelpLong(
107 "Examples: \n\
108 \n\
109    expr my_struct->a = my_array[3] \n\
110    expr -f bin -- (index * 8) + 5 \n\
111    expr char c[] = \"foo\"; c[0]\n");
112 }
113 
114 CommandObjectExpression::~CommandObjectExpression ()
115 {
116 }
117 
118 Options *
119 CommandObjectExpression::GetOptions ()
120 {
121     return &m_options;
122 }
123 
124 
125 bool
126 CommandObjectExpression::Execute
127 (
128     CommandInterpreter &interpreter,
129     Args& command,
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     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
148 
149     switch (notification)
150     {
151     case eInputReaderActivate:
152         reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter expressions, then terminate with an empty line to evaluate:");
153         // Fall through
154     case eInputReaderReactivate:
155         //if (out_fh)
156         //    reader.GetDebugger().GetOutputStream().Printf ("%3u: ", cmd_object_expr->m_expr_line_count);
157         break;
158 
159     case eInputReaderDeactivate:
160         break;
161 
162     case eInputReaderGotToken:
163         ++cmd_object_expr->m_expr_line_count;
164         if (bytes && bytes_len)
165         {
166             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
167         }
168 
169         if (bytes_len == 0)
170             reader.SetIsDone(true);
171         //else if (out_fh && !reader->IsDone())
172         //    ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
173         break;
174 
175     case eInputReaderDone:
176         {
177             bool bare = false;
178             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
179                                                  bare,
180                                                  reader.GetDebugger().GetOutputStream(),
181                                                  reader.GetDebugger().GetErrorStream());
182         }
183         break;
184     }
185 
186     return bytes_len;
187 }
188 
189 bool
190 CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream,
191                                              CommandReturnObject *result)
192 {
193     if (!m_exe_ctx.process)
194     {
195         error_stream.Printf ("Execution context doesn't contain a process");
196         return false;
197     }
198 
199     if (!m_exe_ctx.process->GetDynamicCheckers())
200     {
201         DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
202 
203         StreamString install_errors;
204 
205         if (!dynamic_checkers->Install(install_errors, m_exe_ctx))
206         {
207             error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s", install_errors.GetData());
208             return false;
209         }
210 
211         m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers);
212     }
213 
214     ClangUserExpression user_expression (expr);
215 
216     if (!user_expression.Parse (error_stream, m_exe_ctx))
217     {
218         error_stream.Printf ("Couldn't parse the expresssion");
219         return false;
220     }
221 
222     ClangExpressionVariable *expr_result;
223 
224     if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result))
225     {
226         error_stream.Printf ("Couldn't execute the expresssion");
227         return false;
228     }
229 
230     if (expr_result)
231     {
232         StreamString ss;
233 
234         Error rc = expr_result->Print (ss,
235                                        m_exe_ctx,
236                                        m_options.format,
237                                        m_options.show_types,
238                                        m_options.show_summary,
239                                        m_options.debug);
240 
241         if (rc.Fail()) {
242             error_stream.Printf ("Couldn't print result : %s\n", rc.AsCString());
243             return false;
244         }
245 
246         output_stream.PutCString(ss.GetString().c_str());
247         if (result)
248             result->SetStatus (eReturnStatusSuccessFinishResult);
249     }
250     else
251     {
252         error_stream.Printf ("Expression produced no result\n");
253         if (result)
254             result->SetStatus (eReturnStatusSuccessFinishNoResult);
255     }
256 
257     return true;
258 }
259 
260 bool
261 CommandObjectExpression::ExecuteRawCommandString
262 (
263     CommandInterpreter &interpreter,
264     const char *command,
265     CommandReturnObject &result
266 )
267 {
268     m_exe_ctx = interpreter.GetDebugger().GetExecutionContext();
269 
270     m_options.ResetOptionValues();
271 
272     const char * expr = NULL;
273 
274     if (command[0] == '\0')
275     {
276         m_expr_lines.clear();
277         m_expr_line_count = 0;
278 
279         InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
280         if (reader_sp)
281         {
282             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
283                                               this,                         // baton
284                                               eInputReaderGranularityLine,  // token size, to pass to callback function
285                                               NULL,                         // end token
286                                               NULL,                         // prompt
287                                               true));                       // echo input
288             if (err.Success())
289             {
290                 interpreter.GetDebugger().PushInputReader (reader_sp);
291                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
292             }
293             else
294             {
295                 result.AppendError (err.AsCString());
296                 result.SetStatus (eReturnStatusFailed);
297             }
298         }
299         else
300         {
301             result.AppendError("out of memory");
302             result.SetStatus (eReturnStatusFailed);
303         }
304         return result.Succeeded();
305     }
306 
307     if (command[0] == '-')
308     {
309         // We have some options and these options MUST end with --.
310         const char *end_options = NULL;
311         const char *s = command;
312         while (s && s[0])
313         {
314             end_options = ::strstr (s, "--");
315             if (end_options)
316             {
317                 end_options += 2; // Get past the "--"
318                 if (::isspace (end_options[0]))
319                 {
320                     expr = end_options;
321                     while (::isspace (*expr))
322                         ++expr;
323                     break;
324                 }
325             }
326             s = end_options;
327         }
328 
329         if (end_options)
330         {
331             Args args (command, end_options - command);
332             if (!ParseOptions (interpreter, args, result))
333                 return false;
334         }
335     }
336 
337     if (expr == NULL)
338         expr = command;
339 
340     if (EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream(), &result))
341         return true;
342 
343     result.SetStatus (eReturnStatusFailed);
344     return false;
345 }
346 
347 lldb::OptionDefinition
348 CommandObjectExpression::CommandOptions::g_option_table[] =
349 {
350 { LLDB_OPT_SET_ALL, false, "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
351 { 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."},
352 { LLDB_OPT_SET_ALL, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
353 { LLDB_OPT_SET_ALL, false, "use-ir",     'i', no_argument,       NULL, 0, NULL,                           "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
354 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
355 };
356 
357