This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
PATCH: MIPS support for libjava (version 2).
- From: David Daney <ddaney at avtrex dot com>
- To: java-patches at gcc dot gnu dot org
- Date: Wed, 10 Sep 2003 14:46:59 -0700
- Subject: 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)
+