From 6ff2656c03cd3ec6d773ff7d2684074b5cb63a0c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 19 Jul 2005 23:29:04 +0000 Subject: [PATCH] * We now use libdebug.so, which saves us a couple lines of code. * Print the debugger message in case the debugged team called debugger(), and the description of an occurred exception respectively. * Properly keep gdb's internal thread list up to date. This fixes the problem that an attached debugger always resumed all threads of the debugged team. * A bit of cleanup of the attaching code. Discovered an ugly bug: When invoking gdb with an executable -- regardless of whether attaching gdb to a running process or just starting a debugger session with the executable -- the executable is modified. I tested with "crashing_app" and in the second debug session gdb fails to read the debug info from the file and encounters a weird error when closing the file: "No space left on device." I have the suspicion that this is another bug in Axel's VM/file cache pet. :-P git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13775 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/bin/gdb/gdb/Jamfile | 2 + src/bin/gdb/gdb/haiku-nat.c | 193 ++++++++++++++++++------------------ 2 files changed, 101 insertions(+), 94 deletions(-) diff --git a/src/bin/gdb/gdb/Jamfile b/src/bin/gdb/gdb/Jamfile index f440dfab64..76777bb273 100644 --- a/src/bin/gdb/gdb/Jamfile +++ b/src/bin/gdb/gdb/Jamfile @@ -9,6 +9,7 @@ SubDirHdrs [ FDirName $(OBOS_TOP) src bin gawk intl ] ; # Use gawk's libintl for the time being. # TODO: Put a current version of intl ot src/libs and build a static lib # all interested apps can link against. +UsePrivateHeaders debug ; SubDirCcFlags -DHAVE_CONFIG_H -DLOCALEDIR=\\\"/boot/beos/etc/locale\\\" -DMI_OUT=1 ; @@ -260,6 +261,7 @@ BinCommand gdb : gdb.c : libtermcap.a libroot.so + libdebug.so libbind.so libsocket.so ; diff --git a/src/bin/gdb/gdb/haiku-nat.c b/src/bin/gdb/gdb/haiku-nat.c index e152f78ad2..f18f1a5e2c 100644 --- a/src/bin/gdb/gdb/haiku-nat.c +++ b/src/bin/gdb/gdb/haiku-nat.c @@ -26,6 +26,8 @@ #include #include +#include + #include "defs.h" // include this first -- otherwise "command.h" will choke #include "command.h" #include "gdbcore.h" @@ -91,8 +93,7 @@ typedef struct extended_image_info { typedef struct team_debug_info { team_id team; port_id debugger_port; - port_id nub_port; - port_id reply_port; + debug_context context; thread_debug_info *threads; extended_image_info *images; debug_event_list events; @@ -190,6 +191,8 @@ haiku_find_thread(team_debug_info *teamDebugInfo, thread_id threadID) static thread_debug_info * haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID) { + struct thread_info *gdbThreadInfo; + // find the thread first thread_debug_info *threadDebugInfo = haiku_find_thread(teamDebugInfo, threadID); @@ -208,6 +211,19 @@ haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID) threadDebugInfo->last_event = NULL; teamDebugInfo->threads = threadDebugInfo; + // add it to gdb's thread DB + gdbThreadInfo = add_thread(ptid_build(teamDebugInfo->team, 0, threadID)); + + // Note: In theory we could spare us the whole thread list management, since + // gdb's thread DB is doing exactly the same. We could put our data as + // thread_info::private. The only catch is that when the thread_info is + // freed, xfree() is invoked on the private data directly, but there's no + // callback invoked before that would allow us to do cleanup (e.g. free + // last_event). + + TRACE(("haiku_add_thread(): team %ld thread %ld added: " + "gdb thread info: %p\n", teamDebugInfo->team, threadID, gdbThreadInfo)); + return threadDebugInfo; } @@ -223,6 +239,10 @@ haiku_remove_thread(team_debug_info *teamDebugInfo, thread_id threadID) if (foundInfo->last_event) xfree(foundInfo->last_event); xfree(foundInfo); + + // remove it from gdb's thread DB + delete_thread(ptid_build(teamDebugInfo->team, 0, threadID)); + return; } } @@ -235,6 +255,9 @@ haiku_init_thread_list(team_debug_info *teamDebugInfo) thread_info threadInfo; int32 cookie = 0; + // init gdb's thread DB + init_thread_list(); + while (get_next_thread_info(teamDebugInfo->team, &cookie, &threadInfo) == B_OK) { haiku_add_thread(teamDebugInfo, threadInfo.thread); @@ -250,6 +273,9 @@ haiku_cleanup_thread_list(team_debug_info *teamDebugInfo) teamDebugInfo->threads = thread->next; xfree(thread); } + + // clear gdb's thread DB + init_thread_list(); } @@ -371,11 +397,9 @@ haiku_get_next_image_info(int lastID) static void haiku_cleanup_team_debug_info() { + destroy_debug_context(&sTeamDebugInfo.context); delete_port(sTeamDebugInfo.debugger_port); - delete_port(sTeamDebugInfo.reply_port); sTeamDebugInfo.debugger_port = -1; - sTeamDebugInfo.reply_port = -1; - sTeamDebugInfo.nub_port = -1; sTeamDebugInfo.team = -1; haiku_cleanup_thread_list(&sTeamDebugInfo); @@ -387,29 +411,8 @@ static status_t haiku_send_debugger_message(team_debug_info *teamDebugInfo, int32 messageCode, const void *message, int32 messageSize, void *reply, int32 replySize) { - // send message - while (true) { - status_t result = write_port(teamDebugInfo->nub_port, messageCode, - message, messageSize); - if (result == B_OK) - break; - if (result != B_INTERRUPTED) - return result; - } - - if (!reply) - return B_OK; - - // read reply - while (true) { - int32 code; - ssize_t bytesRead = read_port(teamDebugInfo->reply_port, &code, - reply, replySize); - if (bytesRead > 0) - return B_OK; - if (bytesRead != B_INTERRUPTED) - return bytesRead; - } + return send_debug_message(&teamDebugInfo->context, messageCode, + message, messageSize, reply, replySize); } @@ -418,6 +421,7 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread) { thread_info threadInfo; status_t result; + port_id nubPort; // get a thread info result = get_thread_info(threadID, &threadInfo); @@ -427,8 +431,8 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread) // init our team debug structure sTeamDebugInfo.team = threadInfo.team; sTeamDebugInfo.debugger_port = -1; - sTeamDebugInfo.nub_port = -1; - sTeamDebugInfo.reply_port = -1; + sTeamDebugInfo.context.nub_port = -1; + sTeamDebugInfo.context.reply_port = -1; sTeamDebugInfo.threads = NULL; sTeamDebugInfo.events.head = NULL; sTeamDebugInfo.events.tail = NULL; @@ -440,19 +444,20 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread) strerror(sTeamDebugInfo.debugger_port)); } - // create a reply port - sTeamDebugInfo.reply_port = create_port(10, "gdb debug reply"); - if (sTeamDebugInfo.reply_port < 0) { - error("Failed to create reply port: %s", - strerror(sTeamDebugInfo.reply_port)); + // install ourselves as the team debugger + nubPort = install_team_debugger(sTeamDebugInfo.team, + sTeamDebugInfo.debugger_port); + if (nubPort < 0) { + error("Failed to install ourselves as debugger for team %ld: %s", + sTeamDebugInfo.team, strerror(nubPort)); } - // install ourselves as the team debugger - sTeamDebugInfo.nub_port = install_team_debugger(sTeamDebugInfo.team, - sTeamDebugInfo.debugger_port); - if (sTeamDebugInfo.nub_port < 0) { - error("Failed to install ourselves as debugger for team %ld: %s", - sTeamDebugInfo.team, strerror(sTeamDebugInfo.nub_port)); + // init the debug context + result = init_debug_context(&sTeamDebugInfo.context, sTeamDebugInfo.team, + nubPort); + if (result != B_OK) { + error("Failed to init debug context for team %ld: %s\n", + sTeamDebugInfo.team, strerror(result)); } // start debugging the thread @@ -476,13 +481,12 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread) B_DEBUG_MESSAGE_SET_TEAM_FLAGS, &message, sizeof(message), NULL, 0); } - haiku_init_thread_list(&sTeamDebugInfo); - haiku_init_image_list(&sTeamDebugInfo); // the fun can start: push the target and init the rest push_target(sHaikuTarget); - init_thread_list (); + haiku_init_thread_list(&sTeamDebugInfo); + haiku_init_image_list(&sTeamDebugInfo); disable_breakpoints_in_shlibs (1); @@ -525,7 +529,7 @@ haiku_get_cpu_state(team_debug_info *teamDebugInfo, thread_id threadID = ptid_get_tid(inferior_ptid); debug_nub_get_cpu_state message; - message.reply_port = teamDebugInfo->reply_port; + message.reply_port = teamDebugInfo->context.reply_port; message.thread = threadID; err = haiku_send_debugger_message(teamDebugInfo, @@ -744,20 +748,9 @@ haiku_child_attach (char *args, int from_tty) if (threadID <= 0) error("The given thread-id %ld is invalid.", threadID); -// TODO: When attaching to a crashed team, the crashed thread is continued! -// Don't know yet where that happens, but it needs to be fixed! haiku_init_child_debugging(threadID, true); - while (1) { - stop_after_trap = 1; - wait_for_inferior (); -// TODO: Catch deadly events, so that we won't block here. -// if (debugThread && stop_signal != TARGET_SIGNAL_TRAP) -// resume (0, stop_signal); -// else - break; - } - stop_after_trap = 0; + TRACE(("haiku_child_attach() done\n")); } @@ -927,8 +920,8 @@ haiku_child_resume (ptid_t ptid, int step, enum target_signal sig) static ptid_t -haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, - bool *ignore) +haiku_child_wait_internal (team_debug_info *teamDebugInfo, ptid_t ptid, + struct target_waitstatus *ourstatus, bool *ignore) { team_id teamID = ptid_get_pid(ptid); team_id threadID = ptid_get_tid(ptid); @@ -945,7 +938,7 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, // if we're waiting for any thread, search the thread list for already // stopped threads (needed for reprocessing events) if (threadID < 0) { - for (thread = sTeamDebugInfo.threads; thread; thread = thread->next) { + for (thread = teamDebugInfo->threads; thread; thread = thread->next) { if (thread->stopped) { threadID = thread->thread; break; @@ -955,7 +948,7 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, // check, if the thread exists and is already stopped if (threadID >= 0 - && (thread = haiku_find_thread(&sTeamDebugInfo, threadID)) != NULL + && (thread = haiku_find_thread(teamDebugInfo, threadID)) != NULL && thread->stopped) { // remove the event that stopped the thread from the thread (we will // add it again, if it shall not be ignored) @@ -969,22 +962,22 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, } else { // prepare closure for finding interesting events thread_event_closure threadEventClosure; - threadEventClosure.context = &sTeamDebugInfo; + threadEventClosure.context = teamDebugInfo; threadEventClosure.thread = threadID; threadEventClosure.event = NULL; // find the first interesting queued event threadEventClosure.event = haiku_find_next_debug_event( - &sTeamDebugInfo.events, haiku_thread_event_predicate, + &teamDebugInfo->events, haiku_thread_event_predicate, &threadEventClosure); // read all events pending on the port - haiku_read_pending_debug_events(&sTeamDebugInfo, + haiku_read_pending_debug_events(teamDebugInfo, (threadEventClosure.event == NULL), haiku_thread_event_predicate, &threadEventClosure); // get the event of interest - event = haiku_remove_debug_event(&sTeamDebugInfo.events, + event = haiku_remove_debug_event(&teamDebugInfo->events, threadEventClosure.event); if (!event) { @@ -998,7 +991,7 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, event->data.origin.nub_port)); } - if (event->data.origin.team != sTeamDebugInfo.team) { + if (event->data.origin.team != teamDebugInfo->team) { // Spurious debug message. Doesn't concern our team. Ignore. xfree(event); return retval; @@ -1010,7 +1003,23 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, switch (event->message) { case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: - // TODO: Print the debugger message. + { + // print the debugger message + char debuggerMessage[1024]; + ssize_t bytesRead = debug_read_string(&teamDebugInfo->context, + event->data.debugger_call.message, debuggerMessage, + sizeof(debuggerMessage)); + if (bytesRead > 0) { + printf_unfiltered ("Thread %ld called debugger(): %s\n", + event->data.origin.thread, debuggerMessage); + } else { + printf_unfiltered ("Thread %ld called debugger(), but failed" + "to get the debugger message.\n", + event->data.origin.thread); + } + + // fall through... + } case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: @@ -1039,12 +1048,20 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, break; case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: - // TODO: Print the exception message. + { + // print the exception message + char exception[1024]; + get_debug_exception_string(event->data.exception_occurred.exception, + exception, sizeof(exception)); + printf_unfiltered ("Thread %ld caused an exception: %s\n", + event->data.origin.thread, exception); + pendingSignal = event->data.exception_occurred.signal; pendingSignalStatus = SIGNAL_WILL_ARRIVE; ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->value.sig = haiku_to_target_signal(pendingSignal); break; + } case B_DEBUGGER_MESSAGE_TEAM_CREATED: // ignore @@ -1059,14 +1076,14 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, case B_DEBUGGER_MESSAGE_THREAD_CREATED: // internal bookkeeping only - haiku_add_thread(&sTeamDebugInfo, + haiku_add_thread(teamDebugInfo, event->data.thread_created.new_thread); *ignore = true; break; case B_DEBUGGER_MESSAGE_THREAD_DELETED: // internal bookkeeping - haiku_remove_thread(&sTeamDebugInfo, + haiku_remove_thread(teamDebugInfo, event->data.thread_deleted.origin.thread); *ignore = true; @@ -1076,10 +1093,10 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, case B_DEBUGGER_MESSAGE_IMAGE_CREATED: if (reprocessEvent < 0) { // first time we see the event: update our image list -// haiku_add_image(&sTeamDebugInfo, +// haiku_add_image(teamDebugInfo, // &event->data.image_created.info); -haiku_cleanup_image_list(&sTeamDebugInfo); -haiku_init_image_list(&sTeamDebugInfo); +haiku_cleanup_image_list(teamDebugInfo); +haiku_init_image_list(teamDebugInfo); // TODO: We don't get events when images have been removed in preparation of // an exec*() yet. } @@ -1137,7 +1154,7 @@ TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n")) break; case B_DEBUGGER_MESSAGE_IMAGE_DELETED: - haiku_remove_image(&sTeamDebugInfo, + haiku_remove_image(teamDebugInfo, event->data.image_created.info.id); // send TARGET_WAITKIND_LOADED here too, it causes the shared @@ -1154,7 +1171,7 @@ TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n")) // make the event the thread's last event or delete it if (!*ignore && event->data.origin.thread >= 0) { - struct thread_debug_info *thread = haiku_find_thread(&sTeamDebugInfo, + struct thread_debug_info *thread = haiku_find_thread(teamDebugInfo, event->data.origin.thread); if (thread->last_event) xfree(thread->last_event); @@ -1169,7 +1186,7 @@ TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n")) // continue the thread if (event->data.origin.thread >= 0) { - haiku_continue_thread(&sTeamDebugInfo, event->data.origin.thread, + haiku_continue_thread(teamDebugInfo, event->data.origin.thread, B_THREAD_DEBUG_HANDLE_EVENT, false); } @@ -1192,7 +1209,8 @@ haiku_child_wait (ptid_t ptid, struct target_waitstatus *ourstatus) haiku_pid_to_str(ptid), ourstatus)); do { - retval = haiku_child_wait_internal(ptid, ourstatus, &ignore); + retval = haiku_child_wait_internal(&sTeamDebugInfo, ptid, ourstatus, + &ignore); } while (ignore); TRACE(("haiku_child_wait() done: `%s'\n", haiku_pid_to_str(retval))); @@ -1269,7 +1287,7 @@ haiku_child_deprecated_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, if (len > B_MAX_READ_WRITE_MEMORY_SIZE) len = B_MAX_READ_WRITE_MEMORY_SIZE; - message.reply_port = sTeamDebugInfo.reply_port; + message.reply_port = sTeamDebugInfo.context.reply_port; message.address = (void*)memaddr; message.size = len; memcpy(message.data, myaddr, len); @@ -1288,22 +1306,9 @@ TRACE(("haiku_child_deprecated_xfer_memory(): -> %ld\n", reply.size)); return reply.size; } else { // read - debug_nub_read_memory message; - debug_nub_read_memory_reply reply; - status_t err; - - message.reply_port = sTeamDebugInfo.reply_port; - message.address = (void*)memaddr; - message.size = len; - - err = haiku_send_debugger_message(&sTeamDebugInfo, - B_DEBUG_MESSAGE_READ_MEMORY, &message, sizeof(message), &reply, - sizeof(reply)); - if (err != B_OK || reply.error != B_OK) - return 0; - - memcpy(myaddr, reply.data, reply.size); - return reply.size; + ssize_t bytesRead = debug_read_memory_partial(&sTeamDebugInfo.context, + (const void *)memaddr, myaddr, len); + return (bytesRead < 0 ? 0 : bytesRead); } return -1;