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