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 "lldb/lldb-python.h" 11 12 #include "CommandObjectExpression.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Interpreter/Args.h" 19 #include "lldb/Core/Value.h" 20 #include "lldb/Core/ValueObjectVariable.h" 21 #include "lldb/DataFormatters/ValueObjectPrinter.h" 22 #include "lldb/Expression/ClangExpressionVariable.h" 23 #include "lldb/Expression/ClangUserExpression.h" 24 #include "lldb/Expression/ClangFunction.h" 25 #include "lldb/Expression/DWARFExpression.h" 26 #include "lldb/Host/Host.h" 27 #include "lldb/Core/Debugger.h" 28 #include "lldb/Interpreter/CommandInterpreter.h" 29 #include "lldb/Interpreter/CommandReturnObject.h" 30 #include "lldb/Target/ObjCLanguageRuntime.h" 31 #include "lldb/Symbol/ObjectFile.h" 32 #include "lldb/Symbol/Variable.h" 33 #include "lldb/Target/Process.h" 34 #include "lldb/Target/StackFrame.h" 35 #include "lldb/Target/Target.h" 36 #include "lldb/Target/Thread.h" 37 #include "llvm/ADT/STLExtras.h" 38 #include "llvm/ADT/StringRef.h" 39 40 using namespace lldb; 41 using namespace lldb_private; 42 43 CommandObjectExpression::CommandOptions::CommandOptions () : 44 OptionGroup() 45 { 46 } 47 48 49 CommandObjectExpression::CommandOptions::~CommandOptions () 50 { 51 } 52 53 static OptionEnumValueElement g_description_verbosity_type[] = 54 { 55 { eLanguageRuntimeDescriptionDisplayVerbosityCompact, "compact", "Only show the description string"}, 56 { eLanguageRuntimeDescriptionDisplayVerbosityFull, "full", "Show the full output, including persistent variable's name and type"}, 57 { 0, NULL, NULL } 58 }; 59 60 OptionDefinition 61 CommandObjectExpression::CommandOptions::g_option_table[] = 62 { 63 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."}, 64 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"}, 65 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."}, 66 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."}, 67 { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "debug", 'g', OptionParser::eNoArgument , NULL, 0, eArgTypeNone, "When specified, debug the JIT code by setting a breakpoint on the first instruction and forcing breakpoints to not be ignored (-i0) and no unwinding to happen on error (-u0)."}, 68 { LLDB_OPT_SET_1, false, "description-verbosity", 'v', OptionParser::eOptionalArgument, g_description_verbosity_type, 0, eArgTypeDescriptionVerbosity, "How verbose should the output of this expression be, if the object description is asked for."}, 69 }; 70 71 72 uint32_t 73 CommandObjectExpression::CommandOptions::GetNumDefinitions () 74 { 75 return llvm::array_lengthof(g_option_table); 76 } 77 78 Error 79 CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter, 80 uint32_t option_idx, 81 const char *option_arg) 82 { 83 Error error; 84 85 const int short_option = g_option_table[option_idx].short_option; 86 87 switch (short_option) 88 { 89 //case 'l': 90 //if (language.SetLanguageFromCString (option_arg) == false) 91 //{ 92 // error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg); 93 //} 94 //break; 95 96 case 'a': 97 { 98 bool success; 99 bool result; 100 result = Args::StringToBoolean(option_arg, true, &success); 101 if (!success) 102 error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg); 103 else 104 try_all_threads = result; 105 } 106 break; 107 108 case 'i': 109 { 110 bool success; 111 bool tmp_value = Args::StringToBoolean(option_arg, true, &success); 112 if (success) 113 ignore_breakpoints = tmp_value; 114 else 115 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); 116 break; 117 } 118 case 't': 119 { 120 bool success; 121 uint32_t result; 122 result = Args::StringToUInt32(option_arg, 0, 0, &success); 123 if (success) 124 timeout = result; 125 else 126 error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg); 127 } 128 break; 129 130 case 'u': 131 { 132 bool success; 133 bool tmp_value = Args::StringToBoolean(option_arg, true, &success); 134 if (success) 135 unwind_on_error = tmp_value; 136 else 137 error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg); 138 break; 139 } 140 141 case 'v': 142 if (!option_arg) 143 { 144 m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityFull; 145 break; 146 } 147 m_verbosity = (LanguageRuntimeDescriptionDisplayVerbosity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); 148 if (!error.Success()) 149 error.SetErrorStringWithFormat ("unrecognized value for description-verbosity '%s'", option_arg); 150 break; 151 152 case 'g': 153 debug = true; 154 unwind_on_error = false; 155 ignore_breakpoints = false; 156 break; 157 158 default: 159 error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); 160 break; 161 } 162 163 return error; 164 } 165 166 void 167 CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter) 168 { 169 Process *process = interpreter.GetExecutionContext().GetProcessPtr(); 170 if (process != NULL) 171 { 172 ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions(); 173 unwind_on_error = process->GetUnwindOnErrorInExpressions(); 174 } 175 else 176 { 177 ignore_breakpoints = true; 178 unwind_on_error = true; 179 } 180 181 show_summary = true; 182 try_all_threads = true; 183 timeout = 0; 184 debug = false; 185 m_verbosity = eLanguageRuntimeDescriptionDisplayVerbosityCompact; 186 } 187 188 const OptionDefinition* 189 CommandObjectExpression::CommandOptions::GetDefinitions () 190 { 191 return g_option_table; 192 } 193 194 CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) : 195 CommandObjectRaw (interpreter, 196 "expression", 197 "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.", 198 NULL, 199 eFlagProcessMustBePaused | eFlagTryTargetAPILock), 200 IOHandlerDelegate (IOHandlerDelegate::Completion::Expression), 201 m_option_group (interpreter), 202 m_format_options (eFormatDefault), 203 m_command_options (), 204 m_expr_line_count (0), 205 m_expr_lines () 206 { 207 SetHelpLong( 208 "Timeouts:\n\ 209 If the expression can be evaluated statically (without running code) then it will be.\n\ 210 Otherwise, by default the expression will run on the current thread with a short timeout:\n\ 211 currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\ 212 and resumed with all threads running. You can use the -a option to disable retrying on all\n\ 213 threads. You can use the -t option to set a shorter timeout.\n\ 214 \n\ 215 User defined variables:\n\ 216 You can define your own variables for convenience or to be used in subsequent expressions.\n\ 217 You define them the same way you would define variables in C. If the first character of \n\ 218 your user defined variable is a $, then the variable's value will be available in future\n\ 219 expressions, otherwise it will just be available in the current expression.\n\ 220 \n\ 221 \n\ 222 Continuing evaluation after a breakpoint:\n\ 223 If the \"-i false\" option is used, and execution is interrupted by a breakpoint hit, once\n\ 224 you are done with your investigation, you can either remove the expression execution frames\n\ 225 from the stack with \"thread return -x\" or if you are still interested in the expression result\n\ 226 you can issue the \"continue\" command and the expression evaluation will complete and the\n\ 227 expression result will be available using the \"thread.completed-expression\" key in the thread\n\ 228 format.\n\ 229 \n\ 230 Examples: \n\ 231 \n\ 232 expr my_struct->a = my_array[3] \n\ 233 expr -f bin -- (index * 8) + 5 \n\ 234 expr unsigned int $foo = 5\n\ 235 expr char c[] = \"foo\"; c[0]\n"); 236 237 CommandArgumentEntry arg; 238 CommandArgumentData expression_arg; 239 240 // Define the first (and only) variant of this arg. 241 expression_arg.arg_type = eArgTypeExpression; 242 expression_arg.arg_repetition = eArgRepeatPlain; 243 244 // There is only one variant this argument could be; put it into the argument entry. 245 arg.push_back (expression_arg); 246 247 // Push the data for the first argument into the m_arguments vector. 248 m_arguments.push_back (arg); 249 250 // Add the "--format" and "--gdb-format" 251 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1); 252 m_option_group.Append (&m_command_options); 253 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2); 254 m_option_group.Finalize(); 255 } 256 257 CommandObjectExpression::~CommandObjectExpression () 258 { 259 } 260 261 Options * 262 CommandObjectExpression::GetOptions () 263 { 264 return &m_option_group; 265 } 266 267 bool 268 CommandObjectExpression::EvaluateExpression 269 ( 270 const char *expr, 271 Stream *output_stream, 272 Stream *error_stream, 273 CommandReturnObject *result 274 ) 275 { 276 // Don't use m_exe_ctx as this might be called asynchronously 277 // after the command object DoExecute has finished when doing 278 // multi-line expression that use an input reader... 279 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 280 281 Target *target = exe_ctx.GetTargetPtr(); 282 283 if (!target) 284 target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get(); 285 286 if (target) 287 { 288 lldb::ValueObjectSP result_valobj_sp; 289 290 bool keep_in_memory = true; 291 292 EvaluateExpressionOptions options; 293 options.SetCoerceToId(m_varobj_options.use_objc); 294 options.SetUnwindOnError(m_command_options.unwind_on_error); 295 options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints); 296 options.SetKeepInMemory(keep_in_memory); 297 options.SetUseDynamic(m_varobj_options.use_dynamic); 298 options.SetTryAllThreads(m_command_options.try_all_threads); 299 options.SetDebug(m_command_options.debug); 300 301 // If there is any chance we are going to stop and want to see 302 // what went wrong with our expression, we should generate debug info 303 if (!m_command_options.ignore_breakpoints || 304 !m_command_options.unwind_on_error) 305 options.SetGenerateDebugInfo(true); 306 307 if (m_command_options.timeout > 0) 308 options.SetTimeoutUsec(m_command_options.timeout); 309 else 310 options.SetTimeoutUsec(0); 311 312 target->EvaluateExpression(expr, exe_ctx.GetFramePtr(), 313 result_valobj_sp, options); 314 315 if (result_valobj_sp) 316 { 317 Format format = m_format_options.GetFormat(); 318 319 if (result_valobj_sp->GetError().Success()) 320 { 321 if (format != eFormatVoid) 322 { 323 if (format != eFormatDefault) 324 result_valobj_sp->SetFormat (format); 325 326 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(m_command_options.m_verbosity,format)); 327 328 result_valobj_sp->Dump(*output_stream,options); 329 330 if (result) 331 result->SetStatus (eReturnStatusSuccessFinishResult); 332 } 333 } 334 else 335 { 336 if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult) 337 { 338 if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid()) 339 { 340 error_stream->PutCString("(void)\n"); 341 } 342 343 if (result) 344 result->SetStatus (eReturnStatusSuccessFinishResult); 345 } 346 else 347 { 348 const char *error_cstr = result_valobj_sp->GetError().AsCString(); 349 if (error_cstr && error_cstr[0]) 350 { 351 const size_t error_cstr_len = strlen (error_cstr); 352 const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n'; 353 if (strstr(error_cstr, "error:") != error_cstr) 354 error_stream->PutCString ("error: "); 355 error_stream->Write(error_cstr, error_cstr_len); 356 if (!ends_with_newline) 357 error_stream->EOL(); 358 } 359 else 360 { 361 error_stream->PutCString ("error: unknown error\n"); 362 } 363 364 if (result) 365 result->SetStatus (eReturnStatusFailed); 366 } 367 } 368 } 369 } 370 else 371 { 372 error_stream->Printf ("error: invalid execution context for expression\n"); 373 return false; 374 } 375 376 return true; 377 } 378 379 void 380 CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) 381 { 382 io_handler.SetIsDone(true); 383 // StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream(); 384 // StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream(); 385 StreamFileSP output_sp(io_handler.GetOutputStreamFile()); 386 StreamFileSP error_sp(io_handler.GetErrorStreamFile()); 387 388 EvaluateExpression (line.c_str(), 389 output_sp.get(), 390 error_sp.get()); 391 if (output_sp) 392 output_sp->Flush(); 393 if (error_sp) 394 error_sp->Flush(); 395 } 396 397 LineStatus 398 CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler, 399 StringList &lines, 400 uint32_t line_idx, 401 Error &error) 402 { 403 if (line_idx == UINT32_MAX) 404 { 405 // Remove the last line from "lines" so it doesn't appear 406 // in our final expression 407 lines.PopBack(); 408 error.Clear(); 409 return LineStatus::Done; 410 } 411 else if (line_idx + 1 == lines.GetSize()) 412 { 413 // The last line was edited, if this line is empty, then we are done 414 // getting our multiple lines. 415 if (lines[line_idx].empty()) 416 return LineStatus::Done; 417 } 418 return LineStatus::Success; 419 } 420 421 void 422 CommandObjectExpression::GetMultilineExpression () 423 { 424 m_expr_lines.clear(); 425 m_expr_line_count = 0; 426 427 Debugger &debugger = GetCommandInterpreter().GetDebugger(); 428 const bool multiple_lines = true; // Get multiple lines 429 IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, 430 "lldb-expr", // Name of input reader for history 431 NULL, // No prompt 432 multiple_lines, 433 1, // Show line numbers starting at 1 434 *this)); 435 436 StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile()); 437 if (output_sp) 438 { 439 output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n"); 440 output_sp->Flush(); 441 } 442 debugger.PushIOHandler(io_handler_sp); 443 } 444 445 bool 446 CommandObjectExpression::DoExecute 447 ( 448 const char *command, 449 CommandReturnObject &result 450 ) 451 { 452 m_option_group.NotifyOptionParsingStarting(); 453 454 const char * expr = NULL; 455 456 if (command[0] == '\0') 457 { 458 GetMultilineExpression (); 459 return result.Succeeded(); 460 } 461 462 if (command[0] == '-') 463 { 464 // We have some options and these options MUST end with --. 465 const char *end_options = NULL; 466 const char *s = command; 467 while (s && s[0]) 468 { 469 end_options = ::strstr (s, "--"); 470 if (end_options) 471 { 472 end_options += 2; // Get past the "--" 473 if (::isspace (end_options[0])) 474 { 475 expr = end_options; 476 while (::isspace (*expr)) 477 ++expr; 478 break; 479 } 480 } 481 s = end_options; 482 } 483 484 if (end_options) 485 { 486 Args args (command, end_options - command); 487 if (!ParseOptions (args, result)) 488 return false; 489 490 Error error (m_option_group.NotifyOptionParsingFinished()); 491 if (error.Fail()) 492 { 493 result.AppendError (error.AsCString()); 494 result.SetStatus (eReturnStatusFailed); 495 return false; 496 } 497 498 // No expression following options 499 if (expr == NULL || expr[0] == '\0') 500 { 501 GetMultilineExpression (); 502 return result.Succeeded(); 503 } 504 } 505 } 506 507 if (expr == NULL) 508 expr = command; 509 510 if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result)) 511 return true; 512 513 result.SetStatus (eReturnStatusFailed); 514 return false; 515 } 516 517