Subject: toolchain/21710: Add support for remote debugging of PowerPC targets
To: None <gnats-bugs@gnats.netbsd.org>
From: None <john_94501@yahoo.com>
List: netbsd-bugs
Date: 05/29/2003 08:45:45
>Number: 21710
>Category: toolchain
>Synopsis: Add support for remote debugging of PowerPC targets
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: toolchain-manager
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu May 29 08:46:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator: John Gordon
>Release: -current (5/27/2003)
>Organization:
blueDonkey.org
>Environment:
N/A
>Description:
The current version of gdbserver does not have support for PowerPC, nor does it have support for threads.
>How-To-Repeat:
N/A
>Fix:
The patch below adds support for PowerPC to gdbserver, and also adds supports for pthreads using the pthread_dbg library (this was based on the code in gdb itself for native debugging of threaded applications).
More information about this can be found at: http://www.bluedonkey.org/cgi-bin/twiki/bin/view/Netbsd/RemoteDebugging
One additional file is needed in the tree, src/gnu/usr.bin/gdb/arch/powerpc/gdbserver.mk, the content of which is as follows:
G_INTERNAL_CFLAGS=-g -I. -I.. -I${DIST}/gdb/gdbserver -I${DIST}/gdb/gdbserver/.. -I${DIST}/gdb/gdbserver/../config -I${DIST}/gdb/gdbserver/../../include -I../../bfd -I${DIST}/gdb/gdbserver/../../bfd -DGDBSERVER
G_OBS=utils.o low-nbsd.o server.o remote-utils.o
This file can be downloaded from http://www.bluedonkey.org/twiki/pub/Netbsd/RemoteDebugging/gdbserver.mk
The patch can be downloaded from: http://www.bluedonkey.org/twiki/pub/Netbsd/RemoteDebugging/gdbserver-20030527.patch
It is also pasted here:
? gnu/usr.bin/gdb/arch/powerpc/gdbserver.mk
Index: gnu/dist/toolchain/gdb/remote.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/remote.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 remote.c
--- gnu/dist/toolchain/gdb/remote.c 2000/07/26 00:32:58 1.1.1.1
+++ gnu/dist/toolchain/gdb/remote.c 2003/05/29 06:54:15
@@ -91,6 +91,8 @@
static void extended_remote_open PARAMS ((char *name, int from_tty));
static void extended_remote_async_open PARAMS ((char *name, int from_tty));
+static void remote_check_symbols PARAMS ((struct objfile *objfile));
+
static void remote_open_1 PARAMS ((char *, int, struct target_ops *,
int extended_p));
static void remote_async_open_1 PARAMS ((char *, int, struct target_ops *,
@@ -185,6 +187,8 @@
static void record_currthread PARAMS ((int currthread));
+static int hex2bin PARAMS ((const char *hex, char *bin, int count));
+
/* exported functions */
extern int fromhex PARAMS ((int a));
@@ -1595,10 +1599,16 @@
char *buf = alloca (PBUFSIZ);
char *bufp;
int tid;
+ static int threading_initialised = 0;
if (remote_desc == 0) /* paranoia */
error ("Command can only be used when connected to the remote target.");
+ if (!threading_initialised)
+ {
+ remote_check_symbols(symfile_objfile);
+ }
+
if (use_threadinfo_query)
{
putpkt ("qfThreadInfo");
@@ -1606,12 +1616,21 @@
getpkt (bufp, PBUFSIZ, 0);
if (bufp[0] != '\0') /* q packet recognized */
{
+ if (bufp[0] == 'l')
+ return;
+
+ threading_initialised = 1; /* threading is now ready */
+
while (*bufp++ == 'm') /* reply contains one or more TID */
{
do
{
tid = strtol (bufp, &bufp, 16);
+#if 0
if (tid != 0 && !in_thread_list (tid))
+#else
+ if (!in_thread_list (tid))
+#endif
add_thread (tid);
}
while (*bufp++ == ','); /* comma-separated list */
@@ -2004,6 +2023,61 @@
remote_async_open_1 (name, from_tty, &extended_async_remote_ops, 1 /*extended_p */ );
}
+/* Hex/numeric conversion */
+
+static int
+hex2bin (const char *hex, char *bin, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (hex[0] == 0 || hex[1] == 0)
+ {
+ /* Hex string is short, or of uneven length.
+ Return the count that has been converted so far. */
+ return i;
+ }
+ *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
+ hex += 2;
+ }
+ return i;
+}
+
+/* Symbol lookup support */
+
+static void
+remote_check_symbols (struct objfile *objfile)
+{
+ char *msg, *reply, *tmp;
+ struct minimal_symbol *sym;
+ int end;
+
+ msg = alloca (PBUFSIZ);
+ reply = alloca (PBUFSIZ);
+
+ /* Invite target to request symbol lookups. */
+
+ putpkt ("qSymbol::");
+ getpkt (reply, PBUFSIZ, 0);
+
+ while (strncmp (reply, "qSymbol:", 8) == 0)
+ {
+ tmp = &reply[8];
+ end = hex2bin (tmp, msg, strlen (tmp) / 2);
+ msg[end] = '\0';
+ sym = lookup_minimal_symbol (msg, NULL, NULL);
+ if (sym == NULL)
+ sprintf (msg, "qSymbol::%s", &reply[8]);
+ else
+ sprintf (msg, "qSymbol:%s:%s",
+ paddr_nz (SYMBOL_VALUE_ADDRESS (sym)),
+ &reply[8]);
+ putpkt (msg);
+ getpkt (reply, PBUFSIZ, 0);
+ }
+}
+
/* Generic code for opening a connection to a remote target. */
static DCACHE *remote_dcache;
@@ -2015,6 +2089,10 @@
struct target_ops *target;
int extended_p;
{
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ extern bfd *exec_bfd;
+#endif
+
if (name == 0)
error ("To open a remote debug connection, you need to specify what\n\
serial device is attached to the remote system\n\
@@ -2096,6 +2174,20 @@
putpkt ("!");
getpkt (buf, PBUFSIZ, 0);
}
+
+ /* Deal with any symbols that the target side needs */
+
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+ if (exec_bfd)
+ {
+ struct minimal_symbol *start;
+ struct target_waitstatus status;
+ CORE_ADDR _start_addr;
+ char saved [BREAKPOINT_MAX];
+
+ SOLIB_CREATE_INFERIOR_HOOK (inferior_pid);
+ }
+#endif
}
/* Just like remote_open but with asynchronous support. */
@@ -5597,6 +5689,8 @@
#if 0
init_remote_threadtests ();
#endif
+
+ init_thread_list ();
add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, "\
Remote protocol specific variables\n\
Index: gnu/dist/toolchain/gdb/solib.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/solib.c,v
retrieving revision 1.5
diff -u -r1.5 solib.c
--- gnu/dist/toolchain/gdb/solib.c 2002/01/18 04:15:02 1.5
+++ gnu/dist/toolchain/gdb/solib.c 2003/05/29 06:54:19
@@ -19,6 +19,10 @@
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/*
+ * Enable debug output
+ */
+#undef DEBUG
#include "defs.h"
@@ -1809,6 +1813,7 @@
CORE_ADDR load_addr;
bfd *tmp_bfd;
CORE_ADDR sym_addr = 0;
+ char * tmp_buf;
/* Read the contents of the .interp section into a local buffer;
the contents specify the dynamic linker this program uses. */
@@ -1825,10 +1830,40 @@
to find any magic formula to find it for Solaris (appears to
be trivial on GNU/Linux). Therefore, we have to try an alternate
mechanism to find the dynamic linker's base address. */
- tmp_bfd = bfd_openr (buf, gnutarget);
+
+ /* If the absolute prefix is set, use it */
+
+ if (solib_absolute_prefix != NULL)
+ {
+ tmp_buf = xmalloc (strlen (buf) + strlen (solib_absolute_prefix) + 1);
+
+ if (tmp_buf)
+ {
+ strcpy (tmp_buf, solib_absolute_prefix);
+ strcat (tmp_buf, buf);
+ }
+ }
+ else
+ {
+ tmp_buf = buf;
+ }
+
+ tmp_bfd = bfd_openr (tmp_buf, gnutarget);
+#ifdef DEBUG
+ fprintf (stderr, "bfd_openr ('%s', '%s') == %p\n", tmp_buf, gnutarget,
+ tmp_bfd);
+#endif
+
if (tmp_bfd == NULL)
- goto bkpt_at_symbol;
+ {
+ goto bkpt_at_symbol;
+ }
+
+ /* Free the buffer we allocated, if we did allocate one */
+ if ((solib_absolute_prefix != NULL) && (tmp_buf))
+ free (tmp_buf);
+
/* Make sure the dynamic linker's really a useful object. */
if (!bfd_check_format (tmp_bfd, bfd_object))
{
@@ -1861,10 +1896,21 @@
interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
}
+#ifdef DEBUG
+ fprintf (stderr, "interp_text_sect_low = %#x\n", interp_text_sect_low);
+ fprintf (stderr, "interp_text_sect_high = %#x\n", interp_text_sect_high);
+ fprintf (stderr, "interp_plt_sect_low = %#x\n", interp_plt_sect_low);
+ fprintf (stderr, "interp_plt_sect_high = %#x\n", interp_plt_sect_high);
+#endif
+
/* Now try to set a breakpoint in the dynamic linker. */
for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
{
sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep);
+#ifdef DEBUG
+ fprintf (stderr, "bfd_lookup_symbol (%p, '%s') = %#x\n", tmp_bfd,
+ *bkpt_namep, sym_addr);
+#endif
if (sym_addr != 0)
break;
}
Index: gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt,v
retrieving revision 1.3
diff -u -r1.3 nbsd.mt
--- gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt 2002/01/22 12:25:57 1.3
+++ gnu/dist/toolchain/gdb/config/powerpc/nbsd.mt 2003/05/29 06:54:21
@@ -1,5 +1,5 @@
# Target: Big-endian PowerPC running NetBSD
-TDEPFILES= rs6000-tdep.o
+TDEPFILES= rs6000-tdep.o solib.o
TM_FILE= tm-nbsd.h
SIM_OBS = remote-sim.o
Index: gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h,v
retrieving revision 1.3
diff -u -r1.3 tm-nbsd.h
--- gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h 2003/03/04 21:12:32 1.3
+++ gnu/dist/toolchain/gdb/config/powerpc/tm-nbsd.h 2003/05/29 06:54:21
@@ -27,6 +27,13 @@
#define SOLIB_BKPT_NAME "_start"
+#if !defined(NO_SOLIB)
+#ifndef SVR4_SHARED_LIBS
+#define SVR4_SHARED_LIBS
+#include "solib.h"
+#endif
+#endif
+
#define CANNOT_FETCH_REGISTER(regno) (regno == PS_REGNUM || regno >= MQ_REGNUM)
#define CANNOT_STORE_REGISTER(regno) (regno == PS_REGNUM || regno >= MQ_REGNUM)
Index: gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 low-nbsd.c
--- gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c 2000/07/26 00:33:51 1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/low-nbsd.c 2003/05/29 06:54:23
@@ -17,6 +17,11 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#include "server.h"
+
+#include <pthread.h>
+#include <pthread_dbg.h>
+
#include "defs.h"
#include <sys/types.h>
#include <sys/wait.h>
@@ -35,11 +40,51 @@
register N. */
char buf2[MAX_REGISTER_RAW_SIZE];
+
+/* Thread support */
+
+static td_proc_t *main_ta;
+/* static int cached_thread; */
+
+struct td_proc_callbacks_t nbsd_thread_callbacks;
+
+/* Size of the string passed back to host to describe a thread */
+#define THREAD_INFO_DESC_SIZE 160
+
/***************End MY defs*********************/
#include <sys/ptrace.h>
#include <machine/reg.h>
+/*
+ * Enable lots of debug output - use with care!
+ */
+#undef DEBUG
+
+/* Very minimal symbol table needed for thread support */
+
+struct nbsd_symtbl
+ {
+ char * name;
+ CORE_ADDR addr;
+ } pthread_syms[] = {
+ {"pthread__dbg", NULL},
+ {"pthread__allqueue", NULL},
+ {"pthread__maxlwps", NULL},
+ {"pthread__tsd_alloc", NULL},
+ {"pthread__tsd_destructors", NULL},
+ {NULL, NULL}
+};
+
+/* Thread state strings */
+
+static const char *syncnames[] = {"unknown",
+ "mutex",
+ "cond var",
+ "spinlock",
+ "joining thread"};
+
+
extern int sys_nerr;
// extern char **sys_errlist;
extern char **environ;
@@ -84,7 +129,330 @@
#endif
+#ifdef __powerpc__
+
+void
+supply_register (regno, val)
+ int regno;
+ char *val;
+{
+ if (val)
+ memcpy (®isters[REGISTER_BYTE (regno)], val, REGISTER_RAW_SIZE (regno));
+ else
+ memset (®isters[REGISTER_BYTE (regno)], '\000', REGISTER_RAW_SIZE (regno));
+}
+
+supply_regs (regs)
+ char *regs;
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ supply_register (GP0_REGNUM + i, regs + (i * 4));
+
+ supply_register (LR_REGNUM, regs + (32 * 4));
+ supply_register (CR_REGNUM, regs + (33 * 4));
+ supply_register (XER_REGNUM, regs + (34 * 4));
+ supply_register (CTR_REGNUM, regs + (35 * 4));
+ supply_register (PC_REGNUM, regs + (36 * 4));
+ i = 0;
+ supply_register (PS_REGNUM, (char *) &i);
+}
+
+static void
+unsupply_regs (regs)
+ struct reg *regs;
+{
+ memcpy (regs->fixreg, ®isters[REGISTER_BYTE (GP0_REGNUM)],
+ sizeof (regs->fixreg));
+ memcpy (®s->pc, ®isters[REGISTER_BYTE (PC_REGNUM)],
+ sizeof (regs->pc));
+ memcpy (®s->cr, ®isters[REGISTER_BYTE (CR_REGNUM)],
+ sizeof (regs->cr));
+ memcpy (®s->lr, ®isters[REGISTER_BYTE (LR_REGNUM)],
+ sizeof (regs->lr));
+ memcpy (®s->ctr, ®isters[REGISTER_BYTE (CTR_REGNUM)],
+ sizeof (regs->ctr));
+ memcpy (®s->xer, ®isters[REGISTER_BYTE (XER_REGNUM)],
+ sizeof (regs->xer));
+
+}
+
+static void
+supply_fpregs (fregs)
+ char *fregs;
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ supply_register (FP0_REGNUM + i, fregs + (i * 8));
+}
+
+static void
+unsupply_fpregs (fregs)
+ struct fpreg *fregs;
+{
+ memset (fregs, 0, sizeof (*fregs));
+ memcpy (fregs->fpreg, ®isters[REGISTER_BYTE (FP0_REGNUM)], sizeof (fregs->fpreg));
+}
+
+static void
+nbsd_reg_to_internal (regs)
+ char *regs;
+{
+ supply_regs (regs);
+}
+
+static void
+nbsd_fpreg_to_internal (fregs)
+ char *fregs;
+{
+ supply_fpregs (fregs);
+}
+
+static void
+nbsd_internal_to_reg (regs)
+ char *regs;
+{
+ unsupply_regs (regs);
+}
+
+
+static void
+nbsd_internal_to_fpreg (regs)
+ char *regs;
+{
+ unsupply_fpregs (regs);
+}
+
+static void
+initialize_arch()
+{
+}
+
+#endif /* __powerpc__ */
+
+/* Internal symbol management (mainly for thread support) */
+
+static void
+mysymbol (char * own_buf)
+{
+ static int i;
+ char * p;
+ char * q;
+
+ if (strcmp ("qSymbol::", own_buf) == 0)
+ {
+ /* First step in the process, reset the counter */
+
+ i = 0;
+ }
+ else
+ {
+ p = own_buf + strlen ("qSymbol:");
+ q = p;
+ while (*q && (*q != ':'))
+ q++;
+
+ if ((p != q) && (*q != '\0'))
+ {
+ /* Found a value */
+
+ decode_address (&pthread_syms[i].addr, p, q - p);
+ }
+
+ i++;
+ }
+
+ if (pthread_syms[i].name != NULL)
+ {
+ strcpy (own_buf, "qSymbol:");
+ hexify (own_buf + strlen (own_buf), pthread_syms[i].name,
+ strlen (pthread_syms[i].name));
+ }
+ else
+ {
+ strcpy (own_buf, "OK");
+ }
+ return;
+}
+
+struct string_map
+ {
+ int num;
+ char *str;
+ };
+
+static char *
+td_err_string (errcode)
+ int errcode;
+{
+ static struct string_map
+ td_err_table[] =
+ {
+ {TD_ERR_OK, "generic \"call succeeded\""},
+ {TD_ERR_ERR, "generic error."},
+ {TD_ERR_NOSYM, "symbol not found"},
+ {TD_ERR_NOOBJ, "no object can be found to satisfy query"},
+ {TD_ERR_BADTHREAD, "thread can not answer request"},
+ {TD_ERR_INUSE, "debugging interface already in use for this process"},
+ {TD_ERR_NOLIB, "process is not using libpthread"},
+ {TD_ERR_NOMEM, "out of memory"},
+ {TD_ERR_IO, "process callback error"},
+ {TD_ERR_INVAL, "invalid argument"},
+ };
+ const int td_err_size = sizeof td_err_table / sizeof (struct string_map);
+ int i;
+ static char buf[90];
+
+ for (i = 0; i < td_err_size; i++)
+ if (td_err_table[i].num == errcode)
+ return td_err_table[i].str;
+
+ sprintf (buf, "Unknown thread_db error code: %d", errcode);
+
+ return buf;
+}
+
+/* Thread support routines */
+
+nbsd_thread_proc_read (void *arg, caddr_t addr, void *buf, size_t size)
+{
+ read_inferior_memory ((CORE_ADDR)addr, buf, size);
+ return 0;
+}
+
+static int
+nbsd_thread_proc_write (void *arg, caddr_t addr, void *buf, size_t size)
+{
+ int val;
+
+ val = write_inferior_memory ((CORE_ADDR)addr, buf, size);
+
+ if (val == 0)
+ return 0;
+ else
+ return TD_ERR_IO;
+}
+
+static int
+nbsd_thread_proc_lookup (void *arg, char *sym, caddr_t *addr)
+{
+ int i = 0;
+
+ while (pthread_syms[i].name != NULL)
+ {
+ if (strcmp (pthread_syms[i].name, sym) == 0)
+ {
+ if (pthread_syms[i].addr)
+ {
+ *addr = (caddr_t) pthread_syms[i].addr;
+ return 0;
+ }
+ break;
+ }
+ i++;
+ }
+
+ /*
+ * If we get here, then either the symbol wasn't in the table,
+ * or it had no value associated with it (yet).
+ */
+
+#ifdef DEBUG
+ fprintf (stderr, "lookup failed for %s\n", sym);
+#endif
+
+ return TD_ERR_NOSYM;
+}
+static int
+nbsd_thread_proc_regsize (void *arg, int regset, size_t *size)
+{
+ switch (regset)
+ {
+ case 0:
+ *size = sizeof (struct reg);
+ break;
+ case 1:
+ *size = sizeof (struct fpreg);
+ break;
+ default:
+ return TD_ERR_INVAL;
+ }
+
+ return 0;
+}
+
+static int
+nbsd_thread_proc_getregs (void *arg, int regset, int lwp, void *buf)
+{
+ struct reg gregs;
+ struct fpreg fpregs;
+ int saved_tid = general_thread;
+ int ret;
+
+ /* Build the thread ID for this LWP within the main process */
+
+ general_thread = lwp;
+
+ fetch_inferior_registers (0);
+
+ ret = 0;
+ switch (regset)
+ {
+ case 0:
+ nbsd_internal_to_reg (&gregs);
+ memcpy (buf, &gregs, sizeof (struct reg));
+ break;
+ case 1:
+ nbsd_internal_to_fpreg (&fpregs);
+ memcpy (buf, &fpregs, sizeof (struct fpreg));
+ break;
+ default: /* XXX need to handle other reg sets: SSE, AltiVec, etc. */
+ ret = TD_ERR_INVAL;
+ }
+
+ /* Restore the thread process ID */
+
+ general_thread = saved_tid;
+
+ return ret;
+}
+
+static int
+nbsd_thread_proc_setregs (void *arg, int regset, int lwp, void *buf)
+{
+ struct reg gregs;
+ struct fpreg fpregs;
+ int saved_tid = general_thread;
+ int ret;
+
+ ret = 0;
+
+ switch (regset)
+ {
+ case 0:
+ memcpy (&gregs, buf, sizeof (struct reg));
+ nbsd_reg_to_internal (&gregs);
+ break;
+ case 1:
+ memcpy (&fpregs, buf, sizeof (struct fpreg));
+ nbsd_fpreg_to_internal (&fpregs);
+ break;
+ default: /* XXX need to handle other reg sets: SSE, AltiVec, etc. */
+ ret = TD_ERR_INVAL;
+ }
+
+ general_thread = lwp;
+
+ store_inferior_registers (0);
+
+ general_thread = saved_tid;
+
+ return ret;
+}
+
/* Start an inferior process and returns its pid.
ALLARGS is a vector of program-name and args.
ENV is the environment vector to pass. */
@@ -112,6 +480,14 @@
_exit (0177);
}
+#ifdef DEBUG
+ fprintf (stderr, "create_inferior ('%s', ...) = %d\n", program, pid);
+#endif /* DEBUG */
+
+ /* Record the main thread as the current inferior thread too */
+
+ general_thread = GET_THREAD(pid);
+
return pid;
}
@@ -120,9 +496,15 @@
void
kill_inferior ()
{
+#ifdef DEBUG
+ fprintf (stderr, "kill_inferior() called [inferior_pid = %#x]\n",
+ inferior_pid);
+#endif /* DEBUG */
+
if (inferior_pid == 0)
return;
- ptrace (PT_KILL, inferior_pid, 0, 0);
+ general_thread = 0;
+ ptrace (PT_KILL, GET_PROCESS (inferior_pid), 0, 0);
wait (0);
/*************inferior_died ();****VK**************/
}
@@ -131,10 +513,275 @@
int
mythread_alive (pid)
int pid;
+{
+ td_thread_t * thread;
+ td_thread_info_t ti;
+
+#ifdef DEBUG
+ fprintf (stderr, "mythread_alive(%d) called\n", pid);
+#endif /* DEBUG */
+
+ if (threads_active)
+ {
+ if (td_map_id2thr (main_ta, pid, &thread) == 0)
+ {
+ if (td_thr_info (thread, &ti) == 0)
+ {
+ /* Found thread OK => must be alive */
+
+ return 1;
+ }
+ }
+
+ /* Not found */
+ return 0;
+ }
+ else
+ return 1; /* Not threading, or request for main thread */
+}
+
+/* Find active thread */
+
+int
+myfind_active_thread()
+{
+ int val;
+ td_thread_t * thread;
+ td_thread_info_t ti;
+
+ if (!threads_active)
+ return -1;
+
+ if ((val = td_map_lwps (main_ta)) != 0)
+ {
+ fprintf (stderr, "myfind_active_threads: td_map_lwps error = %s\n",
+ td_err_string (val));
+ return -1;
+ }
+
+ if ((val = td_map_lwp2thr (main_ta, 0, &thread)) != 0)
+ {
+ fprintf (stderr, "myfind_active_threads: td_map_lwp2thr error = %s\n",
+ td_err_string (val));
+ return -1;
+ }
+
+ if ((val = td_thr_info (thread, &ti)) != 0)
+ {
+ fprintf (stderr, "myfind_active_threads: td_thr_info error = %s\n",
+ td_err_string (val));
+ return -1;
+ }
+
+ return ti.thread_id;
+}
+
+/* Obtain information about a thread */
+
+static int
+waiter_cb (td_thread_t * thr, void * d)
+{
+ td_thread_info_t ti;
+ char * desc = (char *) d;
+
+ if (td_thr_info (thr, &ti) == 0)
+ {
+ sprintf (desc + strlen(desc), " %d", ti.thread_id);
+ }
+
+ return 0;
+}
+
+char *
+mythread_info (int tid)
+{
+ /*
+ * This is not very secure... should have a better technique to
+ * allocate this string really
+ */
+ static char desc [THREAD_INFO_DESC_SIZE];
+ int val;
+ char name [32];
+ td_thread_t * thread;
+ td_thread_info_t ti, ti2;
+ td_sync_t * ts;
+ td_sync_info_t tsi;
+
+#ifdef DEBUG
+ fprintf (stderr, "mythread_info (%d) called\n", tid);
+#endif
+
+ if ((val = td_map_id2thr (main_ta, tid, &thread)) != 0)
+ {
+ fprintf (stderr, "mythread_info: td_map_id2thr error = %s\n",
+ td_err_string (val));
+ return NULL;
+ }
+
+ if ((val = td_thr_info (thread, &ti)) != 0)
+ {
+ fprintf (stderr, "mythread_info: td_thr_info error = %s\n",
+ td_err_string (val));
+ return NULL;
+ }
+
+ if (ti.thread_type != TD_TYPE_USER)
+ return NULL;
+
+ td_thr_getname (thread, name, 32);
+
+ if (name[0] != '\0')
+ sprintf (desc, "%s: ", name);
+ else
+ strcpy (desc, "<no name>: ");
+
+ switch (ti.thread_state)
+ {
+ default:
+ case TD_STATE_UNKNOWN:
+ strcat (desc, "<unknown state> ");
+ break;
+
+ case TD_STATE_RUNNING:
+ strcat (desc, "running ");
+ break;
+
+ case TD_STATE_RUNNABLE:
+ strcat (desc, "active ");
+ break;
+
+ case TD_STATE_BLOCKED:
+ strcat (desc, "in kernel ");
+ break;
+
+ case TD_STATE_SLEEPING:
+ strcat (desc, "sleeping ");
+ break;
+
+ case TD_STATE_ZOMBIE:
+ strcat (desc, "zombie ");
+ break;
+ }
+
+ if (ti.thread_state == TD_STATE_SLEEPING)
+ {
+ td_thr_sleepinfo (thread, &ts);
+ td_sync_info (ts, &tsi);
+ if (tsi.sync_type == TD_SYNC_JOIN)
+ {
+ td_thr_info (tsi.sync_data.join.thread, &ti2);
+ sprintf (desc + strlen(desc), "joining thread %d ", ti2.thread_id);
+ }
+ else
+ {
+ sprintf (desc + strlen(desc), "on %s at %p ",
+ syncnames[tsi.sync_type], (void *) tsi.sync_addr);
+ if (tsi.sync_type == TD_SYNC_MUTEX)
+ {
+ td_thr_info (tsi.sync_data.mutex.owner, &ti2);
+ sprintf (desc + strlen (desc), "owned by %d ", ti2.thread_id);
+ }
+ }
+ }
+
+ if (ti.thread_hasjoiners)
+ {
+ strcat (desc, "[being joined by");
+ td_thr_join_iter (thread, waiter_cb, desc);
+ strcat (desc, "]");
+ }
+
+ return desc;
+}
+
+/* Enable thread support, if possible */
+
+void
+mythread_activate ()
+{
+ int val;
+
+ val = td_open (&nbsd_thread_callbacks, NULL, &main_ta);
+
+ if (val != 0)
+ {
+ fprintf (stderr, "mythread_activate: td_open() error = %s\n",
+ td_err_string (val));
+ return;
+ }
+
+ threads_active = 1;
+
+#ifdef DEBUG
+ fprintf (stderr, "Thread support activated...\n");
+#endif
+
+ myfind_new_threads ();
+
+ val = myfind_active_thread();
+ if (val == -1)
+ {
+ fprintf (stderr, "Unable to find active thread\n");
+ }
+ else
+ {
+ general_thread = val;
+ }
+ return;
+}
+
+/* Find all the threads in the current process */
+
+static int
+nbsd_find_new_threads_callback (th, ignored)
+ td_thread_t *th;
+ void *ignored;
{
- return 1;
+ int retval;
+ td_thread_info_t ti;
+ int pid;
+
+ if ((retval = td_thr_info (th, &ti)) != 0)
+ return -1;
+
+ pid = BUILD_THREAD (ti.thread_id, inferior_pid);
+
+#ifdef DEBUG
+ fprintf (stderr, "tid = %#x, pid = %#x\n", ti.thread_id, pid);
+#endif
+
+ if (ti.thread_type == TD_TYPE_USER &&
+ ti.thread_state != TD_STATE_ZOMBIE &&
+ !in_thread_list (pid))
+ {
+ add_thread (pid);
+#ifdef DEBUG
+ fprintf (stderr, "Added thread ID = %#x\n", pid);
+#endif
+ }
+
+ return 0;
}
+void
+myfind_new_threads ()
+{
+ int retval;
+
+ if (threads_active == 0)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "myfind_new_threads: thread support not active\n");
+#endif
+ return;
+ }
+
+ retval = td_thr_iter (main_ta, nbsd_find_new_threads_callback, (void *) 0);
+ if (retval != 0)
+ fprintf (stderr, "nbsd_find_new_threads: td_thr_iter: %s",
+ td_err_string (retval));
+}
+
/* Wait for process, returns status */
unsigned char
@@ -144,6 +791,10 @@
int pid;
int w;
+#ifdef DEBUG
+ fprintf (stderr, "mywait() called\n");
+#endif /* DEBUG */
+
pid = wait (&w);
if (pid != inferior_pid)
perror_with_name ("wait");
@@ -161,6 +812,21 @@
return ((unsigned char) WTERMSIG (w));
}
+ if (threads_active)
+ {
+ int tid;
+
+ if ((tid = myfind_active_thread ()) != -1)
+ {
+ if (!in_thread_list (tid))
+ add_thread (tid);
+#ifdef DEBUG
+ fprintf (stderr, "mywait: Setting general thread to %d\n", tid);
+#endif
+ general_thread = tid;
+ }
+ }
+
fetch_inferior_registers (0);
*status = 'T';
@@ -176,8 +842,12 @@
int step;
int signal;
{
+#ifdef DEBUG
+ fprintf (stderr, "myresume (%d, %d) called\n", step, signal);
+#endif /* DEBUG */
+
errno = 0;
- ptrace (step ? PT_STEP : PT_CONTINUE, inferior_pid,
+ ptrace (step ? PT_STEP : PT_CONTINUE, GET_PROCESS (inferior_pid),
(PTRACE_ARG3_TYPE) 1, signal);
if (errno)
perror_with_name ("ptrace");
@@ -194,17 +864,62 @@
struct reg inferior_registers;
struct fpreg inferior_fp_registers;
- ptrace (PT_GETREGS, inferior_pid,
- (PTRACE_ARG3_TYPE) &inferior_registers, 0);
- memcpy (®isters[REGISTER_BYTE(0)], &inferior_registers,
- sizeof(inferior_registers));
-
-#if 0 /* def FP0_REGNUM */
- ptrace (PT_GETFPREGS, inferior_pid,
- (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
- memcpy (®isters[REGISTER_BYTE(FP0_REGNUM)], &inferior_fp_registers,
- sizeof(inferior_fp_registers));
-#endif
+#ifdef DEBUG
+ fprintf (stderr, "fetch_inferior_registers() called\n");
+ fprintf (stderr, " inferior_pid = %#x\n", inferior_pid);
+ fprintf (stderr, " general_thread = %#x\n", general_thread);
+#endif /* DEBUG */
+
+ if (threads_active && general_thread != 0)
+ {
+ td_thread_t *thread;
+ int val;
+
+ if ((val = td_map_id2thr (main_ta, general_thread, &thread)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_map_id2thr -> %s\n",
+ td_err_string (val));
+ return;
+ }
+ if ((val = td_thr_getregs (thread, 0, &inferior_registers)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(0) -> %s\n",
+ td_err_string (val));
+ return;
+ }
+ if ((val = td_thr_getregs (thread, 1, &inferior_fp_registers)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(1) -> %s\n",
+ td_err_string (val));
+ return;
+ }
+ supply_regs ((char *) &inferior_registers);
+ supply_fpregs ((char *) &inferior_fp_registers);
+ }
+ else
+ {
+ ptrace (PT_GETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers, general_thread);
+ supply_regs ((char *) &inferior_registers);
+
+ ptrace (PT_GETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, general_thread);
+ supply_fpregs ((char *) &inferior_fp_registers);
+ }
+#ifdef DEBUG
+ {
+ int r;
+ for (r=0; r < 32; r++) {
+ fprintf (stderr, "R%-2d = %#08x\n",r,inferior_registers.fixreg[r]);
+ }
+ fprintf (stderr, "lr = %#08x\n", inferior_registers.lr);
+ fprintf (stderr, "cr = %#08x\n", inferior_registers.cr);
+ fprintf (stderr, "xer = %#08x\n", inferior_registers.xer);
+ fprintf (stderr, "ctr = %#08x\n", inferior_registers.ctr);
+ fprintf (stderr, "pc = %#08x\n", inferior_registers.pc);
+ }
+#endif /* DEBUG */
+
}
/* Store our register values back into the inferior.
@@ -218,17 +933,50 @@
struct reg inferior_registers;
struct fpreg inferior_fp_registers;
- memcpy (&inferior_registers, ®isters[REGISTER_BYTE(0)],
- sizeof(inferior_registers));
- ptrace (PT_SETREGS, inferior_pid,
- (PTRACE_ARG3_TYPE) &inferior_registers, 0);
-
-#if 0 /* def FP0_REGNUM */
- memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
- sizeof (inferior_fp_registers));
- ptrace (PT_SETFPREGS, inferior_pid,
- (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
+#ifdef DEBUG
+ fprintf (stderr, "store_inferior_registers() called\n");
+ fprintf (stderr, " inferior_pid = %#x\n", inferior_pid);
+ fprintf (stderr, " general_thread = %#x\n", general_thread);
#endif
+
+ if (threads_active && general_thread != 0)
+ {
+ td_thread_t *thread;
+ int val;
+
+ if ((val = td_map_id2thr (main_ta, general_thread, &thread)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_map_id2thr -> %s\n",
+ td_err_string (val));
+ return;
+ }
+
+ unsupply_regs ((char *) &inferior_registers);
+ unsupply_fpregs ((char *) &inferior_fp_registers);
+
+ if ((val = td_thr_setregs (thread, 0, &inferior_registers)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(0) -> %s\n",
+ td_err_string (val));
+ return;
+ }
+ if ((val = td_thr_setregs (thread, 1, &inferior_fp_registers)) != 0)
+ {
+ fprintf (stderr, "fetch_inferior_registers: td_thr_getregs(1) -> %s\n",
+ td_err_string (val));
+ return;
+ }
+ }
+ else
+ {
+ unsupply_regs ((char *) &inferior_registers);
+ ptrace (PT_SETREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_registers, general_thread);
+
+ unsupply_fpregs ((char *) &inferior_fp_registers);
+ ptrace (PT_SETFPREGS, inferior_pid,
+ (PTRACE_ARG3_TYPE) &inferior_fp_registers, general_thread);
+ }
}
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
@@ -240,6 +988,7 @@
/* Copy LEN bytes from inferior's memory starting at MEMADDR
to debugger memory starting at MYADDR. */
+void
read_inferior_memory (memaddr, myaddr, len)
CORE_ADDR memaddr;
char *myaddr;
@@ -254,10 +1003,15 @@
/* Allocate buffer of that many longwords. */
register int *buffer = (int *) alloca (count * sizeof (int));
+#ifdef DEBUG
+ fprintf (stderr, "read_inferior_memory (%p, %p, %d)\n", memaddr, myaddr, len);
+#endif /* DEBUG */
+
/* Read all the longwords */
for (i = 0; i < count; i++, addr += sizeof (int))
{
- buffer[i] = ptrace (PT_READ_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+ buffer[i] = ptrace (PT_READ_D, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr, 0);
}
/* Copy appropriate bytes out of the buffer. */
@@ -285,15 +1039,19 @@
register int *buffer = (int *) alloca (count * sizeof (int));
extern int errno;
+#ifdef DEBUG
+ fprintf (stderr, "read_inferior_memory (%p, %p, %d)\n", memaddr, myaddr, len);
+#endif /* DEBUG */
+
/* Fill start and end extra bytes of buffer with existing memory data. */
- buffer[0] = ptrace (PT_READ_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+ buffer[0] = ptrace (PT_READ_D, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr, 0);
if (count > 1)
{
- buffer[count - 1]
- = ptrace (PT_READ_D, inferior_pid,
- (PTRACE_ARG3_TYPE) addr + (count - 1) * sizeof (int), 0);
+ buffer[count - 1] = ptrace (PT_READ_D, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr + (count - 1) * sizeof (int), 0);
}
/* Copy data to be written over corresponding part of buffer */
@@ -305,7 +1063,8 @@
for (i = 0; i < count; i++, addr += sizeof (int))
{
errno = 0;
- ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ ptrace (PT_WRITE_D, inferior_pid,
+ (PTRACE_ARG3_TYPE) addr, buffer[i]);
if (errno)
return errno;
}
@@ -317,4 +1076,13 @@
initialize_low ()
{
initialize_arch ();
+
+ nbsd_thread_callbacks.proc_read = nbsd_thread_proc_read;
+ nbsd_thread_callbacks.proc_write = nbsd_thread_proc_write;
+ nbsd_thread_callbacks.proc_lookup = nbsd_thread_proc_lookup;
+ nbsd_thread_callbacks.proc_regsize = nbsd_thread_proc_regsize;
+ nbsd_thread_callbacks.proc_getregs = nbsd_thread_proc_getregs;
+ nbsd_thread_callbacks.proc_setregs = nbsd_thread_proc_setregs;
+
+ mysymbol_hook = mysymbol;
}
Index: gnu/dist/toolchain/gdb/gdbserver/remote-utils.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/remote-utils.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 remote-utils.c
--- gnu/dist/toolchain/gdb/gdbserver/remote-utils.c 2000/07/26 00:33:51 1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/remote-utils.c 2003/05/29 06:54:23
@@ -192,6 +192,42 @@
return 'a' + nib - 10;
}
+int
+hexify (char *hex, const char *bin, int count)
+{
+ int i;
+
+ /* May use a length, or a nul-terminated string as input. */
+ if (count == 0)
+ count = strlen (bin);
+
+ for (i = 0; i < count; i++)
+ {
+ *hex++ = tohex ((*bin >> 4) & 0xf);
+ *hex++ = tohex (*bin++ & 0xf);
+ }
+ *hex = 0;
+ return i;
+}
+
+void
+decode_address (CORE_ADDR *addrp, const char *start, int len)
+{
+ CORE_ADDR addr;
+ char ch;
+ int i;
+
+ addr = 0;
+ for (i = 0; i < len; i++)
+ {
+ ch = start[i];
+ addr = addr << 4;
+ addr = addr | (fromhex (ch) & 0x0f);
+ }
+ *addrp = addr;
+}
+
+
/* Send a packet to the remote machine, with error checking.
The data of the packet is in BUF. Returns >= 0 on success, -1 otherwise. */
Index: gnu/dist/toolchain/gdb/gdbserver/server.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/server.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 server.c
--- gnu/dist/toolchain/gdb/gdbserver/server.c 2000/07/26 00:33:51 1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/server.c 2003/05/29 06:54:24
@@ -20,6 +20,11 @@
#include "server.h"
+/*
+ * Enable server debug
+ */
+#undef DEBUG
+
int cont_thread;
int general_thread;
int thread_from_wait;
@@ -27,6 +32,10 @@
int extended_protocol;
jmp_buf toplevel;
int inferior_pid;
+int threads_active;
+struct thread_list_element * thread_list_head;
+
+void (*mysymbol_hook) PARAMS ((char * own_buf));
static unsigned char
start_inferior (argv, statusptr)
@@ -40,6 +49,187 @@
return mywait (statusptr);
}
+void
+add_thread (int id)
+{
+ struct thread_list_element * new_thread;
+
+ if ((new_thread = malloc (sizeof (struct thread_list_element))) == NULL)
+ return;
+
+ new_thread->id = id;
+ new_thread->next = thread_list_head;
+ thread_list_head = new_thread;
+
+ return;
+}
+
+void
+delete_thread (int id)
+{
+ struct thread_list_element * thread_ptr = thread_list_head;
+ struct thread_list_element ** previous = &thread_list_head;
+
+ while (thread_ptr != NULL)
+ {
+ if (thread_ptr->id == id)
+ {
+ *previous = thread_ptr->next;
+ free (thread_ptr);
+ return;
+ }
+ previous = &(thread_ptr->next);
+ thread_ptr = thread_ptr->next;
+ }
+ return;
+}
+
+int
+in_thread_list (int id)
+{
+ struct thread_list_element * thread_ptr = thread_list_head;
+
+ while (thread_ptr != NULL)
+ {
+ if (thread_ptr->id == id)
+ return 1;
+ thread_ptr = thread_ptr->next;
+ }
+
+ /* If we get here, the thread ID was not in the list */
+
+ return 0;
+}
+
+/* -- Handle all of the extended 'q' packets. */
+void
+handle_query (own_buf)
+ char* own_buf;
+{
+ static struct thread_list_element * thread_ptr;
+ int tid;
+
+ /* Current thread ID */
+
+ if (strcmp ("qC", own_buf) == 0)
+ {
+ if ((tid = myfind_active_thread()) == -1)
+ sprintf (own_buf, "QC0");
+ else
+ sprintf (own_buf, "QC%x", tid);
+
+#ifdef DEBUG
+ fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+ return;
+ }
+
+ /*
+ * Symbol resolution
+ */
+
+ if (strncmp ("qSymbol:", own_buf, 8) == 0)
+ {
+ if (mysymbol_hook != NULL)
+ (*mysymbol_hook)(own_buf);
+ return;
+ }
+
+ if (strcmp ("qfThreadInfo", own_buf) == 0)
+ {
+ if (!threads_active)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "Trying to activate thread support\n");
+#endif
+ mythread_activate();
+ }
+
+ /*
+ * Check again in case the previous call failed to activate thread
+ * support
+ */
+
+ if (threads_active)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "Checking for new threads\n");
+#endif
+ myfind_new_threads ();
+
+ thread_ptr = thread_list_head;
+ sprintf (own_buf, "m%x", GET_THREAD(thread_ptr->id));
+ thread_ptr = thread_ptr->next;
+ }
+ else
+ {
+ /* Threads not active yet, just return an empty list */
+
+ strcpy (own_buf, "l");
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+ return;
+ }
+
+ if (strcmp ("qsThreadInfo", own_buf) == 0)
+ {
+ if (thread_ptr != NULL)
+ {
+ sprintf (own_buf, "m%x", GET_THREAD(thread_ptr->id));
+ thread_ptr = thread_ptr->next;
+ }
+ else
+ {
+ strcpy (own_buf, "l");
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "Sending: %s\n", own_buf);
+#endif
+
+ return;
+ }
+
+ if (strncmp ("qThreadExtraInfo,", own_buf, 17) == 0)
+ {
+ char * info;
+ int tid;
+
+ tid = strtol (&own_buf[17], NULL, 16);
+
+#ifdef DEBUG
+ fprintf (stderr, "Request for info on thread %d\n", tid);
+#endif
+
+ if ((info = mythread_info (tid)) != NULL)
+ {
+ hexify (own_buf, info, strlen (info));
+#ifdef DEBUG
+ fprintf (stderr, "Thread Info (%d chars): '%s'\n",
+ strlen (info), info);
+ fprintf (stderr, "Sending: '%s'\n", own_buf);
+#endif
+ return;
+ }
+ own_buf[0] = '\0';
+ return;
+ }
+
+ /* Don't understand the query... */
+
+#ifdef DEBUG
+ fprintf (stderr, "Unknown query %s\n", own_buf);
+#endif
+
+ own_buf[0] = '\0';
+ return;
+}
+
extern int remote_debug;
int
@@ -80,8 +270,16 @@
unsigned char sig;
i = 0;
ch = own_buf[i++];
+
+#ifdef DEBUG
+ fprintf (stderr, "Command: %s\n", own_buf);
+#endif /* DEBUG */
+
switch (ch)
{
+ case 'q':
+ handle_query (own_buf);
+ break;
case 'd':
remote_debug = !remote_debug;
break;
@@ -206,6 +404,10 @@
/* It is a request we don't understand. Respond with an
empty packet so that gdb knows that we don't support this
request. */
+#ifdef DEBUG
+ fprintf (stderr, "Unknown request (%s)\n", own_buf);
+#endif /* DEBUG */
+
own_buf[0] = '\0';
break;
}
Index: gnu/dist/toolchain/gdb/gdbserver/server.h
===================================================================
RCS file: /cvsroot/src/gnu/dist/toolchain/gdb/gdbserver/server.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 server.h
--- gnu/dist/toolchain/gdb/gdbserver/server.h 2000/07/26 00:33:51 1.1.1.1
+++ gnu/dist/toolchain/gdb/gdbserver/server.h 2003/05/29 06:54:24
@@ -21,13 +21,24 @@
#include "defs.h"
#include <setjmp.h>
+/* Thread list element type */
+
+struct thread_list_element
+ {
+ int id;
+ struct thread_list_element * next;
+ };
+
/* Target-specific functions */
int create_inferior PARAMS ((char *program, char **allargs));
void kill_inferior PARAMS ((void));
void fetch_inferior_registers PARAMS ((int regno));
void store_inferior_registers PARAMS ((int regno));
+void mythread_activate PARAMS ((void));
+void myfind_new_threads PARAMS ((void));
int mythread_alive PARAMS ((int pid));
+char * mythread_info PARAMS ((int tid));
void myresume PARAMS ((int step, int signo));
unsigned char mywait PARAMS ((char *status));
void read_inferior_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
@@ -35,10 +46,18 @@
int create_inferior ();
void initialize_low ();
+extern void (*mysymbol_hook) PARAMS ((char * own_buf));
+
/* Target-specific variables */
extern char *registers;
+/* Public functions in server.c */
+
+void add_thread PARAMS ((int id));
+void delete_thread PARAMS ((int id));
+int in_thread_list PARAMS ((int id));
+
/* Public variables in server.c */
extern int cont_thread;
@@ -48,6 +67,8 @@
extern jmp_buf toplevel;
extern int inferior_pid;
+extern int threads_active;
+extern struct thread_list_element * thread_list_head;
/* Functions from remote-utils.c */
@@ -68,6 +89,8 @@
void decode_M_packet PARAMS ((char *from, CORE_ADDR * mem_addr_ptr,
unsigned int *len_ptr, char *to));
+int hexify PARAMS ((char *hex, const char *bin, int count));
+void decode_address PARAMS ((CORE_ADDR *addrp, const char *start, int len));
/* Functions from utils.c */
Index: gnu/usr.bin/gdb/Makefile
===================================================================
RCS file: /cvsroot/src/gnu/usr.bin/gdb/Makefile,v
retrieving revision 1.53
diff -u -r1.53 Makefile
--- gnu/usr.bin/gdb/Makefile 2002/09/22 12:58:23 1.53
+++ gnu/usr.bin/gdb/Makefile 2003/05/29 06:54:43
@@ -1,5 +1,13 @@
# $NetBSD: Makefile,v 1.53 2002/09/22 12:58:23 wiz Exp $
+#
+# Set the environment variable MKGDBSERVER to yes to build the gdbserver binary
+#
+
+.if (${MKGDBSERVER} == "yes")
+SUBDIR= gdb gdbserver # gdbreplay
+.else
SUBDIR= gdb # gdbreplay gdbserver
+.endif
.include <bsd.subdir.mk>
Index: gnu/usr.bin/gdb/gdbserver/Makefile
===================================================================
RCS file: /cvsroot/src/gnu/usr.bin/gdb/gdbserver/Makefile,v
retrieving revision 1.2
diff -u -r1.2 Makefile
--- gnu/usr.bin/gdb/gdbserver/Makefile 2002/09/19 03:09:37 1.2
+++ gnu/usr.bin/gdb/gdbserver/Makefile 2003/05/29 06:54:43
@@ -14,6 +14,8 @@
${G_INTERNAL_CFLAGS:M-[ID]*:N*readline*:N*intl*:N-I.*} \
-I${TOP}/lib/libbfd/arch/${MACHINE_ARCH}
+LDADD += -lpthread_dbg
+
.include "../../Makefile.inc"
.include <bsd.prog.mk>
>Release-Note:
>Audit-Trail:
>Unformatted: