This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: MIPS support for libjava (version 2).


Greetings again,

This is the second version of my patch. Thanks to those who insisted that I do better.

The patch now relies on being able to properly unwind through signal handlers. I split that part of the patch out, so you will have to apply it seperatly. It can be found at:

http://gcc.gnu.org/ml/gcc-patches/2003-09/msg00652.html

Some small notes on building...

This has only been tested with the configuration shown below.  The
target platform tested is linux 2.4.18 w/ glibc 2.2.4.


Use Binutils 2.14 or later.


I configured with this configure command:

../gcc-3.3.1/configure --host=i686-pc-linux-gnu --target=mipsisa32el-linux \
--enable-languages=c,c++,java \
--with-headers=/home/mipsel-linux/mipsel-linux/include \
--prefix=/home/mipsel-linux \
--with-libgcj-mips-xgot --with-broken-dladdr


My dladdr seems to be broken hence --with-broken-dladdr.


Binutils seems to have broken multi-got support.  So if you get GOT
overflow type messages from ld, configure with --with-libgcj-mips-xgot.


One observant reader noted that the problem may not be with ld per se, but is a result of multiple link phases needed due to command line length limitations. In any case you may need --with-libgcj-mips-xgot


On an in-house build of libgcj I removed many unneeded files from
libgcj and am able to link without --with-libgcj-mips-xgot.






2003-09-10  David Daney <ddaney@avtrex.com>

	MIPS support for libjava.
	* libjava/Makefile.am: Support for extra .c and .S files.
	* libjava/configure.host: Added mips*el*-linux* host.
	* libjava/configure.in: Added --with-broken-dladdr,
	--with-libgcj-mips-xgot and mips*-*-linux* host.
	* libjava/include/mips-signal.h: New file.
	* libjava/sysdep/mips/mipsel-backtracer.c: New file.
	* libjava/sysdep/mips/mipsel-backtracer.h: New file.
	* libjava/sysdep/mips/mipsel-bthelper.S: New file.

diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/Makefile.am gcc-3.3.1.dave/libjava/Makefile.am
--- gcc-3.3.1/libjava/Makefile.am	Sat Mar  1 14:57:52 2003
+++ gcc-3.3.1.dave/libjava/Makefile.am	Fri Sep  5 15:37:07 2003
@@ -115,6 +115,8 @@
 x_nat_files = $(x_nat_source_files:.cc=.lo)
 ## Objects from C sources in subdirs.
 c_files = $(c_source_files:.c=.lo)
+
+s_files = $(s_source_files:.S=.lo)
 ## Objects from Java sources in subdirs.
 javao_files = $(java_source_files:.java=.lo) \
 	$(built_java_source_files:.java=.lo)
@@ -125,12 +127,13 @@
 	$(nat_source_files)
 EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
 	win32-threads.cc posix.cc win32.cc \
-	$(c_source_files) $(java_source_files) $(built_java_source_files)
+	$(c_source_files) $(s_source_files) \
+        $(java_source_files) $(built_java_source_files)
 libgcj_la_DEPENDENCIES = libgcj-@gcc_version@.jar $(javao_files) \
-	$(c_files) $(GCOBJS) $(THREADOBJS) $(PLATFORMOBJS) $(LIBLTDL) \
-	$(LIBFFI) $(ZLIBS) $(GCLIBS)
+	$(c_files) $(s_files) $(GCOBJS) $(THREADOBJS) \
+        $(PLATFORMOBJS) $(LIBLTDL) $(LIBFFI) $(ZLIBS) $(GCLIBS)
 
-libgcj_la_LIBADD = $(javao_files) $(c_files) $(GCOBJS) \
+libgcj_la_LIBADD = $(javao_files) $(c_files) $(s_files) $(GCOBJS) \
 	$(THREADOBJS) $(PLATFORMOBJS)
 # Include THREADLIBS here to ensure that the correct version of
 # certain linuxthread functions get linked:
@@ -228,7 +231,8 @@
 	  sed -e '/\/\./d' -e '/\/xlib/d' | \
 	  $(ZIP) cfM0E@ $@
 
-MOSTLYCLEANFILES = $(javao_files) $(nat_files) $(nat_headers) $(c_files) $(x_javao_files) $(x_nat_files) $(x_nat_headers)
+MOSTLYCLEANFILES = $(javao_files) $(nat_files) $(nat_headers) $(c_files) \
+ $(s_files) $(x_javao_files) $(x_nat_files) $(x_nat_headers)
 CLEANFILES = libgcj-@gcc_version@.jar
 
 clean-local:
