* 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
This commit is contained in:
Ingo Weinhold
2005-07-19 23:29:04 +00:00
parent a79265708d
commit 6ff2656c03
2 changed files with 101 additions and 94 deletions
+2
View File
@@ -9,6 +9,7 @@ SubDirHdrs [ FDirName $(OBOS_TOP) src bin gawk intl ] ;
# Use gawk's libintl for the time being. # Use gawk's libintl for the time being.
# TODO: Put a current version of intl ot src/libs and build a static lib # TODO: Put a current version of intl ot src/libs and build a static lib
# all interested apps can link against. # all interested apps can link against.
UsePrivateHeaders debug ;
SubDirCcFlags -DHAVE_CONFIG_H -DLOCALEDIR=\\\"/boot/beos/etc/locale\\\" SubDirCcFlags -DHAVE_CONFIG_H -DLOCALEDIR=\\\"/boot/beos/etc/locale\\\"
-DMI_OUT=1 ; -DMI_OUT=1 ;
@@ -260,6 +261,7 @@ BinCommand gdb : gdb.c :
libtermcap.a libtermcap.a
libroot.so libroot.so
libdebug.so
libbind.so libbind.so
libsocket.so libsocket.so
; ;
+99 -94
View File
@@ -26,6 +26,8 @@
#include <image.h> #include <image.h>
#include <OS.h> #include <OS.h>
#include <debug_support.h>
#include "defs.h" // include this first -- otherwise "command.h" will choke #include "defs.h" // include this first -- otherwise "command.h" will choke
#include "command.h" #include "command.h"
#include "gdbcore.h" #include "gdbcore.h"
@@ -91,8 +93,7 @@ typedef struct extended_image_info {
typedef struct team_debug_info { typedef struct team_debug_info {
team_id team; team_id team;
port_id debugger_port; port_id debugger_port;
port_id nub_port; debug_context context;
port_id reply_port;
thread_debug_info *threads; thread_debug_info *threads;
extended_image_info *images; extended_image_info *images;
debug_event_list events; debug_event_list events;
@@ -190,6 +191,8 @@ haiku_find_thread(team_debug_info *teamDebugInfo, thread_id threadID)
static thread_debug_info * static thread_debug_info *
haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID) haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID)
{ {
struct thread_info *gdbThreadInfo;
// find the thread first // find the thread first
thread_debug_info *threadDebugInfo thread_debug_info *threadDebugInfo
= haiku_find_thread(teamDebugInfo, threadID); = haiku_find_thread(teamDebugInfo, threadID);
@@ -208,6 +211,19 @@ haiku_add_thread(team_debug_info *teamDebugInfo, thread_id threadID)
threadDebugInfo->last_event = NULL; threadDebugInfo->last_event = NULL;
teamDebugInfo->threads = threadDebugInfo; 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; return threadDebugInfo;
} }
@@ -223,6 +239,10 @@ haiku_remove_thread(team_debug_info *teamDebugInfo, thread_id threadID)
if (foundInfo->last_event) if (foundInfo->last_event)
xfree(foundInfo->last_event); xfree(foundInfo->last_event);
xfree(foundInfo); xfree(foundInfo);
// remove it from gdb's thread DB
delete_thread(ptid_build(teamDebugInfo->team, 0, threadID));
return; return;
} }
} }
@@ -235,6 +255,9 @@ haiku_init_thread_list(team_debug_info *teamDebugInfo)
thread_info threadInfo; thread_info threadInfo;
int32 cookie = 0; int32 cookie = 0;
// init gdb's thread DB
init_thread_list();
while (get_next_thread_info(teamDebugInfo->team, &cookie, &threadInfo) while (get_next_thread_info(teamDebugInfo->team, &cookie, &threadInfo)
== B_OK) { == B_OK) {
haiku_add_thread(teamDebugInfo, threadInfo.thread); haiku_add_thread(teamDebugInfo, threadInfo.thread);
@@ -250,6 +273,9 @@ haiku_cleanup_thread_list(team_debug_info *teamDebugInfo)
teamDebugInfo->threads = thread->next; teamDebugInfo->threads = thread->next;
xfree(thread); xfree(thread);
} }
// clear gdb's thread DB
init_thread_list();
} }
@@ -371,11 +397,9 @@ haiku_get_next_image_info(int lastID)
static void static void
haiku_cleanup_team_debug_info() haiku_cleanup_team_debug_info()
{ {
destroy_debug_context(&sTeamDebugInfo.context);
delete_port(sTeamDebugInfo.debugger_port); delete_port(sTeamDebugInfo.debugger_port);
delete_port(sTeamDebugInfo.reply_port);
sTeamDebugInfo.debugger_port = -1; sTeamDebugInfo.debugger_port = -1;
sTeamDebugInfo.reply_port = -1;
sTeamDebugInfo.nub_port = -1;
sTeamDebugInfo.team = -1; sTeamDebugInfo.team = -1;
haiku_cleanup_thread_list(&sTeamDebugInfo); haiku_cleanup_thread_list(&sTeamDebugInfo);
@@ -387,29 +411,8 @@ static status_t
haiku_send_debugger_message(team_debug_info *teamDebugInfo, int32 messageCode, haiku_send_debugger_message(team_debug_info *teamDebugInfo, int32 messageCode,
const void *message, int32 messageSize, void *reply, int32 replySize) const void *message, int32 messageSize, void *reply, int32 replySize)
{ {
// send message return send_debug_message(&teamDebugInfo->context, messageCode,
while (true) { message, messageSize, reply, replySize);
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;
}
} }
@@ -418,6 +421,7 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread)
{ {
thread_info threadInfo; thread_info threadInfo;
status_t result; status_t result;
port_id nubPort;
// get a thread info // get a thread info
result = get_thread_info(threadID, &threadInfo); result = get_thread_info(threadID, &threadInfo);
@@ -427,8 +431,8 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread)
// init our team debug structure // init our team debug structure
sTeamDebugInfo.team = threadInfo.team; sTeamDebugInfo.team = threadInfo.team;
sTeamDebugInfo.debugger_port = -1; sTeamDebugInfo.debugger_port = -1;
sTeamDebugInfo.nub_port = -1; sTeamDebugInfo.context.nub_port = -1;
sTeamDebugInfo.reply_port = -1; sTeamDebugInfo.context.reply_port = -1;
sTeamDebugInfo.threads = NULL; sTeamDebugInfo.threads = NULL;
sTeamDebugInfo.events.head = NULL; sTeamDebugInfo.events.head = NULL;
sTeamDebugInfo.events.tail = NULL; sTeamDebugInfo.events.tail = NULL;
@@ -440,19 +444,20 @@ haiku_init_child_debugging (thread_id threadID, bool debugThread)
strerror(sTeamDebugInfo.debugger_port)); strerror(sTeamDebugInfo.debugger_port));
} }
// create a reply port // install ourselves as the team debugger
sTeamDebugInfo.reply_port = create_port(10, "gdb debug reply"); nubPort = install_team_debugger(sTeamDebugInfo.team,
if (sTeamDebugInfo.reply_port < 0) { sTeamDebugInfo.debugger_port);
error("Failed to create reply port: %s", if (nubPort < 0) {
strerror(sTeamDebugInfo.reply_port)); error("Failed to install ourselves as debugger for team %ld: %s",
sTeamDebugInfo.team, strerror(nubPort));
} }
// install ourselves as the team debugger // init the debug context
sTeamDebugInfo.nub_port = install_team_debugger(sTeamDebugInfo.team, result = init_debug_context(&sTeamDebugInfo.context, sTeamDebugInfo.team,
sTeamDebugInfo.debugger_port); nubPort);
if (sTeamDebugInfo.nub_port < 0) { if (result != B_OK) {
error("Failed to install ourselves as debugger for team %ld: %s", error("Failed to init debug context for team %ld: %s\n",
sTeamDebugInfo.team, strerror(sTeamDebugInfo.nub_port)); sTeamDebugInfo.team, strerror(result));
} }
// start debugging the thread // 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); 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 // the fun can start: push the target and init the rest
push_target(sHaikuTarget); push_target(sHaikuTarget);
init_thread_list (); haiku_init_thread_list(&sTeamDebugInfo);
haiku_init_image_list(&sTeamDebugInfo);
disable_breakpoints_in_shlibs (1); 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); thread_id threadID = ptid_get_tid(inferior_ptid);
debug_nub_get_cpu_state message; debug_nub_get_cpu_state message;
message.reply_port = teamDebugInfo->reply_port; message.reply_port = teamDebugInfo->context.reply_port;
message.thread = threadID; message.thread = threadID;
err = haiku_send_debugger_message(teamDebugInfo, err = haiku_send_debugger_message(teamDebugInfo,
@@ -744,20 +748,9 @@ haiku_child_attach (char *args, int from_tty)
if (threadID <= 0) if (threadID <= 0)
error("The given thread-id %ld is invalid.", threadID); 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); haiku_init_child_debugging(threadID, true);
while (1) { TRACE(("haiku_child_attach() done\n"));
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;
} }
@@ -927,8 +920,8 @@ haiku_child_resume (ptid_t ptid, int step, enum target_signal sig)
static ptid_t static ptid_t
haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus, haiku_child_wait_internal (team_debug_info *teamDebugInfo, ptid_t ptid,
bool *ignore) struct target_waitstatus *ourstatus, bool *ignore)
{ {
team_id teamID = ptid_get_pid(ptid); team_id teamID = ptid_get_pid(ptid);
team_id threadID = ptid_get_tid(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 // if we're waiting for any thread, search the thread list for already
// stopped threads (needed for reprocessing events) // stopped threads (needed for reprocessing events)
if (threadID < 0) { if (threadID < 0) {
for (thread = sTeamDebugInfo.threads; thread; thread = thread->next) { for (thread = teamDebugInfo->threads; thread; thread = thread->next) {
if (thread->stopped) { if (thread->stopped) {
threadID = thread->thread; threadID = thread->thread;
break; 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 // check, if the thread exists and is already stopped
if (threadID >= 0 if (threadID >= 0
&& (thread = haiku_find_thread(&sTeamDebugInfo, threadID)) != NULL && (thread = haiku_find_thread(teamDebugInfo, threadID)) != NULL
&& thread->stopped) { && thread->stopped) {
// remove the event that stopped the thread from the thread (we will // remove the event that stopped the thread from the thread (we will
// add it again, if it shall not be ignored) // 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 { } else {
// prepare closure for finding interesting events // prepare closure for finding interesting events
thread_event_closure threadEventClosure; thread_event_closure threadEventClosure;
threadEventClosure.context = &sTeamDebugInfo; threadEventClosure.context = teamDebugInfo;
threadEventClosure.thread = threadID; threadEventClosure.thread = threadID;
threadEventClosure.event = NULL; threadEventClosure.event = NULL;
// find the first interesting queued event // find the first interesting queued event
threadEventClosure.event = haiku_find_next_debug_event( threadEventClosure.event = haiku_find_next_debug_event(
&sTeamDebugInfo.events, haiku_thread_event_predicate, &teamDebugInfo->events, haiku_thread_event_predicate,
&threadEventClosure); &threadEventClosure);
// read all events pending on the port // 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.event == NULL), haiku_thread_event_predicate,
&threadEventClosure); &threadEventClosure);
// get the event of interest // get the event of interest
event = haiku_remove_debug_event(&sTeamDebugInfo.events, event = haiku_remove_debug_event(&teamDebugInfo->events,
threadEventClosure.event); threadEventClosure.event);
if (!event) { if (!event) {
@@ -998,7 +991,7 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus,
event->data.origin.nub_port)); 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. // Spurious debug message. Doesn't concern our team. Ignore.
xfree(event); xfree(event);
return retval; return retval;
@@ -1010,7 +1003,23 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus,
switch (event->message) { switch (event->message) {
case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 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_THREAD_DEBUGGED:
case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
@@ -1039,12 +1048,20 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus,
break; break;
case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 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; pendingSignal = event->data.exception_occurred.signal;
pendingSignalStatus = SIGNAL_WILL_ARRIVE; pendingSignalStatus = SIGNAL_WILL_ARRIVE;
ourstatus->kind = TARGET_WAITKIND_STOPPED; ourstatus->kind = TARGET_WAITKIND_STOPPED;
ourstatus->value.sig = haiku_to_target_signal(pendingSignal); ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
break; break;
}
case B_DEBUGGER_MESSAGE_TEAM_CREATED: case B_DEBUGGER_MESSAGE_TEAM_CREATED:
// ignore // ignore
@@ -1059,14 +1076,14 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus,
case B_DEBUGGER_MESSAGE_THREAD_CREATED: case B_DEBUGGER_MESSAGE_THREAD_CREATED:
// internal bookkeeping only // internal bookkeeping only
haiku_add_thread(&sTeamDebugInfo, haiku_add_thread(teamDebugInfo,
event->data.thread_created.new_thread); event->data.thread_created.new_thread);
*ignore = true; *ignore = true;
break; break;
case B_DEBUGGER_MESSAGE_THREAD_DELETED: case B_DEBUGGER_MESSAGE_THREAD_DELETED:
// internal bookkeeping // internal bookkeeping
haiku_remove_thread(&sTeamDebugInfo, haiku_remove_thread(teamDebugInfo,
event->data.thread_deleted.origin.thread); event->data.thread_deleted.origin.thread);
*ignore = true; *ignore = true;
@@ -1076,10 +1093,10 @@ haiku_child_wait_internal (ptid_t ptid, struct target_waitstatus *ourstatus,
case B_DEBUGGER_MESSAGE_IMAGE_CREATED: case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
if (reprocessEvent < 0) { if (reprocessEvent < 0) {
// first time we see the event: update our image list // first time we see the event: update our image list
// haiku_add_image(&sTeamDebugInfo, // haiku_add_image(teamDebugInfo,
// &event->data.image_created.info); // &event->data.image_created.info);
haiku_cleanup_image_list(&sTeamDebugInfo); haiku_cleanup_image_list(teamDebugInfo);
haiku_init_image_list(&sTeamDebugInfo); haiku_init_image_list(teamDebugInfo);
// TODO: We don't get events when images have been removed in preparation of // TODO: We don't get events when images have been removed in preparation of
// an exec*() yet. // an exec*() yet.
} }
@@ -1137,7 +1154,7 @@ TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n"))
break; break;
case B_DEBUGGER_MESSAGE_IMAGE_DELETED: case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
haiku_remove_image(&sTeamDebugInfo, haiku_remove_image(teamDebugInfo,
event->data.image_created.info.id); event->data.image_created.info.id);
// send TARGET_WAITKIND_LOADED here too, it causes the shared // 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 // make the event the thread's last event or delete it
if (!*ignore && event->data.origin.thread >= 0) { 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); event->data.origin.thread);
if (thread->last_event) if (thread->last_event)
xfree(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 // continue the thread
if (event->data.origin.thread >= 0) { 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); 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)); haiku_pid_to_str(ptid), ourstatus));
do { do {
retval = haiku_child_wait_internal(ptid, ourstatus, &ignore); retval = haiku_child_wait_internal(&sTeamDebugInfo, ptid, ourstatus,
&ignore);
} while (ignore); } while (ignore);
TRACE(("haiku_child_wait() done: `%s'\n", haiku_pid_to_str(retval))); 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) if (len > B_MAX_READ_WRITE_MEMORY_SIZE)
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.address = (void*)memaddr;
message.size = len; message.size = len;
memcpy(message.data, myaddr, len); memcpy(message.data, myaddr, len);
@@ -1288,22 +1306,9 @@ TRACE(("haiku_child_deprecated_xfer_memory(): -> %ld\n", reply.size));
return reply.size; return reply.size;
} else { } else {
// read // read
debug_nub_read_memory message; ssize_t bytesRead = debug_read_memory_partial(&sTeamDebugInfo.context,
debug_nub_read_memory_reply reply; (const void *)memaddr, myaddr, len);
status_t err; return (bytesRead < 0 ? 0 : bytesRead);
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;
} }
return -1; return -1;