Details:
1. Adds vendor config option/variable CONFIG_USER_GDB_HOST which makes
optional the building of the host-based gdb application
2. Makes gdbserver NOMMU / uClinux friendly, by
(a) fork() -> vfork()
(b) Adds support for qOffset packets for uClinux PTRACE debugging
These changes based on Miles Bader's previous NOMMU gdbserver support
3. Makes gdbserver properly save and restore process group / termio
settings (prevent killing shell on exit)
4. Adds MicroBlaze support for gdbserver
diffstat output follows:
[jwilliams@g512-9423 uClinux-dist]$ diffstat gdb.patch
config/config.in | 1
user/Makefile | 1
user/gdb/config.sub | 2
user/gdb/configure.in | 3
user/gdb/gdb/ChangeLog | 4 +
user/gdb/gdb/configure.host | 2
user/gdb/gdb/gdbserver/ChangeLog | 13 ++++
user/gdb/gdb/gdbserver/Makefile.in | 7 +-
user/gdb/gdb/gdbserver/configure.srv | 4 +
user/gdb/gdb/gdbserver/linux-low.c | 62 ++++++++++++++++++-
user/gdb/gdb/gdbserver/linux-mb-low.c | 109 +++++++++++++++++++++++++
user/gdb/gdb/gdbserver/server.c | 18 +++++
user/gdb/gdb/gdbserver/target.h | 5 +
user/gdb/gdb/regformats/reg-mb.dat | 41 ++++++++++++
user/gdb/makefile | 10 ++-
15 files changed, 274 insertions(+), 8 deletions(-)
Thanks,
John
------------------------------------------------------------------------
Index: user/Makefile
===================================================================
--- user/Makefile (revision 70)
+++ user/Makefile (working copy)
@@ -138,6 +141,7 @@
dir_$(CONFIG_USER_FTPD_FTPD) += ftpd
dir_$(CONFIG_USER_GDBSERVER_GDBREPLAY) += gdbserver
dir_$(CONFIG_USER_GDBSERVER_GDBSERVER) += gdbserver
+dir_$(CONFIG_USER_GDB_HOST) += gdb
dir_$(CONFIG_USER_GDB_GDBREPLAY) += gdb
dir_$(CONFIG_USER_GDB_GDBSERVER) += gdb
dir_$(CONFIG_USER_GETTYD_GETTYD) += gettyd
Index: user/gdb/config.sub
===================================================================
--- user/gdb/config.sub (revision 70)
+++ user/gdb/config.sub (working copy)
@@ -238,6 +238,7 @@
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| m32r | m32rle | m68000 | m68k | m88k | mcore \
+ | mb | microblaze \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
@@ -311,6 +312,7 @@
| m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \
+ | mb-* | microblaze-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
Index: user/gdb/configure.in
===================================================================
--- user/gdb/configure.in (revision 70)
+++ user/gdb/configure.in (working copy)
@@ -635,6 +635,9 @@
m68k-*-coff*)
noconfigdirs="$noconfigdirs ${libgcj}"
;;
+ mb-*-*)
+ noconfigdirs="$noconfigdirs ${libgcj}"
+ ;;
mcore-*-pe*)
# The EPOC C++ environment does not support exceptions or rtti,
# and so building libstdc++-v3 tends not to always work.
Index: user/gdb/gdb/ChangeLog
===================================================================
--- user/gdb/gdb/ChangeLog (revision 70)
+++ user/gdb/gdb/ChangeLog (working copy)
@@ -1,3 +1,7 @@
+2005-10-05 John Williams <john.williams@xxxxxxxxxxxxx>
+
+ * regformats/reg-mb.dat: New file
+
2004-11-08 Andrew Cagney <cagney@xxxxxxx>
GDB 6.3 released.
Index: user/gdb/gdb/regformats/reg-mb.dat
===================================================================
--- user/gdb/gdb/regformats/reg-mb.dat (revision 0)
+++ user/gdb/gdb/regformats/reg-mb.dat (revision 240)
@@ -0,0 +1,41 @@
+name:mb
+expedite:sp,pc
+32:r0
+32:sp
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:r13
+32:r14
+32:lp
+32:r16
+32:r17
+32:r18
+32:r19
+32:r20
+32:r21
+32:r22
+32:r23
+32:r24
+32:r25
+32:r26
+32:r27
+32:r28
+32:r29
+32:r30
+32:r31
+
+32:pc
+32:msr
+32:ear
+32:esr
+32:fsr
+
Index: user/gdb/gdb/gdbserver/linux-low.c
===================================================================
--- user/gdb/gdb/gdbserver/linux-low.c (revision 70)
+++ user/gdb/gdb/gdbserver/linux-low.c (working copy)
@@ -139,9 +139,9 @@
void *new_process;
int pid;
- pid = fork ();
+ pid = vfork ();
if (pid < 0)
- perror_with_name ("fork");
+ perror_with_name ("vfork");
if (pid == 0)
{
@@ -917,6 +917,7 @@
errno = 0;
process->stopped = 0;
process->stepping = step;
+
ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, process->lwpid, 0, signal);
current_inferior = saved_inferior;
@@ -1379,7 +1380,17 @@
if (debug_threads)
{
- fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr);
+ const unsigned char *m = (const unsigned char *)myaddr;
+ int l = len;
+ char buf[100], *p = buf;
+ while (l > 0 && p < buf + sizeof buf - 10)
+ {
+ p += sprintf (p, "%s0x%02x", p > buf ? ", " : "", *m++);
+ l--;
+ }
+ if (l > 0)
+ strcpy (p, "...");
+ fprintf (stderr, "Writing %s to %0lx\n", buf, (long)memaddr);
}
/* Fill start and end extra bytes of buffer with existing memory data. */
@@ -1466,6 +1477,50 @@
return n;
}
+/* Some linux-specific handling for extended 'q' packets. */
+static int
+linux_handle_query (char *own_buf)
+{
+#if defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) && defined(PT_TEXT_LEN)
+ /* Under uClinux, programs are loaded at non-zero offsets, which we need
+ to tell gdb about. */
+ if (strcmp ("qOffsets", own_buf) == 0)
+ {
+ unsigned long text, text_len, real_data;
+ int pid = get_thread_process (current_inferior)->head.id;
+
+ errno = 0;
+
+ text = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_ADDR, 0);
+ text_len = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_LEN, 0);
+ real_data = ptrace (PTRACE_PEEKUSER, pid, (long)PT_DATA_ADDR, 0);
+
+ if (errno == 0)
+ {
+ /* Both text and data offsets produced at compile-time (and so
+ used by gdb) are relative to the beginning of the program,
+ with the data segment immediately following the text segment.
+ However, the actual runtime layout in memory may put the data
+ somewhere else, so when we send gdb a data base-address, we
+ use the real data base address and subtract the compile-time
+ data base-address from it (which is just the length of the
+ text segment). BSS immediately follows data in both cases. */
+ unsigned long data = real_data - text_len;
+ unsigned long bss = data;
+ sprintf (own_buf, "Text=%lx;Data=%lx;Bss=%lx", text, data, bss);
+ }
+ else
+ sprintf (own_buf, "ENN");
+
+ return 1;
+ }
+#endif
+
+ /* Something we don't handle. */
+ return 0;
+}
+
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
@@ -1482,6 +1537,7 @@
linux_look_up_symbols,
linux_send_signal,
linux_read_auxv,
+ linux_handle_query
};
static void
Index: user/gdb/gdb/gdbserver/Makefile.in
===================================================================
--- user/gdb/gdb/gdbserver/Makefile.in (revision 70)
+++ user/gdb/gdb/gdbserver/Makefile.in (working copy)
@@ -198,8 +198,8 @@
clean:
rm -f *.o ${ADD_FILES} *~
rm -f gdbserver gdbreplay core make.log
- rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m68k.c reg-mips.c
- rm -f reg-ppc.c reg-sh.c reg-x86-64.c reg-i386-linux.c
+ rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m68k.c reg-mips.c reg-mb.c
+ rm -f reg-ppc.c reg-sh.c reg-x86-64.c reg-i386-linux.c reg-mb.c
maintainer-clean realclean distclean: clean
rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@@ -281,6 +281,9 @@
reg-ia64.o : reg-ia64.c $(regdef_h)
reg-ia64.c : $(srcdir)/../regformats/reg-ia64.dat $(regdat_sh)
sh $(regdat_sh) $(srcdir)/../regformats/reg-ia64.dat reg-ia64.c
+reg-mb.o : reg-mb.c $(regdef_h)
+reg-mb.c : $(srcdir)/../regformats/reg-mb.dat $(regdat_sh)
+ sh $(regdat_sh) $(srcdir)/../regformats/reg-mb.dat reg-mb.c
reg-m68k.o : reg-m68k.c $(regdef_h)
reg-m68k.c : $(srcdir)/../regformats/reg-m68k.dat $(regdat_sh)
sh $(regdat_sh) $(srcdir)/../regformats/reg-m68k.dat reg-m68k.c
Index: user/gdb/gdb/gdbserver/ChangeLog
===================================================================
--- user/gdb/gdb/gdbserver/ChangeLog (revision 70)
+++ user/gdb/gdb/gdbserver/ChangeLog (working copy)
@@ -1,3 +1,16 @@
+2005-10-05 John Williams <john.williams@xxxxxxxxxxxxx>
+ (based on patches from Miles Bader <miles@xxxxxxx>)
+
+ * target.h (struct target_ops): Add `handle_query' op.
+ * server.c (handle_query): If target has a handle_query op, try
+ to use it first.
+ * linux-low.c (linux_handle_query): New function.
+ * (linux_target_ops): Refer to it.
+ * linux-low.c (linux_create_inferior): Use vfork instead of fork.
+ * (linux_write_memory): Be more clever about debugging message.
+ * configure.srv: Handle `mb*-*-*'.
+ * linux-mb-low.c: New file.
+
2004-10-21 Joel Brobecker <brobecker@xxxxxxxx>
* linux-x86-64-low.c (ARCH_SET_GS): Add definition if missing.
Index: user/gdb/gdb/gdbserver/server.c
===================================================================
--- user/gdb/gdb/gdbserver/server.c (revision 70)
+++ user/gdb/gdb/gdbserver/server.c (working copy)
@@ -42,6 +42,16 @@
int signal_pid;
+/* Save the old process group ID, so it can be restored prior to exit */
+int old_pgrp;
+
+/* Common exit function to restore process group stuff, prevents killing
+ TTY on microblaze. No idea what's going on, but it works */
+void restore_tcpgrp(void)
+{
+ tcsetpgrp (fileno (stderr), old_pgrp);
+}
+
static unsigned char
start_inferior (char *argv[], char *statusptr)
{
@@ -55,8 +65,12 @@
signal (SIGTTOU, SIG_IGN);
signal (SIGTTIN, SIG_IGN);
+ old_pgrp=tcgetpgrp(fileno(stderr));
tcsetpgrp (fileno (stderr), signal_pid);
+ /* Ensure tcpgrp is reset on exit */
+ atexit(restore_tcpgrp);
+
/* Wait till we are at 1st instruction in program, return signal number. */
return mywait (statusptr, 0);
}
@@ -90,6 +104,10 @@
{
static struct inferior_list_entry *thread_ptr;
+ /* First see if the target-specific code wants to deal with this. */
+ if (the_target->handle_query && (*the_target->handle_query) (own_buf))
+ return;
+
if (strcmp ("qSymbol::", own_buf) == 0)
{
if (the_target->look_up_symbols != NULL)
Index: user/gdb/gdb/gdbserver/target.h
===================================================================
--- user/gdb/gdb/gdbserver/target.h (revision 70)
+++ user/gdb/gdb/gdbserver/target.h (working copy)
@@ -133,6 +133,11 @@
Read LEN bytes at OFFSET into a buffer at MYADDR. */
int (*read_auxv) (CORE_ADDR offset, char *myaddr, unsigned int len);
+
+ /* If non-zero, handle a `q' op from gdb, updating OWN_BUF with the result.
+ Should return 1 if the op was handled, otherwise 0. */
+
+ int (*handle_query) (char *own_buf);
};
extern struct target_ops *the_target;
Index: user/gdb/gdb/gdbserver/configure.srv
===================================================================
--- user/gdb/gdb/gdbserver/configure.srv (revision 70)
+++ user/gdb/gdb/gdbserver/configure.srv (working copy)
@@ -33,6 +33,10 @@
srv_tgtobj="linux-low.o linux-ia64-low.o"
srv_linux_usrregs=yes
;;
+ mb*-*-*) srv_regobj=reg-mb.o
+ srv_tgtobj="linux-low.o linux-mb-low.o"
+ srv_linux_usrregs=yes
+ ;;
m68*-*-linux*) srv_regobj=reg-m68k.o
srv_tgtobj="linux-low.o linux-m68k-low.o"
srv_linux_usrregs=yes
Index: user/gdb/gdb/gdbserver/linux-mb-low.c
===================================================================
--- user/gdb/gdb/gdbserver/linux-mb-low.c (revision 0)
+++ user/gdb/gdb/gdbserver/linux-mb-low.c (revision 238)
@@ -0,0 +1,109 @@
+/* linux-mb-low.c -- uClinux/mb target code for gdbserver
+
+ Written by John Williams <john.williams@xxxxxxxxxxxxx>
+ based on patches by Miles Bader <miles@xxxxxxx>
+
+ Copyright 2003 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#include "server.h"
+#include "linux-low.h"
+
+/* This matches the layout of `mbe_reg_names' in mb-tdep.c (not sure if
+ it really has too [e.g., perhaps the registers get remapped by name
+ using ../regformats/reg-mb.dat or something], but why not), and maps
+ register numbers into struct pt_regs offsets. */
+static int mb_regmap[] = {
+ -1, PT_GPR(1), PT_GPR(2), PT_GPR(3),
+ PT_GPR(4), PT_GPR(5), PT_GPR(6), PT_GPR(7),
+ PT_GPR(8), PT_GPR(9), PT_GPR(10), PT_GPR(11),
+ PT_GPR(12), PT_GPR(13), PT_GPR(14), PT_GPR(15),
+ PT_GPR(16), PT_GPR(17), PT_GPR(18), PT_GPR(19),
+ PT_GPR(20), PT_GPR(21), PT_GPR(22), PT_GPR(23),
+ PT_GPR(24), PT_GPR(25), PT_GPR(26), PT_GPR(27),
+ PT_GPR(28), PT_GPR(29), PT_GPR(30), PT_GPR(31),
+ PT_PC, PT_PSW, PT_EAR, PT_ESR,
+ PT_FSR
+};
+#define mb_num_regs (sizeof mb_regmap / sizeof mb_regmap[0])
+
+static int
+mb_cannot_store_register (int regno)
+{
+ return regno < 0 || regno >= mb_num_regs || mb_regmap[regno] < 0;
+}
+
+static int
+mb_cannot_fetch_register (int regno)
+{
+ return regno < 0 || regno >= mb_num_regs || mb_regmap[regno] < 0;
+}
+
+static CORE_ADDR
+mb_get_pc (void)
+{
+ unsigned long pc;
+ collect_register_by_name ("pc", &pc);
+ return (CORE_ADDR) pc;
+}
+
+static void
+mb_set_pc (CORE_ADDR pc)
+{
+ unsigned long newpc = pc;
+ supply_register_by_name ("pc", &newpc);
+}
+
+/* dbtrap insn */
+/* brki r14, 0x60; */
+typedef unsigned long mb_breakpoint_t;
+static const mb_breakpoint_t mb_breakpoint = 0xb9cc0060;
+#define mb_breakpoint_len 4
+
+static int
+mb_breakpoint_at (CORE_ADDR where)
+{
+ mb_breakpoint_t insn;
+
+ (*the_target->read_memory) (where, (char *) &insn, mb_breakpoint_len);
+ if (insn == mb_breakpoint)
+ return 1;
+ /* If necessary, recognize more trap instructions here. GDB only uses the
+ one. */
+ return 0;
+}
+
+struct linux_target_ops the_low_target = {
+ mb_num_regs,
+ mb_regmap,
+ mb_cannot_fetch_register,
+ mb_cannot_store_register,
+ mb_get_pc,
+ mb_set_pc,
+ (const char *) &mb_breakpoint,
+ mb_breakpoint_len,
+ 0,
+ mb_breakpoint_len,
+ mb_breakpoint_at,
+};
Index: user/gdb/gdb/configure.host
===================================================================
--- user/gdb/gdb/configure.host (revision 70)
+++ user/gdb/gdb/configure.host (working copy)
@@ -17,6 +17,7 @@
arm*) gdb_host_cpu=arm ;;
hppa*) gdb_host_cpu=pa ;;
i[34567]86*) gdb_host_cpu=i386 ;;
+mb*) gdb_host_cpu=mb ;;
m68*) gdb_host_cpu=m68k ;;
m88*) gdb_host_cpu=m88k ;;
mips*) gdb_host_cpu=mips ;;
@@ -90,6 +91,7 @@
ia64-*-aix*) gdb_host=aix ;;
ia64-*-linux*) gdb_host=linux ;;
+mb*-*-*) gdb_host=linux ;;
m68*-*-linux*) gdb_host=linux ;;
m68*-*-netbsdelf* | m68*-*-knetbsd*-gnu)
gdb_host=nbsdelf ;;
Index: user/gdb/makefile
===================================================================
--- user/gdb/makefile (revision 70)
+++ user/gdb/makefile (working copy)
@@ -1,6 +1,8 @@
all: build/build host/build
$(MAKE) -C build
- $(MAKE) -C host
+ if [ "$(CONFIG_USER_GDB_HOST)" == "y" ]; then \
+ $(MAKE) -C host; \
+ fi
build/build: makefile
rm -rf build
@@ -11,8 +13,10 @@
host/build: makefile
rm -rf host
mkdir host
- (cd host; CC= CFLAGS= ../configure --target=$(CROSS_COMPILE:-=))
- touch host/build
+ if [ "$(CONFIG_USER_GDB_HOST)" == "y" ]; then \
+ (cd host; CC= CFLAGS= ../configure --target=$(CROSS_COMPILE:-=)); \
+ touch host/build; \
+ fi
clean:
rm -rf build host
Index: config/config.in
===================================================================
--- config/config.in (revision 70)
+++ config/config.in (working copy)
@@ -752,6 +771,7 @@
bool 'frob-led' CONFIG_USER_FROB_LED_FROB_LED
bool 'gdbreplay' CONFIG_USER_GDB_GDBREPLAY
bool 'gdbserver' CONFIG_USER_GDB_GDBSERVER
+bool 'gdb (host)' CONFIG_USER_GDB_HOST
bool 'gdbreplay (old)' CONFIG_USER_GDBSERVER_GDBREPLAY
bool 'gdbserver (old)' CONFIG_USER_GDBSERVER_GDBSERVER
bool 'grep' CONFIG_USER_GREP_GREP
------------------------------------------------------------------------
_______________________________________________
uClinux-dev mailing list
uClinux-dev@xxxxxxxxxxx
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@xxxxxxxxxxx