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