xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision 1a8d40935d1e545e02149345b24ccbec19ed7db1)
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     ClangUserExpression user_expression (expr);
194 
195     if (!user_expression.Parse (error_stream, m_exe_ctx))
196     {
197         error_stream.Printf ("Couldn't parse the expresssion");
198         return false;
199     }
200 
201     ClangExpressionVariable *expr_result;
202 
203     if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result))
204     {
205         error_stream.Printf ("Couldn't execute the expresssion");
206         return false;
207     }
208 
209     if (expr_result)
210     {
211         StreamString ss;
212 
213         Error rc = expr_result->Print (ss,
214                                        m_exe_ctx,
215                                        m_options.format,
216                                        m_options.show_types,
217                                        m_options.show_summary,
218                                        m_options.debug);
219 
220         if (rc.Fail()) {
221             error_stream.Printf ("Couldn't print result : %s\n", rc.AsCString());
222             return false;
223         }
224 
225         output_stream.PutCString(ss.GetString().c_str());
226         if (result)
227             result->SetStatus (eReturnStatusSuccessFinishResult);
228     }
229     else
230     {
231         error_stream.Printf ("Expression produced no result\n");
232         if (result)
233             result->SetStatus (eReturnStatusSuccessFinishNoResult);
234     }
235 
236     return true;
237 }
238 
239 bool
240 CommandObjectExpression::ExecuteRawCommandString
241 (
242     CommandInterpreter &interpreter,
243     const char *command,
244     CommandReturnObject &result
245 )
246 {
247     m_exe_ctx = interpreter.GetDebugger().GetExecutionContext();
248 
249     m_options.ResetOptionValues();
250 
251     const char * expr = NULL;
252 
253     if (command[0] == '\0')
254     {
255         m_expr_lines.clear();
256         m_expr_line_count = 0;
257 
258         InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
259         if (reader_sp)
260         {
261             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
262                                               this,                         // baton
263                                               eInputReaderGranularityLine,  // token size, to pass to callback function
264                                               NULL,                         // end token
265                                               NULL,                         // prompt
266                                               true));                       // echo input
267             if (err.Success())
268             {
269                 interpreter.GetDebugger().PushInputReader (reader_sp);
270                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
271             }
272             else
273             {
274                 result.AppendError (err.AsCString());
275                 result.SetStatus (eReturnStatusFailed);
276             }
277         }
278         else
279         {
280             result.AppendError("out of memory");
281             result.SetStatus (eReturnStatusFailed);
282         }
283         return result.Succeeded();
284     }
285 
286     if (command[0] == '-')
287     {
288         // We have some options and these options MUST end with --.
289         const char *end_options = NULL;
290         const char *s = command;
291         while (s && s[0])
292         {
293             end_options = ::strstr (s, "--");
294             if (end_options)
295             {
296                 end_options += 2; // Get past the "--"
297                 if (::isspace (end_options[0]))
298                 {
299                     expr = end_options;
300                     while (::isspace (*expr))
301                         ++expr;
302                     break;
303                 }
304             }
305             s = end_options;
306         }
307 
308         if (end_options)
309         {
310             Args args (command, end_options - command);
311             if (!ParseOptions (interpreter, args, result))
312                 return false;
313         }
314     }
315 
316     if (expr == NULL)
317         expr = command;
318 
319     if (EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream(), &result))
320         return true;
321 
322     result.SetStatus (eReturnStatusFailed);
323     return false;
324 }
325 
326 lldb::OptionDefinition
327 CommandObjectExpression::CommandOptions::g_option_table[] =
328 {
329 { LLDB_OPT_SET_ALL, false, "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
330 { 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."},
331 { LLDB_OPT_SET_ALL, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
332 { LLDB_OPT_SET_ALL, false, "use-ir",     'i', no_argument,       NULL, 0, NULL,                           "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
333 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
334 };
335 
336