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]

warning: reality as about to implode (was: MIPS support for libjava)


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


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