* 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.
# 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
;
+99 -94
View File
@@ -26,6 +26,8 @@
#include <image.h>
#include <OS.h>
#include <debug_support.h>
#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;