]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.
authorMark Wielaard <mark@klomp.org>
Sat, 24 Aug 2002 22:46:19 +0000 (22:46 +0000)
committerMark Wielaard <mark@gcc.gnu.org>
Sat, 24 Aug 2002 22:46:19 +0000 (22:46 +0000)
        * 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.

From-SVN: r56556

13 files changed:
libjava/ChangeLog
libjava/Makefile.am
libjava/Makefile.in
libjava/gcj/javaprims.h
libjava/gnu/gcj/runtime/NameFinder.java [new file with mode: 0644]
libjava/gnu/gcj/runtime/natNameFinder.cc [new file with mode: 0644]
libjava/include/name-finder.h [deleted file]
libjava/java/lang/Throwable.java
libjava/java/lang/VMThrowable.java [new file with mode: 0644]
libjava/java/lang/natThrowable.cc [deleted file]
libjava/java/lang/natVMThrowable.cc [new file with mode: 0644]
libjava/name-finder.cc [deleted file]
libjava/prims.cc

index b4f319f5315f99e9cc86f17ef37a89d561796efa..71b789ff50d25b9c18e5200932bc1a81b2aa6a88 100644 (file)
@@ -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,
index 89fff76cbfbcbe8e3fd42a2138ef99eb209bd518..ef10fe91c0d24a15e91ca007ee8b1d38cfbb2ebf 100644 (file)
@@ -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 \
index d165075518e6327d7add589948104fb04d0af354..2de61223dc67f58ab786b393515dad33cc068178 100644 (file)
@@ -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 \
index 99442c5ca2ae009326963732b4f87e3b741b37d8..3378a9faf6688bfdd8df9bac6f611c86cc4facb4 100644 (file)
@@ -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 (file)
index 0000000..60f47ac
--- /dev/null
@@ -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 (file)
index 0000000..42cc164
--- /dev/null
@@ -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 (file)
index 67ae058..0000000
+++ /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
-};
index 56c9d542a500e014cc761693b8aa7263f4f32ff1..613f43ffe9b32c71d9dfaa5f1b11850e2e9da580 100644 (file)
@@ -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 (file)
index 0000000..0a2c922
--- /dev/null
@@ -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 (file)
index c2f7d1b..0000000
+++ /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 (file)
index 0000000..358bab7
--- /dev/null
@@ -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 (file)
index 2d383aa..0000000
+++ /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));
-}
index 054290b16ad798e36e994641b748dfc603f52436..710139bab067f0f6da39495ab6c729e5057346a6 100644 (file)
@@ -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 ();