1 /* 2 * Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <map> 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <stdio.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include <Alert.h> 15 #include <AppMisc.h> 16 #include <AutoDeleter.h> 17 #include <Autolock.h> 18 #include <debug_support.h> 19 #include <Entry.h> 20 #include <Invoker.h> 21 22 #include <RosterPrivate.h> 23 #include <Server.h> 24 25 #include <util/DoublyLinkedList.h> 26 27 #define USE_GUI true 28 // define to false if the debug server shouldn't use GUI (i.e. an alert) 29 30 //#define TRACE_DEBUG_SERVER 31 #ifdef TRACE_DEBUG_SERVER 32 # define TRACE(x) printf x 33 #else 34 # define TRACE(x) ; 35 #endif 36 37 using std::map; 38 using std::nothrow; 39 40 static const char *kSignature = "application/x-vnd.haiku-debug-server"; 41 42 // paths to the apps used for debugging 43 static const char *kConsoledPath = "/bin/consoled"; 44 static const char *kTerminalPath = "/boot/beos/apps/Terminal"; 45 static const char *kGDBPath = "/bin/gdb"; 46 47 48 // KillTeam 49 static void 50 KillTeam(team_id team, const char *appName = NULL) 51 { 52 // get a team info to verify the team still lives 53 team_info info; 54 if (!appName) { 55 status_t error = get_team_info(team, &info); 56 if (error != B_OK) { 57 printf("debug_server: KillTeam(): Error getting info for team %ld: " 58 "%s\n", team, strerror(error)); 59 info.args[0] = '\0'; 60 } 61 62 appName = info.args; 63 } 64 65 printf("debug_server: Killing team %ld (%s)\n", team, appName); 66 67 kill_team(team); 68 } 69 70 71 // #pragma mark - 72 73 // DebugMessage 74 class DebugMessage : public DoublyLinkedListLinkImpl<DebugMessage> { 75 public: 76 DebugMessage() 77 { 78 } 79 80 void SetCode(debug_debugger_message code) { fCode = code; } 81 debug_debugger_message Code() const { return fCode; } 82 83 debug_debugger_message_data &Data() { return fData; } 84 const debug_debugger_message_data &Data() const { return fData; } 85 86 private: 87 debug_debugger_message fCode; 88 debug_debugger_message_data fData; 89 }; 90 91 typedef DoublyLinkedList<DebugMessage> DebugMessageList; 92 93 94 // TeamDebugHandler 95 class TeamDebugHandler : public BLocker { 96 public: 97 TeamDebugHandler(team_id team); 98 ~TeamDebugHandler(); 99 100 status_t Init(port_id nubPort); 101 102 team_id Team() const; 103 104 status_t PushMessage(DebugMessage *message); 105 106 private: 107 status_t _PopMessage(DebugMessage *&message); 108 109 thread_id _EnterDebugger(); 110 void _KillTeam(); 111 112 bool _HandleMessage(DebugMessage *message); 113 114 void _LookupSymbolAddress(debug_symbol_lookup_context *lookupContext, 115 const void *address, char *buffer, int32 bufferSize); 116 void _PrintStackTrace(thread_id thread); 117 void _NotifyAppServer(team_id team); 118 119 status_t _InitGUI(); 120 121 static status_t _HandlerThreadEntry(void *data); 122 status_t _HandlerThread(); 123 124 bool _ExecutableNameEquals(const char *name) const; 125 bool _IsAppServer() const; 126 bool _IsInputServer() const; 127 bool _IsRegistrar() const; 128 bool _IsGUIServer() const; 129 130 static const char *_LastPathComponent(const char *path); 131 static team_id _FindTeam(const char *name); 132 static bool _AreGUIServersAlive(); 133 134 private: 135 DebugMessageList fMessages; 136 sem_id fMessageCountSem; 137 team_id fTeam; 138 team_info fTeamInfo; 139 char fExecutablePath[B_PATH_NAME_LENGTH]; 140 thread_id fHandlerThread; 141 debug_context fDebugContext; 142 }; 143 144 145 // TeamDebugHandlerRoster 146 class TeamDebugHandlerRoster : public BLocker { 147 private: 148 TeamDebugHandlerRoster() 149 : BLocker("team debug handler roster") 150 { 151 } 152 153 public: 154 static TeamDebugHandlerRoster *CreateDefault() 155 { 156 if (!sRoster) 157 sRoster = new(nothrow) TeamDebugHandlerRoster; 158 159 return sRoster; 160 } 161 162 static TeamDebugHandlerRoster *Default() 163 { 164 return sRoster; 165 } 166 167 bool AddHandler(TeamDebugHandler *handler) 168 { 169 if (!handler) 170 return false; 171 172 BAutolock _(this); 173 174 fHandlers[handler->Team()] = handler; 175 176 return true; 177 } 178 179 TeamDebugHandler *RemoveHandler(team_id team) 180 { 181 BAutolock _(this); 182 183 TeamDebugHandler *handler = NULL; 184 185 TeamDebugHandlerMap::iterator it = fHandlers.find(team); 186 if (it != fHandlers.end()) { 187 handler = it->second; 188 fHandlers.erase(it); 189 } 190 191 return handler; 192 } 193 194 TeamDebugHandler *HandlerFor(team_id team) 195 { 196 BAutolock _(this); 197 198 TeamDebugHandler *handler = NULL; 199 200 TeamDebugHandlerMap::iterator it = fHandlers.find(team); 201 if (it != fHandlers.end()) 202 handler = it->second; 203 204 return handler; 205 } 206 207 status_t DispatchMessage(DebugMessage *message) 208 { 209 if (!message) 210 return B_BAD_VALUE; 211 212 ObjectDeleter<DebugMessage> messageDeleter(message); 213 214 team_id team = message->Data().origin.team; 215 216 // get the responsible team debug handler 217 BAutolock _(this); 218 219 TeamDebugHandler *handler = HandlerFor(team); 220 if (!handler) { 221 // no handler yet, we need to create one 222 handler = new(nothrow) TeamDebugHandler(team); 223 if (!handler) { 224 KillTeam(team); 225 return B_NO_MEMORY; 226 } 227 228 status_t error = handler->Init(message->Data().origin.nub_port); 229 if (error != B_OK) { 230 delete handler; 231 KillTeam(team); 232 return error; 233 } 234 235 if (!AddHandler(handler)) { 236 delete handler; 237 KillTeam(team); 238 return B_NO_MEMORY; 239 } 240 } 241 242 // hand over the message to it 243 handler->PushMessage(message); 244 messageDeleter.Detach(); 245 246 return B_OK; 247 } 248 249 private: 250 typedef map<team_id, TeamDebugHandler*> TeamDebugHandlerMap; 251 252 static TeamDebugHandlerRoster *sRoster; 253 254 TeamDebugHandlerMap fHandlers; 255 }; 256 257 TeamDebugHandlerRoster *TeamDebugHandlerRoster::sRoster = NULL; 258 259 260 // DebugServer 261 class DebugServer : public BServer 262 { 263 public: 264 DebugServer(status_t &error); 265 266 status_t Init(); 267 268 virtual bool QuitRequested(); 269 270 private: 271 static status_t _ListenerEntry(void *data); 272 status_t _Listener(); 273 274 void _DeleteTeamDebugHandler(TeamDebugHandler *handler); 275 276 private: 277 typedef map<team_id, TeamDebugHandler*> TeamDebugHandlerMap; 278 279 port_id fListenerPort; 280 thread_id fListener; 281 bool fTerminating; 282 }; 283 284 285 // #pragma mark - 286 287 // constructor 288 TeamDebugHandler::TeamDebugHandler(team_id team) 289 : BLocker("team debug handler"), 290 fMessages(), 291 fMessageCountSem(-1), 292 fTeam(team), 293 fHandlerThread(-1) 294 { 295 fDebugContext.nub_port = -1; 296 fDebugContext.reply_port = -1; 297 298 fExecutablePath[0] = '\0'; 299 } 300 301 // destructor 302 TeamDebugHandler::~TeamDebugHandler() 303 { 304 // delete the message count semaphore and wait for the thread to die 305 if (fMessageCountSem >= 0) 306 delete_sem(fMessageCountSem); 307 308 if (fHandlerThread >= 0 && find_thread(NULL) != fHandlerThread) { 309 status_t result; 310 wait_for_thread(fHandlerThread, &result); 311 } 312 313 // destroy debug context 314 if (fDebugContext.nub_port >= 0) 315 destroy_debug_context(&fDebugContext); 316 317 // delete the remaining messages 318 while (DebugMessage *message = fMessages.Head()) { 319 fMessages.Remove(message); 320 delete message; 321 } 322 } 323 324 // Init 325 status_t 326 TeamDebugHandler::Init(port_id nubPort) 327 { 328 // get the team info for the team 329 status_t error = get_team_info(fTeam, &fTeamInfo); 330 if (error != B_OK) { 331 printf("debug_server: TeamDebugHandler::Init(): Failed to get info " 332 "for team %ld: %s\n", fTeam, strerror(error)); 333 return error; 334 } 335 336 // get the executable path 337 error = BPrivate::get_app_path(fTeam, fExecutablePath); 338 if (error != B_OK) { 339 printf("debug_server: TeamDebugHandler::Init(): Failed to get " 340 "executable path of team %ld: %s\n", fTeam, strerror(error)); 341 342 fExecutablePath[0] = '\0'; 343 } 344 345 // init a debug context for the handler 346 error = init_debug_context(&fDebugContext, fTeam, nubPort); 347 if (error != B_OK) { 348 printf("debug_server: TeamDebugHandler::Init(): Failed to init " 349 "debug context for team %ld, port %ld: %s\n", fTeam, nubPort, 350 strerror(error)); 351 return error; 352 } 353 354 // create the message count semaphore 355 char name[B_OS_NAME_LENGTH]; 356 snprintf(name, sizeof(name), "team %ld message count", fTeam); 357 fMessageCountSem = create_sem(0, name); 358 if (fMessageCountSem < 0) { 359 printf("debug_server: TeamDebugHandler::Init(): Failed to create " 360 "message count semaphore: %s\n", strerror(fMessageCountSem)); 361 return fMessageCountSem; 362 } 363 364 // spawn the handler thread 365 snprintf(name, sizeof(name), "team %ld handler", fTeam); 366 fHandlerThread = spawn_thread(&_HandlerThreadEntry, name, B_NORMAL_PRIORITY, 367 this); 368 if (fHandlerThread < 0) { 369 printf("debug_server: TeamDebugHandler::Init(): Failed to spawn " 370 "handler thread: %s\n", strerror(fHandlerThread)); 371 return fHandlerThread; 372 } 373 374 resume_thread(fHandlerThread); 375 376 return B_OK; 377 } 378 379 // Team 380 team_id 381 TeamDebugHandler::Team() const 382 { 383 return fTeam; 384 } 385 386 // PushMessage 387 status_t 388 TeamDebugHandler::PushMessage(DebugMessage *message) 389 { 390 BAutolock _(this); 391 392 fMessages.Add(message); 393 release_sem(fMessageCountSem); 394 395 return B_OK; 396 } 397 398 // _PopMessage 399 status_t 400 TeamDebugHandler::_PopMessage(DebugMessage *&message) 401 { 402 // acquire the semaphore 403 status_t error; 404 do { 405 error = acquire_sem(fMessageCountSem); 406 } while (error == B_INTERRUPTED); 407 408 if (error != B_OK) 409 return error; 410 411 // get the message 412 BAutolock _(this); 413 414 message = fMessages.Head(); 415 fMessages.Remove(message); 416 417 return B_OK; 418 } 419 420 // _EnterDebugger 421 422 thread_id 423 TeamDebugHandler::_EnterDebugger() 424 { 425 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): team %ld\n", 426 fTeam)); 427 428 bool debugInConsoled = _IsAppServer(); 429 430 if (debugInConsoled) { 431 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): team %ld is " 432 "the app server. Killing input_server...\n", fTeam)); 433 434 // kill the input server 435 team_id isTeam = _FindTeam("input_server"); 436 if (isTeam >= 0) { 437 printf("debug_server: preparing for debugging the app server: " 438 "killing the input server\n"); 439 kill_team(isTeam); 440 } 441 } 442 443 // prepare a debugger handover 444 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): preparing " 445 "debugger handover for team %ld...\n", fTeam)); 446 447 status_t error = send_debug_message(&fDebugContext, 448 B_DEBUG_MESSAGE_PREPARE_HANDOVER, NULL, 0, NULL, 0); 449 if (error != B_OK) { 450 printf("debug_server: Failed to prepare debugger handover: %s\n", 451 strerror(error)); 452 return error; 453 } 454 455 // prepare the argument vector 456 char teamString[32]; 457 snprintf(teamString, sizeof(teamString), "%ld", fTeam); 458 459 const char *terminal = (debugInConsoled ? kConsoledPath : kTerminalPath); 460 461 const char *argv[16]; 462 int argc = 0; 463 464 argv[argc++] = terminal; 465 466 if (!debugInConsoled) { 467 char windowTitle[64]; 468 snprintf(windowTitle, sizeof(windowTitle), "Debug of Team %ld: %s", 469 fTeam, _LastPathComponent(fExecutablePath)); 470 argv[argc++] = "-t"; 471 argv[argc++] = windowTitle; 472 } 473 474 argv[argc++] = kGDBPath; 475 argv[argc++] = fExecutablePath; 476 argv[argc++] = teamString; 477 argv[argc] = NULL; 478 479 // start the terminal 480 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting " 481 "terminal (debugger) for team %ld...\n", fTeam)); 482 483 thread_id thread = load_image(argc, argv, (const char**)environ); 484 if (thread < 0) { 485 printf("debug_server: Failed to start consoled + gdb: %s\n", 486 strerror(thread)); 487 return thread; 488 } 489 resume_thread(thread); 490 491 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): debugger started " 492 "for team %ld: thread: %ld\n", fTeam, thread)); 493 494 return thread; 495 } 496 497 // _KillTeam 498 void 499 TeamDebugHandler::_KillTeam() 500 { 501 KillTeam(fTeam, fTeamInfo.args); 502 } 503 504 // _HandleMessage 505 bool 506 TeamDebugHandler::_HandleMessage(DebugMessage *message) 507 { 508 // This method is called only for the first message the debugger gets for 509 // a team. That means only a few messages are actually possible, while 510 // others wouldn't trigger the debugger in the first place. So we deal with 511 // all of them the same way, by popping up an alert. 512 TRACE(("debug_server: TeamDebugHandler::_HandleMessage(): team %ld, code: " 513 "%ld\n", fTeam, (int32)message->Code())); 514 515 thread_id thread = message->Data().origin.thread; 516 517 // get some user-readable message 518 char buffer[512]; 519 switch (message->Code()) { 520 case B_DEBUGGER_MESSAGE_TEAM_DELETED: 521 // This shouldn't happen. 522 printf("debug_server: Got a spurious " 523 "B_DEBUGGER_MESSAGE_TEAM_DELETED message for team %ld\n", 524 fTeam); 525 return true; 526 527 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 528 get_debug_exception_string( 529 message->Data().exception_occurred.exception, buffer, 530 sizeof(buffer)); 531 break; 532 533 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 534 { 535 // get the debugger() message 536 void *messageAddress = message->Data().debugger_call.message; 537 char messageBuffer[128]; 538 status_t error = B_OK; 539 ssize_t bytesRead = debug_read_string(&fDebugContext, 540 messageAddress, messageBuffer, sizeof(messageBuffer)); 541 if (bytesRead < 0) 542 error = bytesRead; 543 544 if (error == B_OK) { 545 sprintf(buffer, "Debugger call: `%s'", messageBuffer); 546 } else { 547 snprintf(buffer, sizeof(buffer), "Debugger call: %p " 548 "(Failed to read message: %s)", messageAddress, 549 strerror(error)); 550 } 551 break; 552 } 553 554 default: 555 get_debug_message_string(message->Code(), buffer, sizeof(buffer)); 556 break; 557 } 558 559 printf("debug_server: Thread %ld entered the debugger: %s\n", thread, 560 buffer); 561 562 _PrintStackTrace(thread); 563 564 bool kill = true; 565 566 // ask the user whether to debug or kill the team 567 if (_IsGUIServer()) { 568 // App or input server. If it's the app server, we'll try to debug it. 569 kill = !(_IsAppServer() && strlen(fExecutablePath) > 0); 570 571 } else if (USE_GUI && _AreGUIServersAlive() && _InitGUI() == B_OK) { 572 // normal app 573 574 _NotifyAppServer(fTeam); 575 576 char buffer[1024]; 577 snprintf(buffer, sizeof(buffer), "The application:\n\n %s\n\n" 578 "has encountered an error which prevents it from continuing. Haiku " 579 "will terminate the application and clean up.", fTeamInfo.args); 580 581 if (strlen(fExecutablePath) > 0) { 582 // we have a usable path, so we can debug the team 583 BAlert *alert = new BAlert(NULL, buffer, "Debug", "OK", NULL, 584 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 585 int32 result = alert->Go(); 586 kill = (result == 1); 587 } else { 588 // no usable path 589 BAlert *alert = new BAlert(NULL, buffer, "OK", NULL, NULL, 590 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 591 alert->Go(); 592 } 593 } 594 595 return kill; 596 } 597 598 // _LookupSymbolAddress 599 void 600 TeamDebugHandler::_LookupSymbolAddress( 601 debug_symbol_lookup_context *lookupContext, const void *address, 602 char *buffer, int32 bufferSize) 603 { 604 // lookup the symbol 605 void *baseAddress; 606 char symbolName[1024]; 607 char imageName[B_OS_NAME_LENGTH]; 608 bool exactMatch; 609 bool lookupSucceeded = false; 610 if (lookupContext) { 611 status_t error = debug_lookup_symbol_address(lookupContext, address, 612 &baseAddress, symbolName, sizeof(symbolName), imageName, 613 sizeof(imageName), &exactMatch); 614 lookupSucceeded = (error == B_OK); 615 } 616 617 if (lookupSucceeded) { 618 // we were able to look something up 619 if (strlen(symbolName) > 0) { 620 // we even got a symbol 621 snprintf(buffer, bufferSize, "%s + %#lx%s", symbolName, 622 (addr_t)address - (addr_t)baseAddress, 623 (exactMatch ? "" : " (closest symbol)")); 624 625 } else { 626 // no symbol: image relative address 627 snprintf(buffer, bufferSize, "(%s + %#lx)", symbolName, 628 (addr_t)address - (addr_t)baseAddress); 629 } 630 631 } else { 632 // lookup failed: find area containing the IP 633 bool useAreaInfo = false; 634 area_info info; 635 int32 cookie = 0; 636 while (get_next_area_info(fTeam, &cookie, &info) == B_OK) { 637 if ((addr_t)info.address <= (addr_t)address 638 && (addr_t)info.address + info.size > (addr_t)address) { 639 useAreaInfo = true; 640 break; 641 } 642 } 643 644 if (useAreaInfo) { 645 snprintf(buffer, bufferSize, "(%s + %#lx)", info.name, 646 (addr_t)address - (addr_t)info.address); 647 } else if (bufferSize > 0) 648 buffer[0] = '\0'; 649 } 650 } 651 652 // _PrintStackTrace 653 void 654 TeamDebugHandler::_PrintStackTrace(thread_id thread) 655 { 656 // print a stacktrace 657 void *ip = NULL; 658 void *stackFrameAddress = NULL; 659 status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip, 660 &stackFrameAddress); 661 662 if (error == B_OK) { 663 // create a symbol lookup context 664 debug_symbol_lookup_context *lookupContext = NULL; 665 error = debug_create_symbol_lookup_context(&fDebugContext, 666 &lookupContext); 667 if (error != B_OK) { 668 printf("debug_server: Failed to create symbol lookup context: %s\n", 669 strerror(error)); 670 } 671 672 // lookup the IP 673 char symbolBuffer[2048]; 674 _LookupSymbolAddress(lookupContext, ip, symbolBuffer, 675 sizeof(symbolBuffer) - 1); 676 677 printf("stack trace, current PC %p %s:\n", ip, symbolBuffer); 678 679 for (int32 i = 0; i < 50; i++) { 680 debug_stack_frame_info stackFrameInfo; 681 682 error = debug_get_stack_frame(&fDebugContext, stackFrameAddress, 683 &stackFrameInfo); 684 if (error < B_OK || stackFrameInfo.parent_frame == NULL) 685 break; 686 687 // lookup the return address 688 _LookupSymbolAddress(lookupContext, stackFrameInfo.return_address, 689 symbolBuffer, sizeof(symbolBuffer) - 1); 690 691 printf(" (%p) %p %s\n", stackFrameInfo.frame, 692 stackFrameInfo.return_address, symbolBuffer); 693 694 stackFrameAddress = stackFrameInfo.parent_frame; 695 } 696 697 // delete the symbol lookup context 698 if (lookupContext) 699 debug_delete_symbol_lookup_context(lookupContext); 700 } 701 } 702 703 704 void 705 TeamDebugHandler::_NotifyAppServer(team_id team) 706 { 707 // This will remove any kWindowScreenFeels of the application, so that 708 // the debugger alert is visible on screen 709 BRoster::Private roster; 710 roster.ApplicationCrashed(team); 711 } 712 713 // _InitGUI 714 status_t 715 TeamDebugHandler::_InitGUI() 716 { 717 DebugServer *app = dynamic_cast<DebugServer*>(be_app); 718 BAutolock _(app); 719 return app->InitGUIContext(); 720 } 721 722 // _HandlerThreadEntry 723 status_t 724 TeamDebugHandler::_HandlerThreadEntry(void *data) 725 { 726 return ((TeamDebugHandler*)data)->_HandlerThread(); 727 } 728 729 // _HandlerThread 730 status_t 731 TeamDebugHandler::_HandlerThread() 732 { 733 TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld\n", 734 fTeam)); 735 736 // get initial message 737 TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %ld: " 738 "getting message...\n", fTeam)); 739 740 DebugMessage *message; 741 status_t error = _PopMessage(message); 742 bool kill; 743 if (error == B_OK) { 744 // handle the message 745 kill = _HandleMessage(message); 746 delete message; 747 } else { 748 printf("TeamDebugHandler::_HandlerThread(): Failed to pop initial " 749 "message: %s", strerror(error)); 750 kill = true; 751 } 752 753 // kill the team or hand it over to the debugger 754 thread_id debuggerThread; 755 if (kill) { 756 // The team shall be killed. Since that is also the handling in case 757 // an error occurs while handing over the team to the debugger, we do 758 // nothing here. 759 } else if ((debuggerThread = _EnterDebugger()) >= 0) { 760 // wait for the "handed over" or a "team deleted" message 761 bool terminate = false; 762 do { 763 error = _PopMessage(message); 764 if (error != B_OK) { 765 printf("TeamDebugHandler::_HandlerThread(): Failed to pop " 766 "message: %s", strerror(error)); 767 kill = true; 768 break; 769 } 770 771 if (message->Code() == B_DEBUGGER_MESSAGE_HANDED_OVER) { 772 // The team has successfully been handed over to the debugger. 773 // Nothing to do. 774 terminate = true; 775 } else if (message->Code() == B_DEBUGGER_MESSAGE_TEAM_DELETED) { 776 // The team died. Nothing to do. 777 terminate = true; 778 } else { 779 // Some message we can ignore. The debugger will take care of 780 // it. 781 782 // check whether the debugger thread still lives 783 thread_info threadInfo; 784 if (get_thread_info(debuggerThread, &threadInfo) != B_OK) { 785 // the debugger is gone 786 printf("debug_server: The debugger for team %ld seems to " 787 "be gone.", fTeam); 788 789 kill = true; 790 terminate = true; 791 } 792 } 793 794 delete message; 795 796 } while (!terminate); 797 } else 798 kill = true; 799 800 if (kill) { 801 // kill the team 802 _KillTeam(); 803 804 // remove this handler from the roster and delete it 805 TeamDebugHandlerRoster::Default()->RemoveHandler(fTeam); 806 807 delete this; 808 } 809 810 return B_OK; 811 } 812 813 // _ExecutableNameEquals 814 bool 815 TeamDebugHandler::_ExecutableNameEquals(const char *name) const 816 { 817 return (strcmp(_LastPathComponent(fExecutablePath), name) == 0); 818 } 819 820 // _IsAppServer 821 bool 822 TeamDebugHandler::_IsAppServer() const 823 { 824 return _ExecutableNameEquals("app_server"); 825 } 826 827 // _IsInputServer 828 bool 829 TeamDebugHandler::_IsInputServer() const 830 { 831 return _ExecutableNameEquals("input_server"); 832 } 833 834 // _IsRegistrar 835 bool 836 TeamDebugHandler::_IsRegistrar() const 837 { 838 return _ExecutableNameEquals("registrar"); 839 } 840 841 // _IsGUIServer 842 bool 843 TeamDebugHandler::_IsGUIServer() const 844 { 845 // app or input server 846 return (_IsAppServer() || _IsInputServer() || _IsRegistrar()); 847 } 848 849 // _LastPathComponent 850 const char * 851 TeamDebugHandler::_LastPathComponent(const char *path) 852 { 853 const char *lastSlash = strrchr(path, '/'); 854 return (lastSlash ? lastSlash + 1 : path); 855 } 856 857 // _FindTeam 858 team_id 859 TeamDebugHandler::_FindTeam(const char *name) 860 { 861 // Iterate through all teams and check their executable name. 862 int32 cookie = 0; 863 team_info teamInfo; 864 while (get_next_team_info(&cookie, &teamInfo) == B_OK) { 865 entry_ref ref; 866 if (BPrivate::get_app_ref(teamInfo.team, &ref) == B_OK) { 867 if (strcmp(ref.name, name) == 0) 868 return teamInfo.team; 869 } 870 } 871 872 return B_ENTRY_NOT_FOUND; 873 } 874 875 // _AreGUIServersAlive 876 bool 877 TeamDebugHandler::_AreGUIServersAlive() 878 { 879 return (_FindTeam("app_server") >= 0 && _FindTeam("input_server") >= 0 880 && _FindTeam("registrar")); 881 } 882 883 884 // #pragma mark - 885 886 // constructor 887 DebugServer::DebugServer(status_t &error) 888 : BServer(kSignature, false, &error), 889 fListenerPort(-1), 890 fListener(-1), 891 fTerminating(false) 892 { 893 } 894 895 // Init 896 status_t 897 DebugServer::Init() 898 { 899 // create listener port 900 fListenerPort = create_port(10, "kernel listener"); 901 if (fListenerPort < 0) 902 return fListenerPort; 903 904 // spawn the listener thread 905 fListener = spawn_thread(_ListenerEntry, "kernel listener", 906 B_NORMAL_PRIORITY, this); 907 if (fListener < 0) 908 return fListener; 909 910 // register as default debugger 911 status_t error = install_default_debugger(fListenerPort); 912 if (error != B_OK) 913 return error; 914 915 // resume the listener 916 resume_thread(fListener); 917 918 return B_OK; 919 } 920 921 // QuitRequested 922 bool 923 DebugServer::QuitRequested() 924 { 925 // Never give up, never surrender. ;-) 926 return false; 927 } 928 929 // _ListenerEntry 930 status_t 931 DebugServer::_ListenerEntry(void *data) 932 { 933 return ((DebugServer*)data)->_Listener(); 934 } 935 936 // _Listener 937 status_t 938 DebugServer::_Listener() 939 { 940 while (!fTerminating) { 941 // receive the next debug message 942 DebugMessage *message = new DebugMessage; 943 int32 code; 944 ssize_t bytesRead; 945 do { 946 bytesRead = read_port(fListenerPort, &code, &message->Data(), 947 sizeof(debug_debugger_message_data)); 948 } while (bytesRead == B_INTERRUPTED); 949 950 if (bytesRead < 0) { 951 fprintf(stderr, "debug_server: Failed to read from listener port: " 952 "%s\n", strerror(bytesRead)); 953 exit(1); 954 } 955 TRACE(("debug_server: Got debug message: team: %ld, code: %ld\n", 956 message->Data().origin.team, code)); 957 958 message->SetCode((debug_debugger_message)code); 959 960 // dispatch the message 961 TeamDebugHandlerRoster::Default()->DispatchMessage(message); 962 } 963 964 return B_OK; 965 } 966 967 968 // #pragma mark - 969 970 // main 971 int 972 main() 973 { 974 status_t error; 975 976 // for the time being let the debug server print to the syslog 977 int console = open("/dev/dprintf", O_RDONLY); 978 if (console < 0) { 979 fprintf(stderr, "debug_server: Failed to open console: %s\n", 980 strerror(errno)); 981 } 982 dup2(console, STDOUT_FILENO); 983 dup2(console, STDERR_FILENO); 984 close(console); 985 986 // create the team debug handler roster 987 if (!TeamDebugHandlerRoster::CreateDefault()) { 988 fprintf(stderr, "debug_server: Failed to create team debug handler " 989 "roster.\n"); 990 exit(1); 991 } 992 993 // create application 994 DebugServer server(error); 995 if (error != B_OK) { 996 fprintf(stderr, "debug_server: Failed to create BApplication: %s\n", 997 strerror(error)); 998 exit(1); 999 } 1000 1001 // init application 1002 error = server.Init(); 1003 if (error != B_OK) { 1004 fprintf(stderr, "debug_server: Failed to init application: %s\n", 1005 strerror(error)); 1006 exit(1); 1007 } 1008 1009 server.Run(); 1010 1011 return 0; 1012 } 1013