int32 TeamDebugHandler::_HandleMessage(DebugMessage *message) { // This method is called only for the first message the debugger gets for // a team. That means only a few messages are actually possible, while // others wouldn't trigger the debugger in the first place. So we deal with // all of them the same way, by popping up an alert. TRACE(("debug_server: TeamDebugHandler::_HandleMessage(): team %" B_PRId32 ", code: %" B_PRId32 "\n", fTeam, (int32)message->Code())); thread_id thread = message->Data().origin.thread; // get some user-readable message char buffer[512]; switch (message->Code()) { case B_DEBUGGER_MESSAGE_TEAM_DELETED: // This shouldn't happen. debug_printf("debug_server: Got a spurious " "B_DEBUGGER_MESSAGE_TEAM_DELETED message for team %" B_PRId32 "\n", fTeam); return true; case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: get_debug_exception_string( message->Data().exception_occurred.exception, buffer, sizeof(buffer)); break; case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: { // get the debugger() message void *messageAddress = message->Data().debugger_call.message; char messageBuffer[128]; status_t error = B_OK; ssize_t bytesRead = debug_read_string(&fDebugContext, messageAddress, messageBuffer, sizeof(messageBuffer)); if (bytesRead < 0) error = bytesRead; if (error == B_OK) { sprintf(buffer, "Debugger call: `%s'", messageBuffer); } else { snprintf(buffer, sizeof(buffer), "Debugger call: %p " "(Failed to read message: %s)", messageAddress, strerror(error)); } break; } default: get_debug_message_string(message->Code(), buffer, sizeof(buffer)); break; } debug_printf("debug_server: Thread %" B_PRId32 " entered the debugger: %s\n", thread, buffer); _PrintStackTrace(thread); int32 debugAction = kActionPromptUser; bool explicitActionFound = false; if (action_for_team(fExecutablePath, debugAction, explicitActionFound) != B_OK) { debugAction = kActionPromptUser; explicitActionFound = false; } // ask the user whether to debug or kill the team if (_IsGUIServer()) { // App server, input server, or registrar. We always debug those. // if not specifically overridden. if (!explicitActionFound) debugAction = kActionDebugTeam; } else if (debugAction == kActionPromptUser && USE_GUI && _AreGUIServersAlive() && _InitGUI() == B_OK) { // normal app -- tell the user _NotifyAppServer(fTeam); _NotifyRegistrar(fTeam, true, false); BString buffer( B_TRANSLATE("The application:\n\n %app\n\n" "has encountered an error which prevents it from continuing. Haiku " "will terminate the application and clean up.")); buffer.ReplaceFirst("%app", fTeamInfo.args); // TODO: It would be nice if the alert would go away automatically // if someone else kills our teams. BAlert *alert = new BAlert(NULL, buffer.String(), B_TRANSLATE("Terminate"), B_TRANSLATE("Debug"), B_TRANSLATE("Write core file"), B_WIDTH_AS_USUAL, B_WARNING_ALERT); #ifdef HANDOVER_USE_DEBUGGER alert->AddButton(B_TRANSLATE("Save report")); #endif alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); debugAction = alert->Go(); if (debugAction < 0) { // Happens when closed by escape key debugAction = kActionKillTeam; } _NotifyRegistrar(fTeam, false, debugAction != kActionKillTeam); } return debugAction; }