@@ -260,6 +264,9 @@
 $(c_files): %.lo: %.c
 	$(LTCOMPILE) -c -o $@ $<
 
+$(s_files): %.lo: %.S
+	$(LTCOMPILE) -c -o $@ $<
+
 $(c_files): java/lang/fdlibm.h java/lang/ieeefp.h java/lang/mprec.h
 
 ## FIXME: GNU make.
@@ -2311,7 +2318,10 @@
   java/lang/e_remainder.c java/lang/s_floor.c     java/lang/w_remainder.c \
   java/lang/e_scalb.c     java/lang/s_rint.c      java/lang/w_sqrt.c      \
   java/lang/e_sqrt.c      java/lang/s_scalbn.c    java/lang/sf_rint.c     \
-  java/lang/k_cos.c       java/lang/s_sin.c       java/lang/sf_fabs.c
+  java/lang/k_cos.c       java/lang/s_sin.c       java/lang/sf_fabs.c     \
+  $(EXTRA_C_FILES)
+
+s_source_files = $(EXTRA_S_FILES)
 
 #java/awt/natToolkit.cc
 
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/configure.host gcc-3.3.1.dave/libjava/configure.host
--- gcc-3.3.1/libjava/configure.host	Wed Feb 12 18:09:26 2003
+++ gcc-3.3.1.dave/libjava/configure.host	Fri Sep  5 15:37:07 2003
@@ -166,6 +166,12 @@
   x86_64*-linux*)
   	can_unwind_signal=yes
 	;;
+  mips*el*-linux*)
+  	can_unwind_signal=yes
+	if test "x${with_libgcj_mips_xgot}" = "xyes"; then
+		libgcj_flags="${libgcj_flags} -Wa,-xgot"
+	fi
+	;;
   *-*-darwin*)
 	enable_hash_synchronization_default=no
 	slow_pthread_self=
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/configure.in gcc-3.3.1.dave/libjava/configure.in
--- gcc-3.3.1/libjava/configure.in	Tue Jun 17 09:04:20 2003
+++ gcc-3.3.1.dave/libjava/configure.in	Wed Sep 10 10:45:41 2003
@@ -19,6 +19,12 @@
 AC_ARG_WITH(newlib,
 [  --with-newlib           Configuring with newlib])
 
+AC_ARG_WITH(broken-dladdr,
+[  --with-broken-dladdr              Configuring to not use dladdr because it is broken])
+
+AC_ARG_WITH(libgcj-mips-xgot,
+[  --with-libgcj-mips-xgot           For MIPS builds use -Wa,-xgot to build libgcj])
+
 LIBGCJ_CONFIGURE(.)
 
 AM_CONFIG_HEADER(include/config.h gcj/libgcj-config.h)
@@ -219,6 +225,11 @@
 TARGET_ECOS="$with_ecos"
 )
 
+EXTRA_S_FILES=
+AC_SUBST(EXTRA_S_FILES)
+EXTRA_C_FILES=
+AC_SUBST(EXTRA_C_FILES)
+
 PLATFORMOBJS=
 case "$TARGET_ECOS" in
    no) case "$host" in
@@ -515,6 +526,13 @@
        ia64-*-linux*)
 	 # Has broken backtrace()
 	 ;;
+       mips*-*-linux*)
+         # Has broken backtrace(), but we supply our own.
+         if test -d sysdep/mips; then true; else mkdir -p sysdep/mips; fi
+         EXTRA_C_FILES="${EXTRA_C_FILES} sysdep/mips/mipsel-backtracer.c"
+         EXTRA_S_FILES="${EXTRA_S_FILES} sysdep/mips/mipsel-bthelper.S"
+         AC_DEFINE(HAVE_BACKTRACE)
+         ;;
        *)
          AC_DEFINE(HAVE_BACKTRACE)
 	 ;;
@@ -529,7 +547,13 @@
    ])
 
    AC_CHECK_LIB(dl, dladdr, [
-     AC_DEFINE(HAVE_DLADDR)])
+     if test "x${with_broken_dladdr}" = "xyes"; then
+       #Broken dladdr().
+       true
+     else
+       AC_DEFINE(HAVE_DLADDR)
+     fi
+   ])
    if test x"$build" = x"$host"; then
      AC_CHECK_FILES(/proc/self/exe, [
        AC_DEFINE(HAVE_PROC_SELF_EXE)])
