This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
warning: reality as about to implode (was: MIPS support for libjava)
- From: Adam Megacz <gcj at lists dot megacz dot com>
- To: David Daney <ddaney at avtrex dot com>
- Cc: java-patches at gcc dot gnu dot org, core at xwt dot org
- Date: 08 Sep 2003 22:33:38 -0700
- Subject: warning: reality as about to implode (was: MIPS support for libjava)
- Organization: Myself
- References: <3F5D2000.9060100@avtrex.com>
Uh oh... in the last week we've seen both a tool to run MIPS code in a
JVM and a tool to run Java code on a MIPS CPU... I fear an infinite
recursion... ;)
http://www.xwt.org/mips2java/
- a
David Daney <ddaney@avtrex.com> writes:
> Greetings:
>
> Here is a patch against 3.3.1 that adds SIGSEGV handling of
> NullPointerExceptions for a MIPS host. It also contains a custom
> backtrace function as the version we have in our libc is broken.
>
> After patching you have to run automake, autoconf and autoheader.
>
> 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-custom-backtrace \
> --with-libgcj-mips-xgot --with-broken-dladdr
>
> My backtrace is broken hence the --with-custom-backtrace.
>
> My dladdr also seems to be broken hence --with-broken-dladdr.
>
> These two are only important if you are throwing and catching exceptions.
>
> Binutils seems to have broken multi-got support. So if you get GOT
> overflow type messages from ld, configure with --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.
>
>
> David Daney
>
> 2003-09-08 David Daney <ddaney@avtrex.com>
>
> MIPS support for libjava
> * libjava/acconfig.h: Added BROKEN_DLADDR and CUSTOM_BACKTRACE
> * libjava/Makefile.am: Support for extra .c and .S files.
> * libjava/configure.in: Added --with-custom-backtrace,
> --with-broken-dladdr, --with-libgcj-mips-xgot and mips*-*-linux* host.
> * libjava/configure.host: Added mips*el*-linux* host.
> * libjava/gnu/gcj/runtime/natNameFinder.cc (dladdrLookup): Don't use dladdr() if
> BROKEN_DLADDR is defined.
> * libjava/gnu/gcj/runtime/natStackTrace.cc (fillInStackTrace): Use
> CUSTOM_BACKTRACE if available.
> * 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.
> * libjava/sysdep/mips/mipsel-sighelper.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/acconfig.h gcc-3.3.1.dave/libjava/acconfig.h
> --- gcc-3.3.1/libjava/acconfig.h Thu Aug 29 11:05:14 2002
> +++ gcc-3.3.1.dave/libjava/acconfig.h Mon Sep 8 16:23:39 2003
> @@ -140,6 +140,9 @@
> /* Define if you have dladdr() */
> #undef HAVE_DLADDR
>
> +/* Define if you have a broken dladdr() */
> +#undef BROKEN_DLADDR
> +
> /* Define if tzname is missing. */
> #undef NO_TZNAME
>
> @@ -160,6 +163,11 @@
>
> /* Define if your platform has a working backtrace() function. */
> #undef HAVE_BACKTRACE
> +
> +/* Defined as the backtrace function name if your platform has a
> + custom backtrace() that should be used instead of the platform's
> + version. */
> +#undef CUSTOM_BACKTRACE
>
> /* Define if your platform has the global _timezone variable. */
> #undef HAVE_UNDERSCORE_TIMEZONE
> 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 Mon Sep 8 16:28:23 2003
> @@ -19,6 +19,15 @@
> AC_ARG_WITH(newlib,
> [ --with-newlib Configuring with newlib])
>
> +AC_ARG_WITH(custom-backtrace,
> +[ --with-custom-backtrace Configuring with custom backtrace() function])
> +
> +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 +228,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
> @@ -440,6 +454,14 @@
> AC_SUBST(THREADSPEC)
> AC_SUBST(THREADLDFLAGS)
>
> +if test "x${with_custom_backtrace}" = "xyes"; then
> + AC_DEFINE(CUSTOM_BACKTRACE, _Jv_CustomBacktrace, [Defined to be the custom backtracer])
> +fi
> +
> +if test "x${with_broken_dladdr}" = "xyes"; then
> + AC_DEFINE(BROKEN_DLADDR, 1, [Do not use dladdr because it is broken])
> +fi
> +
> if test -d sysdep; then true; else mkdir sysdep; fi
> AC_LINK_FILES(sysdep/$sysdeps_dir/locks.h, sysdep/locks.h)
>
> @@ -515,6 +537,16 @@
> ia64-*-linux*)
> # Has broken backtrace()
> ;;
> + mips*-*-linux*)
> + if test "x${with_custom_backtrace}" = "xyes"; then
> + # Has broken backtrace()
> + 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"
> + else
> + AC_DEFINE(HAVE_BACKTRACE)
> + fi
> + ;;
> *)
> AC_DEFINE(HAVE_BACKTRACE)
> ;;
> @@ -940,6 +972,10 @@
> ;;
> *mingw*)
> SIGNAL_HANDLER=include/win32-signal.h
> + ;;
> + mips*-*-linux*)
> + SIGNAL_HANDLER=include/mips-signal.h
> + EXTRA_S_FILES="${EXTRA_S_FILES} sysdep/mips/mipsel-sighelper.S"
> ;;
> *)
> 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/gnu/gcj/runtime/natNameFinder.cc gcc-3.3.1.dave/libjava/gnu/gcj/runtime/natNameFinder.cc
> --- gcc-3.3.1/libjava/gnu/gcj/runtime/natNameFinder.cc Mon Mar 10 11:34:30 2003
> +++ gcc-3.3.1.dave/libjava/gnu/gcj/runtime/natNameFinder.cc Mon Sep 8 16:28:28 2003
> @@ -92,7 +92,7 @@
> java::lang::StackTraceElement*
> gnu::gcj::runtime::NameFinder::dladdrLookup(RawData* addrs, jint n)
> {
> -#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
> +#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) && !defined(BROKEN_DLADDR)
> extern char **_Jv_argv;
> char name[1024];
> char file_name[1024];
> diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/libjava/gnu/gcj/runtime/natStackTrace.cc gcc-3.3.1.dave/libjava/gnu/gcj/runtime/natStackTrace.cc
> --- gcc-3.3.1/libjava/gnu/gcj/runtime/natStackTrace.cc Wed Feb 19 08:27:22 2003
> +++ gcc-3.3.1.dave/libjava/gnu/gcj/runtime/natStackTrace.cc Fri Sep 5 15:37:07 2003
> @@ -45,14 +45,22 @@
> #include <unwind.h>
>
>
> +#ifdef CUSTOM_BACKTRACE
> +extern "C" int CUSTOM_BACKTRACE (void **, int);
> +#endif
> +
> // Fill in this stack trace with MAXLEN elements starting at offset.
> void
> gnu::gcj::runtime::StackTrace::fillInStackTrace (jint maxlen, jint offset)
> {
> -#ifdef HAVE_BACKTRACE
> +#if defined(HAVE_BACKTRACE) || defined(CUSTOM_BACKTRACE)
> offset += 1;
> void *_p[maxlen + offset];
> +#ifdef CUSTOM_BACKTRACE
> + len = CUSTOM_BACKTRACE (_p, maxlen + offset) - offset;
> +#else // must be HAVE_BACKTRACE
> len = backtrace (_p, maxlen + offset) - offset;
> +#endif // CUSTOM_BACKTRACE
> void **p = _p + offset;
> _Jv_frame_info *frame;
> if (len > 0)
> 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 Fri Sep 5 15:37:07 2003
> @@ -0,0 +1,108 @@
> +// 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 (loosely) from sparc-signal.h by David Daney <ddaney@avtrex.com> */
> +
> +#ifndef JAVA_SIGNAL_H
> +#define JAVA_SIGNAL_H 1
> +
> +#include <signal.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;
> +
> +
> +#define SIGNAL_HANDLER(_name) \
> +extern "C" void _Jv_MipselThrowNPE(); \
> +void _Jv_MipselThrowNPE() \
> +{ \
> + _Jv_ThrowSignal (nullp); \
> +} \
> +static void _name (int _dummy, siginfo_t *_info, void *arg)
> +
> +/*
> + * Build a stack frame with the layout used by __sig2exdummy just
> + * above the frame of the faulting function. And then jump to
> + * _Jv_MipselThrowNPE() simulating a jal from
> + * $sig2exdummy_fakeout_point.
> + *
> + * The result is that the signal handler's stack frame and trampoline
> + * code are obliterated and the stack is in a state that looks like
> + * __sig2exdummy was called from the faulting point, and it then
> + * called _Jv_MipselThrowNPE(). Unwinding can then proceed
> + * "normally".
> + *
> + * Note that in prims.cc that the call to _Jv_ThrowSignal(nullp) is
> + * never reached.
> + */
> +
> +#define MAKE_THROW_FRAME(_exception) \
> +do \
> +{ \
> + sig_ucontext_t *_context = (sig_ucontext_t *) arg; \
> + (void)_dummy; \
> + (void)_info; \
> + void *reg_save_area = (void *)_context->uc_mcontext.sc_regs; \
> + char *xxx = (char *)(long)_context->uc_mcontext.sc_regs[29]; \
> + xxx -= 32; \
> + void **dummy_frame = (void **)xxx; \
> + dummy_frame[7] = (void *)(((long)_context->uc_mcontext.sc_pc) + 4); \
> + asm volatile ("lw\t$16,128(%1)\n\t" \
> + "lw\t$17,136(%1)\n\t" \
> + "lw\t$18,144(%1)\n\t" \
> + "lw\t$19,152(%1)\n\t" \
> + "lw\t$20,160(%1)\n\t" \
> + "lw\t$21,168(%1)\n\t" \
> + "lw\t$22,176(%1)\n\t" \
> + "lw\t$23,184(%1)\n\t" \
> + "lw\t$30,240(%1)\n\t" \
> + "lw\t$31,__sig2exdummy_fakeout_point\n\t" \
> + "la\t$25,_Jv_MipselThrowNPE\n\t" \
> + ".set\tnoreorder\n\t" \
> + ".set\tnomacro\n\t" \
> + "move\t$29,%0\n\t" \
> + "jr\t$25\n\t" \
> + "nop\n\t" \
> + ".set\tmacro\n\t" \
> + ".set\treorder" \
> + : : "r" (dummy_frame), "r" (reg_save_area)); \
> +} \
> +while (0)
> +
> +#define INIT_SEGV \
> +do \
> + { \
> + nullp = new java::lang::NullPointerException (); \
> + struct sigaction act; \
> + act.sa_sigaction = catch_segv; \
> + act.sa_flags = SA_SIGINFO | SA_NODEFER; \
> + sigemptyset (&act.sa_mask); \
> + sigaction (SIGSEGV, &act, 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 Fri Sep 5 15:37:07 2003
> @@ -0,0 +1,493 @@
> +/* 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;
> +
> +static void dump_maps(memory_map_block *f);
> +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;
> +}
> +
> +/*
> + * 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 */
> + 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;
> +
> + /*
> + * 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;
> +}
> +
> +
> +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;
> + }
> +}
> +
> +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 */
> +
> +#ifdef CUSTOM_BACKTRACE
> +int
> +CUSTOM_BACKTRACE (void **locations, int len)
> +{
> + return mips_backtracer_with_skip(locations, len, 1);
> +}
> +
> +
> +#endif
> 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)
> +
> 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-sighelper.S gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-sighelper.S
> --- gcc-3.3.1/libjava/sysdep/mips/mipsel-sighelper.S Wed Dec 31 16:00:00 1969
> +++ gcc-3.3.1.dave/libjava/sysdep/mips/mipsel-sighelper.S Fri Sep 5 15:37:07 2003
> @@ -0,0 +1,122 @@
> + # mipsel-sighelper.S - Help convert signals to java Exceptions
> + #
> + #
> + # 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>
> + #
> + # The following was generated by gcc-3.3 by compiling this code (ttx.c):
> + #
> + #typedef void (*vpf)();
> + #void __sig2exdummy()
> + #{
> + # vpf x = (vpf)0x40000;
> + # (*x)();
> + #}
> + #
> + # like this:
> + # mipsel-linux-gcc -S -O2 -fexceptions ttx.c
> + #
> + # We make gcc do the hard part of generating the eh_frame data.
> + #
> + # Then the $sig2exdummy_fakeout_point: label is added after the jal
> + # instruction and __sig2exdummy_fakeout_point: which contains the
> + # address of $sig2exdummy_fakeout_point:
> + #
> + # The code in mips-signal.h then builds a stack frame with the
> + # layout used by this function just above the frame of the faulting
> + # function. And then jumps to _Jv_MipselThrowNPE() simulating a
> + # jal from $sig2exdummy_fakeout_point:
> + #
> + # The result is that the signal handler's stack frame and trampoline code
> + # are obliterated and the stack is in a state that looks like __sig2exdummy
> + # was called from the faulting point, and it then called _Jv_MipselThrowNPE().
> + # Unwinding can then proceed "normally".
> + #
> +
> + .section .mdebug.abi32
> + .previous
> + .abicalls
> + .text
> + .align 2
> + .globl __sig2exdummy
> + .ent __sig2exdummy
> + .type __sig2exdummy, @function
> +__sig2exdummy:
> +$LFB3:
> + .frame $sp,32,$31 # vars= 0, regs= 2/0, args= 16, extra= 8
> + .mask 0x90000000,-4
> + .fmask 0x00000000,0
> + .set noreorder
> + .cpload $25
> + .set reorder
> + subu $sp,$sp,32
> + .cprestore 16
> +$LCFI0:
> + sw $31,28($sp)
> +$LCFI1:
> + sw $28,24($sp)
> +$LCFI2:
> + li $25,262144
> + jal $31,$25
> +$sig2exdummy_fakeout_point:
> + lw $31,28($sp)
> + #nop
> + .set noreorder
> + .set nomacro
> + j $31
> + addu $sp,$sp,32
> + .set macro
> + .set reorder
> +
> +$LFE3:
> + .end __sig2exdummy
> + .data
> + .globl __sig2exdummy_fakeout_point
> +__sig2exdummy_fakeout_point:
> + .word $sig2exdummy_fakeout_point
> + .section .eh_frame,"a",@progbits
> +$Lframe1:
> + .4byte $LECIE1-$LSCIE1
> +$LSCIE1:
> + .4byte 0x0
> + .byte 0x1
> + .ascii "zR\000"
> + .uleb128 0x1
> + .sleb128 4
> + .byte 0x40
> + .uleb128 0x1
> + .byte 0x1b
> + .byte 0xc
> + .uleb128 0x1d
> + .uleb128 0x0
> + .align 2
> +$LECIE1:
> +$LSFDE1:
> + .4byte $LEFDE1-$LASFDE1
> +$LASFDE1:
> + .4byte $LASFDE1-$Lframe1
> + .4byte $LFB3-.
> + .4byte $LFE3-$LFB3
> + .uleb128 0x0
> + .byte 0x4
> + .4byte $LCFI0-$LFB3
> + .byte 0xe
> + .uleb128 0x20
> + .byte 0x4
> + .4byte $LCFI2-$LCFI0
> + .byte 0x11
> + .uleb128 0x1c
> + .sleb128 -2
> + .byte 0x11
> + .uleb128 0x40
> + .sleb128 -1
> + .align 2
> +$LEFDE1:
> + .align 0
--
"Education is not filling a bucket but lighting a fire." -- WB Yeats