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
This commit is contained in:
Mark Wielaard 2002-08-24 22:46:19 +00:00 committed by Mark Wielaard
parent 4906d5d83e
commit 6e0532cdf6
13 changed files with 821 additions and 645 deletions

View 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,

View 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 \

View 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 \

View File

@ -211,6 +211,7 @@ extern "Java"
class UnsupportedOperationException;
class VMClassLoader;
class VMSecurityManager;
class VMThrowable;
class VerifyError;
class VirtualMachineError;
class Void;

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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
};

View 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];
this.stackTrace = st;
}
private native final StackTraceElement[] getStackTrace0 ();
// 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;
}

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -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));
}

View 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 ();