@@ -940,6 +964,9 @@
     ;;
  *mingw*)
     SIGNAL_HANDLER=include/win32-signal.h
+    ;;
+ mips*-*-linux*)
+    SIGNAL_HANDLER=include/mips-signal.h
     ;;
  *)
     SIGNAL_HANDLER=include/default-signal.h
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/include/mips-signal.h gcc-3.3.1.dave/libjava/include/mips-signal.h
--- gcc-3.3.1/libjava/include/mips-signal.h	Wed Dec 31 16:00:00 1969
+++ gcc-3.3.1.dave/libjava/include/mips-signal.h	Wed Sep 10 11:13:49 2003
@@ -0,0 +1,90 @@
+// mips-signal.h - Catch runtime signals and turn them into exceptions
+// on an mipsel based Linux system that use the "o32" ABI. 
+
+/* Copyright (C) 1998, 1999, 2001, 2002, 2003  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+/* Adapted from sparc-signal.h and powerpc-signal.h
+   by David Daney <ddaney@avtrex.com> */
+
+#ifndef JAVA_SIGNAL_H
+#define JAVA_SIGNAL_H 1
+
+#include <signal.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+/* #include <asm/ucontext.h> structures we use are here but clash with
+   sys/ucontext.h included by java-signal.h from prims.cc */
+
+#define HANDLE_SEGV 1
+#undef HANDLE_FPE
+
+/* The third parameter to the signal handler points to something with
+ * this structure defined in asm/ucontext.h, but the name clashes with
+ * struct ucontext from sys/ucontext.h so this private copy is used. */
+typedef struct _sig_ucontext {
+    unsigned long	  uc_flags;
+    struct _sig_ucontext  *uc_link;
+    stack_t		  uc_stack;
+    struct sigcontext uc_mcontext;
+    sigset_t	  uc_sigmask;
+} sig_ucontext_t;
+
+/* We use kernel_sigaction here because we're calling the kernel
+   directly rather than via glibc. The sigaction structure that the
+   syscall uses is a different shape from the one in userland and not
+   visible to us in a header file so we define it here.
+   Additionally we want a proper prototype for the handler function
+   with the struct sigcontext pointer passed by the kernel as the 2nd
+   argument, which isn't there in userland headers. */
+
+struct kernel_sigaction {
+    unsigned int k_sa_flags;
+    void       (*k_sa_handler) (int, siginfo_t *, sig_ucontext_t *);
+    sigset_t     k_sa_mask;
+    void       (*k_sa_restorer)(void);
+    int          k_sa_resv[1];	/* reserved */
+};
+
+
+
+#define SIGNAL_HANDLER(_name) \
+static void _name (int _dummy, siginfo_t *_info, sig_ucontext_t *_arg)
+
+/*
+ *  MIPS leaves pc pointing at the faulting instruction, but the
+ *  unwinder expects it to point to the following instruction
+ */
+
+#define MAKE_THROW_FRAME(_exception) \
+do                                   \
+{                                    \
+  _arg->uc_mcontext.sc_pc += 4;      \
+  (void)_dummy;                      \
+  (void)_info;                       \
+}                                    \
+while (0)
+
+/* For an explanation why we cannot simply use sigaction to
+   install the handlers, see i386-signal.h.  */
+
+#define INIT_SEGV                                    \
+do                                                   \
+  {                                                  \
+    nullp = new java::lang::NullPointerException (); \
+    struct kernel_sigaction kact;                    \
+    kact.k_sa_handler = catch_segv;                  \
+    kact.k_sa_flags = SA_SIGINFO | SA_NODEFER;       \
+    sigemptyset (&kact.k_sa_mask);                   \
+    syscall (SYS_sigaction, SIGSEGV, &kact, NULL);   \
+  }                                                  \
+while (0)
+								
+
+#endif /* JAVA_SIGNAL_H */
+  
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/sysdep/mips/mipsel-backtracer.c gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-backtracer.c
--- gcc-3.3.1/libjava/sysdep/mips/mipsel-backtracer.c	Wed Dec 31 16:00:00 1969
+++ gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-backtracer.c	Wed Sep 10 13:20:57 2003
@@ -0,0 +1,660 @@
+/* mipsel-backtracer.c - Helper functions for generating a backtrace
+ * on mipsel platforms that use the "o32" ABI. 
+ */
+
+/* Copyright (C) 2003  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+/* Written by David Daney <ddaney@avtrex.com> */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <unistd.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <execinfo.h>
+
+#include "config.h"
+#include "mipsel-backtracer.h"
+
+#ifdef HAVE_PROC_SELF_EXE
+#define USE_PROC_MAPS 1
+#endif
+
+#ifdef USE_PROC_MAPS
+
+#define FILENAME_SIZE 128
+#define PROC_MAPSLINE_LEN (80 + FILENAME_SIZE)
+
+#define MEMORY_EXECUTABLE 1
+#define MEMORY_READABLE 4
+#define MEMORY_WRITABLE 2
+
+typedef struct _memory_map_block
+{
+  struct _memory_map_block *next, *prev;
+  void *start;
+  void *end;
+  unsigned offset;
+  int flags;
+  char filename[FILENAME_SIZE];
+}
+memory_map_block;
+
+#if 0
+static void dump_maps (memory_map_block * f);
+#endif
+static void free_maps (memory_map_block * f);
+static memory_map_block *parse_maps ();
+static memory_map_block *find_in_maps (memory_map_block * start_point,
+				       void *addr, int mode);
+
+#endif /* USE_PROC_MAPS */
+
+static int
+is_branch (int opcode)
+{
+  if (0x10000000 == (opcode & 0xb0000000) ||	/* branch instructions */
+      0x08000000 == (opcode & 0xf8000000) ||	/* j and jl */
+      0x04000000 == (opcode & 0xfc0c0000) ||	/* more branches */
+      0x00000009 == (opcode & 0xfc1f003f) ||	/* jalr */
+      0x00000008 == (opcode & 0xfc1ff83f) ||	/* jr */
+      0xa1000000 == (opcode & 0xf3e00000))
+    {				/* coprocessor branch */
+      return 1;
+    }
+  return 0;
+}
+
+/*
+ * Look for a move which could be (ADDU, OR, SUBU, XOR) with a source of $sp
+ * op $fp, $sp, $0
+ * op $fp, $0, $sp
+ *
+ * return the dest reg or -1
+ */
+static int
+is_fp_reg (int opcode)
+{
+  int i;
+
+  if ((0x03a00020 == (opcode & 0xffff07f8)) ||	/* op ??, $sp, $0 */
+      (0x001d0020 == (opcode & 0xffff07f8)))
+    {				/* op ??, $0, $sp */
+      i = opcode & 7;
+      if (1 == i ||		/* addu */
+	  3 == i ||		/* subu */
+	  5 == i ||		/* or */
+	  6 == i)
+	{			/* xor */
+	  i = (opcode >> 11) & 0x1f;
+	  return i;
+	}
+    }
+  return -1;
+}
+
+/*
+ * Is the opcode a sw $fp,##(sp)
+ *
+ */
+static int
+get_fp_save_location (int opcode)
+{
+  int rv = -1;
+
+  if (0xafbe0000 == (0xffff0000 & opcode))
+    {
+      rv = 0xffff & opcode;
+      if (0x8000 & rv)
+	{
+	  rv |= 0xffff0000;
+	}
+    }
+  return rv;
+}
+
+/*
+ * Is the opcode a sw $31,##(sp)
+ *
+ */
+static int
+get_ra_save_location (int opcode)
+{
+  int rv = -1;
+
+  if (0xafbf0000 == (0xffff0000 & opcode))
+    {
+      rv = 0xffff & opcode;
+      if (0x8000 & rv)
+	{
+	  rv |= 0xffff0000;
+	}
+    }
+  return rv;
+}
+
+struct _sig_ucontext
+{
+  unsigned long uc_flags;
+  struct _sig_ucontext *uc_link;
+  stack_t uc_stack;
+  struct sigcontext uc_mcontext;
+  sigset_t uc_sigmask;
+};
+
+struct sigframe
+{
+  unsigned int trampoline[2];
+  struct sigcontext sigctx;
+};
+
+struct rt_sigframe
+{
+  unsigned int trampoline[2];
+  struct siginfo info;
+  struct _sig_ucontext uc;
+};
+
+/*
+ * Do the backtrace.  Normally called only from
+ * mips_backtracer_with_skip or mips_backtracer which are located in
+ * mipsel-bthelper.S
+ **/
+int
+do_mips_backtrace (void **locations,
+		   int len,
+		   char *callers_sp,
+		   char *callers_fp,
+		   char *callers_return, int frame_skip_count)
+{
+  int *ip;			/* instruction pointer */
+  struct sigcontext *sc;
+  int stack_adjustment;
+  int ra_save_location;
+
+  int fp_register, fp_save_location;
+  int num_saved;		/* number of stack trace elements saved so far. */
+
+#ifdef USE_PROC_MAPS
+  memory_map_block *maps;	/* memory map info */
+  memory_map_block *s_map;	/* positioned on stack area */
+  memory_map_block *c_map;	/* positioned on code area */
+  memory_map_block *t_map;	/* temp */
+
+
+  maps = parse_maps ();
+
+  s_map = maps;
+  c_map = maps;
+#endif /* USE_PROC_MAPS */
+
+  num_saved = 0;
+
+  if (0 == len)
+    {
+      /*
+       * zero frames requested.  we are already done.
+       */
+      goto error_exit;
+    }
+  else
+    {
+      /* The first one is just our ra argument.
+       * adjust by 8 bytes to get address before the call.
+       */
+      if (frame_skip_count)
+	{
+	  frame_skip_count--;
+	}
+      else
+	{
+	  locations[num_saved++] = (callers_return - 8);
+	}
+    }
+
+  while (num_saved < len)
+    {
+      ip = (int *) callers_return;
+
+      /* Check for a signal return trampoline
+       *
+       * 24021061 li v0, 0x1061 (rt_sigreturn)
+       * 0000000c syscall
+       *    or
+       * 24021017 li v0, 0x1017 (sigreturn)
+       * 0000000c syscall  */
+
+#ifdef USE_PROC_MAPS
+      t_map = find_in_maps (c_map, ip, MEMORY_EXECUTABLE);
+      if (!t_map)
+	{
+	  goto error_exit;
+	}
+      t_map = find_in_maps (t_map, ip + 1, MEMORY_EXECUTABLE);
+      if (!t_map)
+	{
+	  goto error_exit;
+	}
+      c_map = t_map;
+#endif
+      sc = NULL;
+      if (0x0000000c == ip[1])
+	{
+	  if (0x24021061 == ip[0])
+	    {
+#ifdef USE_PROC_MAPS
+	      t_map = find_in_maps (c_map,
+				    (char *) ip + sizeof (struct rt_sigframe),
+				    MEMORY_EXECUTABLE);
+	      if (!t_map)
+		{
+		  goto error_exit;
+		}
+	      c_map = t_map;
+#endif
+	      sc = &((struct rt_sigframe *) ip)->uc.uc_mcontext;
+	    }
+	  else if (0x24021017 == ip[0])
+	    {
+#ifdef USE_PROC_MAPS
+	      t_map = find_in_maps (c_map,
+				    (char *) ip + sizeof (struct sigframe),
+				    MEMORY_EXECUTABLE);
+	      if (!t_map)
+		{
+		  goto error_exit;
+		}
+	      c_map = t_map;
+#endif
+	      sc = &((struct sigframe *) ip)->sigctx;
+	    }
+	  /* else not signal return trampoline */
+	}
+      if (sc)
+	{
+	  /* Do signal return trace */
+	  callers_return = (char *) (long) sc->sc_pc;
+	  callers_sp = (char *) (long) sc->sc_regs[29];
+	  callers_fp = (char *) (long) sc->sc_regs[30];
+	  if (frame_skip_count)
+	    {
+	      frame_skip_count--;
+	    }
+	  else
+	    {
+	      locations[num_saved++] = callers_return;
+	    }
+	  continue;
+	}
+
+      /*
+       * Find function prolog.  It will have the form:
+       *
+       *      3c1c????        lui     gp,????
+       *      279c????        addiu   gp,gp,????
+       *      0399e021        addu    gp,gp,t9
+       *      27bd####        addiu   sp,sp,####
+       *
+       * Where ???? are the offset of the GOT from the function
+       * entrypoint, and #### is the amount added to the stack poiner.
+       */
+      for (;;)
+	{
+#ifdef USE_PROC_MAPS
+	  t_map = find_in_maps (c_map, ip, MEMORY_EXECUTABLE);
+	  if (!t_map)
+	    {
+	      goto error_exit;
+	    }
+	  c_map = t_map;
+#endif
+	  if (*ip == 0x0399e021)
+	    {
+	      break;
+	    }
+	  ip--;
+	}
+#ifdef USE_PROC_MAPS
+      t_map = find_in_maps (c_map, ip - 2, MEMORY_EXECUTABLE);
+      if (!t_map)
+	{
+	  goto error_exit;
+	}
+      c_map = t_map;
+#endif
+
+      if (0x279c0000 == ((ip[-1]) & 0xffff0000) &&
+	  0x3c1c0000 == ((ip[-2]) & 0xffff0000) &&
+	  0x27bd8000 == ((ip[1]) & 0xffff8000))
+	{
+	  /* We found a function prolog!! */
+	  stack_adjustment = ip[1] | 0xffff0000;
+	  ip += 2;		/* to end of prolog */
+
+	  /*
+	   * Now find where things are in the stack frame by
+	   * analyzing the function prolog.
+	   *
+	   */
+	  ra_save_location = -1;
+	  fp_register = -1;
+	  fp_save_location = -1;
+
+	  while (((char *) ip) < callers_return)
+	    {
+	      if (is_branch (*ip))
+		{
+		  break;
+		}
+	      if (-1 == ra_save_location)
+		{
+		  ra_save_location = get_ra_save_location (*ip);
+		  if (fp_register > 0 &&
+		      -1 != fp_save_location && -1 != ra_save_location)
+		    {
+		      break;
+		    }
+		}
+	      if (-1 == fp_save_location)
+		{
+		  fp_save_location = get_fp_save_location (*ip);
+		}
+	      if (fp_register < 0)
+		{
+		  fp_register = is_fp_reg (*ip);
+		  if (fp_register > 0 &&
+		      -1 != fp_save_location && ra_save_location != -1)
+		    {
+		      break;
+		    }
+		}
+	      ip++;
+	    }
+	  if (-1 == ra_save_location)
+	    {
+	      break;
+	    }
+	  if (30 == fp_register)
+	    {
+	      /* this frame used the fp */
+#ifdef USE_PROC_MAPS
+	      /* if stack not writable, then we probably are out of sync */
+	      t_map =
+		find_in_maps (s_map, callers_fp + ra_save_location,
+			      MEMORY_WRITABLE);
+	      if (!t_map)
+		{
+		  goto error_exit;
+		}
+	      s_map = t_map;
+	      t_map =
+		find_in_maps (s_map, callers_fp + fp_save_location,
+			      MEMORY_WRITABLE);
+	      if (!t_map)
+		{
+		  goto error_exit;
+		}
+	      s_map = t_map;
+#endif
+	      callers_return = *(char **) (callers_fp + ra_save_location);
+	      callers_sp = callers_fp - stack_adjustment;
+	      callers_fp = *(char **) (callers_fp + fp_save_location);
+	    }
+	  else if (-1 == fp_register)
+	    {
+	      /* this frame uses sp as frame pointer */
+#ifdef USE_PROC_MAPS
+	      /* if stack not writable, then we probably are out of sync */
+	      t_map =
+		find_in_maps (s_map, callers_sp + ra_save_location,
+			      MEMORY_WRITABLE);
+	      if (!t_map)
+		{
+		  goto error_exit;
+		}
+	      s_map = t_map;
+#endif
+	      callers_return = *(char **) (callers_sp + ra_save_location);
+	      if (-1 != fp_save_location)
+		{
+		  /* fp was saved, but unused in this frame.
+		   * we may need it in subsequent frames
+		   */
+#ifdef USE_PROC_MAPS
+		  t_map =
+		    find_in_maps (s_map, callers_sp + fp_save_location,
+				  MEMORY_WRITABLE);
+		  if (!t_map)
+		    {
+		      goto error_exit;
+		    }
+		  s_map = t_map;
+#endif
+		  callers_fp = *(char **) (callers_sp + fp_save_location);
+		}
+	      callers_sp = callers_sp - stack_adjustment;
+	    }
+	  else
+	    {
+	      printf ("Cannot handle fp in register %d, aborting trace\n",
+		      fp_register);
+	      break;
+	    }
+#ifdef USE_PROC_MAPS
+	  t_map = find_in_maps (c_map, callers_return, MEMORY_EXECUTABLE);
+	  if (!t_map)
+	    {
+	      goto error_exit;
+	    }
+	  c_map = t_map;
+#else
+	  if (NULL == callers_return)
+	    {
+	      break;
+	    }
+#endif
+	  if (frame_skip_count)
+	    {
+	      frame_skip_count--;
+	    }
+	  else
+	    {
+	      /* 
+	       * Adjust by 8 bytes to get address before the call.
+	       */
+	      locations[num_saved++] = (callers_return - 8);
+	    }
+	}
+      else
+	{
+	  /* Prolog search failed. */
+	  goto error_exit;
+	}
+    }
+error_exit:
+#ifdef USE_PROC_MAPS
+  free_maps (maps);
+#endif
+  return num_saved;
+}
+
+#ifdef USE_PROC_MAPS
+static memory_map_block *
+find_in_maps (memory_map_block * start_point, void *addr, int mode)
+{
+  int dir = 0;			/* 0 = unknown, -1 down, 1 up */
+
+  while (start_point)
+    {
+      if (addr >= start_point->start)
+	{
+	  if (addr < start_point->end)
+	    {
+	      /* it is in this block */
+	      if (mode & start_point->flags)
+		{
+		  return start_point;
+		}
+	      else
+		{
+		  /* wrong mode */
+		  break;
+		}
+	    }
+	  else
+	    {
+	      if (0 <= dir)
+		{
+		  start_point = start_point->next;
+		  dir = 1;
+		  continue;
+		}
+	      else
+		{
+		  /* must be between blocks */
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  if (0 >= dir)
+	    {
+	      start_point = start_point->prev;
+	      dir = -1;
+	      continue;
+	    }
+	  else
+	    {
+	      /* must be between blocks */
+	      break;
+	    }
+	}
+    }
+  return NULL;
+}
+
+#if 0
+static void
+dump_maps (memory_map_block * f)
+{
+  while (f)
+    {
+      printf ("%p-%p %1.1x <%s>:%x\n", f->start, f->end, f->flags,
+	      f->filename, f->offset);
+      f = f->next;
+    }
+}
+#endif
+
+static void
+free_maps (memory_map_block * f)
+{
+  memory_map_block *n;
+
+  while (f)
+    {
+      n = f->next;
+      free (f);
+      f = n;
+    }
+}
+
+
+static memory_map_block *
+parse_maps ()
+{
+  int n;
+
+  char fn[FILENAME_SIZE];
+  char line[PROC_MAPSLINE_LEN + 1];
+  char mode[4];
+
+  FILE *f;
+  unsigned s, e, o;
+
+  memory_map_block *first, *current;
+  first = NULL;
+  current = NULL;
+
+  f = fopen ("/proc/self/maps", "r");
+  if (NULL == f)
+    {
+      perror ("could not open proc file");
+      return NULL;
+    }
+
+  while (fgets (line, PROC_MAPSLINE_LEN, f))
+    {
+      n = sscanf (line, "%8x-%8x %4s %8x %*s %*s %s\n", &s, &e, mode, &o, fn);
+      if (n >= 4)
+	{
+	  if ('r' != mode[0])
+	    {
+	      /* not readable, do not worry about it */
+	      continue;
+	    }
+	  /* good parse. */
+	  memory_map_block *mbp =
+	    (memory_map_block *) calloc (1, sizeof (memory_map_block));
+	  if (NULL == mbp)
+	    {
+	      break;
+	    }
+	  if (NULL == first)
+	    {
+	      first = mbp;
+	      current = mbp;
+	    }
+	  else
+	    {
+	      current->next = mbp;
+	      mbp->prev = current;
+	      current = mbp;
+	    }
+	  current->start = (void *) s;
+	  current->end = (void *) e;
+	  current->offset = o;
+	  current->flags = MEMORY_READABLE;
+	  if ('x' == mode[2])
+	    {
+	      current->flags |= MEMORY_EXECUTABLE;
+	    }
+	  if ('w' == mode[1])
+	    {
+	      current->flags |= MEMORY_WRITABLE;
+	    }
+	  if (5 == n)
+	    {
+	      strncpy (current->filename, fn, FILENAME_SIZE);
+	      current->filename[FILENAME_SIZE - 1] = 0;
+	    }
+	}
+    }
+
+  fclose (f);
+
+  return first;
+}
+
+#endif /* USE_PROC_MAPS */
+
+
+int
+backtrace (void **locations, int len)
+{
+  /* Return a backtrace skipping the extra call inserted by calling
+     mips_backtracer_with_skip */
+  return mips_backtracer_with_skip (locations, len, 1);
+}
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/sysdep/mips/mipsel-backtracer.h gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-backtracer.h
--- gcc-3.3.1/libjava/sysdep/mips/mipsel-backtracer.h	Wed Dec 31 16:00:00 1969
+++ gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-backtracer.h	Fri Sep  5 15:37:07 2003
@@ -0,0 +1,28 @@
+/* mipsel-backtracer.h - Include file for mipsel-backtracer.c */
+
+/* Copyright (C) 2003  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+/* Written by David Daney <ddaney@avtrex.com> */
+
+#ifndef _MIPSEL_BACKTRACER_H
+#define _MIPSEL_BACKTRACER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int do_mips_backtrace(void **locations, int len, char *sp, char *fp, char *ra, int frame_skip_count);
+int mips_backtracer(void **locations, int len);
+int mips_backtracer_with_skip(void **locations, int len, int frame_skip_count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MIPSEL_BACKTRACER_H */
diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/sysdep/mips/mipsel-bthelper.S gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-bthelper.S
--- gcc-3.3.1/libjava/sysdep/mips/mipsel-bthelper.S	Wed Dec 31 16:00:00 1969
+++ gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-bthelper.S	Fri Sep  5 15:37:07 2003
@@ -0,0 +1,93 @@
+	# mipsel-bthelper.S - Generate a stacktrace on mipsel o32 ABI platform.
+	#
+	#
+	# Copyright (C) 2003  Free Software Foundation
+	#
+	# This file is part of libgcj.
+	#
+	# This software is copyrighted work licensed under the terms
+	# of the Libgcj License.  Please consult the file "LIBGCJ_LICENSE"
+	# for details.
+	#
+	# Written by David Daney <ddaney@avtrex.com>
+	#
+	
+#include <sys/asm.h>
+#include <sys/regdef.h>
+	
+	#
+	# Create a backtrace by passing some values to do_mips_backtrace
+	# 
+	# Our stack frame is layed out as follows:
+	# 32 -> top of stack
+	# 28 -> ra.
+	# 24 -> gp (aka cprestore value)
+	# 20 -> 6th argument to do_mips_backtrace() i.e. frame_skip_count
+	# 16 -> 5th argument to do_mips_backtrace() i.e. return address
+	# 12 -> callee saves 4th arg
+	# 8  -> callee saves 3rd arg
+	# 4  -> callee saves 2nd arg
+	# 0  -> callee saves 1st arg
+	
+	.equ	stack_size,32
+	.equ	ra_loc,28
+	.equ	gp_loc,24
+	.equ	sa_loc,20
+	.equ	fa_loc,16
+	
+	.abicalls
+	.text
+mips_backtracer:
+	NESTED(mips_backtracer, stack_size, ra)
+	.mask	0x90000000,ra_loc-stack_size 
+	.fmask	0x00000000,0
+	.set	noreorder
+	CPLOAD(t9)			# standard function entry
+	.set	reorder
+	subu	sp,sp,stack_size	# allocate local stack frame
+	sw	ra,ra_loc(sp)		# $ra
+	CPRESTORE(gp_loc)		# $gp
+					# first and second parameters are passed through
+	move	a2,sp			# $sp is third parameter
+	addu	a2,a2,stack_size	# but it has to be re-adjusted!
+	move	a3,s8			# $s8/$fp is fourth parameter
+	sw	ra,fa_loc(sp)		# $ra is the fifth parameter
+	sw	zero,sa_loc(sp)		# frame_skip_count of zero.
+	la	t9,do_mips_backtrace
+	jal	ra,t9			# call do_mips_backtrace()
+	lw	ra,ra_loc(sp)		# restore $ra
+	.set	noreorder
+	.set	nomacro
+	j	ra			# return with do_back_trace's return values
+	addu	sp,sp,stack_size	# delay slot restores stack
+	.set	macro
+	.set	reorder
+	END(mips_backtracer)
+
+mips_backtracer_with_skip:
+	NESTED(mips_backtracer_with_skip, stack_size, ra)
+	.mask	0x90000000,ra_loc-stack_size 
+	.fmask	0x00000000,0
+	.set	noreorder
+	CPLOAD(t9)			# standard function entry
+	.set	reorder
+	subu	sp,sp,stack_size	# allocate local stack frame
+	sw	ra,ra_loc(sp)		# $ra
+	CPRESTORE(gp_loc)		# $gp
+					# first and second arguments are passed through
+	sw	a2,sa_loc(sp)		# our third parameter goes to 6th (frame_skip_count).
+	move	a2,sp			# $sp is third parameter
+	addu	a2,a2,stack_size	# but it has to be re-adjusted!
+	move	a3,s8			# $s8/$fp is fourth parameter
+	sw	ra,fa_loc(sp)		# $ra is the fifth parameter
+	la	t9,do_mips_backtrace
+	jal	ra,t9			# call do_mips_backtrace()
+	lw	ra,ra_loc(sp)		# restore $ra
+	.set	noreorder
+	.set	nomacro
+	j	ra			# return with do_back_trace's return values
+	addu	sp,sp,stack_size	# delay slot restores stack
+	.set	macro
+	.set	reorder
+	END(mips_backtracer_with_skip)
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]