aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2002-08-24 22:46:19 +0000
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2002-08-24 22:46:19 +0000
commit22bd464fb14254908fedcdc08a0a8a3068c62098 (patch)
tree2194f5746d8d192d6202800f3df90a8ccb1675e0 /libjava
parentbf81fbc51e651ae09cf076d677f052f460aca5fd (diff)
* Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.
(core_java_source_files): Add VMThrowable.java and NameFinder.java (nat_source_files): Remove natThrowable.cc, add natVMThrowable.cc and natNameFinder.cc. * Makefile.in: Regenerate. * prims.cc: Use trace_enabled from VMThrowable. * name-finder.cc: Removed. * gcj/javaprims.h: Add class VMThrowable. * gnu/gcj/runtime/NameFinder.java: New file. * gnu/gcj/runtime/natNameFinder.cc: Likewise. * include/name-finder.h: Removed. * java/lang/Throwable.java (printStackTrace (PrintStream)): Use new method stackTraceString(). (printStackTrace (PrintWriter)): Likewise. (stackTraceString): Complete rewrite of old printStackTrace using StringBuffer. (stackTraceStringBuffer): New helper method for stackTraceString(). (fillInStackTrace): Delegate to VMTrowable. (getStackTrace): Likewise. (getStackTrace0): Removed. (trace_enabled, stackTraceBytes): Moved to new VMThrowable.java. (setStackTrace): Copy given array. * java/lang/natThrowable.cc: Removed (replaced by natVMThrowable). * java/lang/VMThrowable.java: New class. * java/lang/natVMThrowable.cc: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@56556 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog28
-rw-r--r--libjava/Makefile.am7
-rw-r--r--libjava/Makefile.in44
-rw-r--r--libjava/gcj/javaprims.h1
-rw-r--r--libjava/gnu/gcj/runtime/NameFinder.java407
-rw-r--r--libjava/gnu/gcj/runtime/natNameFinder.cc84
-rw-r--r--libjava/include/name-finder.h103
-rw-r--r--libjava/java/lang/Throwable.java160
-rw-r--r--libjava/java/lang/VMThrowable.java97
-rw-r--r--libjava/java/lang/natThrowable.cc99
-rw-r--r--libjava/java/lang/natVMThrowable.cc73
-rw-r--r--libjava/name-finder.cc356
-rw-r--r--libjava/prims.cc7
13 files changed, 821 insertions, 645 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index b4f319f5315..71b789ff50d 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,31 @@
+2002-08-24 Mark Wielaard <mark@klomp.org>
+
+ * Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.
+ (core_java_source_files): Add VMThrowable.java and NameFinder.java
+ (nat_source_files): Remove natThrowable.cc, add natVMThrowable.cc
+ and natNameFinder.cc.
+ * Makefile.in: Regenerate.
+ * prims.cc: Use trace_enabled from VMThrowable.
+ * name-finder.cc: Removed.
+ * gcj/javaprims.h: Add class VMThrowable.
+ * gnu/gcj/runtime/NameFinder.java: New file.
+ * gnu/gcj/runtime/natNameFinder.cc: Likewise.
+ * include/name-finder.h: Removed.
+ * java/lang/Throwable.java (printStackTrace (PrintStream)): Use new
+ method stackTraceString().
+ (printStackTrace (PrintWriter)): Likewise.
+ (stackTraceString): Complete rewrite of old printStackTrace using
+ StringBuffer.
+ (stackTraceStringBuffer): New helper method for stackTraceString().
+ (fillInStackTrace): Delegate to VMTrowable.
+ (getStackTrace): Likewise.
+ (getStackTrace0): Removed.
+ (trace_enabled, stackTraceBytes): Moved to new VMThrowable.java.
+ (setStackTrace): Copy given array.
+ * java/lang/natThrowable.cc: Removed (replaced by natVMThrowable).
+ * java/lang/VMThrowable.java: New class.
+ * java/lang/natVMThrowable.cc: New file.
+
2003-08-23 Michael Koch <konqueror@gmx.de>
* java/net/URLConnection.java,
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index 89fff76cbfb..ef10fe91c0d 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -128,7 +128,7 @@ javao_files = $(java_source_files:.java=.lo) \
x_javao_files = $(x_java_source_files:.java=.lo)
libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
- resolve.cc defineclass.cc interpret.cc name-finder.cc verify.cc \
+ resolve.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files)
EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
win32-threads.cc posix.cc win32.cc \
@@ -1527,6 +1527,7 @@ java/lang/VerifyError.java \
java/lang/VirtualMachineError.java \
java/lang/VMClassLoader.java \
java/lang/VMSecurityManager.java \
+java/lang/VMThrowable.java \
java/lang/Void.java \
java/io/BufferedInputStream.java \
java/io/BufferedOutputStream.java \
@@ -1687,6 +1688,7 @@ gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/FirstThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
+gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/VMClassLoader.java \
@@ -2204,6 +2206,7 @@ gnu/gcj/io/shs.cc \
gnu/gcj/protocol/core/natCoreInputStream.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natFirstThread.cc \
+gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
gnu/gcj/runtime/natStringBuffer.cc \
java/io/natFile.cc \
@@ -2223,7 +2226,7 @@ java/lang/natString.cc \
java/lang/natStringBuffer.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
-java/lang/natThrowable.cc \
+java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index d165075518e..2de61223dc6 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -195,7 +195,7 @@ javao_files = $(java_source_files:.java=.lo) \
x_javao_files = $(x_java_source_files:.java=.lo)
libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
- resolve.cc defineclass.cc interpret.cc name-finder.cc verify.cc \
+ resolve.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files)
EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
@@ -1294,6 +1294,7 @@ java/lang/VerifyError.java \
java/lang/VirtualMachineError.java \
java/lang/VMClassLoader.java \
java/lang/VMSecurityManager.java \
+java/lang/VMThrowable.java \
java/lang/Void.java \
java/io/BufferedInputStream.java \
java/io/BufferedOutputStream.java \
@@ -1449,6 +1450,7 @@ gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/FirstThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
+gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/VMClassLoader.java \
@@ -1965,6 +1967,7 @@ gnu/gcj/io/shs.cc \
gnu/gcj/protocol/core/natCoreInputStream.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natFirstThread.cc \
+gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
gnu/gcj/runtime/natStringBuffer.cc \
java/io/natFile.cc \
@@ -1984,7 +1987,7 @@ java/lang/natString.cc \
java/lang/natStringBuffer.cc \
java/lang/natSystem.cc \
java/lang/natThread.cc \
-java/lang/natThrowable.cc \
+java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
@@ -2123,7 +2126,7 @@ X_LIBS = @X_LIBS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
libgcj_la_OBJECTS = prims.lo jni.lo exception.lo resolve.lo \
-defineclass.lo interpret.lo name-finder.lo verify.lo gnu/gcj/natCore.lo \
+defineclass.lo interpret.lo verify.lo gnu/gcj/natCore.lo \
gnu/gcj/convert/JIS0208_to_Unicode.lo \
gnu/gcj/convert/JIS0212_to_Unicode.lo gnu/gcj/convert/Unicode_to_JIS.lo \
gnu/gcj/convert/natIconv.lo gnu/gcj/convert/natInput_EUCJIS.lo \
@@ -2131,7 +2134,7 @@ gnu/gcj/convert/natInput_SJIS.lo gnu/gcj/convert/natOutput_EUCJIS.lo \
gnu/gcj/convert/natOutput_SJIS.lo gnu/gcj/io/natSimpleSHSStream.lo \
gnu/gcj/io/shs.lo gnu/gcj/protocol/core/natCoreInputStream.lo \
gnu/gcj/runtime/natFinalizerThread.lo gnu/gcj/runtime/natFirstThread.lo \
-gnu/gcj/runtime/natSharedLibLoader.lo \
+gnu/gcj/runtime/natNameFinder.lo gnu/gcj/runtime/natSharedLibLoader.lo \
gnu/gcj/runtime/natStringBuffer.lo java/io/natFile.lo \
java/io/natFileDescriptor.lo java/io/natObjectInputStream.lo \
java/io/natObjectOutputStream.lo java/lang/natCharacter.lo \
@@ -2140,7 +2143,7 @@ java/lang/natConcreteProcess.lo java/lang/natDouble.lo \
java/lang/natFloat.lo java/lang/natMath.lo java/lang/natObject.lo \
java/lang/natRuntime.lo java/lang/natString.lo \
java/lang/natStringBuffer.lo java/lang/natSystem.lo \
-java/lang/natThread.lo java/lang/natThrowable.lo \
+java/lang/natThread.lo java/lang/natVMThrowable.lo \
java/lang/ref/natReference.lo java/lang/reflect/natArray.lo \
java/lang/reflect/natConstructor.lo java/lang/reflect/natField.lo \
java/lang/reflect/natMethod.lo java/net/natInetAddress.lo \
@@ -2246,11 +2249,13 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/gnu/gcj/runtime/FileDeleter.P \
.deps/gnu/gcj/runtime/FinalizerThread.P \
.deps/gnu/gcj/runtime/FirstThread.P .deps/gnu/gcj/runtime/JNIWeakRef.P \
+.deps/gnu/gcj/runtime/NameFinder.P \
.deps/gnu/gcj/runtime/SharedLibLoader.P \
.deps/gnu/gcj/runtime/StringBuffer.P \
.deps/gnu/gcj/runtime/VMClassLoader.P \
.deps/gnu/gcj/runtime/natFinalizerThread.P \
.deps/gnu/gcj/runtime/natFirstThread.P \
+.deps/gnu/gcj/runtime/natNameFinder.P \
.deps/gnu/gcj/runtime/natSharedLibLoader.P \
.deps/gnu/gcj/runtime/natStringBuffer.P .deps/gnu/gcj/xlib/Clip.P \
.deps/gnu/gcj/xlib/Colormap.P .deps/gnu/gcj/xlib/Display.P \
@@ -2813,8 +2818,9 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/lang/UnsupportedClassVersionError.P \
.deps/java/lang/UnsupportedOperationException.P \
.deps/java/lang/VMClassLoader.P .deps/java/lang/VMSecurityManager.P \
-.deps/java/lang/VerifyError.P .deps/java/lang/VirtualMachineError.P \
-.deps/java/lang/Void.P .deps/java/lang/dtoa.P .deps/java/lang/e_acos.P \
+.deps/java/lang/VMThrowable.P .deps/java/lang/VerifyError.P \
+.deps/java/lang/VirtualMachineError.P .deps/java/lang/Void.P \
+.deps/java/lang/dtoa.P .deps/java/lang/e_acos.P \
.deps/java/lang/e_asin.P .deps/java/lang/e_atan2.P \
.deps/java/lang/e_exp.P .deps/java/lang/e_fmod.P \
.deps/java/lang/e_log.P .deps/java/lang/e_pow.P \
@@ -2828,7 +2834,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/java/lang/natMath.P .deps/java/lang/natObject.P \
.deps/java/lang/natRuntime.P .deps/java/lang/natString.P \
.deps/java/lang/natStringBuffer.P .deps/java/lang/natSystem.P \
-.deps/java/lang/natThread.P .deps/java/lang/natThrowable.P \
+.deps/java/lang/natThread.P .deps/java/lang/natVMThrowable.P \
.deps/java/lang/ref/PhantomReference.P .deps/java/lang/ref/Reference.P \
.deps/java/lang/ref/ReferenceQueue.P \
.deps/java/lang/ref/SoftReference.P .deps/java/lang/ref/WeakReference.P \
@@ -3468,17 +3474,17 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
.deps/javax/transaction/UserTransaction.P \
.deps/javax/transaction/xa/XAException.P \
.deps/javax/transaction/xa/XAResource.P \
-.deps/javax/transaction/xa/Xid.P .deps/jni.P .deps/name-finder.P \
-.deps/no-threads.P .deps/nogc.P .deps/org/w3c/dom/Attr.P \
-.deps/org/w3c/dom/CDATASection.P .deps/org/w3c/dom/CharacterData.P \
-.deps/org/w3c/dom/Comment.P .deps/org/w3c/dom/DOMException.P \
-.deps/org/w3c/dom/DOMImplementation.P .deps/org/w3c/dom/Document.P \
-.deps/org/w3c/dom/DocumentFragment.P .deps/org/w3c/dom/DocumentType.P \
-.deps/org/w3c/dom/Element.P .deps/org/w3c/dom/Entity.P \
-.deps/org/w3c/dom/EntityReference.P .deps/org/w3c/dom/NamedNodeMap.P \
-.deps/org/w3c/dom/Node.P .deps/org/w3c/dom/NodeList.P \
-.deps/org/w3c/dom/Notation.P .deps/org/w3c/dom/ProcessingInstruction.P \
-.deps/org/w3c/dom/Text.P .deps/org/w3c/dom/ranges/DocumentRange.P \
+.deps/javax/transaction/xa/Xid.P .deps/jni.P .deps/no-threads.P \
+.deps/nogc.P .deps/org/w3c/dom/Attr.P .deps/org/w3c/dom/CDATASection.P \
+.deps/org/w3c/dom/CharacterData.P .deps/org/w3c/dom/Comment.P \
+.deps/org/w3c/dom/DOMException.P .deps/org/w3c/dom/DOMImplementation.P \
+.deps/org/w3c/dom/Document.P .deps/org/w3c/dom/DocumentFragment.P \
+.deps/org/w3c/dom/DocumentType.P .deps/org/w3c/dom/Element.P \
+.deps/org/w3c/dom/Entity.P .deps/org/w3c/dom/EntityReference.P \
+.deps/org/w3c/dom/NamedNodeMap.P .deps/org/w3c/dom/Node.P \
+.deps/org/w3c/dom/NodeList.P .deps/org/w3c/dom/Notation.P \
+.deps/org/w3c/dom/ProcessingInstruction.P .deps/org/w3c/dom/Text.P \
+.deps/org/w3c/dom/ranges/DocumentRange.P \
.deps/org/w3c/dom/ranges/Range.P \
.deps/org/w3c/dom/ranges/RangeException.P \
.deps/org/w3c/dom/traversal/DocumentTraversal.P \
diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h
index 99442c5ca2a..3378a9faf66 100644
--- a/libjava/gcj/javaprims.h
+++ b/libjava/gcj/javaprims.h
@@ -211,6 +211,7 @@ extern "Java"
class UnsupportedOperationException;
class VMClassLoader;
class VMSecurityManager;
+ class VMThrowable;
class VerifyError;
class VirtualMachineError;
class Void;
diff --git a/libjava/gnu/gcj/runtime/NameFinder.java b/libjava/gnu/gcj/runtime/NameFinder.java
new file mode 100644
index 00000000000..60f47ac64fe
--- /dev/null
+++ b/libjava/gnu/gcj/runtime/NameFinder.java
@@ -0,0 +1,407 @@
+/* NameFinder.java -- Translates addresses to StackTraceElements.
+ Copyright (C) 2002 Free Software Foundation, 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. */
+
+package gnu.gcj.runtime;
+
+import gnu.gcj.RawData;
+
+import java.lang.StringBuffer;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Helper class that translates addresses (represented as longs) to a
+ * StackTraceElement array.
+ *
+ * There are a couple of system properties that can be set to manipulate the
+ * result (all default to true):
+ * <li>
+ * <ul><code>gnu.gcj.runtime.NameFinder.demangle</code>
+ * Whether names should be demangled.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.sanitize</code></ul>
+ * Whether calls to initialize exceptions and starting the runtime system
+ * should be removed from the stack trace. Only done when names are
+ * demangled.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.remove_unknown</code>
+ * Wheter calls to unknown functions (class and method names are unknown)
+ * should be removed from the stack trace. Only done when the stack is
+ * sanitized.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
+ * Wheter an external process (addr2line or addr2name.awk) should be used
+ * as fallback to convert the addresses to function names when the runtime
+ * is unable to do it through <code>dladdr</code>.</ul>
+ * </li>
+ *
+ * <code>close()</code> should be called to get rid of all resources.
+ *
+ * This class is used from <code>java.lang.VMThrowable</code>.
+ *
+ * Currently the <code>lookup(long[])</code> method is not thread safe.
+ * It can easily be made thread safe by synchronizing access to all external
+ * processes when used.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NameFinder
+{
+ // Set these to false when not needed.
+ private static final boolean demangle
+ = Boolean.valueOf(System.getProperty
+ ("gnu.gcj.runtime.NameFinder.demangle", "true")
+ ).booleanValue();
+ private static final boolean sanitize
+ = Boolean.valueOf(System.getProperty
+ ("gnu.gcj.runtime.NameFinder.sanitize", "true")
+ ).booleanValue();
+ private static final boolean remove_unknown
+ = Boolean.valueOf(System.getProperty
+ ("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
+ ).booleanValue();
+ private static final boolean use_addr2line
+ = Boolean.valueOf(System.getProperty
+ ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
+ ).booleanValue();
+
+ /**
+ * The name of the currently running executable.
+ */
+ private final String executable;
+
+ /**
+ * Process used for demangling names.
+ */
+ private Process cppfilt;
+
+ private BufferedWriter cppfiltOut;
+ private BufferedReader cppfiltIn;
+
+ /**
+ * Process used for translating addresses to function/file names.
+ */
+ private Process addr2line;
+
+ private BufferedWriter addr2lineOut;
+ private BufferedReader addr2lineIn;
+
+ /**
+ * Creates a new NameFinder. Call close to get rid of any resources
+ * created while using the <code>lookup</code> methods.
+ */
+ public NameFinder()
+ {
+ executable = getExecutable();
+ Runtime runtime = Runtime.getRuntime();
+ if (demangle)
+ {
+ try
+ {
+ String[] exec = new String[] {"c++filt", "-s", "java"};
+ cppfilt = runtime.exec(exec);
+ cppfiltIn = new BufferedReader
+ (new InputStreamReader(cppfilt.getInputStream()));
+ cppfiltOut = new BufferedWriter
+ (new OutputStreamWriter(cppfilt.getOutputStream()));
+ }
+ catch (IOException ioe)
+ {
+ if (cppfilt != null)
+ cppfilt.destroy();
+ cppfilt = null;
+ }
+ }
+
+ if (use_addr2line)
+ {
+ try
+ {
+ String[] exec = new String[] {"addr2line", "-f", "-e", executable};
+ addr2line = runtime.exec(exec);
+ }
+ catch (IOException ioe)
+ {
+ try
+ {
+ String[] exec = new String[] {"addr2name.awk", executable};
+ addr2line = runtime.exec(exec);
+ }
+ catch (IOException ioe2) { addr2line = null; }
+ }
+
+ if (addr2line != null)
+ {
+ try
+ {
+ addr2lineIn = new BufferedReader
+ (new InputStreamReader(addr2line.getInputStream()));
+ addr2lineOut = new BufferedWriter
+ (new OutputStreamWriter(addr2line.getOutputStream()));
+ }
+ catch (IOException ioe)
+ {
+ addr2line.destroy();
+ addr2line = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the name of the currently running process.
+ */
+ native private static String getExecutable();
+
+ /**
+ * Tries to use dladdr to create the nth StackTraceElement from the given
+ * addresses. Returns null on failure.
+ */
+ native private StackTraceElement dladdrLookup(RawData addrs, int n);
+
+ /**
+ * Returns the nth element from the stack as a hex encoded String.
+ */
+ native private String getAddrAsString(RawData addrs, int n);
+
+ /**
+ * Creates the nth StackTraceElement from the given native stacktrace.
+ */
+ private StackTraceElement lookup(RawData addrs, int n)
+ {
+ StackTraceElement result;
+
+ result = dladdrLookup(addrs, n);
+ if (result == null)
+ {
+ String name = null;
+ String file = null;
+ String hex = getAddrAsString(addrs, n);
+
+ if (addr2line != null)
+ {
+ try
+ {
+ addr2lineOut.write(hex);
+ addr2lineOut.newLine();
+ addr2lineOut.flush();
+ name = addr2lineIn.readLine();
+ file = addr2lineIn.readLine();
+ }
+ catch (IOException ioe) { addr2line = null; }
+ }
+
+ if (name == null || "??".equals(name))
+ name = hex;
+
+ result = createStackTraceElement(name, file);
+ }
+
+ return result;
+ }
+
+ /**
+ * Given an Throwable and a native stacktrace returns an array of
+ * StackTraceElement containing class, method, file and linenumbers.
+ */
+ public StackTraceElement[] lookup(Throwable t, RawData addrs, int length)
+ {
+ StackTraceElement[] elements = new StackTraceElement[length];
+ for (int i=0; i < length; i++)
+ elements[i] = lookup(addrs, i);
+
+ if (demangle && sanitize)
+ return sanitizeStack(elements, t);
+ else
+ return elements;
+ }
+
+
+ /**
+ * Removes calls to initialize exceptions and the runtime system from
+ * the stack trace including stack frames of which nothing usefull is known.
+ * Throw away the top of the stack till we find the constructor(s)
+ * of this Throwable or at least the contructors of java.lang.Throwable
+ * or the actual fillInStackTrace call.
+ * Also throw away from the top everything before and including a runtime
+ * _Jv_Throw call.
+ */
+ private static StackTraceElement[] sanitizeStack(StackTraceElement[] elements,
+ Throwable t)
+ {
+ StackTraceElement[] stack;
+
+ String className = t.getClass().getName();
+ String consName;
+ int lastDot = className.lastIndexOf('.');
+ if (lastDot == -1)
+ consName = className + '(';
+ else
+ consName = className.substring(lastDot + 1) + '(';
+
+ int unknown = 0;
+ int last_throw = -1;
+ int length = elements.length;
+ int end = length-1;
+ for (int i = 0; i < length; i++)
+ {
+ String CName = elements[i].getClassName();
+ String MName = elements[i].getMethodName();
+ if ((CName == null && MName != null && MName.startsWith("_Jv_Throw"))
+ ||
+ (CName != null
+ && (CName.equals(className)
+ || CName.equals("java.lang.Throwable")
+ || CName.equals("java.lang.VMThrowable"))
+ && MName != null
+ && (MName.startsWith(consName)
+ || MName.startsWith("Throwable(")
+ || MName.startsWith("fillInStackTrace("))))
+ last_throw = i;
+ else if (remove_unknown && CName == null
+ && (MName == null || MName.startsWith("0x")))
+ unknown++;
+ else if ("main(java.lang.String[])".equals(MName))
+ {
+ end = i;
+ break;
+ }
+ }
+ int begin = last_throw+1;
+
+ // Now filter out everything at the start and the end that is not part
+ // of the "normal" user program including any elements that have no
+ // usefull information whatsoever unless that means we filter out all info.
+ int nr_elements = end-begin-unknown+1;
+ if ((begin > 0 || end < length-1 || unknown > 0) && nr_elements > 0)
+ {
+ stack = new StackTraceElement[nr_elements];
+ int pos =0;
+ for (int i=begin; i<=end; i++)
+ {
+ String MName;
+ if (unknown == 0
+ || !(elements[i].getClassName() == null
+ && ((MName = elements[i].getMethodName()) == null
+ || MName.startsWith("0x"))))
+ {
+ stack[pos] = elements[i];
+ pos++;
+ }
+ }
+ }
+ else
+ stack = elements;
+
+ return stack;
+ }
+
+ /**
+ * Creates a StackTraceElement given a string and a filename.
+ * Splits the given string into the class and method part.
+ * The string name will be a demangled to a fully qualified java method
+ * string. The string file will be decomposed into a file name and possibly
+ * a line number. The name should never be null, but the file may be if it
+ * is unknown.
+ */
+ private StackTraceElement createStackTraceElement(String name, String file)
+ {
+ if (!demangle)
+ return new StackTraceElement(file, -1, null, name, false);
+
+ String s = demangleName(name);
+ String methodName = s;
+ String className = null;
+ int bracket = s.indexOf('(');
+ if (bracket > 0)
+ {
+ int dot = s.lastIndexOf('.', bracket);
+ if (dot > 0)
+ {
+ className = s.substring(0, dot);
+ methodName = s.substring(dot+1, s.length());
+ }
+ }
+
+ String fileName = file;
+ int line = -1;
+ if (fileName != null)
+ {
+ int colon = file.indexOf(':');
+ if (colon > 0)
+ {
+ fileName = file.substring(0, colon);
+ try
+ {
+ line = Integer.parseInt(file.substring(colon+1, file.length()));
+ }
+ catch (NumberFormatException nfe) { /* ignore */ }
+ }
+
+ if (line == 0)
+ line =-1;
+
+ if ("".equals(fileName) || "??".equals(fileName))
+ fileName = null;
+ else if (fileName != null)
+ {
+ try
+ {
+ fileName = new File(fileName).getCanonicalPath();
+ }
+ catch (IOException ioe) { /* ignore */ }
+ }
+ }
+
+ return new StackTraceElement(fileName, line, className, methodName, false);
+ }
+
+ /**
+ * Demangles the given String if possible. Returns the demangled String or
+ * the original string if demangling is impossible.
+ */
+ private String demangleName(String s)
+ {
+ if (cppfilt != null)
+ {
+ try
+ {
+ cppfiltOut.write(s);
+ cppfiltOut.newLine();
+ cppfiltOut.flush();
+ return cppfiltIn.readLine();
+ }
+ catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
+ }
+
+ return s;
+ }
+
+ /**
+ * Releases all resources used by this NameFinder.
+ */
+ public void close()
+ {
+ if (cppfilt != null)
+ cppfilt.destroy();
+
+ if (addr2line != null)
+ addr2line.destroy();
+ }
+
+ /**
+ * Calls close to get rid of all resources.
+ */
+ protected void finalize()
+ {
+ close();
+ }
+}
diff --git a/libjava/gnu/gcj/runtime/natNameFinder.cc b/libjava/gnu/gcj/runtime/natNameFinder.cc
new file mode 100644
index 00000000000..42cc164c324
--- /dev/null
+++ b/libjava/gnu/gcj/runtime/natNameFinder.cc
@@ -0,0 +1,84 @@
+// natNameFinder.cc - native helper methods for NameFiner.java
+
+/* Copyright (C) 2002 Free Software Foundation, 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 Mark Wielaard (mark@klomp.org)
+ * Based on the old name-finder.cc by Andrew Haley <aph@cygnus.com>.
+ */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java/lang/String.h>
+#include <java/lang/StackTraceElement.h>
+
+#include <gnu/gcj/runtime/NameFinder.h>
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+java::lang::String*
+gnu::gcj::runtime::NameFinder::getExecutable (void)
+{
+ return JvNewStringLatin1 (_Jv_ThisExecutable ());
+}
+
+java::lang::String*
+gnu::gcj::runtime::NameFinder::getAddrAsString(RawData* addrs, jint n)
+{
+ void **p = (void **) addrs;
+ typedef unsigned word_t __attribute ((mode (word)));
+ word_t w = (word_t) p[n];
+ int digits = sizeof (void *) * 2;
+ char hex[digits+5];
+
+ strcpy (hex, "0x");
+ for (int i = digits - 1; i >= 0; i--)
+ {
+ int digit = w % 16;
+
+ w /= 16;
+ hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit;
+ }
+ hex [digits+2] = 0;
+
+ return JvNewStringLatin1(hex);
+}
+
+java::lang::StackTraceElement*
+gnu::gcj::runtime::NameFinder::dladdrLookup(RawData* addrs, jint n)
+{
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+ extern char **_Jv_argv;
+ char name[1024];
+ char file_name[1024];
+ void **stack = (void **) addrs;
+ void* p = stack[n];
+ Dl_info dl_info;
+
+ if (dladdr (p, &dl_info))
+ {
+ if (dl_info.dli_fname)
+ strncpy (file_name, dl_info.dli_fname, sizeof file_name);
+ if (dl_info.dli_sname)
+ strncpy (name, dl_info.dli_sname, sizeof name);
+
+ /* Don't trust dladdr() if the address is from the main program. */
+ if (dl_info.dli_fname != NULL
+ && dl_info.dli_sname != NULL
+ && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
+ return createStackTraceElement (JvNewStringLatin1 (name),
+ JvNewStringLatin1 (file_name));
+ }
+#endif
+ return NULL;
+}
diff --git a/libjava/include/name-finder.h b/libjava/include/name-finder.h
deleted file mode 100644
index 67ae0587fb0..00000000000
--- a/libjava/include/name-finder.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// name-finder.h - Convert addresses to names
-
-/* Copyright (C) 2000, 2002 Free Software Foundation, 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>
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#include <string.h>
-#include <stdio.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <java/lang/StackTraceElement.h>
-
-/* _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)
- myclose (f_pipe[0]);
- myclose (f_pipe[1]);
- myclose (b_pipe[0]);
- myclose (b_pipe[1]);
- if (b_pipe_fd != NULL)
- fclose (b_pipe_fd);
-
- myclose (f2_pipe[0]);
- myclose (f2_pipe[1]);
- myclose (b2_pipe[0]);
- myclose (b2_pipe[1]);
- if (b2_pipe_fd != NULL)
- fclose (b2_pipe_fd);
-
- if (pid >= 0)
- {
- int wstat;
- // We don't care about errors here.
- waitpid (pid, &wstat, 0);
- }
-
- if (pid2 >= 0)
- {
- int wstat;
- // We don't care about errors here.
- waitpid (pid2, &wstat, 0);
- }
-#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 NULL if the lookup fails. Even if this happens, the field
- hex will have been correctly filled in with the pointer. */
-
- java::lang::StackTraceElement* lookup (void *p);
-
- char hex[sizeof (void *) * 2 + 5];
-
-private:
- void toHex (void *p);
- java::lang::StackTraceElement* createStackTraceElement(char *s, char *f);
-#if defined (HAVE_PIPE) && defined (HAVE_FORK)
- pid_t pid, pid2;
- int f_pipe[2], b_pipe[2], f2_pipe[2], b2_pipe[2];
- FILE *b_pipe_fd, *b2_pipe_fd;
- int demangling_error, lookup_error;
-
- // Close a descriptor only if it has not been closed.
- void myclose (int fd)
- {
- if (fd != -1)
- close (fd);
- }
-
-#endif
-};
diff --git a/libjava/java/lang/Throwable.java b/libjava/java/lang/Throwable.java
index 56c9d542a50..613f43ffe9b 100644
--- a/libjava/java/lang/Throwable.java
+++ b/libjava/java/lang/Throwable.java
@@ -46,11 +46,6 @@ import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.OutputStream;
-/**
- * @author Tom Tromey <tromey@cygnus.com>
- * @date October 30, 1998
- */
-
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* "The Java Language Specification", ISBN 0-201-63451-1
* Status: Sufficient for compiled code, but methods applicable to
@@ -116,7 +111,7 @@ import java.io.OutputStream;
* @author Tom Tromey
* @author Eric Blake <ebb9@email.byu.edu>
* @since 1.0
- * @status still missing 1.4 functionality
+ * @status updated to 1.4
*/
public class Throwable implements Serializable
{
@@ -130,7 +125,7 @@ public class Throwable implements Serializable
*
* @serial specific details about the exception, may be null
*/
- private String detailMessage;
+ private final String detailMessage;
/**
* The cause of the throwable, including null for an unknown or non-chained
@@ -374,7 +369,7 @@ public class Throwable implements Serializable
*/
public void printStackTrace(PrintStream s)
{
- printStackTrace(new PrintWriter(s));
+ s.print(stackTraceString());
}
/**
@@ -409,72 +404,88 @@ public class Throwable implements Serializable
*/
public void printStackTrace (PrintWriter pw)
{
- // First line
- pw.println(toString());
+ pw.print(stackTraceString());
+ }
- // The stacktrace
+ private static final String nl = System.getProperty("line.separator");
+ // Create whole stack trace in a stringbuffer so we don't have to print
+ // it line by line. This prevents printing multiple stack traces from
+ // different threads to get mixed up when written to the same PrintWriter.
+ private String stackTraceString()
+ {
+ StringBuffer sb = new StringBuffer();
+
+ // Main stacktrace
StackTraceElement[] stack = getStackTrace();
- if (stack == null || stack.length == 0)
- {
- pw.println(" <<No stacktrace available>>");
- return;
- }
- else
- {
- for (int i = 0; i < stack.length; i++)
- pw.println(" at " + stack[i]);
- }
+ stackTraceStringBuffer(sb, this.toString(), stack, 0);
// The cause(s)
Throwable cause = getCause();
while (cause != null)
{
- // Cause first line
- pw.println("Caused by: " + cause);
+ // Cause start first line
+ sb.append("Caused by: ");
// Cause stacktrace
StackTraceElement[] parentStack = stack;
stack = cause.getStackTrace();
- if (stack == null || stack.length == 0)
- {
- pw.println(" <<No stacktrace available>>");
- }
- else if (parentStack == null || parentStack.length == 0)
- {
- for (int i = 0; i < stack.length; i++)
- pw.println(" at " + stack[i]);
- }
+ if (parentStack == null || parentStack.length == 0)
+ stackTraceStringBuffer(sb, cause.toString(), stack, 0);
else
{
- boolean equal = false; // Is rest of stack equal to parent frame?
- for (int i = 0; i < stack.length && ! equal; i++)
+ int equal = 0; // Count how many of the last stack frames are equal
+ int frame = stack.length-1;
+ int parentFrame = parentStack.length-1;
+ while (frame > 0 && parentFrame > 0)
{
- // Check if we already printed the rest of the stack
- // since it was the tail of the parent stack
- int remaining = stack.length - i;
- int element = i;
- int parentElement = parentStack.length - remaining;
- equal = parentElement >= 0
- && parentElement < parentStack.length; // be optimistic
- while (equal && element < stack.length)
+ if (stack[frame].equals(parentStack[parentFrame]))
{
- if (stack[element].equals(parentStack[parentElement]))
- {
- element++;
- parentElement++;
- }
- else
- equal = false;
+ equal++;
+ frame--;
+ parentFrame--;
}
- // Print stacktrace element or indicate the rest is equal
- if (! equal)
- pw.println(" at " + stack[i]);
else
- pw.println(" ..." + remaining + " more");
+ break;
}
+ stackTraceStringBuffer(sb, cause.toString(), stack, equal);
}
cause = cause.getCause();
}
+
+ return sb.toString();
+ }
+
+ // Adds to the given StringBuffer a line containing the name and
+ // all stacktrace elements minus the last equal ones.
+ private static void stackTraceStringBuffer(StringBuffer sb, String name,
+ StackTraceElement[] stack, int equal)
+ {
+ // (finish) first line
+ sb.append(name);
+ sb.append(nl);
+
+ // The stacktrace
+ if (stack == null || stack.length == 0)
+ {
+ sb.append(" <<No stacktrace available>>");
+ sb.append(nl);
+ }
+ else
+ {
+ for (int i = 0; i < stack.length-equal; i++)
+ {
+ sb.append(" at ");
+ sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString());
+ sb.append(nl);
+ }
+ if (equal > 0)
+ {
+ sb.append(" ...");
+ sb.append(equal);
+ sb.append(" more");
+ sb.append(nl);
+ }
+ }
}
/**
@@ -483,7 +494,13 @@ public class Throwable implements Serializable
* @return this same throwable
* @see #printStackTrace()
*/
- public native Throwable fillInStackTrace();
+ public Throwable fillInStackTrace()
+ {
+ vmState = VMThrowable.fillInStackTrace(this);
+ stackTrace = null; // Should be regenerated when used.
+
+ return this;
+ }
/**
* Provides access to the information printed in {@link #printStackTrace()}.
@@ -499,7 +516,13 @@ public class Throwable implements Serializable
public StackTraceElement[] getStackTrace()
{
if (stackTrace == null)
- stackTrace = getStackTrace0();
+ if (vmState == null)
+ stackTrace = new StackTraceElement[0];
+ else
+ {
+ stackTrace = vmState.getStackTrace(this);
+ vmState = null; // No longer needed
+ }
return stackTrace;
}
@@ -508,6 +531,10 @@ public class Throwable implements Serializable
* Change the stack trace manually. This method is designed for remote
* procedure calls, which intend to alter the stack trace before or after
* serialization according to the context of the remote call.
+ * <p>
+ * The contents of the given stacktrace is copied so changes to the
+ * original * array do not change the stack trace elements of this
+ * throwable.
*
* @param stackTrace the new trace to use
* @throws NullPointerException if stackTrace is null or has null elements
@@ -515,15 +542,22 @@ public class Throwable implements Serializable
*/
public void setStackTrace(StackTraceElement[] stackTrace)
{
- for (int i = stackTrace.length; --i >= 0; )
+ int i = stackTrace.length;
+ StackTraceElement[] st = new StackTraceElement[i];
+
+ while (--i >= 0)
if (stackTrace[i] == null)
- throw new NullPointerException();
- this.stackTrace = stackTrace;
- }
+ throw new NullPointerException();
+ else
+ st[i] = stackTrace[i];
- private native final StackTraceElement[] getStackTrace0 ();
+ this.stackTrace = st;
+ }
- // Setting this flag to false prevents fillInStackTrace() from running.
- static boolean trace_enabled = true;
- private transient byte stackTraceBytes[];
+ /**
+ * VM state when fillInStackTrace was called.
+ * Used by getStackTrace() to get an array of StackTraceElements.
+ * Cleared when no longer needed.
+ */
+ private transient VMThrowable vmState;
}
diff --git a/libjava/java/lang/VMThrowable.java b/libjava/java/lang/VMThrowable.java
new file mode 100644
index 00000000000..0a2c9229649
--- /dev/null
+++ b/libjava/java/lang/VMThrowable.java
@@ -0,0 +1,97 @@
+/* java.lang.VMThrowable -- VM support methods for Throwable.
+ Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.lang;
+
+import gnu.gcj.runtime.NameFinder;
+
+/**
+ * VM dependant state and support methods Throwabele.
+ * It is deliberately package local and final and should only be accessed
+ * by the Throwable class.
+ * <p>
+ * This is the version used by libgcj (http://gcc.gnu.org/java/).
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+final class VMThrowable
+{
+ private gnu.gcj.RawData stackTraceAddrs;
+ private int length;
+
+ /**
+ * Private contructor, create VMThrowables with fillInStackTrace();
+ */
+ private VMThrowable() { }
+
+ /**
+ * Fill in the stack trace with the current execution stack.
+ * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
+ * the VM. Can return null when the VM does not support caputing the VM
+ * execution state.
+ *
+ * @return a new VMThrowable containing the current execution stack trace.
+ * @see Throwable#fillInStackTrace()
+ */
+ static native VMThrowable fillInStackTrace(Throwable t);
+
+ /**
+ * Returns an <code>StackTraceElement</code> array based on the execution
+ * state of the VM as captured by <code>fillInStackTrace</code>.
+ * Called by <code>Throwable.getStackTrace()</code>.
+ *
+ * @return a non-null but possible zero length array of StackTraceElement.
+ * @see Throwable#getStackTrace()
+ */
+ StackTraceElement[] getStackTrace(Throwable t)
+ {
+ StackTraceElement[] result;
+ if (stackTraceAddrs != null)
+ {
+ NameFinder nameFinder = new NameFinder();
+ result = nameFinder.lookup(t, stackTraceAddrs, length);
+ nameFinder.close();
+ }
+ else
+ result = new StackTraceElement[0];
+
+ return result;
+ }
+
+ // Setting this flag to false prevents fillInStackTrace() from running.
+ static boolean trace_enabled = true;
+}
diff --git a/libjava/java/lang/natThrowable.cc b/libjava/java/lang/natThrowable.cc
deleted file mode 100644
index c2f7d1b8d8d..00000000000
--- a/libjava/java/lang/natThrowable.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// natThrowable.cc - Superclass for all exceptions.
-
-/* Copyright (C) 2000 Free Software Foundation, 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>
-
-#include <gcj/cni.h>
-#include <jvm.h>
-#include <java/lang/Object.h>
-#include <java-threads.h>
-#include <java/lang/Throwable.h>
-#include <java/lang/StackTraceElement.h>
-#include <java/io/PrintStream.h>
-#include <java/io/PrintWriter.h>
-#include <java/io/IOException.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)
-{
- if (! trace_enabled)
- return this;
-#if defined (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;
-
- if (n > 0)
- {
- // We copy the array below to deal with alignment issues.
- stackTraceBytes = JvNewByteArray (n * sizeof p[0]);
- memcpy (elements (stackTraceBytes), p+1, (n * sizeof p[0]));
- }
-
-#endif
-
- return this;
-}
-
-JArray<java::lang::StackTraceElement*> *
-java::lang::Throwable::getStackTrace0 ()
-{
-#ifdef HAVE_BACKTRACE
- if (!stackTraceBytes)
- return NULL;
-
- int depth = stackTraceBytes->length / sizeof (void *);
- void *p[depth];
- // This memcpy is esential; it ensures that the array of void* is
- // correctly aligned.
- memcpy (p, elements (stackTraceBytes), sizeof p);
-
- JArray<java::lang::StackTraceElement*> *result;
- java::lang::StackTraceElement** el;
- result = reinterpret_cast <JArray<java::lang::StackTraceElement *>*>
- (JvNewObjectArray (depth, &java::lang::StackTraceElement::class$, NULL));
- el = elements (result);
-
- _Jv_name_finder finder (_Jv_ThisExecutable ());
-
- for (int i = 0; i < depth; i++)
- el[i] = finder.lookup (p[i]);
-
- return result;
-#else
- return NULL;
-#endif /* HAVE_BACKTRACE */
-}
diff --git a/libjava/java/lang/natVMThrowable.cc b/libjava/java/lang/natVMThrowable.cc
new file mode 100644
index 00000000000..358bab7f13b
--- /dev/null
+++ b/libjava/java/lang/natVMThrowable.cc
@@ -0,0 +1,73 @@
+// natVMThrowable.cc - native helper methods for Throwable
+
+/* Copyright (C) 2000, 2002 Free Software Foundation, 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>
+ * @author Mark Wielaard <mark@klomp.org>
+ *
+ * Native helper methods for VM specific Throwable support.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <jvm.h>
+#include <gcj/cni.h>
+#include <gnu/gcj/RawData.h>
+#include <java/lang/Object.h>
+#include <java-threads.h>
+#include <java/lang/Throwable.h>
+#include <java/lang/VMThrowable.h>
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#include <unistd.h>
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+/* 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::VMThrowable *
+java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable* t)
+{
+ if (! trace_enabled)
+ return NULL;
+#if defined (HAVE_BACKTRACE)
+ VMThrowable* state = new VMThrowable;
+ void *p[128];
+
+ // We subtract 1 from the number of elements because we don't want
+ // to include the calls to fillInStackTrace in the trace.
+ int n = backtrace (p, 128) - 1;
+
+ void **addrs;
+ if (n > 0)
+ {
+ state->length = n;
+ addrs = (void **) _Jv_Malloc (n * sizeof p[0]);
+ while (n--)
+ addrs[n] = p[n];
+ }
+ else
+ addrs = NULL;
+
+ state->stackTraceAddrs = reinterpret_cast<gnu::gcj::RawData *> (addrs);
+
+ return state;
+#endif
+ return NULL;
+}
diff --git a/libjava/name-finder.cc b/libjava/name-finder.cc
deleted file mode 100644
index 2d383aaa250..00000000000
--- a/libjava/name-finder.cc
+++ /dev/null
@@ -1,356 +0,0 @@
-// name-finder.cc - Convert addresses to names
-
-/* Copyright (C) 2000, 2002 Free Software Foundation, 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)
- demangling_error = lookup_error = 0;
-
- // Initialize file descriptors so that shutdown works properly.
- f_pipe[0] = -1;
- f_pipe[1] = -1;
- b_pipe[0] = -1;
- b_pipe[1] = -1;
- b_pipe_fd = NULL;
-
- f2_pipe[0] = -1;
- f2_pipe[1] = -1;
- b2_pipe[0] = -1;
- b2_pipe[1] = -1;
- b2_pipe_fd = NULL;
-
- // addr2line helper process.
-
- char *argv[5];
- {
- int arg = 0;
-#ifdef __ia64__
- argv[arg++] = "addr2name.awk";
-#else
- argv[arg++] = "addr2line";
- argv[arg++] = "-f";
- argv[arg++] = "-e";
-#endif
- argv[arg++] = executable;
- argv[arg] = NULL;
- }
-
- lookup_error |= pipe (f_pipe) < 0;
- lookup_error |= pipe (b_pipe) < 0;
-
- if (lookup_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 child end of pipes. Set local descriptors to -1 so we
- // don't try to close the fd again.
- close (f_pipe [0]);
- f_pipe[0] = -1;
- close (b_pipe [1]);
- b_pipe[1] = -1;
-
- if (pid < 0)
- {
- lookup_error |= 1;
- return;
- }
-
- b_pipe_fd = fdopen (b_pipe[0], "r");
- lookup_error |= !b_pipe_fd;
-
- if (! lookup_error)
- {
- // Don't try to close the fd twice.
- b_pipe[0] = -1;
- }
-
- // c++filt helper process.
-
- char *argv2[4];
- argv2[0] = "c++filt";
- argv2[1] = "-s";
- argv2[2] = "java";
- argv2[3] = NULL;
-
- demangling_error |= pipe (f2_pipe) < 0;
- demangling_error |= pipe (b2_pipe) < 0;
-
- if (demangling_error)
- return;
-
- pid2 = fork ();
- if (pid2 == 0)
- {
- close (f2_pipe[1]);
- close (b2_pipe[0]);
- dup2 (f2_pipe[0], fileno (stdin));
- dup2 (b2_pipe[1], fileno (stdout));
- execvp (argv2[0], argv2);
- _exit (127);
- }
-
- // Close child end of pipes. Set local descriptors to -1 so we
- // don't try to close the fd again.
- close (f2_pipe [0]);
- f2_pipe[0] = -1;
- close (b2_pipe [1]);
- b2_pipe[1] = -1;
-
- if (pid2 < 0)
- {
- demangling_error |= 1;
- return;
- }
-
- b2_pipe_fd = fdopen (b2_pipe[0], "r");
- demangling_error |= !b2_pipe_fd;
-
- if (! demangling_error)
- {
- // Don't try to close the fd twice.
- b2_pipe[0] = -1;
- }
-#endif
-}
-
-/* Convert a pointer to hex. */
-
-void
-_Jv_name_finder::toHex (void *p)
-{
- typedef unsigned word_t __attribute ((mode (word)));
- word_t n = (word_t) 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;
-}
-
-/* Creates a StackTraceElement given a string and a filename.
- Splits the given string into the class and method part.
- The string s will be a demangled to a fully qualified java method string.
- The string f will be decomposed into a file name and a possible line number.
- The given strings will be altered. */
-
-java::lang::StackTraceElement*
-_Jv_name_finder::createStackTraceElement(char *s, char *f)
-{
- char *c;
- char *class_name = NULL;
- char *method_name = NULL;
-
-#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
- if (demangling_error)
- goto fail;
-
- demangling_error |= write (f2_pipe[1], s, strlen (s)) < 0;
- if (demangling_error)
- goto fail;
- demangling_error |= write (f2_pipe[1], "\n", 1) < 0;
- if (demangling_error)
- goto fail;
-
- char name[1024];
- demangling_error |= (fgets (name, sizeof name, b2_pipe_fd) == NULL);
- if (demangling_error)
- goto fail;
-
- c = strchr (name, '\n');
- if (c)
- *c = 0;
- s = name;
-#endif
-
- c = strchr (s, '(');
- if (c)
- {
- while(c-->s)
- if (*c == '.')
- break;
-
- if (*c == '.')
- {
- *c = 0;
- class_name = s;
- method_name = c+1;
- }
- else
- {
- class_name = NULL;
- method_name = s;
- }
- }
- else
- {
- class_name = NULL;
- method_name = s;
- }
-
- // Get line number
- int line_number;
- c = strrchr (f, ':');
- if (c)
- {
- if (c[1] != 0)
- line_number = atoi(c+1);
- else
- line_number = -1;
- *c = 0;
- }
- else
- {
- line_number = -1;
- c = strchr (f, '\n');
- if (c)
- *c = 0;
- }
-
- fail:
- return new java::lang::StackTraceElement(
- f ? JvNewStringLatin1 (f) : NULL,
- line_number,
- class_name ? JvNewStringLatin1 (class_name) : NULL,
- JvNewStringLatin1 (method_name ? method_name : s),
- false);
-}
-
-/* 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. */
-
-java::lang::StackTraceElement*
-_Jv_name_finder::lookup (void *p)
-{
- extern char **_Jv_argv;
- toHex (p);
-
- char name[1024];
- char file_name[1024];
-
- file_name[0] = 0;
-
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
- {
- Dl_info dl_info;
-
- if (dladdr (p, &dl_info))
- {
- if (dl_info.dli_fname)
- strncpy (file_name, dl_info.dli_fname, sizeof file_name);
- if (dl_info.dli_sname)
- strncpy (name, dl_info.dli_sname, sizeof name);
-
- /* Don't trust dladdr() if the address is from the main program. */
- if (dl_info.dli_fname != NULL
- && dl_info.dli_sname != NULL
- && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
- return createStackTraceElement (name, file_name);
- }
- }
-#endif
-
- memcpy (name, hex, strlen (hex) + 1);
-
-#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
- if (lookup_error)
- goto fail;
-
- lookup_error |= write (f_pipe[1], hex, strlen (hex)) < 0;
- if (lookup_error)
- goto fail;
- lookup_error |= write (f_pipe[1], "\n", 1) < 0;
- if (lookup_error)
- goto fail;
-
- lookup_error |= (fgets (name, sizeof name, b_pipe_fd) == NULL);
- if (lookup_error)
- goto fail;
- lookup_error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
- if (lookup_error)
- goto fail;
-
- {
- char *newline = strchr (name, '\n');
- if (newline)
- *newline = 0;
- }
-#endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
-
- fail:
- return (createStackTraceElement (name, file_name));
-}
diff --git a/libjava/prims.cc b/libjava/prims.cc
index 054290b16ad..710139bab06 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -53,6 +53,7 @@ details. */
#include <java/lang/NullPointerException.h>
#include <java/lang/OutOfMemoryError.h>
#include <java/lang/System.h>
+#include <java/lang/VMThrowable.h>
#include <java/lang/reflect/Modifier.h>
#include <java/io/PrintStream.h>
#include <java/lang/UnsatisfiedLinkError.h>
@@ -910,8 +911,8 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
_Jv_InitPrimClass (&_Jv_voidClass, "void", 'V', 0, &_Jv_voidVTable);
// Turn stack trace generation off while creating exception objects.
- _Jv_InitClass (&java::lang::Throwable::class$);
- java::lang::Throwable::trace_enabled = 0;
+ _Jv_InitClass (&java::lang::VMThrowable::class$);
+ java::lang::VMThrowable::trace_enabled = 0;
INIT_SEGV;
#ifdef HANDLE_FPE
@@ -923,7 +924,7 @@ _Jv_CreateJavaVM (void* /*vm_args*/)
no_memory = new java::lang::OutOfMemoryError;
- java::lang::Throwable::trace_enabled = 1;
+ java::lang::VMThrowable::trace_enabled = 1;
#ifdef USE_LTDL
LTDL_SET_PRELOADED_SYMBOLS ();