xref: /llvm-project/lldb/source/Commands/CommandObjectExpression.cpp (revision a701509229f658eac7c10bd6aa54cf6ed5b5011d)
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 (CommandInterpreter &interpreter) :
99     CommandObject (interpreter,
100                    "expression",
101                    "Evaluate an Objective-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     Args& command,
129     CommandReturnObject &result
130 )
131 {
132     return false;
133 }
134 
135 
136 size_t
137 CommandObjectExpression::MultiLineExpressionCallback
138 (
139     void *baton,
140     InputReader &reader,
141     lldb::InputReaderAction notification,
142     const char *bytes,
143     size_t bytes_len
144 )
145 {
146     CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
147 
148     switch (notification)
149     {
150     case eInputReaderActivate:
151         reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter expressions, then terminate with an empty line to evaluate:");
152         // Fall through
153     case eInputReaderReactivate:
154         //if (out_fh)
155         //    reader.GetDebugger().GetOutputStream().Printf ("%3u: ", cmd_object_expr->m_expr_line_count);
156         break;
157 
158     case eInputReaderDeactivate:
159         break;
160 
161     case eInputReaderGotToken:
162         ++cmd_object_expr->m_expr_line_count;
163         if (bytes && bytes_len)
164         {
165             cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
166         }
167 
168         if (bytes_len == 0)
169             reader.SetIsDone(true);
170         //else if (out_fh && !reader->IsDone())
171         //    ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count);
172         break;
173 
174     case eInputReaderDone:
175         {
176             bool bare = false;
177             cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
178                                                  bare,
179                                                  reader.GetDebugger().GetOutputStream(),
180                                                  reader.GetDebugger().GetErrorStream());
181         }
182         break;
183     }
184 
185     return bytes_len;
186 }
187 
188 bool
189 CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream,
190                                              CommandReturnObject *result)
191 {
192     if (!m_exe_ctx.process)
193     {
194         error_stream.Printf ("Execution context doesn't contain a process\n");
195         return false;
196     }
197 
198     if (!m_exe_ctx.process->GetDynamicCheckers())
199     {
200         DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
201 
202         StreamString install_errors;
203 
204         if (!dynamic_checkers->Install(install_errors, m_exe_ctx))
205         {
206             error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s\n", install_errors.GetData());
207             return false;
208         }
209 
210         m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers);
211     }
212 
213     ClangUserExpression user_expression (expr);
214 
215     if (!user_expression.Parse (error_stream, m_exe_ctx))
216     {
217         error_stream.Printf ("Couldn't parse the expresssion\n");
218         return false;
219     }
220 
221     ClangExpressionVariable *expr_result = NULL;
222 
223     if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result))
224     {
225         error_stream.Printf ("Couldn't execute the expresssion\n");
226         return false;
227     }
228 
229     if (expr_result)
230     {
231         StreamString ss;
232 
233         Error rc = expr_result->Print (ss,
234                                        m_exe_ctx,
235                                        m_options.format,
236                                        m_options.show_types,
237                                        m_options.show_summary,
238                                        m_options.debug);
239 
240         if (rc.Fail()) {
241             error_stream.Printf ("Couldn't print result : %s\n", rc.AsCString());
242             return false;
243         }
244 
245         output_stream.PutCString(ss.GetString().c_str());
246         if (result)
247             result->SetStatus (eReturnStatusSuccessFinishResult);
248     }
249     else
250     {
251         if (result)
252             result->SetStatus (eReturnStatusSuccessFinishNoResult);
253     }
254 
255     return true;
256 }
257 
258 bool
259 CommandObjectExpression::ExecuteRawCommandString
260 (
261     const char *command,
262     CommandReturnObject &result
263 )
264 {
265     m_exe_ctx = m_interpreter.GetDebugger().GetExecutionContext();
266 
267     m_options.ResetOptionValues();
268 
269     const char * expr = NULL;
270 
271     if (command[0] == '\0')
272     {
273         m_expr_lines.clear();
274         m_expr_line_count = 0;
275 
276         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
277         if (reader_sp)
278         {
279             Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
280                                               this,                         // baton
281                                               eInputReaderGranularityLine,  // token size, to pass to callback function
282                                               NULL,                         // end token
283                                               NULL,                         // prompt
284                                               true));                       // echo input
285             if (err.Success())
286             {
287                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
288                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
289             }
290             else
291             {
292                 result.AppendError (err.AsCString());
293                 result.SetStatus (eReturnStatusFailed);
294             }
295         }
296         else
297         {
298             result.AppendError("out of memory");
299             result.SetStatus (eReturnStatusFailed);
300         }
301         return result.Succeeded();
302     }
303 
304     if (command[0] == '-')
305     {
306         // We have some options and these options MUST end with --.
307         const char *end_options = NULL;
308         const char *s = command;
309         while (s && s[0])
310         {
311             end_options = ::strstr (s, "--");
312             if (end_options)
313             {
314                 end_options += 2; // Get past the "--"
315                 if (::isspace (end_options[0]))
316                 {
317                     expr = end_options;
318                     while (::isspace (*expr))
319                         ++expr;
320                     break;
321                 }
322             }
323             s = end_options;
324         }
325 
326         if (end_options)
327         {
328             Args args (command, end_options - command);
329             if (!ParseOptions (args, result))
330                 return false;
331         }
332     }
333 
334     if (expr == NULL)
335         expr = command;
336 
337     if (EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream(), &result))
338         return true;
339 
340     result.SetStatus (eReturnStatusFailed);
341     return false;
342 }
343 
344 lldb::OptionDefinition
345 CommandObjectExpression::CommandOptions::g_option_table[] =
346 {
347   //{ LLDB_OPT_SET_ALL, false, "language",   'l', required_argument, NULL, 0, "[c|c++|objc|objc++]",          "Sets the language to use when parsing the expression."},
348 { 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."},
349 { LLDB_OPT_SET_ALL, false, "debug",      'g', no_argument,       NULL, 0, NULL,                           "Enable verbose debug logging of the expression parsing and evaluation."},
350 { LLDB_OPT_SET_ALL, false, "use-ir",     'i', no_argument,       NULL, 0, NULL,                           "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
351 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL }
352 };
353 
354