[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[microblaze-uclinux] Re: [uClinux-dev] [patch] NOMMU and MicroBlaze gdb/gdbserver



Hi John,

John Williams wrote:
Attached is a patch against current uClinux-dist relating to gdb and gdbserver. Can you please check it out, and if happy that I'm not breaking any non-microblaze stuff, apply? :)

Nothing obviuous that I can see. I have commited it for the next
dist test cut. Lets see what falls out then :-)

Regards
Greg



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

--
------------------------------------------------------------------------
Greg Ungerer  --  Chief Software Dude       EMAIL:     gerg@xxxxxxxxxxxx
SnapGear -- a CyberGuard Company            PHONE:       +61 7 3435 2888
825 Stanley St,                             FAX:         +61 7 3891 3630
Woolloongabba, QLD, 4102, Australia         WEB: http://www.SnapGear.com
___________________________
microblaze-uclinux mailing list
microblaze-uclinux@xxxxxxxxxxxxxx
Project Home Page : http://www.itee.uq.edu.au/~jwilliams/mblaze-uclinux
Mailing List Archive : http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/