2 * Copyright 2011-2014, Rene Gollent, rene@gollent.com.
3 * Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net.
4 * Distributed under the terms of the MIT License.
18 #include <AutoDeleter.h>
21 #include <debug_support.h>
23 #include <FindDirectory.h>
28 #include <DriverSettings.h>
29 #include <MessengerPrivate.h>
31 #include <RegistrarDefs.h>
32 #include <RosterPrivate.h>
34 #include <StringList.h>
36 #include <util/DoublyLinkedList.h>
43 kActionSaveReportTeam
,
48 static const char* kDebuggerSignature
= "application/x-vnd.Haiku-Debugger";
49 static const int32 MSG_DEBUG_THIS_TEAM
= 'dbtt';
52 //#define HANDOVER_USE_GDB 1
53 #define HANDOVER_USE_DEBUGGER 1
55 #undef B_TRANSLATION_CONTEXT
56 #define B_TRANSLATION_CONTEXT "DebugServer"
59 // define to false if the debug server shouldn't use GUI (i.e. an alert)
61 //#define TRACE_DEBUG_SERVER
62 #ifdef TRACE_DEBUG_SERVER
63 # define TRACE(x) debug_printf x
73 static const char *kSignature
= "application/x-vnd.Haiku-debug_server";
77 action_for_string(const char* action
, int32
& _action
)
79 if (strcmp(action
, "kill") == 0)
80 _action
= kActionKillTeam
;
81 else if (strcmp(action
, "debug") == 0)
82 _action
= kActionDebugTeam
;
83 else if (strcmp(action
, "log") == 0
84 || strcmp(action
, "report") == 0) {
85 _action
= kActionSaveReportTeam
;
86 } else if (strcasecmp(action
, "core") == 0)
87 _action
= kActionWriteCoreFile
;
88 else if (strcasecmp(action
, "user") == 0)
89 _action
= kActionPromptUser
;
98 match_team_name(const char* teamName
, const char* parameterName
)
100 RegExp expressionMatcher
;
101 if (expressionMatcher
.SetPattern(parameterName
,
102 RegExp::PATTERN_TYPE_WILDCARD
)) {
103 BString value
= teamName
;
104 if (parameterName
[0] != '/') {
105 // the expression in question is a team name match only,
106 // so we need to extract that.
107 BPath
path(teamName
);
108 if (path
.InitCheck() == B_OK
)
112 RegExp::MatchResult match
= expressionMatcher
.Match(value
);
113 if (match
.HasMatched())
122 action_for_team(const char* teamName
, int32
& _action
,
123 bool& _explicitActionFound
)
125 status_t error
= B_OK
;
127 error
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
131 path
.Append("system/debug_server/settings");
132 BDriverSettings settings
;
133 error
= settings
.Load(path
.Path());
138 if (action_for_string(settings
.GetParameterValue("default_action",
139 "user", "user"), tempAction
) == B_OK
) {
140 _action
= tempAction
;
142 _action
= kActionPromptUser
;
143 _explicitActionFound
= false;
145 BDriverParameter parameter
= settings
.GetParameter("executable_actions");
146 for (BDriverParameterIterator iterator
= parameter
.ParameterIterator();
147 iterator
.HasNext();) {
148 BDriverParameter child
= iterator
.Next();
149 if (!match_team_name(teamName
, child
.Name()))
152 if (child
.CountValues() > 0) {
153 if (action_for_string(child
.ValueAt(0), tempAction
) == B_OK
) {
154 _action
= tempAction
;
155 _explicitActionFound
= true;
167 KillTeam(team_id team
, const char *appName
= NULL
)
169 // get a team info to verify the team still lives
172 status_t error
= get_team_info(team
, &info
);
174 debug_printf("debug_server: KillTeam(): Error getting info for "
175 "team %" B_PRId32
": %s\n", team
, strerror(error
));
182 debug_printf("debug_server: Killing team %" B_PRId32
" (%s)\n", team
,
192 class DebugMessage
: public DoublyLinkedListLinkImpl
<DebugMessage
> {
198 void SetCode(debug_debugger_message code
) { fCode
= code
; }
199 debug_debugger_message
Code() const { return fCode
; }
201 debug_debugger_message_data
&Data() { return fData
; }
202 const debug_debugger_message_data
&Data() const { return fData
; }
205 debug_debugger_message fCode
;
206 debug_debugger_message_data fData
;
209 typedef DoublyLinkedList
<DebugMessage
> DebugMessageList
;
212 class TeamDebugHandler
: public BLocker
{
214 TeamDebugHandler(team_id team
);
217 status_t
Init(port_id nubPort
);
219 team_id
Team() const;
221 status_t
PushMessage(DebugMessage
*message
);
224 status_t
_PopMessage(DebugMessage
*&message
);
226 thread_id
_EnterDebugger(bool saveReport
);
227 status_t
_SetupGDBArguments(BStringList
&arguments
, bool usingConsoled
);
228 status_t
_WriteCoreFile();
231 int32
_HandleMessage(DebugMessage
*message
);
233 void _LookupSymbolAddress(debug_symbol_lookup_context
*lookupContext
,
234 const void *address
, char *buffer
, int32 bufferSize
);
235 void _PrintStackTrace(thread_id thread
);
236 void _NotifyAppServer(team_id team
);
237 void _NotifyRegistrar(team_id team
, bool openAlert
, bool stopShutdown
);
241 static status_t
_HandlerThreadEntry(void *data
);
242 status_t
_HandlerThread();
244 bool _ExecutableNameEquals(const char *name
) const;
245 bool _IsAppServer() const;
246 bool _IsInputServer() const;
247 bool _IsRegistrar() const;
248 bool _IsGUIServer() const;
250 static const char *_LastPathComponent(const char *path
);
251 static team_id
_FindTeam(const char *name
);
252 static bool _AreGUIServersAlive();
255 DebugMessageList fMessages
;
256 sem_id fMessageCountSem
;
259 char fExecutablePath
[B_PATH_NAME_LENGTH
];
260 thread_id fHandlerThread
;
261 debug_context fDebugContext
;
265 class TeamDebugHandlerRoster
: public BLocker
{
267 TeamDebugHandlerRoster()
269 BLocker("team debug handler roster")
274 static TeamDebugHandlerRoster
*CreateDefault()
277 sRoster
= new(nothrow
) TeamDebugHandlerRoster
;
282 static TeamDebugHandlerRoster
*Default()
287 bool AddHandler(TeamDebugHandler
*handler
)
294 fHandlers
[handler
->Team()] = handler
;
299 TeamDebugHandler
*RemoveHandler(team_id team
)
303 TeamDebugHandler
*handler
= NULL
;
305 TeamDebugHandlerMap::iterator it
= fHandlers
.find(team
);
306 if (it
!= fHandlers
.end()) {
307 handler
= it
->second
;
314 TeamDebugHandler
*HandlerFor(team_id team
)
318 TeamDebugHandler
*handler
= NULL
;
320 TeamDebugHandlerMap::iterator it
= fHandlers
.find(team
);
321 if (it
!= fHandlers
.end())
322 handler
= it
->second
;
327 status_t
DispatchMessage(DebugMessage
*message
)
332 ObjectDeleter
<DebugMessage
> messageDeleter(message
);
334 team_id team
= message
->Data().origin
.team
;
336 // get the responsible team debug handler
339 TeamDebugHandler
*handler
= HandlerFor(team
);
341 // no handler yet, we need to create one
342 handler
= new(nothrow
) TeamDebugHandler(team
);
348 status_t error
= handler
->Init(message
->Data().origin
.nub_port
);
355 if (!AddHandler(handler
)) {
362 // hand over the message to it
363 handler
->PushMessage(message
);
364 messageDeleter
.Detach();
370 typedef map
<team_id
, TeamDebugHandler
*> TeamDebugHandlerMap
;
372 static TeamDebugHandlerRoster
*sRoster
;
374 TeamDebugHandlerMap fHandlers
;
378 TeamDebugHandlerRoster
*TeamDebugHandlerRoster::sRoster
= NULL
;
381 class DebugServer
: public BServer
{
383 DebugServer(status_t
&error
);
387 virtual bool QuitRequested();
390 static status_t
_ListenerEntry(void *data
);
391 status_t
_Listener();
393 void _DeleteTeamDebugHandler(TeamDebugHandler
*handler
);
396 typedef map
<team_id
, TeamDebugHandler
*> TeamDebugHandlerMap
;
398 port_id fListenerPort
;
407 TeamDebugHandler::TeamDebugHandler(team_id team
)
409 BLocker("team debug handler"),
411 fMessageCountSem(-1),
415 fDebugContext
.nub_port
= -1;
416 fDebugContext
.reply_port
= -1;
418 fExecutablePath
[0] = '\0';
422 TeamDebugHandler::~TeamDebugHandler()
424 // delete the message count semaphore and wait for the thread to die
425 if (fMessageCountSem
>= 0)
426 delete_sem(fMessageCountSem
);
428 if (fHandlerThread
>= 0 && find_thread(NULL
) != fHandlerThread
) {
430 wait_for_thread(fHandlerThread
, &result
);
433 // destroy debug context
434 if (fDebugContext
.nub_port
>= 0)
435 destroy_debug_context(&fDebugContext
);
437 // delete the remaining messages
438 while (DebugMessage
*message
= fMessages
.Head()) {
439 fMessages
.Remove(message
);
446 TeamDebugHandler::Init(port_id nubPort
)
448 // get the team info for the team
449 status_t error
= get_team_info(fTeam
, &fTeamInfo
);
451 debug_printf("debug_server: TeamDebugHandler::Init(): Failed to get "
452 "info for team %" B_PRId32
": %s\n", fTeam
, strerror(error
));
456 // get the executable path
457 error
= BPrivate::get_app_path(fTeam
, fExecutablePath
);
459 debug_printf("debug_server: TeamDebugHandler::Init(): Failed to get "
460 "executable path of team %" B_PRId32
": %s\n", fTeam
,
463 fExecutablePath
[0] = '\0';
466 // init a debug context for the handler
467 error
= init_debug_context(&fDebugContext
, fTeam
, nubPort
);
469 debug_printf("debug_server: TeamDebugHandler::Init(): Failed to init "
470 "debug context for team %" B_PRId32
", port %" B_PRId32
": %s\n",
471 fTeam
, nubPort
, strerror(error
));
476 debug_nub_set_team_flags message
;
477 message
.flags
= B_TEAM_DEBUG_PREVENT_EXIT
;
479 send_debug_message(&fDebugContext
, B_DEBUG_MESSAGE_SET_TEAM_FLAGS
, &message
,
480 sizeof(message
), NULL
, 0);
482 // create the message count semaphore
483 char name
[B_OS_NAME_LENGTH
];
484 snprintf(name
, sizeof(name
), "team %" B_PRId32
" message count", fTeam
);
485 fMessageCountSem
= create_sem(0, name
);
486 if (fMessageCountSem
< 0) {
487 debug_printf("debug_server: TeamDebugHandler::Init(): Failed to create "
488 "message count semaphore: %s\n", strerror(fMessageCountSem
));
489 return fMessageCountSem
;
492 // spawn the handler thread
493 snprintf(name
, sizeof(name
), "team %" B_PRId32
" handler", fTeam
);
494 fHandlerThread
= spawn_thread(&_HandlerThreadEntry
, name
, B_NORMAL_PRIORITY
,
496 if (fHandlerThread
< 0) {
497 debug_printf("debug_server: TeamDebugHandler::Init(): Failed to spawn "
498 "handler thread: %s\n", strerror(fHandlerThread
));
499 return fHandlerThread
;
502 resume_thread(fHandlerThread
);
509 TeamDebugHandler::Team() const
516 TeamDebugHandler::PushMessage(DebugMessage
*message
)
520 fMessages
.Add(message
);
521 release_sem(fMessageCountSem
);
528 TeamDebugHandler::_PopMessage(DebugMessage
*&message
)
530 // acquire the semaphore
533 error
= acquire_sem(fMessageCountSem
);
534 } while (error
== B_INTERRUPTED
);
542 message
= fMessages
.Head();
543 fMessages
.Remove(message
);
550 TeamDebugHandler::_SetupGDBArguments(BStringList
&arguments
, bool usingConsoled
)
552 // prepare the argument vector
554 teamString
.SetToFormat("--pid=%" B_PRId32
, fTeam
);
559 error
= find_directory(B_SYSTEM_BIN_DIRECTORY
, &terminalPath
);
561 debug_printf("debug_server: can't find system-bin directory: %s\n",
565 error
= terminalPath
.Append("consoled");
567 debug_printf("debug_server: can't append to system-bin path: %s\n",
572 error
= find_directory(B_SYSTEM_APPS_DIRECTORY
, &terminalPath
);
574 debug_printf("debug_server: can't find system-apps directory: %s\n",
578 error
= terminalPath
.Append("Terminal");
580 debug_printf("debug_server: can't append to system-apps path: %s\n",
586 arguments
.MakeEmpty();
587 if (!arguments
.Add(terminalPath
.Path()))
590 if (!usingConsoled
) {
592 windowTitle
.SetToFormat("Debug of Team %" B_PRId32
": %s", fTeam
,
593 _LastPathComponent(fExecutablePath
));
594 if (!arguments
.Add("-t") || !arguments
.Add(windowTitle
))
599 error
= find_directory(B_SYSTEM_BIN_DIRECTORY
, &gdbPath
);
601 debug_printf("debug_server: can't find system-bin directory: %s\n",
605 error
= gdbPath
.Append("gdb");
607 debug_printf("debug_server: can't append to system-bin path: %s\n",
611 if (!arguments
.Add(gdbPath
.Path()) || !arguments
.Add(teamString
))
614 if (strlen(fExecutablePath
) > 0 && !arguments
.Add(fExecutablePath
))
622 TeamDebugHandler::_EnterDebugger(bool saveReport
)
624 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): team %" B_PRId32
627 // prepare a debugger handover
628 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): preparing "
629 "debugger handover for team %" B_PRId32
"...\n", fTeam
));
631 status_t error
= send_debug_message(&fDebugContext
,
632 B_DEBUG_MESSAGE_PREPARE_HANDOVER
, NULL
, 0, NULL
, 0);
634 debug_printf("debug_server: Failed to prepare debugger handover: %s\n",
639 BStringList arguments
;
640 const char *argv
[16];
643 bool debugInConsoled
= _IsGUIServer() || !_AreGUIServersAlive();
644 #ifdef HANDOVER_USE_GDB
646 error
= _SetupGDBArguments(arguments
, debugInConsoled
);
648 debug_printf("debug_server: Failed to set up gdb arguments: %s\n",
653 // start the terminal
654 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting "
655 "terminal (debugger) for team %" B_PRId32
"...\n", fTeam
));
657 #elif defined(HANDOVER_USE_DEBUGGER)
658 if (!debugInConsoled
&& !saveReport
659 && be_roster
->IsRunning(kDebuggerSignature
)) {
661 // for graphical handovers, check if Debugger is already running,
662 // and if it is, simply send it a message to attach to the requested
664 BMessenger
messenger(kDebuggerSignature
);
665 BMessage
message(MSG_DEBUG_THIS_TEAM
);
666 if (message
.AddInt32("team", fTeam
) == B_OK
667 && messenger
.SendMessage(&message
) == B_OK
) {
672 // prepare the argument vector
674 if (debugInConsoled
) {
675 error
= find_directory(B_SYSTEM_BIN_DIRECTORY
, &debuggerPath
);
677 debug_printf("debug_server: can't find system-bin directory: %s\n",
681 error
= debuggerPath
.Append("consoled");
683 debug_printf("debug_server: can't append to system-bin path: %s\n",
688 if (!arguments
.Add(debuggerPath
.Path()))
692 error
= find_directory(B_SYSTEM_APPS_DIRECTORY
, &debuggerPath
);
694 debug_printf("debug_server: can't find system-apps directory: %s\n",
698 error
= debuggerPath
.Append("Debugger");
700 debug_printf("debug_server: can't append to system-apps path: %s\n",
704 if (!arguments
.Add(debuggerPath
.Path()))
707 if (debugInConsoled
&& !arguments
.Add("--cli"))
710 BString debuggerParam
;
711 debuggerParam
.SetToFormat("%" B_PRId32
, fTeam
);
713 if (!arguments
.Add("--save-report"))
716 if (!arguments
.Add("--team") || !arguments
.Add(debuggerParam
))
719 // start the debugger
720 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting "
721 "%s debugger for team %" B_PRId32
"...\n",
722 debugInConsoled
? "command line" : "graphical", fTeam
));
725 for (int32 i
= 0; i
< arguments
.CountStrings(); i
++)
726 argv
[argc
++] = arguments
.StringAt(i
).String();
729 thread_id thread
= load_image(argc
, argv
, (const char**)environ
);
731 debug_printf("debug_server: Failed to start debugger: %s\n",
735 resume_thread(thread
);
737 TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): debugger started "
738 "for team %" B_PRId32
": thread: %" B_PRId32
"\n", fTeam
, thread
));
745 TeamDebugHandler::_KillTeam()
747 KillTeam(fTeam
, fTeamInfo
.args
);
752 TeamDebugHandler::_WriteCoreFile()
754 // get a usable path for the core file
756 status_t error
= find_directory(B_DESKTOP_DIRECTORY
, &directoryPath
);
758 debug_printf("debug_server: Couldn't get desktop directory: %s\n",
763 const char* executableName
= strrchr(fExecutablePath
, '/');
764 if (executableName
== NULL
)
765 executableName
= fExecutablePath
;
769 BString
fileBaseName("core-");
770 fileBaseName
<< executableName
<< '-' << fTeam
;
773 for (int32 index
= 0;; index
++) {
774 BString
fileName(fileBaseName
);
776 fileName
<< '-' << index
;
778 error
= filePath
.SetTo(directoryPath
.Path(), fileName
.String());
780 debug_printf("debug_server: Couldn't get core file path for team %"
781 B_PRId32
": %s\n", fTeam
, strerror(error
));
786 if (lstat(filePath
.Path(), &st
) != 0) {
787 if (errno
== B_ENTRY_NOT_FOUND
)
792 debug_printf("debug_server: Couldn't get usable core file path for "
793 "team %" B_PRId32
"\n", fTeam
);
798 debug_nub_write_core_file message
;
799 message
.reply_port
= fDebugContext
.reply_port
;
800 strlcpy(message
.path
, filePath
.Path(), sizeof(message
.path
));
802 debug_nub_write_core_file_reply reply
;
804 error
= send_debug_message(&fDebugContext
, B_DEBUG_WRITE_CORE_FILE
,
805 &message
, sizeof(message
), &reply
, sizeof(reply
));
809 debug_printf("debug_server: Failed to write core file for team %"
810 B_PRId32
": %s\n", fTeam
, strerror(error
));
818 TeamDebugHandler::_HandleMessage(DebugMessage
*message
)
820 // This method is called only for the first message the debugger gets for
821 // a team. That means only a few messages are actually possible, while
822 // others wouldn't trigger the debugger in the first place. So we deal with
823 // all of them the same way, by popping up an alert.
824 TRACE(("debug_server: TeamDebugHandler::_HandleMessage(): team %" B_PRId32
825 ", code: %" B_PRId32
"\n", fTeam
, (int32
)message
->Code()));
827 thread_id thread
= message
->Data().origin
.thread
;
829 // get some user-readable message
831 switch (message
->Code()) {
832 case B_DEBUGGER_MESSAGE_TEAM_DELETED
:
833 // This shouldn't happen.
834 debug_printf("debug_server: Got a spurious "
835 "B_DEBUGGER_MESSAGE_TEAM_DELETED message for team %" B_PRId32
839 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED
:
840 get_debug_exception_string(
841 message
->Data().exception_occurred
.exception
, buffer
,
845 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL
:
847 // get the debugger() message
848 void *messageAddress
= message
->Data().debugger_call
.message
;
849 char messageBuffer
[128];
850 status_t error
= B_OK
;
851 ssize_t bytesRead
= debug_read_string(&fDebugContext
,
852 messageAddress
, messageBuffer
, sizeof(messageBuffer
));
857 sprintf(buffer
, "Debugger call: `%s'", messageBuffer
);
859 snprintf(buffer
, sizeof(buffer
), "Debugger call: %p "
860 "(Failed to read message: %s)", messageAddress
,
867 get_debug_message_string(message
->Code(), buffer
, sizeof(buffer
));
871 debug_printf("debug_server: Thread %" B_PRId32
" entered the debugger: %s\n",
874 _PrintStackTrace(thread
);
876 int32 debugAction
= kActionPromptUser
;
877 bool explicitActionFound
= false;
878 if (action_for_team(fExecutablePath
, debugAction
, explicitActionFound
)
880 debugAction
= kActionPromptUser
;
881 explicitActionFound
= false;
884 // ask the user whether to debug or kill the team
885 if (_IsGUIServer()) {
886 // App server, input server, or registrar. We always debug those.
887 // if not specifically overridden.
888 if (!explicitActionFound
)
889 debugAction
= kActionDebugTeam
;
890 } else if (debugAction
== kActionPromptUser
&& USE_GUI
891 && _AreGUIServersAlive() && _InitGUI() == B_OK
) {
892 // normal app -- tell the user
893 _NotifyAppServer(fTeam
);
894 _NotifyRegistrar(fTeam
, true, false);
897 B_TRANSLATE("The application:\n\n %app\n\n"
898 "has encountered an error which prevents it from continuing. Haiku "
899 "will terminate the application and clean up."));
900 buffer
.ReplaceFirst("%app", fTeamInfo
.args
);
902 // TODO: It would be nice if the alert would go away automatically
903 // if someone else kills our teams.
904 BAlert
*alert
= new BAlert(NULL
, buffer
.String(),
905 B_TRANSLATE("Terminate"), B_TRANSLATE("Debug"),
906 B_TRANSLATE("Write core file"),
907 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
908 #ifdef HANDOVER_USE_DEBUGGER
909 alert
->AddButton(B_TRANSLATE("Save report"));
911 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
912 debugAction
= alert
->Go();
913 if (debugAction
< 0) {
914 // Happens when closed by escape key
915 debugAction
= kActionKillTeam
;
917 _NotifyRegistrar(fTeam
, false, debugAction
!= kActionKillTeam
);
925 TeamDebugHandler::_LookupSymbolAddress(
926 debug_symbol_lookup_context
*lookupContext
, const void *address
,
927 char *buffer
, int32 bufferSize
)
931 char symbolName
[1024];
932 char imageName
[B_PATH_NAME_LENGTH
];
934 bool lookupSucceeded
= false;
936 status_t error
= debug_lookup_symbol_address(lookupContext
, address
,
937 &baseAddress
, symbolName
, sizeof(symbolName
), imageName
,
938 sizeof(imageName
), &exactMatch
);
939 lookupSucceeded
= (error
== B_OK
);
942 if (lookupSucceeded
) {
943 // we were able to look something up
944 if (strlen(symbolName
) > 0) {
945 // we even got a symbol
946 snprintf(buffer
, bufferSize
, "%s + %#lx%s", symbolName
,
947 (addr_t
)address
- (addr_t
)baseAddress
,
948 (exactMatch
? "" : " (closest symbol)"));
951 // no symbol: image relative address
952 snprintf(buffer
, bufferSize
, "(%s + %#lx)", imageName
,
953 (addr_t
)address
- (addr_t
)baseAddress
);
957 // lookup failed: find area containing the IP
958 bool useAreaInfo
= false;
961 while (get_next_area_info(fTeam
, &cookie
, &info
) == B_OK
) {
962 if ((addr_t
)info
.address
<= (addr_t
)address
963 && (addr_t
)info
.address
+ info
.size
> (addr_t
)address
) {
970 snprintf(buffer
, bufferSize
, "(%s + %#lx)", info
.name
,
971 (addr_t
)address
- (addr_t
)info
.address
);
972 } else if (bufferSize
> 0)
979 TeamDebugHandler::_PrintStackTrace(thread_id thread
)
981 // print a stacktrace
983 void *stackFrameAddress
= NULL
;
984 status_t error
= debug_get_instruction_pointer(&fDebugContext
, thread
, &ip
,
988 // create a symbol lookup context
989 debug_symbol_lookup_context
*lookupContext
= NULL
;
990 error
= debug_create_symbol_lookup_context(fTeam
, -1, &lookupContext
);
992 debug_printf("debug_server: Failed to create symbol lookup "
993 "context: %s\n", strerror(error
));
997 char symbolBuffer
[2048];
998 _LookupSymbolAddress(lookupContext
, ip
, symbolBuffer
,
999 sizeof(symbolBuffer
) - 1);
1001 debug_printf("stack trace, current PC %p %s:\n", ip
, symbolBuffer
);
1003 for (int32 i
= 0; i
< 50; i
++) {
1004 debug_stack_frame_info stackFrameInfo
;
1006 error
= debug_get_stack_frame(&fDebugContext
, stackFrameAddress
,
1008 if (error
< B_OK
|| stackFrameInfo
.parent_frame
== NULL
)
1011 // lookup the return address
1012 _LookupSymbolAddress(lookupContext
, stackFrameInfo
.return_address
,
1013 symbolBuffer
, sizeof(symbolBuffer
) - 1);
1015 debug_printf(" (%p) %p %s\n", stackFrameInfo
.frame
,
1016 stackFrameInfo
.return_address
, symbolBuffer
);
1018 stackFrameAddress
= stackFrameInfo
.parent_frame
;
1021 // delete the symbol lookup context
1023 debug_delete_symbol_lookup_context(lookupContext
);
1029 TeamDebugHandler::_NotifyAppServer(team_id team
)
1031 // This will remove any kWindowScreenFeels of the application, so that
1032 // the debugger alert is visible on screen
1033 BRoster::Private roster
;
1034 roster
.ApplicationCrashed(team
);
1039 TeamDebugHandler::_NotifyRegistrar(team_id team
, bool openAlert
,
1042 BMessage
notify(BPrivate::B_REG_TEAM_DEBUGGER_ALERT
);
1043 notify
.AddInt32("team", team
);
1044 notify
.AddBool("open", openAlert
);
1045 notify
.AddBool("stop shutdown", stopShutdown
);
1047 BRoster::Private roster
;
1049 roster
.SendTo(¬ify
, &reply
, false);
1054 TeamDebugHandler::_InitGUI()
1056 DebugServer
*app
= dynamic_cast<DebugServer
*>(be_app
);
1058 return app
->InitGUIContext();
1063 TeamDebugHandler::_HandlerThreadEntry(void *data
)
1065 return ((TeamDebugHandler
*)data
)->_HandlerThread();
1070 TeamDebugHandler::_HandlerThread()
1072 TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %" B_PRId32
1075 // get initial message
1076 TRACE(("debug_server: TeamDebugHandler::_HandlerThread(): team %" B_PRId32
1077 ": getting message...\n", fTeam
));
1079 DebugMessage
*message
;
1080 status_t error
= _PopMessage(message
);
1081 int32 debugAction
= kActionKillTeam
;
1082 if (error
== B_OK
) {
1083 // handle the message
1084 debugAction
= _HandleMessage(message
);
1087 debug_printf("TeamDebugHandler::_HandlerThread(): Failed to pop "
1088 "initial message: %s", strerror(error
));
1091 // kill the team or hand it over to the debugger
1092 thread_id debuggerThread
= -1;
1093 if (debugAction
== kActionKillTeam
) {
1094 // The team shall be killed. Since that is also the handling in case
1095 // an error occurs while handing over the team to the debugger, we do
1097 } else if (debugAction
== kActionWriteCoreFile
) {
1099 debugAction
= kActionKillTeam
;
1100 } else if ((debuggerThread
= _EnterDebugger(
1101 debugAction
== kActionSaveReportTeam
)) >= 0) {
1102 // wait for the "handed over" or a "team deleted" message
1103 bool terminate
= false;
1105 error
= _PopMessage(message
);
1106 if (error
!= B_OK
) {
1107 debug_printf("TeamDebugHandler::_HandlerThread(): Failed to "
1108 "pop message: %s", strerror(error
));
1109 debugAction
= kActionKillTeam
;
1113 if (message
->Code() == B_DEBUGGER_MESSAGE_HANDED_OVER
) {
1114 // The team has successfully been handed over to the debugger.
1117 } else if (message
->Code() == B_DEBUGGER_MESSAGE_TEAM_DELETED
) {
1118 // The team died. Nothing to do.
1121 // Some message we can ignore. The debugger will take care of
1124 // check whether the debugger thread still lives
1125 thread_info threadInfo
;
1126 if (get_thread_info(debuggerThread
, &threadInfo
) != B_OK
) {
1127 // the debugger is gone
1128 debug_printf("debug_server: The debugger for team %"
1129 B_PRId32
" seems to be gone.", fTeam
);
1131 debugAction
= kActionKillTeam
;
1137 } while (!terminate
);
1139 debugAction
= kActionKillTeam
;
1141 if (debugAction
== kActionKillTeam
) {
1146 // remove this handler from the roster and delete it
1147 TeamDebugHandlerRoster::Default()->RemoveHandler(fTeam
);
1156 TeamDebugHandler::_ExecutableNameEquals(const char *name
) const
1158 return strcmp(_LastPathComponent(fExecutablePath
), name
) == 0;
1163 TeamDebugHandler::_IsAppServer() const
1165 return _ExecutableNameEquals("app_server");
1170 TeamDebugHandler::_IsInputServer() const
1172 return _ExecutableNameEquals("input_server");
1177 TeamDebugHandler::_IsRegistrar() const
1179 return _ExecutableNameEquals("registrar");
1184 TeamDebugHandler::_IsGUIServer() const
1186 // app or input server
1187 return _IsAppServer() || _IsInputServer() || _IsRegistrar();
1192 TeamDebugHandler::_LastPathComponent(const char *path
)
1194 const char *lastSlash
= strrchr(path
, '/');
1195 return lastSlash
? lastSlash
+ 1 : path
;
1200 TeamDebugHandler::_FindTeam(const char *name
)
1202 // Iterate through all teams and check their executable name.
1205 while (get_next_team_info(&cookie
, &teamInfo
) == B_OK
) {
1207 if (BPrivate::get_app_ref(teamInfo
.team
, &ref
) == B_OK
) {
1208 if (strcmp(ref
.name
, name
) == 0)
1209 return teamInfo
.team
;
1213 return B_ENTRY_NOT_FOUND
;
1218 TeamDebugHandler::_AreGUIServersAlive()
1220 return _FindTeam("app_server") >= 0 && _FindTeam("input_server") >= 0
1221 && _FindTeam("registrar");
1228 DebugServer::DebugServer(status_t
&error
)
1230 BServer(kSignature
, false, &error
),
1241 // create listener port
1242 fListenerPort
= create_port(10, "kernel listener");
1243 if (fListenerPort
< 0)
1244 return fListenerPort
;
1246 // spawn the listener thread
1247 fListener
= spawn_thread(_ListenerEntry
, "kernel listener",
1248 B_NORMAL_PRIORITY
, this);
1252 // register as default debugger
1253 // TODO: could set default flags
1254 status_t error
= install_default_debugger(fListenerPort
);
1258 // resume the listener
1259 resume_thread(fListener
);
1266 DebugServer::QuitRequested()
1268 // Never give up, never surrender. ;-)
1274 DebugServer::_ListenerEntry(void *data
)
1276 return ((DebugServer
*)data
)->_Listener();
1281 DebugServer::_Listener()
1283 while (!fTerminating
) {
1284 // receive the next debug message
1285 DebugMessage
*message
= new DebugMessage
;
1289 bytesRead
= read_port(fListenerPort
, &code
, &message
->Data(),
1290 sizeof(debug_debugger_message_data
));
1291 } while (bytesRead
== B_INTERRUPTED
);
1293 if (bytesRead
< 0) {
1294 debug_printf("debug_server: Failed to read from listener port: "
1295 "%s. Terminating!\n", strerror(bytesRead
));
1298 TRACE(("debug_server: Got debug message: team: %" B_PRId32
", code: %" B_PRId32
1299 "\n", message
->Data().origin
.team
, code
));
1301 message
->SetCode((debug_debugger_message
)code
);
1303 // dispatch the message
1304 TeamDebugHandlerRoster::Default()->DispatchMessage(message
);
1319 // for the time being let the debug server print to the syslog
1320 int console
= open("/dev/dprintf", O_RDONLY
);
1322 debug_printf("debug_server: Failed to open console: %s\n",
1325 dup2(console
, STDOUT_FILENO
);
1326 dup2(console
, STDERR_FILENO
);
1329 // create the team debug handler roster
1330 if (!TeamDebugHandlerRoster::CreateDefault()) {
1331 debug_printf("debug_server: Failed to create team debug handler "
1336 // create application
1337 DebugServer
server(error
);
1338 if (error
!= B_OK
) {
1339 debug_printf("debug_server: Failed to create BApplication: %s\n",
1345 error
= server
.Init();
1346 if (error
!= B_OK
) {
1347 debug_printf("debug_server: Failed to init application: %s\n",