Commit 6e0532cd by Mark Wielaard Committed by Mark Wielaard

Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.

        * 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
parent 4906d5d8
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,
......
......@@ -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 \
......
......@@ -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 \
......
......@@ -211,6 +211,7 @@ extern "Java"
class UnsupportedOperationException;
class VMClassLoader;
class VMSecurityManager;
class VMThrowable;
class VerifyError;
class VirtualMachineError;
class Void;
......
// 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;
}
// 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
};
......@@ -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;
}
/* 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;
}
// natThrowable.cc - Superclass for all exceptions.
// natVMThrowable.cc - native helper methods for Throwable
/* Copyright (C) 2000 Free Software Foundation, Inc
/* Copyright (C) 2000, 2002 Free Software Foundation, Inc
This file is part of libgcj.
......@@ -10,27 +10,26 @@ details. */
/**
* @author Andrew Haley <aph@cygnus.com>
* @date Jan 6 2000
* @author Mark Wielaard <mark@klomp.org>
*
* Native helper methods for VM specific Throwable support.
*/
#include <config.h>
#include <string.h>
#include <gcj/cni.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/StackTraceElement.h>
#include <java/io/PrintStream.h>
#include <java/io/PrintWriter.h>
#include <java/io/IOException.h>
#include <java/lang/VMThrowable.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
......@@ -38,62 +37,37 @@ details. */
#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)
java::lang::VMThrowable *
java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable* t)
{
if (! trace_enabled)
return this;
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 call to fillInStackTrace in the trace.
// to include the calls to fillInStackTrace in the trace.
int n = backtrace (p, 128) - 1;
void **addrs;
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]));
state->length = n;
addrs = (void **) _Jv_Malloc (n * sizeof p[0]);
while (n--)
addrs[n] = p[n];
}
else
addrs = NULL;
#endif
return this;
}
state->stackTraceAddrs = reinterpret_cast<gnu::gcj::RawData *> (addrs);
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 state;
#endif
return NULL;
#endif /* HAVE_BACKTRACE */
}
// 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));
}
......@@ -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 ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment