Commit 283a159f by Andrew Haley Committed by Andrew Haley

natThrowable.cc: New file.

2000-01-14  Andrew Haley  <aph@cygnus.com>

	* java/lang/natThrowable.cc: New file.

	* java/lang/Throwable.java (fillInStackTrace): Make native.
	(printStackTrace): Call native method to do this.
	(Throwable): Call fillInStackTrace.
	(stackTrace): New variable.

	* include/jvm.h: Add _Jv_ThisExecutable functions.

	* prims.cc: (_Jv_execName): New variable.
	(catch_segv): Call fillInStackTrace.
	(catch_fpe): Ditto.
	(_Jv_ThisExecutable): New functions.
	(JvRunMain): Set the name of this executable.

	* Makefile.am: Add java/lang/natThrowable.cc.
	Add name-finder.cc.
	* Makefile.in: Rebuilt.

	* acconfig.h: Add HAVE_PROC_SELF_EXE.

	* configure.in: Force link with __frame_state_for in
	FORCELIBGCCSPEC.  Add new checks for backtrace.
	* include/config.h.in: Rebuilt.

	* name-finder.cc: New file.
	* include/name-finder.h: New file.

From-SVN: r31460
parent 13536812
2000-01-14 Andrew Haley <aph@cygnus.com>
* java/lang/natThrowable.cc: New file.
* java/lang/Throwable.java (fillInStackTrace): Make native.
(printStackTrace): Call native method to do this.
(Throwable): Call fillInStackTrace.
(stackTrace): New variable.
* include/jvm.h: Add _Jv_ThisExecutable functions.
* prims.cc: (_Jv_execName): New variable.
(catch_segv): Call fillInStackTrace.
(catch_fpe): Ditto.
(_Jv_ThisExecutable): New functions.
(JvRunMain): Set the name of this executable.
* Makefile.am: Add java/lang/natThrowable.cc.
Add name-finder.cc.
* Makefile.in: Rebuilt.
* acconfig.h: Add HAVE_PROC_SELF_EXE.
* configure.in: Force link with __frame_state_for in
FORCELIBGCCSPEC. Add new checks for backtrace.
* include/config.h.in: Rebuilt.
* name-finder.cc: New file.
* include/name-finder.h: New file.
2000-01-16 Anthony Green <green@cygnus.com>
* java/lang/StringBuffer.java (StringBuffer): Don't special case
......
......@@ -112,7 +112,7 @@ javao_files = $(java_source_files:.java=.lo) \
libffi_files = `$(AR) t ../libffi/.libs/libffi.a 2>/dev/null | sed 's/\.o/\.lo/g' | sed 's/^/..\/libffi\//g'`
libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
resolve.cc defineclass.cc interpret.cc
resolve.cc defineclass.cc interpret.cc name-finder.cc
EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
$(c_source_files) $(java_source_files) $(built_java_source_files)
libgcj_la_DEPENDENCIES = libgcj.zip $(javao_files) $(nat_files) \
......@@ -804,6 +804,7 @@ java/lang/natRuntime.cc \
java/lang/natString.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natThrowable.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc \
......
......@@ -184,7 +184,7 @@ javao_files = $(java_source_files:.java=.lo) \
libffi_files = `$(AR) t ../libffi/.libs/libffi.a 2>/dev/null | sed 's/\.o/\.lo/g' | sed 's/^/..\/libffi\//g'`
libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
resolve.cc defineclass.cc interpret.cc
resolve.cc defineclass.cc interpret.cc name-finder.cc
EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
$(c_source_files) $(java_source_files) $(built_java_source_files)
......@@ -618,6 +618,7 @@ java/lang/natRuntime.cc \
java/lang/natString.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natThrowable.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc \
......@@ -699,7 +700,7 @@ libgcjdata_a_LIBADD =
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
libgcj_la_OBJECTS = prims.lo jni.lo exception.lo resolve.lo \
defineclass.lo interpret.lo
defineclass.lo interpret.lo name-finder.lo
@NATIVE_TRUE@bin_PROGRAMS = jv-convert$(EXEEXT) gij$(EXEEXT)
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS$(EXEEXT)
......@@ -923,8 +924,8 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/util/zip/ZipException.P .deps/java/util/zip/ZipFile.P \
.deps/java/util/zip/ZipInputStream.P \
.deps/java/util/zip/ZipOutputStream.P .deps/jni.P .deps/libgcjdata.P \
.deps/no-threads.P .deps/nogc.P .deps/posix-threads.P .deps/prims.P \
.deps/resolve.P
.deps/name-finder.P .deps/no-threads.P .deps/nogc.P \
.deps/posix-threads.P .deps/prims.P .deps/resolve.P
SOURCES = $(libgcjdata_a_SOURCES) $(libgcj_la_SOURCES) $(EXTRA_libgcj_la_SOURCES) $(jv_convert_SOURCES) $(EXTRA_jv_convert_SOURCES) $(gij_SOURCES) $(EXTRA_gij_SOURCES) $(gen_from_JIS_SOURCES) $(EXTRA_gen_from_JIS_SOURCES)
OBJECTS = $(libgcjdata_a_OBJECTS) $(libgcj_la_OBJECTS) $(jv_convert_OBJECTS) $(gij_OBJECTS) $(gen_from_JIS_OBJECTS)
......
......@@ -120,5 +120,8 @@
/* Define if using setjmp/longjmp exceptions. */
#undef SJLJ_EXCEPTIONS
/* Define if you have /proc/self/exe */
#undef HAVE_PROC_SELF_EXE
/* Define if getuid() and friends are missing. */
#undef NO_GETUID
......@@ -86,7 +86,7 @@ fi
FORCELIBGCCSPEC=
dnl Work around libgcc design flaw.
if test "$ac_cv_prog_gnu_ld" = yes; then
FORCELIBGCCSPEC="-u __rethrow -lgcc"
FORCELIBGCCSPEC="-u __rethrow -u __frame_state_for -lgcc"
fi
AC_MSG_CHECKING([for data_start])
......@@ -360,6 +360,10 @@ else
AC_CHECK_FUNCS(access stat mkdir rename rmdir unlink realpath)
AC_CHECK_FUNCS(inet_aton inet_addr, break)
AC_CHECK_FUNCS(inet_pton uname inet_ntoa)
AC_CHECK_FUNCS(backtrace fork execvp pipe)
AC_CHECK_HEADERS(execinfo.h unistd.h dlfcn.h)
AC_CHECK_FILES(/proc/self/exe, [
AC_DEFINE(HAVE_PROC_SELF_EXE)])
AC_CHECK_FUNCS(gethostbyname_r, [
AC_DEFINE(HAVE_GETHOSTBYNAME_R)
......
......@@ -135,12 +135,25 @@
/* Define if using setjmp/longjmp exceptions. */
#undef SJLJ_EXCEPTIONS
/* Define if you have /proc/self/exe */
#undef HAVE_PROC_SELF_EXE
/* Define if getuid() and friends are missing. */
#undef NO_GETUID
/* Define if you have the access function. */
#undef HAVE_ACCESS
/* Define if you have the backtrace function. */
#undef HAVE_BACKTRACE
/* Define if you have the execvp function. */
#undef HAVE_EXECVP
/* Define if you have the fork function. */
#undef HAVE_FORK
/* Define if you have the fstat function. */
#undef HAVE_FSTAT
......@@ -201,6 +214,9 @@
/* Define if you have the open function. */
#undef HAVE_OPEN
/* Define if you have the pipe function. */
#undef HAVE_PIPE
/* Define if you have the pthread_mutexattr_setkind_np function. */
#undef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
......@@ -252,6 +268,12 @@
/* Define if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
/* Define if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
......
......@@ -182,4 +182,8 @@ extern "C"
jlong _Jv_remJ (jlong, jlong);
}
/* get/set the name of the running executable. */
extern char *_Jv_ThisExecutable (void);
extern void _Jv_ThisExecutable (const char *);
#endif /* __JAVA_JVM_H__ */
// name-finder.h - Convert addresses to names
/* Copyright (C) 2000 Red Hat Inc
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. */
/**
* @author Andrew Haley <aph@cygnus.com>
* @date Jan 6 2000
*/
#include <gcj/cni.h>
#include <jvm.h>
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/* _Jv_name_finder is a class wrapper around a mechanism that can
convert addresses of methods to their names and the names of files
in which they appear. */
class _Jv_name_finder
{
public:
_Jv_name_finder (char *executable);
~_Jv_name_finder ()
{
#if defined (HAVE_PIPE) && defined (HAVE_FORK)
close (f_pipe[1]);
fclose (b_pipe_fd);
#endif
}
/* Given a pointer to a function or method, try to convert it into a
name and the appropriate line and source file. The caller passes
the code pointer in p.
Returns false if the lookup fails. Even if this happens, the field
hex will have been correctly filled in with the pointer.
The other fields are method_name and file_name, which lookup will
attempt to fill appropriately. If the lookup has failed, these
fields contain garbage.*/
bool lookup (void *p);
char method_name[1024];
char file_name[1024];
char hex[sizeof (void *) * 2 + 5];
private:
void toHex (void *p);
#if defined (HAVE_PIPE) && defined (HAVE_FORK)
int pid;
int f_pipe[2], b_pipe[2];
FILE *b_pipe_fd;
int error;
#endif
};
......@@ -12,6 +12,7 @@ package java.lang;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.OutputStreamWriter;
/**
* @author Tom Tromey <tromey@cygnus.com>
......@@ -26,55 +27,51 @@ import java.io.Serializable;
public class Throwable implements Serializable
{
public Throwable fillInStackTrace ()
{
return this;
}
public native Throwable fillInStackTrace ();
public String getLocalizedMessage ()
{
return getMessage ();
}
{
return getMessage ();
}
public String getMessage ()
{
return detailMessage;
}
{
return detailMessage;
}
public void printStackTrace ()
{
printStackTrace (System.err);
}
public void printStackTrace (PrintStream s)
{
// No stack trace, but we can still print this object.
s.println(toString ());
}
public void printStackTrace (PrintWriter wr)
{
// No stack trace, but we can still print this object.
wr.println(toString ());
}
{
printStackTrace (System.err);
}
public void printStackTrace (PrintStream ps)
{
printStackTrace (new PrintWriter(new OutputStreamWriter(ps)));
}
public native void printStackTrace (PrintWriter wr);
public Throwable ()
{
detailMessage = null;
}
{
detailMessage = null;
fillInStackTrace ();
}
public Throwable (String message)
{
detailMessage = message;
}
{
detailMessage = message;
fillInStackTrace ();
}
public String toString ()
{
return ((detailMessage == null)
? getClass().getName()
: getClass().getName() + ": " + getMessage ());
}
{
return ((detailMessage == null)
? getClass().getName()
: getClass().getName() + ": " + getMessage ());
}
// Name of this field comes from serialization spec.
private String detailMessage;
private byte stackTrace[];
}
// natThrowable.cc - Superclass for all exceptions.
/* Copyright (C) 2000 Red Hat Inc
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. */
/**
* @author Andrew Haley <aph@cygnus.com>
* @date Jan 6 2000
*/
#include <config.h>
#include <string.h>
#pragma implementation "Throwable.h"
#include <gcj/cni.h>
#include <jvm.h>
#include <java/lang/Object.h>
#include <java-threads.h>
#include <java/lang/Throwable.h>
#include <java/io/PrintStream.h>
#include <java/io/PrintWriter.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#include <name-finder.h>
/* FIXME: size of the stack trace is limited to 128 elements. It's
undoubtedly sensible to limit the stack trace, but 128 is rather
arbitrary. It may be better to configure this. */
java::lang::Throwable *
java::lang::Throwable::fillInStackTrace (void)
{
#ifdef HAVE_BACKTRACE
void *p[128];
// We subtract 1 from the number of elements because we don't want
// to include the call to fillInStackTrace in the trace.
int n = backtrace (p, 128) - 1;
// ??? Might this cause a problem if the byte array isn't aligned?
stackTrace = JvNewByteArray (n * sizeof p[0]);
memcpy (elements (stackTrace), p+1, (n * sizeof p[0]));
return this;
#endif
}
void
java::lang::Throwable::printStackTrace (java::io::PrintWriter *wr)
{
wr->println (toString ());
#ifdef HAVE_BACKTRACE
if (!stackTrace)
return;
void **p = (void **)elements (stackTrace);
int depth = stackTrace->length / sizeof p[0];
_Jv_name_finder finder (_Jv_ThisExecutable ());
for (int i = 0; i < depth; i++)
{
bool found = finder.lookup (p[i]);
wr->print (JvNewStringLatin1 (" at "));
wr->print (JvNewStringLatin1 (finder.hex));
if (found)
{
wr->print (JvNewStringLatin1 (": "));
wr->print (JvNewStringLatin1 (finder.method_name));
wr->print (JvNewStringLatin1 (" ("));
wr->print (JvNewStringLatin1 (finder.file_name));
wr->print (JvNewStringLatin1 (")"));
}
wr->println ();
}
#endif /* HAVE_BACKTRACE */
}
// name-finder.cc - Convert addresses to names
/* Copyright (C) 2000 Red Hat Inc
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. */
/**
* @author Andrew Haley <aph@cygnus.com>
* @date Jan 6 2000
*/
/* _Jv_name_finder is a class wrapper around a mechanism that can
convert address of methods to their names and the names of files in
which they appear.
Right now, the only implementation of this involves running a copy
of addr2line, but at some point it is worth building this
functionality into libgcj, if only for embedded systems. */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <config.h>
#include <string.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <java/lang/Object.h>
#include <java-threads.h>
#include <java/lang/Throwable.h>
#include <java/io/PrintStream.h>
#include <java/io/PrintWriter.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <name-finder.h>
/* Create a new name finder which will perform address lookups on an
executable. */
_Jv_name_finder::_Jv_name_finder (char *executable)
{
#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
error = 0;
char *argv[6];
{
int arg = 0;
argv[arg++] = "addr2line";
argv[arg++] = "-C";
argv[arg++] = "-f";
argv[arg++] = "-e";
argv[arg++] = executable;
argv[arg] = NULL;
}
error |= pipe (f_pipe) < 0;
error |= pipe (b_pipe) < 0;
if (error)
return;
pid = fork ();
if (pid == 0)
{
close (f_pipe[1]);
close (b_pipe[0]);
dup2 (f_pipe[0], fileno (stdin));
dup2 (b_pipe[1], fileno (stdout));
execvp (argv[0], argv);
_exit (127);
}
close (f_pipe [0]);
close (b_pipe [1]);
if (pid < 0)
{
error |= 1;
return;
}
b_pipe_fd = fdopen (b_pipe[0], "r");
error |= !b_pipe_fd;
#endif
}
/* Convert a pointer to hex. */
void
_Jv_name_finder::toHex (void *p)
{
unsigned long long n = (unsigned long long)p;
int digits = sizeof (void *) * 2;
strcpy (hex, "0x");
for (int i = digits - 1; i >= 0; i--)
{
int digit = n % 16;
n /= 16;
hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit;
}
hex [digits+2] = 0;
}
/* Given a pointer to a function or method, try to convert it into a
name and the appropriate line and source file. The caller passes
the code pointer in p.
Returns false if the lookup fails. Even if this happens, the field
he will have been correctly filled in with the pointer. */
bool
_Jv_name_finder::lookup (void *p)
{
toHex (p);
#ifdef HAVE_DLFCN_H
{
Dl_info dl_info;
if (dladdr (p, &dl_info))
{
strncpy (file_name, dl_info.dli_fname, sizeof file_name);
strncpy (method_name, dl_info.dli_sname, sizeof method_name);
return true;
}
}
#endif
#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
if (error)
return false;
error |= write (f_pipe[1], hex, strlen (hex)) < 0;
if (error)
return false;
error |= write (f_pipe[1], "\n", 1) < 0;
if (error)
return false;
error |= (fgets (method_name, sizeof method_name, b_pipe_fd) == NULL);
if (error)
return false;
error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
if (error)
return false;
char *newline = strchr (method_name, '\n');
if (newline)
*newline = 0;
newline = strchr (file_name, '\n');
if (newline)
*newline = 0;
return true;
#else
return false;
#endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
}
......@@ -16,6 +16,10 @@ details. */
#include <string.h>
#include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <gcj/cni.h>
#include <jvm.h>
#include <java-signal.h>
......@@ -68,6 +72,10 @@ const char **_Jv_Compiler_Properties;
// Property key/value pairs.
property_pair *_Jv_Environment_Properties;
#endif
// The name of this executable.
static char * _Jv_execName;
#ifdef HANDLE_SEGV
......@@ -75,6 +83,7 @@ static java::lang::NullPointerException *nullp;
SIGNAL_HANDLER (catch_segv)
{
MAKE_THROW_FRAME;
nullp->fillInStackTrace ();
_Jv_Throw (nullp);
}
#endif
......@@ -89,6 +98,7 @@ SIGNAL_HANDLER (catch_fpe)
#else
MAKE_THROW_FRAME;
#endif
arithexception->fillInStackTrace ();
_Jv_Throw (arithexception);
}
#endif
......@@ -638,8 +648,24 @@ static java::lang::ThreadGroup *main_group;
// The primary thread.
static java::lang::Thread *main_thread;
char *
_Jv_ThisExecutable (void)
{
return _Jv_execName;
}
void
_Jv_ThisExecutable (const char *name)
{
if (name)
{
_Jv_execName = new char[strlen (name) + 1];
strcpy (_Jv_execName, name);
}
}
static void
main_init (void)
main_init ()
{
INIT_SEGV;
#ifdef HANDLE_FPE
......@@ -812,6 +838,13 @@ JvRunMain (jclass klass, int argc, const char **argv)
PROCESS_GCJ_PROPERTIES;
main_init ();
#ifdef HAVE_PROC_SELF_EXE
char exec_name[20];
sprintf (exec_name, "/proc/%d/exe", getpid ());
_Jv_ThisExecutable (exec_name);
#else
_Jv_ThisExecutable (argv[0]);
#endif
arg_vec = JvConvertArgv (argc - 1, argv + 1);
main_group = new java::lang::ThreadGroup (23);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment