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/Core/ValueObjectVariable.h" 20 #include "lldb/Expression/ClangExpressionVariable.h" 21 #include "lldb/Expression/ClangUserExpression.h" 22 #include "lldb/Expression/ClangFunction.h" 23 #include "lldb/Expression/DWARFExpression.h" 24 #include "lldb/Host/Host.h" 25 #include "lldb/Core/Debugger.h" 26 #include "lldb/Interpreter/CommandInterpreter.h" 27 #include "lldb/Interpreter/CommandReturnObject.h" 28 #include "lldb/Target/ObjCLanguageRuntime.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 case 'o': 76 print_object = true; 77 break; 78 79 default: 80 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 81 break; 82 } 83 84 return error; 85 } 86 87 void 88 CommandObjectExpression::CommandOptions::ResetOptionValues () 89 { 90 Options::ResetOptionValues(); 91 //language.Clear(); 92 debug = false; 93 format = eFormatDefault; 94 print_object = false; 95 show_types = true; 96 show_summary = true; 97 } 98 99 const lldb::OptionDefinition* 100 CommandObjectExpression::CommandOptions::GetDefinitions () 101 { 102 return g_option_table; 103 } 104 105 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) : 106 CommandObject (interpreter, 107 "expression", 108 "Evaluate an Objective-C++ expression in the current program context, using variables currently in scope.", 109 "expression [<cmd-options>] <expr>"), 110 m_expr_line_count (0), 111 m_expr_lines () 112 { 113 SetHelpLong( 114 "Examples: \n\ 115 \n\ 116 expr my_struct->a = my_array[3] \n\ 117 expr -f bin -- (index * 8) + 5 \n\ 118 expr char c[] = \"foo\"; c[0]\n"); 119 } 120 121 CommandObjectExpression::~CommandObjectExpression () 122 { 123 } 124 125 Options * 126 CommandObjectExpression::GetOptions () 127 { 128 return &m_options; 129 } 130 131 132 bool 133 CommandObjectExpression::Execute 134 ( 135 Args& command, 136 CommandReturnObject &result 137 ) 138 { 139 return false; 140 } 141 142 143 size_t 144 CommandObjectExpression::MultiLineExpressionCallback 145 ( 146 void *baton, 147 InputReader &reader, 148 lldb::InputReaderAction notification, 149 const char *bytes, 150 size_t bytes_len 151 ) 152 { 153 CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton; 154 155 switch (notification) 156 { 157 case eInputReaderActivate: 158 reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter expressions, then terminate with an empty line to evaluate:"); 159 // Fall through 160 case eInputReaderReactivate: 161 //if (out_fh) 162 // reader.GetDebugger().GetOutputStream().Printf ("%3u: ", cmd_object_expr->m_expr_line_count); 163 break; 164 165 case eInputReaderDeactivate: 166 break; 167 168 case eInputReaderGotToken: 169 ++cmd_object_expr->m_expr_line_count; 170 if (bytes && bytes_len) 171 { 172 cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1); 173 } 174 175 if (bytes_len == 0) 176 reader.SetIsDone(true); 177 //else if (out_fh && !reader->IsDone()) 178 // ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count); 179 break; 180 181 case eInputReaderDone: 182 { 183 bool bare = false; 184 cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(), 185 bare, 186 reader.GetDebugger().GetOutputStream(), 187 reader.GetDebugger().GetErrorStream()); 188 } 189 break; 190 } 191 192 return bytes_len; 193 } 194 195 bool 196 CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream, 197 CommandReturnObject *result) 198 { 199 if (!m_exe_ctx.process) 200 { 201 error_stream.Printf ("Execution context doesn't contain a process\n"); 202 return false; 203 } 204 205 if (!m_exe_ctx.process->GetDynamicCheckers()) 206 { 207 DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); 208 209 StreamString install_errors; 210 211 if (!dynamic_checkers->Install(install_errors, m_exe_ctx)) 212 { 213 error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s\n", install_errors.GetData()); 214 return false; 215 } 216 217 m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers); 218 } 219 220 ClangUserExpression user_expression (expr); 221 222 if (!user_expression.Parse (error_stream, m_exe_ctx)) 223 { 224 error_stream.Printf ("Couldn't parse the expresssion\n"); 225 return false; 226 } 227 228 ClangExpressionVariable *expr_result = NULL; 229 230 if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result)) 231 { 232 error_stream.Printf ("Couldn't execute the expresssion\n"); 233 return false; 234 } 235 236 if (expr_result) 237 { 238 StreamString ss; 239 240 if (m_options.print_object) 241 { 242 Value result_value; 243 if (expr_result->PointValueAtData(result_value, &m_exe_ctx)) 244 { 245 bool obj_result; 246 ObjCLanguageRuntime *runtime = m_exe_ctx.process->GetObjCLanguageRuntime(); 247 obj_result = runtime->GetObjectDescription (ss, result_value, m_exe_ctx.GetBestExecutionContextScope()); 248 if (!obj_result) 249 { 250 error_stream.Printf ("Could not get object description: %s.\n", ss.GetData()); 251 return false; 252 } 253 // Sometimes the description doesn't have a newline on the end. For now, I'll just add one here, if 254 ss.Printf("\n"); 255 } 256 } 257 else 258 { 259 Error rc = expr_result->Print (ss, 260 m_exe_ctx, 261 m_options.format, 262 m_options.show_types, 263 m_options.show_summary, 264 m_options.debug); 265 266 if (rc.Fail()) { 267 error_stream.Printf ("Couldn't print result : %s\n", rc.AsCString()); 268 return false; 269 } 270 } 271 272 output_stream.PutCString(ss.GetString().c_str()); 273 if (result) 274 result->SetStatus (eReturnStatusSuccessFinishResult); 275 } 276 else 277 { 278 if (result) 279 result->SetStatus (eReturnStatusSuccessFinishNoResult); 280 } 281 282 return true; 283 } 284 285 bool 286 CommandObjectExpression::ExecuteRawCommandString 287 ( 288 const char *command, 289 CommandReturnObject &result 290 ) 291 { 292 m_exe_ctx = m_interpreter.GetDebugger().GetExecutionContext(); 293 294 m_options.ResetOptionValues(); 295 296 const char * expr = NULL; 297 298 if (command[0] == '\0') 299 { 300 m_expr_lines.clear(); 301 m_expr_line_count = 0; 302 303 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 304 if (reader_sp) 305 { 306 Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback, 307 this, // baton 308 eInputReaderGranularityLine, // token size, to pass to callback function 309 NULL, // end token 310 NULL, // prompt 311 true)); // echo input 312 if (err.Success()) 313 { 314 m_interpreter.GetDebugger().PushInputReader (reader_sp); 315 result.SetStatus (eReturnStatusSuccessFinishNoResult); 316 } 317 else 318 { 319 result.AppendError (err.AsCString()); 320 result.SetStatus (eReturnStatusFailed); 321 } 322 } 323 else 324 { 325 result.AppendError("out of memory"); 326 result.SetStatus (eReturnStatusFailed); 327 } 328 return result.Succeeded(); 329 } 330 331 if (command[0] == '-') 332 { 333 // We have some options and these options MUST end with --. 334 const char *end_options = NULL; 335 const char *s = command; 336 while (s && s[0]) 337 { 338 end_options = ::strstr (s, "--"); 339 if (end_options) 340 { 341 end_options += 2; // Get past the "--" 342 if (::isspace (end_options[0])) 343 { 344 expr = end_options; 345 while (::isspace (*expr)) 346 ++expr; 347 break; 348 } 349 } 350 s = end_options; 351 } 352 353 if (end_options) 354 { 355 Args args (command, end_options - command); 356 if (!ParseOptions (args, result)) 357 return false; 358 } 359 } 360 361 if (expr == NULL) 362 expr = command; 363 364 if (EvaluateExpression (expr, false, result.GetOutputStream(), result.GetErrorStream(), &result)) 365 return true; 366 367 result.SetStatus (eReturnStatusFailed); 368 return false; 369 } 370 371 lldb::OptionDefinition 372 CommandObjectExpression::CommandOptions::g_option_table[] = 373 { 374 //{ LLDB_OPT_SET_ALL, false, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."}, 375 { LLDB_OPT_SET_1, 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."}, 376 { LLDB_OPT_SET_2, false, "object-description", 'o', no_argument, NULL, 0, NULL, "Print the object description of the value resulting from the expression"}, 377 { LLDB_OPT_SET_ALL, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."}, 378 { LLDB_OPT_SET_ALL, false, "use-ir", 'i', no_argument, NULL, 0, NULL, "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."}, 379 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } 380 }; 381 382