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