diff options
author | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-08-24 22:46:19 +0000 |
---|---|---|
committer | mark <mark@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-08-24 22:46:19 +0000 |
commit | 22bd464fb14254908fedcdc08a0a8a3068c62098 (patch) | |
tree | 2194f5746d8d192d6202800f3df90a8ccb1675e0 | |
parent | bf81fbc51e651ae09cf076d677f052f460aca5fd (diff) | |
download | gcc-22bd464fb14254908fedcdc08a0a8a3068c62098.tar.gz |
* 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
-rw-r--r-- | libjava/ChangeLog | 28 | ||||
-rw-r--r-- | libjava/Makefile.am | 7 | ||||
-rw-r--r-- | libjava/Makefile.in | 44 | ||||
-rw-r--r-- | libjava/gcj/javaprims.h | 1 | ||||
-rw-r--r-- | libjava/gnu/gcj/runtime/NameFinder.java | 407 | ||||
-rw-r--r-- | libjava/gnu/gcj/runtime/natNameFinder.cc | 84 | ||||
-rw-r--r-- | libjava/include/name-finder.h | 103 | ||||
-rw-r--r-- | libjava/java/lang/Throwable.java | 160 | ||||
-rw-r--r-- | libjava/java/lang/VMThrowable.java | 97 | ||||
-rw-r--r-- | libjava/java/lang/natThrowable.cc | 99 | ||||
-rw-r--r-- | libjava/java/lang/natVMThrowable.cc | 73 | ||||
-rw-r--r-- | libjava/name-finder.cc | 356 | ||||
-rw-r--r-- | libjava/prims.cc | 7 |
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 (); |