1 //===-- Debugger.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 "lldb/Core/Debugger.h" 13 14 #include <map> 15 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/Type.h" 18 #include "llvm/ADT/StringRef.h" 19 20 #include "lldb/lldb-private.h" 21 #include "lldb/Core/Module.h" 22 #include "lldb/Core/PluginManager.h" 23 #include "lldb/Core/RegisterValue.h" 24 #include "lldb/Core/State.h" 25 #include "lldb/Core/StreamAsynchronousIO.h" 26 #include "lldb/Core/StreamCallback.h" 27 #include "lldb/Core/StreamFile.h" 28 #include "lldb/Core/StreamString.h" 29 #include "lldb/Core/StructuredData.h" 30 #include "lldb/Core/Timer.h" 31 #include "lldb/Core/ValueObject.h" 32 #include "lldb/Core/ValueObjectVariable.h" 33 #include "lldb/DataFormatters/DataVisualization.h" 34 #include "lldb/DataFormatters/FormatManager.h" 35 #include "lldb/DataFormatters/TypeSummary.h" 36 #include "lldb/Host/ConnectionFileDescriptor.h" 37 #include "lldb/Host/HostInfo.h" 38 #include "lldb/Host/Terminal.h" 39 #include "lldb/Host/ThreadLauncher.h" 40 #include "lldb/Interpreter/CommandInterpreter.h" 41 #include "lldb/Interpreter/OptionValueSInt64.h" 42 #include "lldb/Interpreter/OptionValueString.h" 43 #include "lldb/Symbol/ClangASTContext.h" 44 #include "lldb/Symbol/CompileUnit.h" 45 #include "lldb/Symbol/Function.h" 46 #include "lldb/Symbol/Symbol.h" 47 #include "lldb/Symbol/VariableList.h" 48 #include "lldb/Target/CPPLanguageRuntime.h" 49 #include "lldb/Target/ObjCLanguageRuntime.h" 50 #include "lldb/Target/TargetList.h" 51 #include "lldb/Target/Process.h" 52 #include "lldb/Target/RegisterContext.h" 53 #include "lldb/Target/SectionLoadList.h" 54 #include "lldb/Target/StopInfo.h" 55 #include "lldb/Target/Target.h" 56 #include "lldb/Target/Thread.h" 57 #include "lldb/Utility/AnsiTerminal.h" 58 59 #include "llvm/Support/DynamicLibrary.h" 60 61 using namespace lldb; 62 using namespace lldb_private; 63 64 65 static uint32_t g_shared_debugger_refcount = 0; 66 static lldb::user_id_t g_unique_id = 1; 67 static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024; 68 69 #pragma mark Static Functions 70 71 static Mutex & 72 GetDebuggerListMutex () 73 { 74 static Mutex g_mutex(Mutex::eMutexTypeRecursive); 75 return g_mutex; 76 } 77 78 typedef std::vector<DebuggerSP> DebuggerList; 79 80 static DebuggerList & 81 GetDebuggerList() 82 { 83 // hide the static debugger list inside a singleton accessor to avoid 84 // global init constructors 85 static DebuggerList g_list; 86 return g_list; 87 } 88 89 OptionEnumValueElement 90 g_show_disassembly_enum_values[] = 91 { 92 { Debugger::eStopDisassemblyTypeNever, "never", "Never show disassembly when displaying a stop context."}, 93 { Debugger::eStopDisassemblyTypeNoSource, "no-source", "Show disassembly when there is no source information, or the source file is missing when displaying a stop context."}, 94 { Debugger::eStopDisassemblyTypeAlways, "always", "Always show disassembly when displaying a stop context."}, 95 { 0, NULL, NULL } 96 }; 97 98 OptionEnumValueElement 99 g_language_enumerators[] = 100 { 101 { eScriptLanguageNone, "none", "Disable scripting languages."}, 102 { eScriptLanguagePython, "python", "Select python as the default scripting language."}, 103 { eScriptLanguageDefault, "default", "Select the lldb default as the default scripting language."}, 104 { 0, NULL, NULL } 105 }; 106 107 #define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}" 108 #define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}" 109 110 #define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\ 111 "{, ${frame.pc}}"\ 112 MODULE_WITH_FUNC\ 113 FILE_AND_LINE\ 114 "{, name = '${thread.name}'}"\ 115 "{, queue = '${thread.queue}'}"\ 116 "{, activity = '${thread.info.activity.name}'}" \ 117 "{, ${thread.info.trace_messages} messages}" \ 118 "{, stop reason = ${thread.stop-reason}}"\ 119 "{\\nReturn value: ${thread.return-value}}"\ 120 "{\\nCompleted expression: ${thread.completed-expression}}"\ 121 "\\n" 122 123 #define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\ 124 MODULE_WITH_FUNC\ 125 FILE_AND_LINE\ 126 "\\n" 127 128 #define DEFAULT_DISASSEMBLY_FORMAT "${addr-file-or-load} <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>: " 129 130 131 static PropertyDefinition 132 g_properties[] = 133 { 134 { "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, 135 { "disassembly-format", OptionValue::eTypeString , true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, 136 { "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, 137 { "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, 138 { "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, 139 { "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, 140 { "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, 141 { "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, 142 { "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, 143 { "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, 144 { "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, 145 { "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, 146 { "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." }, 147 { "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, 148 { "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, 149 150 { NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL } 151 }; 152 153 enum 154 { 155 ePropertyAutoConfirm = 0, 156 ePropertyDisassemblyFormat, 157 ePropertyFrameFormat, 158 ePropertyNotiftVoid, 159 ePropertyPrompt, 160 ePropertyScriptLanguage, 161 ePropertyStopDisassemblyCount, 162 ePropertyStopDisassemblyDisplay, 163 ePropertyStopLineCountAfter, 164 ePropertyStopLineCountBefore, 165 ePropertyTerminalWidth, 166 ePropertyThreadFormat, 167 ePropertyUseExternalEditor, 168 ePropertyUseColor, 169 ePropertyAutoOneLineSummaries 170 }; 171 172 Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; 173 174 Error 175 Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, 176 VarSetOperationType op, 177 const char *property_path, 178 const char *value) 179 { 180 bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0; 181 TargetSP target_sp; 182 LoadScriptFromSymFile load_script_old_value; 183 if (is_load_script && exe_ctx->GetTargetSP()) 184 { 185 target_sp = exe_ctx->GetTargetSP(); 186 load_script_old_value = target_sp->TargetProperties::GetLoadScriptFromSymbolFile(); 187 } 188 Error error (Properties::SetPropertyValue (exe_ctx, op, property_path, value)); 189 if (error.Success()) 190 { 191 // FIXME it would be nice to have "on-change" callbacks for properties 192 if (strcmp(property_path, g_properties[ePropertyPrompt].name) == 0) 193 { 194 const char *new_prompt = GetPrompt(); 195 std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); 196 if (str.length()) 197 new_prompt = str.c_str(); 198 GetCommandInterpreter().UpdatePrompt(new_prompt); 199 EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt))); 200 GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp); 201 } 202 else if (strcmp(property_path, g_properties[ePropertyUseColor].name) == 0) 203 { 204 // use-color changed. Ping the prompt so it can reset the ansi terminal codes. 205 SetPrompt (GetPrompt()); 206 } 207 else if (is_load_script && target_sp && load_script_old_value == eLoadScriptFromSymFileWarn) 208 { 209 if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == eLoadScriptFromSymFileTrue) 210 { 211 std::list<Error> errors; 212 StreamString feedback_stream; 213 if (!target_sp->LoadScriptingResources(errors,&feedback_stream)) 214 { 215 StreamFileSP stream_sp (GetErrorFile()); 216 if (stream_sp) 217 { 218 for (auto error : errors) 219 { 220 stream_sp->Printf("%s\n",error.AsCString()); 221 } 222 if (feedback_stream.GetSize()) 223 stream_sp->Printf("%s",feedback_stream.GetData()); 224 } 225 } 226 } 227 } 228 } 229 return error; 230 } 231 232 bool 233 Debugger::GetAutoConfirm () const 234 { 235 const uint32_t idx = ePropertyAutoConfirm; 236 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); 237 } 238 239 const char * 240 Debugger::GetDisassemblyFormat() const 241 { 242 const uint32_t idx = ePropertyDisassemblyFormat; 243 return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); 244 } 245 246 const char * 247 Debugger::GetFrameFormat() const 248 { 249 const uint32_t idx = ePropertyFrameFormat; 250 return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); 251 } 252 253 bool 254 Debugger::GetNotifyVoid () const 255 { 256 const uint32_t idx = ePropertyNotiftVoid; 257 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); 258 } 259 260 const char * 261 Debugger::GetPrompt() const 262 { 263 const uint32_t idx = ePropertyPrompt; 264 return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); 265 } 266 267 void 268 Debugger::SetPrompt(const char *p) 269 { 270 const uint32_t idx = ePropertyPrompt; 271 m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p); 272 const char *new_prompt = GetPrompt(); 273 std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); 274 if (str.length()) 275 new_prompt = str.c_str(); 276 GetCommandInterpreter().UpdatePrompt(new_prompt); 277 } 278 279 const char * 280 Debugger::GetThreadFormat() const 281 { 282 const uint32_t idx = ePropertyThreadFormat; 283 return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); 284 } 285 286 lldb::ScriptLanguage 287 Debugger::GetScriptLanguage() const 288 { 289 const uint32_t idx = ePropertyScriptLanguage; 290 return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value); 291 } 292 293 bool 294 Debugger::SetScriptLanguage (lldb::ScriptLanguage script_lang) 295 { 296 const uint32_t idx = ePropertyScriptLanguage; 297 return m_collection_sp->SetPropertyAtIndexAsEnumeration (NULL, idx, script_lang); 298 } 299 300 uint32_t 301 Debugger::GetTerminalWidth () const 302 { 303 const uint32_t idx = ePropertyTerminalWidth; 304 return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); 305 } 306 307 bool 308 Debugger::SetTerminalWidth (uint32_t term_width) 309 { 310 const uint32_t idx = ePropertyTerminalWidth; 311 return m_collection_sp->SetPropertyAtIndexAsSInt64 (NULL, idx, term_width); 312 } 313 314 bool 315 Debugger::GetUseExternalEditor () const 316 { 317 const uint32_t idx = ePropertyUseExternalEditor; 318 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); 319 } 320 321 bool 322 Debugger::SetUseExternalEditor (bool b) 323 { 324 const uint32_t idx = ePropertyUseExternalEditor; 325 return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); 326 } 327 328 bool 329 Debugger::GetUseColor () const 330 { 331 const uint32_t idx = ePropertyUseColor; 332 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); 333 } 334 335 bool 336 Debugger::SetUseColor (bool b) 337 { 338 const uint32_t idx = ePropertyUseColor; 339 bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b); 340 SetPrompt (GetPrompt()); 341 return ret; 342 } 343 344 uint32_t 345 Debugger::GetStopSourceLineCount (bool before) const 346 { 347 const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter; 348 return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); 349 } 350 351 Debugger::StopDisassemblyType 352 Debugger::GetStopDisassemblyDisplay () const 353 { 354 const uint32_t idx = ePropertyStopDisassemblyDisplay; 355 return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value); 356 } 357 358 uint32_t 359 Debugger::GetDisassemblyLineCount () const 360 { 361 const uint32_t idx = ePropertyStopDisassemblyCount; 362 return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value); 363 } 364 365 bool 366 Debugger::GetAutoOneLineSummaries () const 367 { 368 const uint32_t idx = ePropertyAutoOneLineSummaries; 369 return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, true); 370 371 } 372 373 #pragma mark Debugger 374 375 //const DebuggerPropertiesSP & 376 //Debugger::GetSettings() const 377 //{ 378 // return m_properties_sp; 379 //} 380 // 381 382 int 383 Debugger::TestDebuggerRefCount () 384 { 385 return g_shared_debugger_refcount; 386 } 387 388 void 389 Debugger::Initialize (LoadPluginCallbackType load_plugin_callback) 390 { 391 g_load_plugin_callback = load_plugin_callback; 392 if (g_shared_debugger_refcount++ == 0) 393 lldb_private::Initialize(); 394 } 395 396 void 397 Debugger::Terminate () 398 { 399 if (g_shared_debugger_refcount > 0) 400 { 401 g_shared_debugger_refcount--; 402 if (g_shared_debugger_refcount == 0) 403 { 404 lldb_private::WillTerminate(); 405 lldb_private::Terminate(); 406 407 // Clear our master list of debugger objects 408 Mutex::Locker locker (GetDebuggerListMutex ()); 409 GetDebuggerList().clear(); 410 } 411 } 412 } 413 414 void 415 Debugger::SettingsInitialize () 416 { 417 Target::SettingsInitialize (); 418 } 419 420 void 421 Debugger::SettingsTerminate () 422 { 423 Target::SettingsTerminate (); 424 } 425 426 bool 427 Debugger::LoadPlugin (const FileSpec& spec, Error& error) 428 { 429 if (g_load_plugin_callback) 430 { 431 llvm::sys::DynamicLibrary dynlib = g_load_plugin_callback (shared_from_this(), spec, error); 432 if (dynlib.isValid()) 433 { 434 m_loaded_plugins.push_back(dynlib); 435 return true; 436 } 437 } 438 else 439 { 440 // The g_load_plugin_callback is registered in SBDebugger::Initialize() 441 // and if the public API layer isn't available (code is linking against 442 // all of the internal LLDB static libraries), then we can't load plugins 443 error.SetErrorString("Public API layer is not available"); 444 } 445 return false; 446 } 447 448 static FileSpec::EnumerateDirectoryResult 449 LoadPluginCallback 450 ( 451 void *baton, 452 FileSpec::FileType file_type, 453 const FileSpec &file_spec 454 ) 455 { 456 Error error; 457 458 static ConstString g_dylibext("dylib"); 459 static ConstString g_solibext("so"); 460 461 if (!baton) 462 return FileSpec::eEnumerateDirectoryResultQuit; 463 464 Debugger *debugger = (Debugger*)baton; 465 466 // If we have a regular file, a symbolic link or unknown file type, try 467 // and process the file. We must handle unknown as sometimes the directory 468 // enumeration might be enumerating a file system that doesn't have correct 469 // file type information. 470 if (file_type == FileSpec::eFileTypeRegular || 471 file_type == FileSpec::eFileTypeSymbolicLink || 472 file_type == FileSpec::eFileTypeUnknown ) 473 { 474 FileSpec plugin_file_spec (file_spec); 475 plugin_file_spec.ResolvePath (); 476 477 if (plugin_file_spec.GetFileNameExtension() != g_dylibext && 478 plugin_file_spec.GetFileNameExtension() != g_solibext) 479 { 480 return FileSpec::eEnumerateDirectoryResultNext; 481 } 482 483 Error plugin_load_error; 484 debugger->LoadPlugin (plugin_file_spec, plugin_load_error); 485 486 return FileSpec::eEnumerateDirectoryResultNext; 487 } 488 489 else if (file_type == FileSpec::eFileTypeUnknown || 490 file_type == FileSpec::eFileTypeDirectory || 491 file_type == FileSpec::eFileTypeSymbolicLink ) 492 { 493 // Try and recurse into anything that a directory or symbolic link. 494 // We must also do this for unknown as sometimes the directory enumeration 495 // might be enumerating a file system that doesn't have correct file type 496 // information. 497 return FileSpec::eEnumerateDirectoryResultEnter; 498 } 499 500 return FileSpec::eEnumerateDirectoryResultNext; 501 } 502 503 void 504 Debugger::InstanceInitialize () 505 { 506 FileSpec dir_spec; 507 const bool find_directories = true; 508 const bool find_files = true; 509 const bool find_other = true; 510 char dir_path[PATH_MAX]; 511 if (HostInfo::GetLLDBPath(ePathTypeLLDBSystemPlugins, dir_spec)) 512 { 513 if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) 514 { 515 FileSpec::EnumerateDirectory (dir_path, 516 find_directories, 517 find_files, 518 find_other, 519 LoadPluginCallback, 520 this); 521 } 522 } 523 524 if (HostInfo::GetLLDBPath(ePathTypeLLDBUserPlugins, dir_spec)) 525 { 526 if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) 527 { 528 FileSpec::EnumerateDirectory (dir_path, 529 find_directories, 530 find_files, 531 find_other, 532 LoadPluginCallback, 533 this); 534 } 535 } 536 537 PluginManager::DebuggerInitialize (*this); 538 } 539 540 DebuggerSP 541 Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton) 542 { 543 DebuggerSP debugger_sp (new Debugger(log_callback, baton)); 544 if (g_shared_debugger_refcount > 0) 545 { 546 Mutex::Locker locker (GetDebuggerListMutex ()); 547 GetDebuggerList().push_back(debugger_sp); 548 } 549 debugger_sp->InstanceInitialize (); 550 return debugger_sp; 551 } 552 553 void 554 Debugger::Destroy (DebuggerSP &debugger_sp) 555 { 556 if (debugger_sp.get() == NULL) 557 return; 558 559 debugger_sp->Clear(); 560 561 if (g_shared_debugger_refcount > 0) 562 { 563 Mutex::Locker locker (GetDebuggerListMutex ()); 564 DebuggerList &debugger_list = GetDebuggerList (); 565 DebuggerList::iterator pos, end = debugger_list.end(); 566 for (pos = debugger_list.begin (); pos != end; ++pos) 567 { 568 if ((*pos).get() == debugger_sp.get()) 569 { 570 debugger_list.erase (pos); 571 return; 572 } 573 } 574 } 575 } 576 577 DebuggerSP 578 Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name) 579 { 580 DebuggerSP debugger_sp; 581 if (g_shared_debugger_refcount > 0) 582 { 583 Mutex::Locker locker (GetDebuggerListMutex ()); 584 DebuggerList &debugger_list = GetDebuggerList(); 585 DebuggerList::iterator pos, end = debugger_list.end(); 586 587 for (pos = debugger_list.begin(); pos != end; ++pos) 588 { 589 if ((*pos).get()->m_instance_name == instance_name) 590 { 591 debugger_sp = *pos; 592 break; 593 } 594 } 595 } 596 return debugger_sp; 597 } 598 599 TargetSP 600 Debugger::FindTargetWithProcessID (lldb::pid_t pid) 601 { 602 TargetSP target_sp; 603 if (g_shared_debugger_refcount > 0) 604 { 605 Mutex::Locker locker (GetDebuggerListMutex ()); 606 DebuggerList &debugger_list = GetDebuggerList(); 607 DebuggerList::iterator pos, end = debugger_list.end(); 608 for (pos = debugger_list.begin(); pos != end; ++pos) 609 { 610 target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid); 611 if (target_sp) 612 break; 613 } 614 } 615 return target_sp; 616 } 617 618 TargetSP 619 Debugger::FindTargetWithProcess (Process *process) 620 { 621 TargetSP target_sp; 622 if (g_shared_debugger_refcount > 0) 623 { 624 Mutex::Locker locker (GetDebuggerListMutex ()); 625 DebuggerList &debugger_list = GetDebuggerList(); 626 DebuggerList::iterator pos, end = debugger_list.end(); 627 for (pos = debugger_list.begin(); pos != end; ++pos) 628 { 629 target_sp = (*pos)->GetTargetList().FindTargetWithProcess (process); 630 if (target_sp) 631 break; 632 } 633 } 634 return target_sp; 635 } 636 637 Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : 638 UserID(g_unique_id++), 639 Properties(OptionValuePropertiesSP(new OptionValueProperties())), 640 m_input_file_sp(new StreamFile(stdin, false)), 641 m_output_file_sp(new StreamFile(stdout, false)), 642 m_error_file_sp(new StreamFile(stderr, false)), 643 m_terminal_state(), 644 m_target_list(*this), 645 m_platform_list(), 646 m_listener("lldb.Debugger"), 647 m_source_manager_ap(), 648 m_source_file_cache(), 649 m_command_interpreter_ap(new CommandInterpreter(*this, eScriptLanguageDefault, false)), 650 m_input_reader_stack(), 651 m_instance_name(), 652 m_loaded_plugins() 653 { 654 char instance_cstr[256]; 655 snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); 656 m_instance_name.SetCString(instance_cstr); 657 if (log_callback) 658 m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton)); 659 m_command_interpreter_ap->Initialize (); 660 // Always add our default platform to the platform list 661 PlatformSP default_platform_sp (Platform::GetHostPlatform()); 662 assert (default_platform_sp.get()); 663 m_platform_list.Append (default_platform_sp, true); 664 665 m_collection_sp->Initialize (g_properties); 666 m_collection_sp->AppendProperty (ConstString("target"), 667 ConstString("Settings specify to debugging targets."), 668 true, 669 Target::GetGlobalProperties()->GetValueProperties()); 670 if (m_command_interpreter_ap.get()) 671 { 672 m_collection_sp->AppendProperty (ConstString("interpreter"), 673 ConstString("Settings specify to the debugger's command interpreter."), 674 true, 675 m_command_interpreter_ap->GetValueProperties()); 676 } 677 OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64 (NULL, ePropertyTerminalWidth); 678 term_width->SetMinimumValue(10); 679 term_width->SetMaximumValue(1024); 680 681 // Turn off use-color if this is a dumb terminal. 682 const char *term = getenv ("TERM"); 683 if (term && !strcmp (term, "dumb")) 684 SetUseColor (false); 685 } 686 687 Debugger::~Debugger () 688 { 689 Clear(); 690 } 691 692 void 693 Debugger::Clear() 694 { 695 ClearIOHandlers(); 696 StopIOHandlerThread(); 697 StopEventHandlerThread(); 698 m_listener.Clear(); 699 int num_targets = m_target_list.GetNumTargets(); 700 for (int i = 0; i < num_targets; i++) 701 { 702 TargetSP target_sp (m_target_list.GetTargetAtIndex (i)); 703 if (target_sp) 704 { 705 ProcessSP process_sp (target_sp->GetProcessSP()); 706 if (process_sp) 707 process_sp->Finalize(); 708 target_sp->Destroy(); 709 } 710 } 711 BroadcasterManager::Clear (); 712 713 // Close the input file _before_ we close the input read communications class 714 // as it does NOT own the input file, our m_input_file does. 715 m_terminal_state.Clear(); 716 if (m_input_file_sp) 717 m_input_file_sp->GetFile().Close (); 718 719 m_command_interpreter_ap->Clear(); 720 } 721 722 bool 723 Debugger::GetCloseInputOnEOF () const 724 { 725 // return m_input_comm.GetCloseOnEOF(); 726 return false; 727 } 728 729 void 730 Debugger::SetCloseInputOnEOF (bool b) 731 { 732 // m_input_comm.SetCloseOnEOF(b); 733 } 734 735 bool 736 Debugger::GetAsyncExecution () 737 { 738 return !m_command_interpreter_ap->GetSynchronous(); 739 } 740 741 void 742 Debugger::SetAsyncExecution (bool async_execution) 743 { 744 m_command_interpreter_ap->SetSynchronous (!async_execution); 745 } 746 747 748 void 749 Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership) 750 { 751 if (m_input_file_sp) 752 m_input_file_sp->GetFile().SetStream (fh, tranfer_ownership); 753 else 754 m_input_file_sp.reset (new StreamFile (fh, tranfer_ownership)); 755 756 File &in_file = m_input_file_sp->GetFile(); 757 if (in_file.IsValid() == false) 758 in_file.SetStream (stdin, true); 759 760 // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState. 761 SaveInputTerminalState (); 762 } 763 764 void 765 Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership) 766 { 767 if (m_output_file_sp) 768 m_output_file_sp->GetFile().SetStream (fh, tranfer_ownership); 769 else 770 m_output_file_sp.reset (new StreamFile (fh, tranfer_ownership)); 771 772 File &out_file = m_output_file_sp->GetFile(); 773 if (out_file.IsValid() == false) 774 out_file.SetStream (stdout, false); 775 776 // do not create the ScriptInterpreter just for setting the output file handle 777 // as the constructor will know how to do the right thing on its own 778 const bool can_create = false; 779 ScriptInterpreter* script_interpreter = GetCommandInterpreter().GetScriptInterpreter(can_create); 780 if (script_interpreter) 781 script_interpreter->ResetOutputFileHandle (fh); 782 } 783 784 void 785 Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership) 786 { 787 if (m_error_file_sp) 788 m_error_file_sp->GetFile().SetStream (fh, tranfer_ownership); 789 else 790 m_error_file_sp.reset (new StreamFile (fh, tranfer_ownership)); 791 792 File &err_file = m_error_file_sp->GetFile(); 793 if (err_file.IsValid() == false) 794 err_file.SetStream (stderr, false); 795 } 796 797 void 798 Debugger::SaveInputTerminalState () 799 { 800 if (m_input_file_sp) 801 { 802 File &in_file = m_input_file_sp->GetFile(); 803 if (in_file.GetDescriptor() != File::kInvalidDescriptor) 804 m_terminal_state.Save(in_file.GetDescriptor(), true); 805 } 806 } 807 808 void 809 Debugger::RestoreInputTerminalState () 810 { 811 m_terminal_state.Restore(); 812 } 813 814 ExecutionContext 815 Debugger::GetSelectedExecutionContext () 816 { 817 ExecutionContext exe_ctx; 818 TargetSP target_sp(GetSelectedTarget()); 819 exe_ctx.SetTargetSP (target_sp); 820 821 if (target_sp) 822 { 823 ProcessSP process_sp (target_sp->GetProcessSP()); 824 exe_ctx.SetProcessSP (process_sp); 825 if (process_sp && process_sp->IsRunning() == false) 826 { 827 ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread()); 828 if (thread_sp) 829 { 830 exe_ctx.SetThreadSP (thread_sp); 831 exe_ctx.SetFrameSP (thread_sp->GetSelectedFrame()); 832 if (exe_ctx.GetFramePtr() == NULL) 833 exe_ctx.SetFrameSP (thread_sp->GetStackFrameAtIndex (0)); 834 } 835 } 836 } 837 return exe_ctx; 838 } 839 840 void 841 Debugger::DispatchInputInterrupt () 842 { 843 Mutex::Locker locker (m_input_reader_stack.GetMutex()); 844 IOHandlerSP reader_sp (m_input_reader_stack.Top()); 845 if (reader_sp) 846 reader_sp->Interrupt(); 847 } 848 849 void 850 Debugger::DispatchInputEndOfFile () 851 { 852 Mutex::Locker locker (m_input_reader_stack.GetMutex()); 853 IOHandlerSP reader_sp (m_input_reader_stack.Top()); 854 if (reader_sp) 855 reader_sp->GotEOF(); 856 } 857 858 void 859 Debugger::ClearIOHandlers () 860 { 861 // The bottom input reader should be the main debugger input reader. We do not want to close that one here. 862 Mutex::Locker locker (m_input_reader_stack.GetMutex()); 863 while (m_input_reader_stack.GetSize() > 1) 864 { 865 IOHandlerSP reader_sp (m_input_reader_stack.Top()); 866 if (reader_sp) 867 { 868 m_input_reader_stack.Pop(); 869 reader_sp->SetIsDone(true); 870 reader_sp->Cancel(); 871 } 872 } 873 } 874 875 void 876 Debugger::ExecuteIOHanders() 877 { 878 879 while (1) 880 { 881 IOHandlerSP reader_sp(m_input_reader_stack.Top()); 882 if (!reader_sp) 883 break; 884 885 reader_sp->Activate(); 886 reader_sp->Run(); 887 reader_sp->Deactivate(); 888 889 // Remove all input readers that are done from the top of the stack 890 while (1) 891 { 892 IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); 893 if (top_reader_sp && top_reader_sp->GetIsDone()) 894 m_input_reader_stack.Pop(); 895 else 896 break; 897 } 898 } 899 ClearIOHandlers(); 900 } 901 902 bool 903 Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp) 904 { 905 return m_input_reader_stack.IsTop (reader_sp); 906 } 907 908 909 ConstString 910 Debugger::GetTopIOHandlerControlSequence(char ch) 911 { 912 return m_input_reader_stack.GetTopIOHandlerControlSequence (ch); 913 } 914 915 void 916 Debugger::RunIOHandler (const IOHandlerSP& reader_sp) 917 { 918 PushIOHandler (reader_sp); 919 920 IOHandlerSP top_reader_sp = reader_sp; 921 while (top_reader_sp) 922 { 923 top_reader_sp->Activate(); 924 top_reader_sp->Run(); 925 top_reader_sp->Deactivate(); 926 927 if (top_reader_sp.get() == reader_sp.get()) 928 { 929 if (PopIOHandler (reader_sp)) 930 break; 931 } 932 933 while (1) 934 { 935 top_reader_sp = m_input_reader_stack.Top(); 936 if (top_reader_sp && top_reader_sp->GetIsDone()) 937 m_input_reader_stack.Pop(); 938 else 939 break; 940 } 941 } 942 } 943 944 void 945 Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, StreamFileSP &err) 946 { 947 // Before an IOHandler runs, it must have in/out/err streams. 948 // This function is called when one ore more of the streams 949 // are NULL. We use the top input reader's in/out/err streams, 950 // or fall back to the debugger file handles, or we fall back 951 // onto stdin/stdout/stderr as a last resort. 952 953 Mutex::Locker locker (m_input_reader_stack.GetMutex()); 954 IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); 955 // If no STDIN has been set, then set it appropriately 956 if (!in) 957 { 958 if (top_reader_sp) 959 in = top_reader_sp->GetInputStreamFile(); 960 else 961 in = GetInputFile(); 962 963 // If there is nothing, use stdin 964 if (!in) 965 in = StreamFileSP(new StreamFile(stdin, false)); 966 } 967 // If no STDOUT has been set, then set it appropriately 968 if (!out) 969 { 970 if (top_reader_sp) 971 out = top_reader_sp->GetOutputStreamFile(); 972 else 973 out = GetOutputFile(); 974 975 // If there is nothing, use stdout 976 if (!out) 977 out = StreamFileSP(new StreamFile(stdout, false)); 978 } 979 // If no STDERR has been set, then set it appropriately 980 if (!err) 981 { 982 if (top_reader_sp) 983 err = top_reader_sp->GetErrorStreamFile(); 984 else 985 err = GetErrorFile(); 986 987 // If there is nothing, use stderr 988 if (!err) 989 err = StreamFileSP(new StreamFile(stdout, false)); 990 991 } 992 } 993 994 void 995 Debugger::PushIOHandler (const IOHandlerSP& reader_sp) 996 { 997 if (!reader_sp) 998 return; 999 1000 // Got the current top input reader... 1001 IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); 1002 1003 // Don't push the same IO handler twice... 1004 if (reader_sp.get() != top_reader_sp.get()) 1005 { 1006 // Push our new input reader 1007 m_input_reader_stack.Push (reader_sp); 1008 1009 // Interrupt the top input reader to it will exit its Run() function 1010 // and let this new input reader take over 1011 if (top_reader_sp) 1012 top_reader_sp->Deactivate(); 1013 } 1014 } 1015 1016 bool 1017 Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) 1018 { 1019 bool result = false; 1020 1021 Mutex::Locker locker (m_input_reader_stack.GetMutex()); 1022 1023 // The reader on the stop of the stack is done, so let the next 1024 // read on the stack refresh its prompt and if there is one... 1025 if (!m_input_reader_stack.IsEmpty()) 1026 { 1027 IOHandlerSP reader_sp(m_input_reader_stack.Top()); 1028 1029 if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get()) 1030 { 1031 reader_sp->Deactivate(); 1032 reader_sp->Cancel(); 1033 m_input_reader_stack.Pop (); 1034 1035 reader_sp = m_input_reader_stack.Top(); 1036 if (reader_sp) 1037 reader_sp->Activate(); 1038 1039 result = true; 1040 } 1041 } 1042 return result; 1043 } 1044 1045 bool 1046 Debugger::HideTopIOHandler() 1047 { 1048 Mutex::Locker locker; 1049 1050 if (locker.TryLock(m_input_reader_stack.GetMutex())) 1051 { 1052 IOHandlerSP reader_sp(m_input_reader_stack.Top()); 1053 if (reader_sp) 1054 reader_sp->Hide(); 1055 return true; 1056 } 1057 return false; 1058 } 1059 1060 void 1061 Debugger::RefreshTopIOHandler() 1062 { 1063 IOHandlerSP reader_sp(m_input_reader_stack.Top()); 1064 if (reader_sp) 1065 reader_sp->Refresh(); 1066 } 1067 1068 1069 StreamSP 1070 Debugger::GetAsyncOutputStream () 1071 { 1072 return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(), 1073 CommandInterpreter::eBroadcastBitAsynchronousOutputData)); 1074 } 1075 1076 StreamSP 1077 Debugger::GetAsyncErrorStream () 1078 { 1079 return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(), 1080 CommandInterpreter::eBroadcastBitAsynchronousErrorData)); 1081 } 1082 1083 size_t 1084 Debugger::GetNumDebuggers() 1085 { 1086 if (g_shared_debugger_refcount > 0) 1087 { 1088 Mutex::Locker locker (GetDebuggerListMutex ()); 1089 return GetDebuggerList().size(); 1090 } 1091 return 0; 1092 } 1093 1094 lldb::DebuggerSP 1095 Debugger::GetDebuggerAtIndex (size_t index) 1096 { 1097 DebuggerSP debugger_sp; 1098 1099 if (g_shared_debugger_refcount > 0) 1100 { 1101 Mutex::Locker locker (GetDebuggerListMutex ()); 1102 DebuggerList &debugger_list = GetDebuggerList(); 1103 1104 if (index < debugger_list.size()) 1105 debugger_sp = debugger_list[index]; 1106 } 1107 1108 return debugger_sp; 1109 } 1110 1111 DebuggerSP 1112 Debugger::FindDebuggerWithID (lldb::user_id_t id) 1113 { 1114 DebuggerSP debugger_sp; 1115 1116 if (g_shared_debugger_refcount > 0) 1117 { 1118 Mutex::Locker locker (GetDebuggerListMutex ()); 1119 DebuggerList &debugger_list = GetDebuggerList(); 1120 DebuggerList::iterator pos, end = debugger_list.end(); 1121 for (pos = debugger_list.begin(); pos != end; ++pos) 1122 { 1123 if ((*pos).get()->GetID() == id) 1124 { 1125 debugger_sp = *pos; 1126 break; 1127 } 1128 } 1129 } 1130 return debugger_sp; 1131 } 1132 1133 #if 0 1134 static void 1135 TestPromptFormats (StackFrame *frame) 1136 { 1137 if (frame == NULL) 1138 return; 1139 1140 StreamString s; 1141 const char *prompt_format = 1142 "{addr = '${addr}'\n}" 1143 "{addr-file-or-load = '${addr-file-or-load}'\n}" 1144 "{current-pc-arrow = '${current-pc-arrow}'\n}" 1145 "{process.id = '${process.id}'\n}" 1146 "{process.name = '${process.name}'\n}" 1147 "{process.file.basename = '${process.file.basename}'\n}" 1148 "{process.file.fullpath = '${process.file.fullpath}'\n}" 1149 "{thread.id = '${thread.id}'\n}" 1150 "{thread.index = '${thread.index}'\n}" 1151 "{thread.name = '${thread.name}'\n}" 1152 "{thread.queue = '${thread.queue}'\n}" 1153 "{thread.stop-reason = '${thread.stop-reason}'\n}" 1154 "{target.arch = '${target.arch}'\n}" 1155 "{module.file.basename = '${module.file.basename}'\n}" 1156 "{module.file.fullpath = '${module.file.fullpath}'\n}" 1157 "{file.basename = '${file.basename}'\n}" 1158 "{file.fullpath = '${file.fullpath}'\n}" 1159 "{frame.index = '${frame.index}'\n}" 1160 "{frame.pc = '${frame.pc}'\n}" 1161 "{frame.sp = '${frame.sp}'\n}" 1162 "{frame.fp = '${frame.fp}'\n}" 1163 "{frame.flags = '${frame.flags}'\n}" 1164 "{frame.reg.rdi = '${frame.reg.rdi}'\n}" 1165 "{frame.reg.rip = '${frame.reg.rip}'\n}" 1166 "{frame.reg.rsp = '${frame.reg.rsp}'\n}" 1167 "{frame.reg.rbp = '${frame.reg.rbp}'\n}" 1168 "{frame.reg.rflags = '${frame.reg.rflags}'\n}" 1169 "{frame.reg.xmm0 = '${frame.reg.xmm0}'\n}" 1170 "{frame.reg.carp = '${frame.reg.carp}'\n}" 1171 "{function.id = '${function.id}'\n}" 1172 "{function.changed = '${function.changed}'\n}" 1173 "{function.initial-function = '${function.initial-function}'\n}" 1174 "{function.name = '${function.name}'\n}" 1175 "{function.name-without-args = '${function.name-without-args}'\n}" 1176 "{function.name-with-args = '${function.name-with-args}'\n}" 1177 "{function.addr-offset = '${function.addr-offset}'\n}" 1178 "{function.concrete-only-addr-offset-no-padding = '${function.concrete-only-addr-offset-no-padding}'\n}" 1179 "{function.line-offset = '${function.line-offset}'\n}" 1180 "{function.pc-offset = '${function.pc-offset}'\n}" 1181 "{line.file.basename = '${line.file.basename}'\n}" 1182 "{line.file.fullpath = '${line.file.fullpath}'\n}" 1183 "{line.number = '${line.number}'\n}" 1184 "{line.start-addr = '${line.start-addr}'\n}" 1185 "{line.end-addr = '${line.end-addr}'\n}" 1186 ; 1187 1188 SymbolContext sc (frame->GetSymbolContext(eSymbolContextEverything)); 1189 ExecutionContext exe_ctx; 1190 frame->CalculateExecutionContext(exe_ctx); 1191 if (Debugger::FormatPrompt (prompt_format, &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s)) 1192 { 1193 printf("%s\n", s.GetData()); 1194 } 1195 else 1196 { 1197 printf ("what we got: %s\n", s.GetData()); 1198 } 1199 } 1200 #endif 1201 1202 static bool 1203 ScanFormatDescriptor (const char* var_name_begin, 1204 const char* var_name_end, 1205 const char** var_name_final, 1206 const char** percent_position, 1207 Format* custom_format, 1208 ValueObject::ValueObjectRepresentationStyle* val_obj_display) 1209 { 1210 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); 1211 *percent_position = ::strchr(var_name_begin,'%'); 1212 if (!*percent_position || *percent_position > var_name_end) 1213 { 1214 if (log) 1215 log->Printf("[ScanFormatDescriptor] no format descriptor in string, skipping"); 1216 *var_name_final = var_name_end; 1217 } 1218 else 1219 { 1220 *var_name_final = *percent_position; 1221 std::string format_name(*var_name_final+1, var_name_end-*var_name_final-1); 1222 if (log) 1223 log->Printf("[ScanFormatDescriptor] parsing %s as a format descriptor", format_name.c_str()); 1224 if ( !FormatManager::GetFormatFromCString(format_name.c_str(), 1225 true, 1226 *custom_format) ) 1227 { 1228 if (log) 1229 log->Printf("[ScanFormatDescriptor] %s is an unknown format", format_name.c_str()); 1230 1231 switch (format_name.front()) 1232 { 1233 case '@': // if this is an @ sign, print ObjC description 1234 *val_obj_display = ValueObject::eValueObjectRepresentationStyleLanguageSpecific; 1235 break; 1236 case 'V': // if this is a V, print the value using the default format 1237 *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 1238 break; 1239 case 'L': // if this is an L, print the location of the value 1240 *val_obj_display = ValueObject::eValueObjectRepresentationStyleLocation; 1241 break; 1242 case 'S': // if this is an S, print the summary after all 1243 *val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; 1244 break; 1245 case '#': // if this is a '#', print the number of children 1246 *val_obj_display = ValueObject::eValueObjectRepresentationStyleChildrenCount; 1247 break; 1248 case 'T': // if this is a 'T', print the type 1249 *val_obj_display = ValueObject::eValueObjectRepresentationStyleType; 1250 break; 1251 case 'N': // if this is a 'N', print the name 1252 *val_obj_display = ValueObject::eValueObjectRepresentationStyleName; 1253 break; 1254 case '>': // if this is a '>', print the name 1255 *val_obj_display = ValueObject::eValueObjectRepresentationStyleExpressionPath; 1256 break; 1257 default: 1258 if (log) 1259 log->Printf("ScanFormatDescriptor] %s is an error, leaving the previous value alone", format_name.c_str()); 1260 break; 1261 } 1262 } 1263 // a good custom format tells us to print the value using it 1264 else 1265 { 1266 if (log) 1267 log->Printf("[ScanFormatDescriptor] will display value for this VO"); 1268 *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 1269 } 1270 } 1271 if (log) 1272 log->Printf("[ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d", 1273 *custom_format, 1274 *val_obj_display); 1275 return true; 1276 } 1277 1278 static bool 1279 ScanBracketedRange (const char* var_name_begin, 1280 const char* var_name_end, 1281 const char* var_name_final, 1282 const char** open_bracket_position, 1283 const char** separator_position, 1284 const char** close_bracket_position, 1285 const char** var_name_final_if_array_range, 1286 int64_t* index_lower, 1287 int64_t* index_higher) 1288 { 1289 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); 1290 *open_bracket_position = ::strchr(var_name_begin,'['); 1291 if (*open_bracket_position && *open_bracket_position < var_name_final) 1292 { 1293 *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield 1294 *close_bracket_position = ::strchr(*open_bracket_position,']'); 1295 // as usual, we assume that [] will come before % 1296 //printf("trying to expand a []\n"); 1297 *var_name_final_if_array_range = *open_bracket_position; 1298 if (*close_bracket_position - *open_bracket_position == 1) 1299 { 1300 if (log) 1301 log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data"); 1302 *index_lower = 0; 1303 } 1304 else if (*separator_position == NULL || *separator_position > var_name_end) 1305 { 1306 char *end = NULL; 1307 *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); 1308 *index_higher = *index_lower; 1309 if (log) 1310 log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", *index_lower); 1311 } 1312 else if (*close_bracket_position && *close_bracket_position < var_name_end) 1313 { 1314 char *end = NULL; 1315 *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); 1316 *index_higher = ::strtoul (*separator_position+1, &end, 0); 1317 if (log) 1318 log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", *index_lower, *index_higher); 1319 } 1320 else 1321 { 1322 if (log) 1323 log->Printf("[ScanBracketedRange] expression is erroneous, cannot extract indices out of it"); 1324 return false; 1325 } 1326 if (*index_lower > *index_higher && *index_higher > 0) 1327 { 1328 if (log) 1329 log->Printf("[ScanBracketedRange] swapping indices"); 1330 int64_t temp = *index_lower; 1331 *index_lower = *index_higher; 1332 *index_higher = temp; 1333 } 1334 } 1335 else if (log) 1336 log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely"); 1337 return true; 1338 } 1339 1340 template <typename T> 1341 static bool RunScriptFormatKeyword(Stream &s, ScriptInterpreter *script_interpreter, T t, const std::string& script_name) 1342 { 1343 if (script_interpreter) 1344 { 1345 Error script_error; 1346 std::string script_output; 1347 1348 if (script_interpreter->RunScriptFormatKeyword(script_name.c_str(), t, script_output, script_error) && script_error.Success()) 1349 { 1350 s.Printf("%s", script_output.c_str()); 1351 return true; 1352 } 1353 else 1354 { 1355 s.Printf("<error: %s>",script_error.AsCString()); 1356 } 1357 } 1358 return false; 1359 } 1360 1361 static ValueObjectSP 1362 ExpandIndexedExpression (ValueObject* valobj, 1363 size_t index, 1364 StackFrame* frame, 1365 bool deref_pointer) 1366 { 1367 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); 1368 const char* ptr_deref_format = "[%d]"; 1369 std::string ptr_deref_buffer(10,0); 1370 ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index); 1371 if (log) 1372 log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str()); 1373 const char* first_unparsed; 1374 ValueObject::GetValueForExpressionPathOptions options; 1375 ValueObject::ExpressionPathEndResultType final_value_type; 1376 ValueObject::ExpressionPathScanEndReason reason_to_stop; 1377 ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); 1378 ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(), 1379 &first_unparsed, 1380 &reason_to_stop, 1381 &final_value_type, 1382 options, 1383 &what_next); 1384 if (!item) 1385 { 1386 if (log) 1387 log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d," 1388 " final_value_type %d", 1389 first_unparsed, reason_to_stop, final_value_type); 1390 } 1391 else 1392 { 1393 if (log) 1394 log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d," 1395 " final_value_type %d", 1396 first_unparsed, reason_to_stop, final_value_type); 1397 } 1398 return item; 1399 } 1400 1401 static inline bool 1402 IsToken(const char *var_name_begin, const char *var) 1403 { 1404 return (::strncmp (var_name_begin, var, strlen(var)) == 0); 1405 } 1406 1407 static bool 1408 IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &format, const char *default_format, 1409 const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr) 1410 { 1411 int var_len = strlen(var); 1412 if (::strncmp (var_name_begin, var, var_len) == 0) 1413 { 1414 var_name_begin += var_len; 1415 if (*var_name_begin == '}') 1416 { 1417 format = default_format; 1418 return true; 1419 } 1420 else if (*var_name_begin == '%') 1421 { 1422 // Allow format specifiers: x|X|u with optional width specifiers. 1423 // ${thread.id%x} ; hex 1424 // ${thread.id%X} ; uppercase hex 1425 // ${thread.id%u} ; unsigned decimal 1426 // ${thread.id%8.8X} ; width.precision + specifier 1427 // ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id) 1428 int dot_count = 0; 1429 const char *specifier = NULL; 1430 int width_precision_length = 0; 1431 const char *width_precision = ++var_name_begin; 1432 while (isdigit(*var_name_begin) || *var_name_begin == '.') 1433 { 1434 dot_count += (*var_name_begin == '.'); 1435 if (dot_count > 1) 1436 break; 1437 var_name_begin++; 1438 width_precision_length++; 1439 } 1440 1441 if (IsToken (var_name_begin, "tid}")) 1442 { 1443 Target *target = Target::GetTargetFromContexts (exe_ctx_ptr, sc_ptr); 1444 if (target) 1445 { 1446 ArchSpec arch (target->GetArchitecture ()); 1447 llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS; 1448 if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux)) 1449 specifier = PRIu64; 1450 } 1451 if (!specifier) 1452 { 1453 format = default_format; 1454 return true; 1455 } 1456 } 1457 else if (IsToken (var_name_begin, "x}")) 1458 specifier = PRIx64; 1459 else if (IsToken (var_name_begin, "X}")) 1460 specifier = PRIX64; 1461 else if (IsToken (var_name_begin, "u}")) 1462 specifier = PRIu64; 1463 1464 if (specifier) 1465 { 1466 format = "%"; 1467 if (width_precision_length) 1468 format += std::string(width_precision, width_precision_length); 1469 format += specifier; 1470 return true; 1471 } 1472 } 1473 } 1474 return false; 1475 } 1476 1477 // Find information for the "thread.info.*" specifiers in a format string 1478 static bool 1479 FormatThreadExtendedInfoRecurse 1480 ( 1481 const char *var_name_begin, 1482 StructuredData::ObjectSP thread_info_dictionary, 1483 const SymbolContext *sc, 1484 const ExecutionContext *exe_ctx, 1485 Stream &s 1486 ) 1487 { 1488 bool var_success = false; 1489 std::string token_format; 1490 1491 llvm::StringRef var_name(var_name_begin); 1492 size_t percent_idx = var_name.find('%'); 1493 size_t close_curly_idx = var_name.find('}'); 1494 llvm::StringRef path = var_name; 1495 llvm::StringRef formatter = var_name; 1496 1497 // 'path' will be the dot separated list of objects to transverse up until we hit 1498 // a close curly brace, a percent sign, or an end of string. 1499 if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos) 1500 { 1501 if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos) 1502 { 1503 if (percent_idx < close_curly_idx) 1504 { 1505 path = var_name.slice(0, percent_idx); 1506 formatter = var_name.substr (percent_idx); 1507 } 1508 else 1509 { 1510 path = var_name.slice(0, close_curly_idx); 1511 formatter = var_name.substr (close_curly_idx); 1512 } 1513 } 1514 else if (percent_idx != llvm::StringRef::npos) 1515 { 1516 path = var_name.slice(0, percent_idx); 1517 formatter = var_name.substr (percent_idx); 1518 } 1519 else if (close_curly_idx != llvm::StringRef::npos) 1520 { 1521 path = var_name.slice(0, close_curly_idx); 1522 formatter = var_name.substr (close_curly_idx); 1523 } 1524 } 1525 1526 StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path); 1527 1528 if (value.get()) 1529 { 1530 if (value->GetType() == StructuredData::Type::eTypeInteger) 1531 { 1532 if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) 1533 { 1534 s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue()); 1535 var_success = true; 1536 } 1537 } 1538 else if (value->GetType() == StructuredData::Type::eTypeFloat) 1539 { 1540 s.Printf ("%f", value->GetAsFloat()->GetValue()); 1541 var_success = true; 1542 } 1543 else if (value->GetType() == StructuredData::Type::eTypeString) 1544 { 1545 s.Printf("%s", value->GetAsString()->GetValue().c_str()); 1546 var_success = true; 1547 } 1548 else if (value->GetType() == StructuredData::Type::eTypeArray) 1549 { 1550 if (value->GetAsArray()->GetSize() > 0) 1551 { 1552 s.Printf ("%zu", value->GetAsArray()->GetSize()); 1553 var_success = true; 1554 } 1555 } 1556 else if (value->GetType() == StructuredData::Type::eTypeDictionary) 1557 { 1558 s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); 1559 var_success = true; 1560 } 1561 } 1562 1563 return var_success; 1564 } 1565 1566 1567 static bool 1568 FormatPromptRecurse 1569 ( 1570 const char *format, 1571 const SymbolContext *sc, 1572 const ExecutionContext *exe_ctx, 1573 const Address *addr, 1574 Stream &s, 1575 const char **end, 1576 ValueObject* valobj, 1577 bool function_changed, 1578 bool initial_function 1579 ) 1580 { 1581 ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers 1582 bool success = true; 1583 const char *p; 1584 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); 1585 1586 for (p = format; *p != '\0'; ++p) 1587 { 1588 if (realvalobj) 1589 { 1590 valobj = realvalobj; 1591 realvalobj = NULL; 1592 } 1593 size_t non_special_chars = ::strcspn (p, "${}\\"); 1594 if (non_special_chars > 0) 1595 { 1596 if (success) 1597 s.Write (p, non_special_chars); 1598 p += non_special_chars; 1599 } 1600 1601 if (*p == '\0') 1602 { 1603 break; 1604 } 1605 else if (*p == '{') 1606 { 1607 // Start a new scope that must have everything it needs if it is to 1608 // to make it into the final output stream "s". If you want to make 1609 // a format that only prints out the function or symbol name if there 1610 // is one in the symbol context you can use: 1611 // "{function =${function.name}}" 1612 // The first '{' starts a new scope that end with the matching '}' at 1613 // the end of the string. The contents "function =${function.name}" 1614 // will then be evaluated and only be output if there is a function 1615 // or symbol with a valid name. 1616 StreamString sub_strm; 1617 1618 ++p; // Skip the '{' 1619 1620 if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj, function_changed, initial_function)) 1621 { 1622 // The stream had all it needed 1623 s.Write(sub_strm.GetData(), sub_strm.GetSize()); 1624 } 1625 if (*p != '}') 1626 { 1627 success = false; 1628 break; 1629 } 1630 } 1631 else if (*p == '}') 1632 { 1633 // End of a enclosing scope 1634 break; 1635 } 1636 else if (*p == '$') 1637 { 1638 // We have a prompt variable to print 1639 ++p; 1640 if (*p == '{') 1641 { 1642 ++p; 1643 const char *var_name_begin = p; 1644 const char *var_name_end = ::strchr (p, '}'); 1645 1646 if (var_name_end && var_name_begin < var_name_end) 1647 { 1648 // if we have already failed to parse, skip this variable 1649 if (success) 1650 { 1651 const char *cstr = NULL; 1652 std::string token_format; 1653 Address format_addr; 1654 1655 // normally "addr" means print a raw address but 1656 // "file-addr-or-load-addr" means print a module + file addr if there's no load addr 1657 bool print_file_addr_or_load_addr = false; 1658 bool addr_offset_concrete_func_only = false; 1659 bool addr_offset_print_with_no_padding = false; 1660 bool calculate_format_addr_function_offset = false; 1661 // Set reg_kind and reg_num to invalid values 1662 RegisterKind reg_kind = kNumRegisterKinds; 1663 uint32_t reg_num = LLDB_INVALID_REGNUM; 1664 FileSpec format_file_spec; 1665 const RegisterInfo *reg_info = NULL; 1666 RegisterContext *reg_ctx = NULL; 1667 bool do_deref_pointer = false; 1668 ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; 1669 ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain; 1670 1671 // Each variable must set success to true below... 1672 bool var_success = false; 1673 switch (var_name_begin[0]) 1674 { 1675 case '*': 1676 case 'v': 1677 case 's': 1678 { 1679 if (!valobj) 1680 break; 1681 1682 if (log) 1683 log->Printf("[Debugger::FormatPrompt] initial string: %s",var_name_begin); 1684 1685 // check for *var and *svar 1686 if (*var_name_begin == '*') 1687 { 1688 do_deref_pointer = true; 1689 var_name_begin++; 1690 if (log) 1691 log->Printf("[Debugger::FormatPrompt] found a deref, new string is: %s",var_name_begin); 1692 } 1693 1694 if (*var_name_begin == 's') 1695 { 1696 if (!valobj->IsSynthetic()) 1697 valobj = valobj->GetSyntheticValue().get(); 1698 if (!valobj) 1699 break; 1700 var_name_begin++; 1701 if (log) 1702 log->Printf("[Debugger::FormatPrompt] found a synthetic, new string is: %s",var_name_begin); 1703 } 1704 1705 // should be a 'v' by now 1706 if (*var_name_begin != 'v') 1707 break; 1708 1709 if (log) 1710 log->Printf("[Debugger::FormatPrompt] string I am working with: %s",var_name_begin); 1711 1712 ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? 1713 ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); 1714 ValueObject::GetValueForExpressionPathOptions options; 1715 options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren(); 1716 ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; 1717 ValueObject* target = NULL; 1718 Format custom_format = eFormatInvalid; 1719 const char* var_name_final = NULL; 1720 const char* var_name_final_if_array_range = NULL; 1721 const char* close_bracket_position = NULL; 1722 int64_t index_lower = -1; 1723 int64_t index_higher = -1; 1724 bool is_array_range = false; 1725 const char* first_unparsed; 1726 bool was_plain_var = false; 1727 bool was_var_format = false; 1728 bool was_var_indexed = false; 1729 1730 if (!valobj) break; 1731 // simplest case ${var}, just print valobj's value 1732 if (IsToken (var_name_begin, "var}")) 1733 { 1734 was_plain_var = true; 1735 target = valobj; 1736 val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 1737 } 1738 else if (IsToken (var_name_begin,"var%")) 1739 { 1740 was_var_format = true; 1741 // this is a variable with some custom format applied to it 1742 const char* percent_position; 1743 target = valobj; 1744 val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 1745 ScanFormatDescriptor (var_name_begin, 1746 var_name_end, 1747 &var_name_final, 1748 &percent_position, 1749 &custom_format, 1750 &val_obj_display); 1751 } 1752 // this is ${var.something} or multiple .something nested 1753 else if (IsToken (var_name_begin, "var")) 1754 { 1755 if (IsToken (var_name_begin, "var[")) 1756 was_var_indexed = true; 1757 const char* percent_position; 1758 ScanFormatDescriptor (var_name_begin, 1759 var_name_end, 1760 &var_name_final, 1761 &percent_position, 1762 &custom_format, 1763 &val_obj_display); 1764 1765 const char* open_bracket_position; 1766 const char* separator_position; 1767 ScanBracketedRange (var_name_begin, 1768 var_name_end, 1769 var_name_final, 1770 &open_bracket_position, 1771 &separator_position, 1772 &close_bracket_position, 1773 &var_name_final_if_array_range, 1774 &index_lower, 1775 &index_higher); 1776 1777 Error error; 1778 1779 std::string expr_path(var_name_final-var_name_begin-1,0); 1780 memcpy(&expr_path[0], var_name_begin+3,var_name_final-var_name_begin-3); 1781 1782 if (log) 1783 log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str()); 1784 1785 target = valobj->GetValueForExpressionPath(expr_path.c_str(), 1786 &first_unparsed, 1787 &reason_to_stop, 1788 &final_value_type, 1789 options, 1790 &what_next).get(); 1791 1792 if (!target) 1793 { 1794 if (log) 1795 log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d," 1796 " final_value_type %d", 1797 first_unparsed, reason_to_stop, final_value_type); 1798 break; 1799 } 1800 else 1801 { 1802 if (log) 1803 log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d," 1804 " final_value_type %d", 1805 first_unparsed, reason_to_stop, final_value_type); 1806 target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get(); 1807 } 1808 } 1809 else 1810 break; 1811 1812 is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange || 1813 final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange); 1814 1815 do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference); 1816 1817 if (do_deref_pointer && !is_array_range) 1818 { 1819 // I have not deref-ed yet, let's do it 1820 // this happens when we are not going through GetValueForVariableExpressionPath 1821 // to get to the target ValueObject 1822 Error error; 1823 target = target->Dereference(error).get(); 1824 if (error.Fail()) 1825 { 1826 if (log) 1827 log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \ 1828 break; 1829 } 1830 do_deref_pointer = false; 1831 } 1832 1833 if (!target) 1834 { 1835 if (log) 1836 log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression"); 1837 break; 1838 } 1839 1840 // we do not want to use the summary for a bitfield of type T:n 1841 // if we were originally dealing with just a T - that would get 1842 // us into an endless recursion 1843 if (target->IsBitfield() && was_var_indexed) 1844 { 1845 // TODO: check for a (T:n)-specific summary - we should still obey that 1846 StreamString bitfield_name; 1847 bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize()); 1848 lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false)); 1849 if (!DataVisualization::GetSummaryForType(type_sp)) 1850 val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; 1851 } 1852 1853 // TODO use flags for these 1854 const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL); 1855 bool is_array = (type_info_flags & eTypeIsArray) != 0; 1856 bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; 1857 bool is_aggregate = target->GetClangType().IsAggregateType(); 1858 1859 if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions 1860 { 1861 StreamString str_temp; 1862 if (log) 1863 log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range"); 1864 1865 if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format)) 1866 { 1867 // try to use the special cases 1868 var_success = target->DumpPrintableRepresentation(str_temp, 1869 val_obj_display, 1870 custom_format); 1871 if (log) 1872 log->Printf("[Debugger::FormatPrompt] special cases did%s match", var_success ? "" : "n't"); 1873 1874 // should not happen 1875 if (var_success) 1876 s << str_temp.GetData(); 1877 var_success = true; 1878 break; 1879 } 1880 else 1881 { 1882 if (was_plain_var) // if ${var} 1883 { 1884 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 1885 } 1886 else if (is_pointer) // if pointer, value is the address stored 1887 { 1888 target->DumpPrintableRepresentation (s, 1889 val_obj_display, 1890 custom_format, 1891 ValueObject::ePrintableRepresentationSpecialCasesDisable); 1892 } 1893 var_success = true; 1894 break; 1895 } 1896 } 1897 1898 // if directly trying to print ${var}, and this is an aggregate, display a nice 1899 // type @ location message 1900 if (is_aggregate && was_plain_var) 1901 { 1902 s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); 1903 var_success = true; 1904 break; 1905 } 1906 1907 // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it 1908 if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue))) 1909 { 1910 s << "<invalid use of aggregate type>"; 1911 var_success = true; 1912 break; 1913 } 1914 1915 if (!is_array_range) 1916 { 1917 if (log) 1918 log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output"); 1919 var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); 1920 } 1921 else 1922 { 1923 if (log) 1924 log->Printf("[Debugger::FormatPrompt] checking if I can handle as array"); 1925 if (!is_array && !is_pointer) 1926 break; 1927 if (log) 1928 log->Printf("[Debugger::FormatPrompt] handle as array"); 1929 const char* special_directions = NULL; 1930 StreamString special_directions_writer; 1931 if (close_bracket_position && (var_name_end-close_bracket_position > 1)) 1932 { 1933 ConstString additional_data; 1934 additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1); 1935 special_directions_writer.Printf("${%svar%s}", 1936 do_deref_pointer ? "*" : "", 1937 additional_data.GetCString()); 1938 special_directions = special_directions_writer.GetData(); 1939 } 1940 1941 // let us display items index_lower thru index_higher of this array 1942 s.PutChar('['); 1943 var_success = true; 1944 1945 if (index_higher < 0) 1946 index_higher = valobj->GetNumChildren() - 1; 1947 1948 uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 1949 1950 for (;index_lower<=index_higher;index_lower++) 1951 { 1952 ValueObject* item = ExpandIndexedExpression (target, 1953 index_lower, 1954 exe_ctx->GetFramePtr(), 1955 false).get(); 1956 1957 if (!item) 1958 { 1959 if (log) 1960 log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index_lower); 1961 } 1962 else 1963 { 1964 if (log) 1965 log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions); 1966 } 1967 1968 if (!special_directions) 1969 var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); 1970 else 1971 var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item, function_changed, initial_function); 1972 1973 if (--max_num_children == 0) 1974 { 1975 s.PutCString(", ..."); 1976 break; 1977 } 1978 1979 if (index_lower < index_higher) 1980 s.PutChar(','); 1981 } 1982 s.PutChar(']'); 1983 } 1984 } 1985 break; 1986 case 'a': 1987 if (IsToken (var_name_begin, "addr-file-or-load}")) 1988 { 1989 print_file_addr_or_load_addr = true; 1990 } 1991 if (IsToken (var_name_begin, "addr}") 1992 || IsToken (var_name_begin, "addr-file-or-load}")) 1993 { 1994 if (addr && addr->IsValid()) 1995 { 1996 var_success = true; 1997 format_addr = *addr; 1998 } 1999 } 2000 break; 2001 2002 case 'p': 2003 if (IsToken (var_name_begin, "process.")) 2004 { 2005 if (exe_ctx) 2006 { 2007 Process *process = exe_ctx->GetProcessPtr(); 2008 if (process) 2009 { 2010 var_name_begin += ::strlen ("process."); 2011 if (IsTokenWithFormat (var_name_begin, "id", token_format, "%" PRIu64, exe_ctx, sc)) 2012 { 2013 s.Printf(token_format.c_str(), process->GetID()); 2014 var_success = true; 2015 } 2016 else if ((IsToken (var_name_begin, "name}")) || 2017 (IsToken (var_name_begin, "file.basename}")) || 2018 (IsToken (var_name_begin, "file.fullpath}"))) 2019 { 2020 Module *exe_module = process->GetTarget().GetExecutableModulePointer(); 2021 if (exe_module) 2022 { 2023 if (var_name_begin[0] == 'n' || var_name_begin[5] == 'f') 2024 { 2025 format_file_spec.GetFilename() = exe_module->GetFileSpec().GetFilename(); 2026 var_success = (bool)format_file_spec; 2027 } 2028 else 2029 { 2030 format_file_spec = exe_module->GetFileSpec(); 2031 var_success = (bool)format_file_spec; 2032 } 2033 } 2034 } 2035 else if (IsToken (var_name_begin, "script:")) 2036 { 2037 var_name_begin += ::strlen("script:"); 2038 std::string script_name(var_name_begin,var_name_end); 2039 ScriptInterpreter* script_interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); 2040 if (RunScriptFormatKeyword (s, script_interpreter, process, script_name)) 2041 var_success = true; 2042 } 2043 } 2044 } 2045 } 2046 break; 2047 2048 case 't': 2049 if (IsToken (var_name_begin, "thread.")) 2050 { 2051 if (exe_ctx) 2052 { 2053 Thread *thread = exe_ctx->GetThreadPtr(); 2054 if (thread) 2055 { 2056 var_name_begin += ::strlen ("thread."); 2057 if (IsTokenWithFormat (var_name_begin, "id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) 2058 { 2059 s.Printf(token_format.c_str(), thread->GetID()); 2060 var_success = true; 2061 } 2062 else if (IsTokenWithFormat (var_name_begin, "protocol_id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) 2063 { 2064 s.Printf(token_format.c_str(), thread->GetProtocolID()); 2065 var_success = true; 2066 } 2067 else if (IsTokenWithFormat (var_name_begin, "index", token_format, "%" PRIu64, exe_ctx, sc)) 2068 { 2069 s.Printf(token_format.c_str(), (uint64_t)thread->GetIndexID()); 2070 var_success = true; 2071 } 2072 else if (IsToken (var_name_begin, "name}")) 2073 { 2074 cstr = thread->GetName(); 2075 var_success = cstr && cstr[0]; 2076 if (var_success) 2077 s.PutCString(cstr); 2078 } 2079 else if (IsToken (var_name_begin, "queue}")) 2080 { 2081 cstr = thread->GetQueueName(); 2082 var_success = cstr && cstr[0]; 2083 if (var_success) 2084 s.PutCString(cstr); 2085 } 2086 else if (IsToken (var_name_begin, "stop-reason}")) 2087 { 2088 StopInfoSP stop_info_sp = thread->GetStopInfo (); 2089 if (stop_info_sp && stop_info_sp->IsValid()) 2090 { 2091 cstr = stop_info_sp->GetDescription(); 2092 if (cstr && cstr[0]) 2093 { 2094 s.PutCString(cstr); 2095 var_success = true; 2096 } 2097 } 2098 } 2099 else if (IsToken (var_name_begin, "return-value}")) 2100 { 2101 StopInfoSP stop_info_sp = thread->GetStopInfo (); 2102 if (stop_info_sp && stop_info_sp->IsValid()) 2103 { 2104 ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); 2105 if (return_valobj_sp) 2106 { 2107 return_valobj_sp->Dump(s); 2108 var_success = true; 2109 } 2110 } 2111 } 2112 else if (IsToken (var_name_begin, "completed-expression}")) 2113 { 2114 StopInfoSP stop_info_sp = thread->GetStopInfo (); 2115 if (stop_info_sp && stop_info_sp->IsValid()) 2116 { 2117 ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp); 2118 if (expression_var_sp && expression_var_sp->GetValueObject()) 2119 { 2120 expression_var_sp->GetValueObject()->Dump(s); 2121 var_success = true; 2122 } 2123 } 2124 } 2125 else if (IsToken (var_name_begin, "script:")) 2126 { 2127 var_name_begin += ::strlen("script:"); 2128 std::string script_name(var_name_begin,var_name_end); 2129 ScriptInterpreter* script_interpreter = thread->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); 2130 if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name)) 2131 var_success = true; 2132 } 2133 else if (IsToken (var_name_begin, "info.")) 2134 { 2135 var_name_begin += ::strlen("info."); 2136 StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); 2137 if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary) 2138 { 2139 var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s); 2140 } 2141 } 2142 } 2143 } 2144 } 2145 else if (IsToken (var_name_begin, "target.")) 2146 { 2147 // TODO: hookup properties 2148 // if (!target_properties_sp) 2149 // { 2150 // Target *target = Target::GetTargetFromContexts (exe_ctx, sc); 2151 // if (target) 2152 // target_properties_sp = target->GetProperties(); 2153 // } 2154 // 2155 // if (target_properties_sp) 2156 // { 2157 // var_name_begin += ::strlen ("target."); 2158 // const char *end_property = strchr(var_name_begin, '}'); 2159 // if (end_property) 2160 // { 2161 // ConstString property_name(var_name_begin, end_property - var_name_begin); 2162 // std::string property_value (target_properties_sp->GetPropertyValue(property_name)); 2163 // if (!property_value.empty()) 2164 // { 2165 // s.PutCString (property_value.c_str()); 2166 // var_success = true; 2167 // } 2168 // } 2169 // } 2170 Target *target = Target::GetTargetFromContexts (exe_ctx, sc); 2171 if (target) 2172 { 2173 var_name_begin += ::strlen ("target."); 2174 if (IsToken (var_name_begin, "arch}")) 2175 { 2176 ArchSpec arch (target->GetArchitecture ()); 2177 if (arch.IsValid()) 2178 { 2179 s.PutCString (arch.GetArchitectureName()); 2180 var_success = true; 2181 } 2182 } 2183 else if (IsToken (var_name_begin, "script:")) 2184 { 2185 var_name_begin += ::strlen("script:"); 2186 std::string script_name(var_name_begin,var_name_end); 2187 ScriptInterpreter* script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); 2188 if (RunScriptFormatKeyword (s, script_interpreter, target, script_name)) 2189 var_success = true; 2190 } 2191 } 2192 } 2193 break; 2194 2195 case 'm': 2196 if (IsToken (var_name_begin, "module.")) 2197 { 2198 if (sc && sc->module_sp.get()) 2199 { 2200 Module *module = sc->module_sp.get(); 2201 var_name_begin += ::strlen ("module."); 2202 2203 if (IsToken (var_name_begin, "file.")) 2204 { 2205 if (module->GetFileSpec()) 2206 { 2207 var_name_begin += ::strlen ("file."); 2208 2209 if (IsToken (var_name_begin, "basename}")) 2210 { 2211 format_file_spec.GetFilename() = module->GetFileSpec().GetFilename(); 2212 var_success = (bool)format_file_spec; 2213 } 2214 else if (IsToken (var_name_begin, "fullpath}")) 2215 { 2216 format_file_spec = module->GetFileSpec(); 2217 var_success = (bool)format_file_spec; 2218 } 2219 } 2220 } 2221 } 2222 } 2223 break; 2224 2225 2226 case 'f': 2227 if (IsToken (var_name_begin, "file.")) 2228 { 2229 if (sc && sc->comp_unit != NULL) 2230 { 2231 var_name_begin += ::strlen ("file."); 2232 2233 if (IsToken (var_name_begin, "basename}")) 2234 { 2235 format_file_spec.GetFilename() = sc->comp_unit->GetFilename(); 2236 var_success = (bool)format_file_spec; 2237 } 2238 else if (IsToken (var_name_begin, "fullpath}")) 2239 { 2240 format_file_spec = *sc->comp_unit; 2241 var_success = (bool)format_file_spec; 2242 } 2243 } 2244 } 2245 else if (IsToken (var_name_begin, "frame.")) 2246 { 2247 if (exe_ctx) 2248 { 2249 StackFrame *frame = exe_ctx->GetFramePtr(); 2250 if (frame) 2251 { 2252 var_name_begin += ::strlen ("frame."); 2253 if (IsToken (var_name_begin, "index}")) 2254 { 2255 s.Printf("%u", frame->GetFrameIndex()); 2256 var_success = true; 2257 } 2258 else if (IsToken (var_name_begin, "pc}")) 2259 { 2260 reg_kind = eRegisterKindGeneric; 2261 reg_num = LLDB_REGNUM_GENERIC_PC; 2262 var_success = true; 2263 } 2264 else if (IsToken (var_name_begin, "sp}")) 2265 { 2266 reg_kind = eRegisterKindGeneric; 2267 reg_num = LLDB_REGNUM_GENERIC_SP; 2268 var_success = true; 2269 } 2270 else if (IsToken (var_name_begin, "fp}")) 2271 { 2272 reg_kind = eRegisterKindGeneric; 2273 reg_num = LLDB_REGNUM_GENERIC_FP; 2274 var_success = true; 2275 } 2276 else if (IsToken (var_name_begin, "flags}")) 2277 { 2278 reg_kind = eRegisterKindGeneric; 2279 reg_num = LLDB_REGNUM_GENERIC_FLAGS; 2280 var_success = true; 2281 } 2282 else if (IsToken (var_name_begin, "reg.")) 2283 { 2284 reg_ctx = frame->GetRegisterContext().get(); 2285 if (reg_ctx) 2286 { 2287 var_name_begin += ::strlen ("reg."); 2288 if (var_name_begin < var_name_end) 2289 { 2290 std::string reg_name (var_name_begin, var_name_end); 2291 reg_info = reg_ctx->GetRegisterInfoByName (reg_name.c_str()); 2292 if (reg_info) 2293 var_success = true; 2294 } 2295 } 2296 } 2297 else if (IsToken (var_name_begin, "script:")) 2298 { 2299 var_name_begin += ::strlen("script:"); 2300 std::string script_name(var_name_begin,var_name_end); 2301 ScriptInterpreter* script_interpreter = frame->GetThread()->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); 2302 if (RunScriptFormatKeyword (s, script_interpreter, frame, script_name)) 2303 var_success = true; 2304 } 2305 } 2306 } 2307 } 2308 else if (IsToken (var_name_begin, "function.")) 2309 { 2310 if (sc && (sc->function != NULL || sc->symbol != NULL)) 2311 { 2312 var_name_begin += ::strlen ("function."); 2313 if (IsToken (var_name_begin, "id}")) 2314 { 2315 if (sc->function) 2316 s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); 2317 else 2318 s.Printf("symbol[%u]", sc->symbol->GetID()); 2319 2320 var_success = true; 2321 } 2322 if (IsToken (var_name_begin, "changed}") && function_changed) 2323 { 2324 var_success = true; 2325 } 2326 if (IsToken (var_name_begin, "initial-function}") && initial_function) 2327 { 2328 var_success = true; 2329 } 2330 else if (IsToken (var_name_begin, "name}")) 2331 { 2332 if (sc->function) 2333 cstr = sc->function->GetName().AsCString (NULL); 2334 else if (sc->symbol) 2335 cstr = sc->symbol->GetName().AsCString (NULL); 2336 if (cstr) 2337 { 2338 s.PutCString(cstr); 2339 2340 if (sc->block) 2341 { 2342 Block *inline_block = sc->block->GetContainingInlinedBlock (); 2343 if (inline_block) 2344 { 2345 const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo(); 2346 if (inline_info) 2347 { 2348 s.PutCString(" [inlined] "); 2349 inline_info->GetName().Dump(&s); 2350 } 2351 } 2352 } 2353 var_success = true; 2354 } 2355 } 2356 else if (IsToken (var_name_begin, "name-without-args}")) 2357 { 2358 ConstString name; 2359 if (sc->function) 2360 name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); 2361 else if (sc->symbol) 2362 name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); 2363 if (name) 2364 { 2365 s.PutCString(name.GetCString()); 2366 var_success = true; 2367 } 2368 } 2369 else if (IsToken (var_name_begin, "name-with-args}")) 2370 { 2371 // Print the function name with arguments in it 2372 2373 if (sc->function) 2374 { 2375 var_success = true; 2376 ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; 2377 cstr = sc->function->GetName().AsCString (NULL); 2378 if (cstr) 2379 { 2380 const InlineFunctionInfo *inline_info = NULL; 2381 VariableListSP variable_list_sp; 2382 bool get_function_vars = true; 2383 if (sc->block) 2384 { 2385 Block *inline_block = sc->block->GetContainingInlinedBlock (); 2386 2387 if (inline_block) 2388 { 2389 get_function_vars = false; 2390 inline_info = sc->block->GetInlinedFunctionInfo(); 2391 if (inline_info) 2392 variable_list_sp = inline_block->GetBlockVariableList (true); 2393 } 2394 } 2395 2396 if (get_function_vars) 2397 { 2398 variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true); 2399 } 2400 2401 if (inline_info) 2402 { 2403 s.PutCString (cstr); 2404 s.PutCString (" [inlined] "); 2405 cstr = inline_info->GetName().GetCString(); 2406 } 2407 2408 VariableList args; 2409 if (variable_list_sp) 2410 variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args); 2411 if (args.GetSize() > 0) 2412 { 2413 const char *open_paren = strchr (cstr, '('); 2414 const char *close_paren = nullptr; 2415 const char *generic = strchr(cstr, '<'); 2416 // if before the arguments list begins there is a template sign 2417 // then scan to the end of the generic args before you try to find 2418 // the arguments list 2419 if (generic && open_paren && generic < open_paren) 2420 { 2421 int generic_depth = 1; 2422 ++generic; 2423 for (; 2424 *generic && generic_depth > 0; 2425 generic++) 2426 { 2427 if (*generic == '<') 2428 generic_depth++; 2429 if (*generic == '>') 2430 generic_depth--; 2431 } 2432 if (*generic) 2433 open_paren = strchr(generic, '('); 2434 else 2435 open_paren = nullptr; 2436 } 2437 if (open_paren) 2438 { 2439 if (IsToken (open_paren, "(anonymous namespace)")) 2440 { 2441 open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '('); 2442 if (open_paren) 2443 close_paren = strchr (open_paren, ')'); 2444 } 2445 else 2446 close_paren = strchr (open_paren, ')'); 2447 } 2448 2449 if (open_paren) 2450 s.Write(cstr, open_paren - cstr + 1); 2451 else 2452 { 2453 s.PutCString (cstr); 2454 s.PutChar ('('); 2455 } 2456 const size_t num_args = args.GetSize(); 2457 for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) 2458 { 2459 std::string buffer; 2460 2461 VariableSP var_sp (args.GetVariableAtIndex (arg_idx)); 2462 ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp)); 2463 const char *var_representation = nullptr; 2464 const char *var_name = var_value_sp->GetName().GetCString(); 2465 if (var_value_sp->GetClangType().IsAggregateType() && 2466 DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) 2467 { 2468 static StringSummaryFormat format(TypeSummaryImpl::Flags() 2469 .SetHideItemNames(false) 2470 .SetShowMembersOneLiner(true), 2471 ""); 2472 format.FormatObject(var_value_sp.get(), buffer); 2473 var_representation = buffer.c_str(); 2474 } 2475 else 2476 var_representation = var_value_sp->GetValueAsCString(); 2477 if (arg_idx > 0) 2478 s.PutCString (", "); 2479 if (var_value_sp->GetError().Success()) 2480 { 2481 if (var_representation) 2482 s.Printf ("%s=%s", var_name, var_representation); 2483 else 2484 s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString()); 2485 } 2486 else 2487 s.Printf ("%s=<unavailable>", var_name); 2488 } 2489 2490 if (close_paren) 2491 s.PutCString (close_paren); 2492 else 2493 s.PutChar(')'); 2494 2495 } 2496 else 2497 { 2498 s.PutCString(cstr); 2499 } 2500 } 2501 } 2502 else if (sc->symbol) 2503 { 2504 cstr = sc->symbol->GetName().AsCString (NULL); 2505 if (cstr) 2506 { 2507 s.PutCString(cstr); 2508 var_success = true; 2509 } 2510 } 2511 } 2512 else if (IsToken (var_name_begin, "addr-offset}") 2513 || IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) 2514 { 2515 if (IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) 2516 { 2517 addr_offset_print_with_no_padding = true; 2518 addr_offset_concrete_func_only = true; 2519 } 2520 var_success = addr != NULL; 2521 if (var_success) 2522 { 2523 format_addr = *addr; 2524 calculate_format_addr_function_offset = true; 2525 } 2526 } 2527 else if (IsToken (var_name_begin, "line-offset}")) 2528 { 2529 var_success = sc->line_entry.range.GetBaseAddress().IsValid(); 2530 if (var_success) 2531 { 2532 format_addr = sc->line_entry.range.GetBaseAddress(); 2533 calculate_format_addr_function_offset = true; 2534 } 2535 } 2536 else if (IsToken (var_name_begin, "pc-offset}")) 2537 { 2538 StackFrame *frame = exe_ctx->GetFramePtr(); 2539 var_success = frame != NULL; 2540 if (var_success) 2541 { 2542 format_addr = frame->GetFrameCodeAddress(); 2543 calculate_format_addr_function_offset = true; 2544 } 2545 } 2546 } 2547 } 2548 break; 2549 2550 case 'l': 2551 if (IsToken (var_name_begin, "line.")) 2552 { 2553 if (sc && sc->line_entry.IsValid()) 2554 { 2555 var_name_begin += ::strlen ("line."); 2556 if (IsToken (var_name_begin, "file.")) 2557 { 2558 var_name_begin += ::strlen ("file."); 2559 2560 if (IsToken (var_name_begin, "basename}")) 2561 { 2562 format_file_spec.GetFilename() = sc->line_entry.file.GetFilename(); 2563 var_success = (bool)format_file_spec; 2564 } 2565 else if (IsToken (var_name_begin, "fullpath}")) 2566 { 2567 format_file_spec = sc->line_entry.file; 2568 var_success = (bool)format_file_spec; 2569 } 2570 } 2571 else if (IsTokenWithFormat (var_name_begin, "number", token_format, "%" PRIu64, exe_ctx, sc)) 2572 { 2573 var_success = true; 2574 s.Printf(token_format.c_str(), (uint64_t)sc->line_entry.line); 2575 } 2576 else if ((IsToken (var_name_begin, "start-addr}")) || 2577 (IsToken (var_name_begin, "end-addr}"))) 2578 { 2579 var_success = sc && sc->line_entry.range.GetBaseAddress().IsValid(); 2580 if (var_success) 2581 { 2582 format_addr = sc->line_entry.range.GetBaseAddress(); 2583 if (var_name_begin[0] == 'e') 2584 format_addr.Slide (sc->line_entry.range.GetByteSize()); 2585 } 2586 } 2587 } 2588 } 2589 break; 2590 case 'c': 2591 if (IsToken (var_name_begin, "current-pc-arrow")) 2592 { 2593 if (addr && exe_ctx && exe_ctx->GetFramePtr()) 2594 { 2595 RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP(); 2596 if (reg_ctx.get()) 2597 { 2598 addr_t pc_loadaddr = reg_ctx->GetPC(); 2599 if (pc_loadaddr != LLDB_INVALID_ADDRESS) 2600 { 2601 Address pc; 2602 pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr()); 2603 if (pc == *addr) 2604 { 2605 s.Printf ("->"); 2606 var_success = true; 2607 } 2608 else 2609 { 2610 s.Printf(" "); 2611 var_success = true; 2612 } 2613 } 2614 } 2615 } 2616 } 2617 break; 2618 } 2619 2620 if (var_success) 2621 { 2622 // If format addr is valid, then we need to print an address 2623 if (reg_num != LLDB_INVALID_REGNUM) 2624 { 2625 StackFrame *frame = exe_ctx->GetFramePtr(); 2626 // We have a register value to display... 2627 if (reg_num == LLDB_REGNUM_GENERIC_PC && reg_kind == eRegisterKindGeneric) 2628 { 2629 format_addr = frame->GetFrameCodeAddress(); 2630 } 2631 else 2632 { 2633 if (reg_ctx == NULL) 2634 reg_ctx = frame->GetRegisterContext().get(); 2635 2636 if (reg_ctx) 2637 { 2638 if (reg_kind != kNumRegisterKinds) 2639 reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); 2640 reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num); 2641 var_success = reg_info != NULL; 2642 } 2643 } 2644 } 2645 2646 if (reg_info != NULL) 2647 { 2648 RegisterValue reg_value; 2649 var_success = reg_ctx->ReadRegister (reg_info, reg_value); 2650 if (var_success) 2651 { 2652 reg_value.Dump(&s, reg_info, false, false, eFormatDefault); 2653 } 2654 } 2655 2656 if (format_file_spec) 2657 { 2658 s << format_file_spec; 2659 } 2660 2661 // If format addr is valid, then we need to print an address 2662 if (format_addr.IsValid()) 2663 { 2664 var_success = false; 2665 2666 if (calculate_format_addr_function_offset) 2667 { 2668 Address func_addr; 2669 2670 if (sc) 2671 { 2672 if (sc->function) 2673 { 2674 func_addr = sc->function->GetAddressRange().GetBaseAddress(); 2675 if (sc->block && addr_offset_concrete_func_only == false) 2676 { 2677 // Check to make sure we aren't in an inline 2678 // function. If we are, use the inline block 2679 // range that contains "format_addr" since 2680 // blocks can be discontiguous. 2681 Block *inline_block = sc->block->GetContainingInlinedBlock (); 2682 AddressRange inline_range; 2683 if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range)) 2684 func_addr = inline_range.GetBaseAddress(); 2685 } 2686 } 2687 else if (sc->symbol && sc->symbol->ValueIsAddress()) 2688 func_addr = sc->symbol->GetAddress(); 2689 } 2690 2691 if (func_addr.IsValid()) 2692 { 2693 const char *addr_offset_padding = " "; 2694 if (addr_offset_print_with_no_padding) 2695 { 2696 addr_offset_padding = ""; 2697 } 2698 if (func_addr.GetSection() == format_addr.GetSection()) 2699 { 2700 addr_t func_file_addr = func_addr.GetFileAddress(); 2701 addr_t addr_file_addr = format_addr.GetFileAddress(); 2702 if (addr_file_addr > func_file_addr) 2703 s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr); 2704 else if (addr_file_addr < func_file_addr) 2705 s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr); 2706 var_success = true; 2707 } 2708 else 2709 { 2710 Target *target = Target::GetTargetFromContexts (exe_ctx, sc); 2711 if (target) 2712 { 2713 addr_t func_load_addr = func_addr.GetLoadAddress (target); 2714 addr_t addr_load_addr = format_addr.GetLoadAddress (target); 2715 if (addr_load_addr > func_load_addr) 2716 s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr); 2717 else if (addr_load_addr < func_load_addr) 2718 s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr); 2719 var_success = true; 2720 } 2721 } 2722 } 2723 } 2724 else 2725 { 2726 Target *target = Target::GetTargetFromContexts (exe_ctx, sc); 2727 addr_t vaddr = LLDB_INVALID_ADDRESS; 2728 if (exe_ctx && !target->GetSectionLoadList().IsEmpty()) 2729 vaddr = format_addr.GetLoadAddress (target); 2730 if (vaddr == LLDB_INVALID_ADDRESS) 2731 vaddr = format_addr.GetFileAddress (); 2732 2733 if (vaddr != LLDB_INVALID_ADDRESS) 2734 { 2735 int addr_width = 0; 2736 if (exe_ctx && target) 2737 { 2738 addr_width = target->GetArchitecture().GetAddressByteSize() * 2; 2739 } 2740 if (addr_width == 0) 2741 addr_width = 16; 2742 if (print_file_addr_or_load_addr) 2743 { 2744 format_addr.Dump (&s, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0); 2745 } 2746 else 2747 { 2748 s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr); 2749 } 2750 var_success = true; 2751 } 2752 } 2753 } 2754 } 2755 2756 if (var_success == false) 2757 success = false; 2758 } 2759 p = var_name_end; 2760 } 2761 else 2762 break; 2763 } 2764 else 2765 { 2766 // We got a dollar sign with no '{' after it, it must just be a dollar sign 2767 s.PutChar(*p); 2768 } 2769 } 2770 else if (*p == '\\') 2771 { 2772 ++p; // skip the slash 2773 switch (*p) 2774 { 2775 case 'a': s.PutChar ('\a'); break; 2776 case 'b': s.PutChar ('\b'); break; 2777 case 'f': s.PutChar ('\f'); break; 2778 case 'n': s.PutChar ('\n'); break; 2779 case 'r': s.PutChar ('\r'); break; 2780 case 't': s.PutChar ('\t'); break; 2781 case 'v': s.PutChar ('\v'); break; 2782 case '\'': s.PutChar ('\''); break; 2783 case '\\': s.PutChar ('\\'); break; 2784 case '0': 2785 // 1 to 3 octal chars 2786 { 2787 // Make a string that can hold onto the initial zero char, 2788 // up to 3 octal digits, and a terminating NULL. 2789 char oct_str[5] = { 0, 0, 0, 0, 0 }; 2790 2791 int i; 2792 for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) 2793 oct_str[i] = p[i]; 2794 2795 // We don't want to consume the last octal character since 2796 // the main for loop will do this for us, so we advance p by 2797 // one less than i (even if i is zero) 2798 p += i - 1; 2799 unsigned long octal_value = ::strtoul (oct_str, NULL, 8); 2800 if (octal_value <= UINT8_MAX) 2801 { 2802 s.PutChar((char)octal_value); 2803 } 2804 } 2805 break; 2806 2807 case 'x': 2808 // hex number in the format 2809 if (isxdigit(p[1])) 2810 { 2811 ++p; // Skip the 'x' 2812 2813 // Make a string that can hold onto two hex chars plus a 2814 // NULL terminator 2815 char hex_str[3] = { 0,0,0 }; 2816 hex_str[0] = *p; 2817 if (isxdigit(p[1])) 2818 { 2819 ++p; // Skip the first of the two hex chars 2820 hex_str[1] = *p; 2821 } 2822 2823 unsigned long hex_value = strtoul (hex_str, NULL, 16); 2824 if (hex_value <= UINT8_MAX) 2825 s.PutChar ((char)hex_value); 2826 } 2827 else 2828 { 2829 s.PutChar('x'); 2830 } 2831 break; 2832 2833 default: 2834 // Just desensitize any other character by just printing what 2835 // came after the '\' 2836 s << *p; 2837 break; 2838 2839 } 2840 2841 } 2842 } 2843 if (end) 2844 *end = p; 2845 return success; 2846 } 2847 2848 bool 2849 Debugger::FormatPrompt 2850 ( 2851 const char *format, 2852 const SymbolContext *sc, 2853 const ExecutionContext *exe_ctx, 2854 const Address *addr, 2855 Stream &s, 2856 ValueObject* valobj 2857 ) 2858 { 2859 bool use_color = exe_ctx ? exe_ctx->GetTargetRef().GetDebugger().GetUseColor() : true; 2860 std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color); 2861 if (format_str.length()) 2862 format = format_str.c_str(); 2863 return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj, false, false); 2864 } 2865 2866 bool 2867 Debugger::FormatDisassemblerAddress (const char *format, 2868 const SymbolContext *sc, 2869 const SymbolContext *prev_sc, 2870 const ExecutionContext *exe_ctx, 2871 const Address *addr, 2872 Stream &s) 2873 { 2874 if (format == NULL && exe_ctx != NULL && exe_ctx->HasTargetScope()) 2875 { 2876 format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); 2877 } 2878 bool function_changed = false; 2879 bool initial_function = false; 2880 if (prev_sc && (prev_sc->function || prev_sc->symbol)) 2881 { 2882 if (sc && (sc->function || sc->symbol)) 2883 { 2884 if (prev_sc->symbol && sc->symbol) 2885 { 2886 if (!sc->symbol->Compare (prev_sc->symbol->GetName(), prev_sc->symbol->GetType())) 2887 { 2888 function_changed = true; 2889 } 2890 } 2891 else if (prev_sc->function && sc->function) 2892 { 2893 if (prev_sc->function->GetMangled() != sc->function->GetMangled()) 2894 { 2895 function_changed = true; 2896 } 2897 } 2898 } 2899 } 2900 // The first context on a list of instructions will have a prev_sc that 2901 // has no Function or Symbol -- if SymbolContext had an IsValid() method, it 2902 // would return false. But we do get a prev_sc pointer. 2903 if ((sc && (sc->function || sc->symbol)) 2904 && prev_sc && (prev_sc->function == NULL && prev_sc->symbol == NULL)) 2905 { 2906 initial_function = true; 2907 } 2908 return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, NULL, function_changed, initial_function); 2909 } 2910 2911 2912 void 2913 Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton) 2914 { 2915 // For simplicity's sake, I am not going to deal with how to close down any 2916 // open logging streams, I just redirect everything from here on out to the 2917 // callback. 2918 m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton)); 2919 } 2920 2921 bool 2922 Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream) 2923 { 2924 Log::Callbacks log_callbacks; 2925 2926 StreamSP log_stream_sp; 2927 if (m_log_callback_stream_sp) 2928 { 2929 log_stream_sp = m_log_callback_stream_sp; 2930 // For now when using the callback mode you always get thread & timestamp. 2931 log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; 2932 } 2933 else if (log_file == NULL || *log_file == '\0') 2934 { 2935 log_stream_sp = GetOutputFile(); 2936 } 2937 else 2938 { 2939 LogStreamMap::iterator pos = m_log_streams.find(log_file); 2940 if (pos != m_log_streams.end()) 2941 log_stream_sp = pos->second.lock(); 2942 if (!log_stream_sp) 2943 { 2944 log_stream_sp.reset (new StreamFile (log_file)); 2945 m_log_streams[log_file] = log_stream_sp; 2946 } 2947 } 2948 assert (log_stream_sp.get()); 2949 2950 if (log_options == 0) 2951 log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; 2952 2953 if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks)) 2954 { 2955 log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream); 2956 return true; 2957 } 2958 else 2959 { 2960 LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel)); 2961 if (log_channel_sp) 2962 { 2963 if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories)) 2964 { 2965 return true; 2966 } 2967 else 2968 { 2969 error_stream.Printf ("Invalid log channel '%s'.\n", channel); 2970 return false; 2971 } 2972 } 2973 else 2974 { 2975 error_stream.Printf ("Invalid log channel '%s'.\n", channel); 2976 return false; 2977 } 2978 } 2979 return false; 2980 } 2981 2982 SourceManager & 2983 Debugger::GetSourceManager () 2984 { 2985 if (m_source_manager_ap.get() == NULL) 2986 m_source_manager_ap.reset (new SourceManager (shared_from_this())); 2987 return *m_source_manager_ap; 2988 } 2989 2990 2991 2992 // This function handles events that were broadcast by the process. 2993 void 2994 Debugger::HandleBreakpointEvent (const EventSP &event_sp) 2995 { 2996 using namespace lldb; 2997 const uint32_t event_type = Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (event_sp); 2998 2999 // if (event_type & eBreakpointEventTypeAdded 3000 // || event_type & eBreakpointEventTypeRemoved 3001 // || event_type & eBreakpointEventTypeEnabled 3002 // || event_type & eBreakpointEventTypeDisabled 3003 // || event_type & eBreakpointEventTypeCommandChanged 3004 // || event_type & eBreakpointEventTypeConditionChanged 3005 // || event_type & eBreakpointEventTypeIgnoreChanged 3006 // || event_type & eBreakpointEventTypeLocationsResolved) 3007 // { 3008 // // Don't do anything about these events, since the breakpoint commands already echo these actions. 3009 // } 3010 // 3011 if (event_type & eBreakpointEventTypeLocationsAdded) 3012 { 3013 uint32_t num_new_locations = Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(event_sp); 3014 if (num_new_locations > 0) 3015 { 3016 BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); 3017 StreamFileSP output_sp (GetOutputFile()); 3018 if (output_sp) 3019 { 3020 output_sp->Printf("%d location%s added to breakpoint %d\n", 3021 num_new_locations, 3022 num_new_locations == 1 ? "" : "s", 3023 breakpoint->GetID()); 3024 RefreshTopIOHandler(); 3025 } 3026 } 3027 } 3028 // else if (event_type & eBreakpointEventTypeLocationsRemoved) 3029 // { 3030 // // These locations just get disabled, not sure it is worth spamming folks about this on the command line. 3031 // } 3032 // else if (event_type & eBreakpointEventTypeLocationsResolved) 3033 // { 3034 // // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy. 3035 // } 3036 } 3037 3038 size_t 3039 Debugger::GetProcessSTDOUT (Process *process, Stream *stream) 3040 { 3041 size_t total_bytes = 0; 3042 if (stream == NULL) 3043 stream = GetOutputFile().get(); 3044 3045 if (stream) 3046 { 3047 // The process has stuff waiting for stdout; get it and write it out to the appropriate place. 3048 if (process == NULL) 3049 { 3050 TargetSP target_sp = GetTargetList().GetSelectedTarget(); 3051 if (target_sp) 3052 process = target_sp->GetProcessSP().get(); 3053 } 3054 if (process) 3055 { 3056 Error error; 3057 size_t len; 3058 char stdio_buffer[1024]; 3059 while ((len = process->GetSTDOUT (stdio_buffer, sizeof (stdio_buffer), error)) > 0) 3060 { 3061 stream->Write(stdio_buffer, len); 3062 total_bytes += len; 3063 } 3064 } 3065 stream->Flush(); 3066 } 3067 return total_bytes; 3068 } 3069 3070 size_t 3071 Debugger::GetProcessSTDERR (Process *process, Stream *stream) 3072 { 3073 size_t total_bytes = 0; 3074 if (stream == NULL) 3075 stream = GetOutputFile().get(); 3076 3077 if (stream) 3078 { 3079 // The process has stuff waiting for stderr; get it and write it out to the appropriate place. 3080 if (process == NULL) 3081 { 3082 TargetSP target_sp = GetTargetList().GetSelectedTarget(); 3083 if (target_sp) 3084 process = target_sp->GetProcessSP().get(); 3085 } 3086 if (process) 3087 { 3088 Error error; 3089 size_t len; 3090 char stdio_buffer[1024]; 3091 while ((len = process->GetSTDERR (stdio_buffer, sizeof (stdio_buffer), error)) > 0) 3092 { 3093 stream->Write(stdio_buffer, len); 3094 total_bytes += len; 3095 } 3096 } 3097 stream->Flush(); 3098 } 3099 return total_bytes; 3100 } 3101 3102 3103 // This function handles events that were broadcast by the process. 3104 void 3105 Debugger::HandleProcessEvent (const EventSP &event_sp) 3106 { 3107 using namespace lldb; 3108 const uint32_t event_type = event_sp->GetType(); 3109 ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); 3110 3111 StreamString output_stream; 3112 StreamString error_stream; 3113 const bool gui_enabled = IsForwardingEvents(); 3114 3115 if (!gui_enabled) 3116 { 3117 bool pop_process_io_handler = false; 3118 assert (process_sp); 3119 3120 if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged) 3121 { 3122 GetProcessSTDOUT (process_sp.get(), &output_stream); 3123 } 3124 3125 if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged) 3126 { 3127 GetProcessSTDERR (process_sp.get(), &error_stream); 3128 } 3129 3130 if (event_type & Process::eBroadcastBitStateChanged) 3131 { 3132 Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler); 3133 } 3134 3135 if (output_stream.GetSize() || error_stream.GetSize()) 3136 { 3137 StreamFileSP error_stream_sp (GetOutputFile()); 3138 bool top_io_handler_hid = false; 3139 3140 if (process_sp->ProcessIOHandlerIsActive() == false) 3141 top_io_handler_hid = HideTopIOHandler(); 3142 3143 if (output_stream.GetSize()) 3144 { 3145 StreamFileSP output_stream_sp (GetOutputFile()); 3146 if (output_stream_sp) 3147 output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize()); 3148 } 3149 3150 if (error_stream.GetSize()) 3151 { 3152 StreamFileSP error_stream_sp (GetErrorFile()); 3153 if (error_stream_sp) 3154 error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize()); 3155 } 3156 3157 if (top_io_handler_hid) 3158 RefreshTopIOHandler(); 3159 } 3160 3161 if (pop_process_io_handler) 3162 process_sp->PopProcessIOHandler(); 3163 } 3164 } 3165 3166 void 3167 Debugger::HandleThreadEvent (const EventSP &event_sp) 3168 { 3169 // At present the only thread event we handle is the Frame Changed event, 3170 // and all we do for that is just reprint the thread status for that thread. 3171 using namespace lldb; 3172 const uint32_t event_type = event_sp->GetType(); 3173 if (event_type == Thread::eBroadcastBitStackChanged || 3174 event_type == Thread::eBroadcastBitThreadSelected ) 3175 { 3176 ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get())); 3177 if (thread_sp) 3178 { 3179 HideTopIOHandler(); 3180 StreamFileSP stream_sp (GetOutputFile()); 3181 thread_sp->GetStatus(*stream_sp, 0, 1, 1); 3182 RefreshTopIOHandler(); 3183 } 3184 } 3185 } 3186 3187 bool 3188 Debugger::IsForwardingEvents () 3189 { 3190 return (bool)m_forward_listener_sp; 3191 } 3192 3193 void 3194 Debugger::EnableForwardEvents (const ListenerSP &listener_sp) 3195 { 3196 m_forward_listener_sp = listener_sp; 3197 } 3198 3199 void 3200 Debugger::CancelForwardEvents (const ListenerSP &listener_sp) 3201 { 3202 m_forward_listener_sp.reset(); 3203 } 3204 3205 3206 void 3207 Debugger::DefaultEventHandler() 3208 { 3209 Listener& listener(GetListener()); 3210 ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); 3211 ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); 3212 ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); 3213 BroadcastEventSpec target_event_spec (broadcaster_class_target, 3214 Target::eBroadcastBitBreakpointChanged); 3215 3216 BroadcastEventSpec process_event_spec (broadcaster_class_process, 3217 Process::eBroadcastBitStateChanged | 3218 Process::eBroadcastBitSTDOUT | 3219 Process::eBroadcastBitSTDERR); 3220 3221 BroadcastEventSpec thread_event_spec (broadcaster_class_thread, 3222 Thread::eBroadcastBitStackChanged | 3223 Thread::eBroadcastBitThreadSelected ); 3224 3225 listener.StartListeningForEventSpec (*this, target_event_spec); 3226 listener.StartListeningForEventSpec (*this, process_event_spec); 3227 listener.StartListeningForEventSpec (*this, thread_event_spec); 3228 listener.StartListeningForEvents (m_command_interpreter_ap.get(), 3229 CommandInterpreter::eBroadcastBitQuitCommandReceived | 3230 CommandInterpreter::eBroadcastBitAsynchronousOutputData | 3231 CommandInterpreter::eBroadcastBitAsynchronousErrorData ); 3232 3233 bool done = false; 3234 while (!done) 3235 { 3236 // Mutex::Locker locker; 3237 // if (locker.TryLock(m_input_reader_stack.GetMutex())) 3238 // { 3239 // if (m_input_reader_stack.IsEmpty()) 3240 // break; 3241 // } 3242 // 3243 EventSP event_sp; 3244 if (listener.WaitForEvent(NULL, event_sp)) 3245 { 3246 if (event_sp) 3247 { 3248 Broadcaster *broadcaster = event_sp->GetBroadcaster(); 3249 if (broadcaster) 3250 { 3251 uint32_t event_type = event_sp->GetType(); 3252 ConstString broadcaster_class (broadcaster->GetBroadcasterClass()); 3253 if (broadcaster_class == broadcaster_class_process) 3254 { 3255 HandleProcessEvent (event_sp); 3256 } 3257 else if (broadcaster_class == broadcaster_class_target) 3258 { 3259 if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(event_sp.get())) 3260 { 3261 HandleBreakpointEvent (event_sp); 3262 } 3263 } 3264 else if (broadcaster_class == broadcaster_class_thread) 3265 { 3266 HandleThreadEvent (event_sp); 3267 } 3268 else if (broadcaster == m_command_interpreter_ap.get()) 3269 { 3270 if (event_type & CommandInterpreter::eBroadcastBitQuitCommandReceived) 3271 { 3272 done = true; 3273 } 3274 else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousErrorData) 3275 { 3276 const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); 3277 if (data && data[0]) 3278 { 3279 StreamFileSP error_sp (GetErrorFile()); 3280 if (error_sp) 3281 { 3282 HideTopIOHandler(); 3283 error_sp->PutCString(data); 3284 error_sp->Flush(); 3285 RefreshTopIOHandler(); 3286 } 3287 } 3288 } 3289 else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousOutputData) 3290 { 3291 const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); 3292 if (data && data[0]) 3293 { 3294 StreamFileSP output_sp (GetOutputFile()); 3295 if (output_sp) 3296 { 3297 HideTopIOHandler(); 3298 output_sp->PutCString(data); 3299 output_sp->Flush(); 3300 RefreshTopIOHandler(); 3301 } 3302 } 3303 } 3304 } 3305 } 3306 3307 if (m_forward_listener_sp) 3308 m_forward_listener_sp->AddEvent(event_sp); 3309 } 3310 } 3311 } 3312 } 3313 3314 lldb::thread_result_t 3315 Debugger::EventHandlerThread (lldb::thread_arg_t arg) 3316 { 3317 ((Debugger *)arg)->DefaultEventHandler(); 3318 return NULL; 3319 } 3320 3321 bool 3322 Debugger::StartEventHandlerThread() 3323 { 3324 if (!m_event_handler_thread.IsJoinable()) 3325 { 3326 // Use larger 8MB stack for this thread 3327 m_event_handler_thread = ThreadLauncher::LaunchThread("lldb.debugger.event-handler", EventHandlerThread, this, NULL, 3328 g_debugger_event_thread_stack_bytes); 3329 } 3330 return m_event_handler_thread.IsJoinable(); 3331 } 3332 3333 void 3334 Debugger::StopEventHandlerThread() 3335 { 3336 if (m_event_handler_thread.IsJoinable()) 3337 { 3338 GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); 3339 m_event_handler_thread.Join(nullptr); 3340 } 3341 } 3342 3343 3344 lldb::thread_result_t 3345 Debugger::IOHandlerThread (lldb::thread_arg_t arg) 3346 { 3347 Debugger *debugger = (Debugger *)arg; 3348 debugger->ExecuteIOHanders(); 3349 debugger->StopEventHandlerThread(); 3350 return NULL; 3351 } 3352 3353 bool 3354 Debugger::StartIOHandlerThread() 3355 { 3356 if (!m_io_handler_thread.IsJoinable()) 3357 m_io_handler_thread = ThreadLauncher::LaunchThread ("lldb.debugger.io-handler", 3358 IOHandlerThread, 3359 this, 3360 NULL, 3361 8*1024*1024); // Use larger 8MB stack for this thread 3362 return m_io_handler_thread.IsJoinable(); 3363 } 3364 3365 void 3366 Debugger::StopIOHandlerThread() 3367 { 3368 if (m_io_handler_thread.IsJoinable()) 3369 { 3370 if (m_input_file_sp) 3371 m_input_file_sp->GetFile().Close(); 3372 m_io_handler_thread.Join(nullptr); 3373 } 3374 } 3375 3376 3377