New Stack Trace infrastructure.

2005-03-10  Bryce McKinlay  <mckinlay@redhat.com>

	New Stack Trace infrastructure.
	* Makefile.am (libgcj0_convenience_la_SOURCES): Add stacktrace.cc.
	(gnu/gcj/runtime/StackTrace.lo): Removed.
	(ordinary_java_source_files): Remove obsolete files.
	(nat_source_files): Remove obsolete files. Add natVMThrowable.cc.
	* configure.host (fallback_backtrace_h): Set backtrace header
	for mingw and cygwin targets.
	* configure.ac: Make symlink for fallback backtrace headers.
	* Makefile.in, configure: Rebuilt.
	* defineclass.cc (_Jv_ClassReader::read_one_code_attribute):
	Read 'LineNumberTable' attribute.
	(_Jv_ClassReader::read_one_class_attribute): Read 'SourceFile'
	attribute.
	(_Jv_ClassReader::handleCodeAttribute): Initialize method line
	table fields.
	* exception.cc: Remove unused include.
	* interpret.cc (DIRECT_THREADED, insn_slot): Moved to java-interp.h.
	(SAVE_PC): New macro. Save current PC in the interpreter frame.
	(NULLCHECK, NULLARRAYCHECK): Use SAVE_PC.
	(_Jv_InterpMethod::compile): Translate bytecode PC values in the line
	table to direct threaded instruction values.
	(_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Removed.
	(_Jv_InterpMethod::run): No longer member function. All
	callers updated. Remove _Unwind calls. Call SAVE_PC whenever a call
	is made or where an instruction could throw.
	(_Jv_InterpMethod::get_source_line): New. Look up source line numbers
	in line_table.
	* prims.cc (catch_segv): Construct exception after MAKE_THROW_FRAME.
	(catch_fpe): Likewise.
	* stacktrace.cc: New file. Stack trace code now here.
	* gnu/gcj/runtime/MethodRef.java:
	* gnu/gcj/runtime/NameFinder.java: Mostly reimplemented. Now simply
	calls addr2line to look up PC addresses in a given binary or shared
	library.
	* gnu/gcj/runtime/StackTrace.java, gnu/gcj/runtime/natNameFinder.cc,
	gnu/gcj/runtime/natStackTrace.cc: Removed.
	* gnu/java/lang/MainThread.java (call_main): Add comment warning that
	this function name is specially recognised by the stack trace code
	and shouldn't be changed.
	* include/java-interp.h (DIRECT_THREADED, insn_slot): Moved here.
	(struct  _Jv_LineTableEntry, line_table, line_table_len): New.
	(_Jv_InterpMethod::run): Update declaration.
	(_Jv_StackTrace_): New friend. NameFinder and StackTrace no longer
	friends.
	(_Jv_InterpFrame): Renamed from _Jv_MethodChain. Add PC field.
	* include/java-stack.h: New file. Declarations for stack tracing.
	* include/jvm.h (_Jv_Frame_info): Removed.
	* java/lang/Class.h: Update friend declarations.
	* java/lang/VMClassLoader.java (getSystemClassLoader): Simplify
	exception message.
	* java/lang/VMThrowable.java (fillInStackTrace): Now native.
	(getStackTrace): Now native.
	(data): New RawDataManaged field.
	* java/lang/natClass.cc: Update includes.
	(forName): Use _Jv_StackTrace::GetCallingClass for
	calling-classloader check.
	(getClassLoader): Likewise.
	* java/lang/natRuntime.cc: Update includes.
	(_load): Use _Jv_StackTrace::GetFirstNonSystemClassLoader.
	* java/lang/natVMSecurityManager.cc: Update includes.
	(getClassContext): Use _Jv_StackTrace::GetClassContext.
	* java/lang/natVMThrowable.cc: New file. Native methods for
	VMThrowable.
	* java/lang/reflect/natArray.cc: Update includes.
	(newInstance): Use _Jv_StackTrace::GetCallingClass to implement
	accessibility check.
	* java/lang/reflect/natConstructor.cc: Update includes.
	(newInstance): Use _Jv_StackTrace::GetCallingClass to implement
	accessibility check.
	* java/lang/reflect/natField.cc: Update includes.
	(getAddr): Use _Jv_StackTrace::GetCallingClass to implement
	accessibility check.
	* java/lang/reflect/natMethod.cc: Update includes.
	(invoke): Use _Jv_StackTrace::GetCallingClass to implement
	accessibility check.
	* java/util/natResourceBundle.cc: Update includes.
	(getCallingClassLoader): Use _Jv_StackTrace::GetCallingClass.
	* java/util/logging/natLogger.cc: Update includes. Use
	_Jv_StackTrace::GetCallerInfo to get call-site info.
	* sysdep/generic/backtrace.h: Fallback backtrace code. Stub
	implementation.
	* sysdep/i386/backtrace.h: New. Fallback backtrace code. i386
	implementation.

From-SVN: r96253
This commit is contained in:
Bryce McKinlay 2005-03-10 19:02:21 +00:00 committed by Bryce McKinlay
parent ca1593fda4
commit 18744d9b72
32 changed files with 1174 additions and 832 deletions

View file

@ -21,7 +21,6 @@ details. */
#include <java/lang/reflect/Modifier.h>
#include <java/security/ProtectionDomain.h>
#include <java/lang/Package.h>
#include <gnu/gcj/runtime/StackTrace.h>
// We declare these here to avoid including gcj/cni.h.
extern "C" void _Jv_InitClass (jclass klass);
@ -238,13 +237,13 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader);
jboolean _Jv_IsInterpretedClass (jclass);
void _Jv_InitField (jobject, jclass, int);
class _Jv_ClassReader;
class _Jv_ClassReader;
class _Jv_InterpClass;
class _Jv_InterpMethod;
#endif
class _Jv_StackTrace;
class _Jv_BytecodeVerifier;
class gnu::gcj::runtime::StackTrace;
class java::io::VMObjectStreamClass;
void _Jv_sharedlib_register_hook (jclass klass);
@ -473,6 +472,7 @@ private:
friend class ::_Jv_ClassReader;
friend class ::_Jv_InterpClass;
friend class ::_Jv_InterpMethod;
friend class ::_Jv_StackTrace;
#endif
#ifdef JV_MARKOBJ_DECL
@ -480,7 +480,6 @@ private:
#endif
friend class ::_Jv_BytecodeVerifier;
friend class gnu::gcj::runtime::StackTrace;
friend class java::io::VMObjectStreamClass;
friend class ::_Jv_Linker;

View file

@ -304,12 +304,10 @@ final class VMClassLoader
default_sys
= (ClassLoader) c.newInstance(new Object[] { default_sys });
}
catch (Exception e)
catch (Exception ex)
{
System.err.println("Requested system classloader "
+ loader + " failed, using "
+ "gnu.gcj.runtime.VMClassLoader");
e.printStackTrace();
throw new Error("Failed to load requested system classloader "
+ loader, ex);
}
}
return default_sys;

View file

@ -1,5 +1,5 @@
/* java.lang.VMThrowable -- VM support methods for Throwable.
Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -37,8 +37,7 @@ exception statement from your version. */
package java.lang;
import gnu.gcj.runtime.NameFinder;
import gnu.gcj.runtime.StackTrace;
import gnu.gcj.RawDataManaged;
/**
* VM dependent state and support methods Throwable.
@ -51,10 +50,8 @@ import gnu.gcj.runtime.StackTrace;
*/
final class VMThrowable
{
private gnu.gcj.runtime.StackTrace trace;
/**
* Private contructor, create VMThrowables with fillInStackTrace();
* Private contructor, create VMThrowables with StackTrace();
*/
private VMThrowable() { }
@ -67,20 +64,7 @@ final class VMThrowable
* @return a new VMThrowable containing the current execution stack trace.
* @see Throwable#fillInStackTrace()
*/
static VMThrowable fillInStackTrace(Throwable t)
{
VMThrowable state = null;
/* 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. */
if (trace_enabled)
{
state = new VMThrowable ();
state.trace = new gnu.gcj.runtime.StackTrace(128);
}
return state;
}
static native VMThrowable fillInStackTrace(Throwable t);
/**
* Returns an <code>StackTraceElement</code> array based on the execution
@ -90,21 +74,11 @@ final class VMThrowable
* @return a non-null but possible zero length array of StackTraceElement.
* @see Throwable#getStackTrace()
*/
StackTraceElement[] getStackTrace(Throwable t)
{
StackTraceElement[] result;
if (trace != null)
{
NameFinder nameFinder = new NameFinder();
result = nameFinder.lookup(t, trace);
nameFinder.close();
}
else
result = new StackTraceElement[0];
return result;
}
native StackTraceElement[] getStackTrace(Throwable t);
// Setting this flag to false prevents fillInStackTrace() from running.
static boolean trace_enabled = true;
// Native stack data.
private RawDataManaged data;
}

View file

@ -53,7 +53,6 @@ details. */
#include <java/lang/SecurityManager.h>
#include <java/lang/StringBuffer.h>
#include <java/lang/VMClassLoader.h>
#include <gnu/gcj/runtime/StackTrace.h>
#include <gcj/method.h>
#include <gnu/gcj/runtime/MethodRef.h>
#include <gnu/gcj/RawData.h>
@ -62,6 +61,7 @@ details. */
#include <java-cpool.h>
#include <java-interp.h>
#include <java-assert.h>
#include <java-stack.h>
#include <execution.h>
@ -101,20 +101,10 @@ jclass
java::lang::Class::forName (jstring className)
{
java::lang::ClassLoader *loader = NULL;
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
java::lang::Class *klass = NULL;
try
{
for (int i = 1; !klass; i++)
{
klass = t->classAt (i);
}
loader = klass->getClassLoaderInternal();
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
if (caller)
loader = caller->getClassLoaderInternal();
return forName (className, true, loader);
}
@ -125,21 +115,10 @@ java::lang::Class::getClassLoader (void)
java::lang::SecurityManager *s = java::lang::System::getSecurityManager();
if (s != NULL)
{
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
Class *caller = NULL;
jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$);
ClassLoader *caller_loader = NULL;
try
{
for (int i = 1; !caller; i++)
{
caller = t->classAt (i);
}
caller_loader = caller->getClassLoaderInternal();
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
if (caller)
caller_loader = caller->getClassLoaderInternal();
// If the caller has a non-null class loader, and that loader
// is not this class' loader or an ancestor thereof, then do a

View file

@ -16,6 +16,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-props.h>
#include <java-stack.h>
#include <java/lang/Long.h>
#include <java/lang/Runtime.h>
#include <java/lang/UnknownError.h>
@ -29,8 +30,6 @@ details. */
#include <java/lang/Process.h>
#include <java/lang/ConcreteProcess.h>
#include <java/lang/ClassLoader.h>
#include <gnu/gcj/runtime/StackTrace.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <jni.h>
@ -164,27 +163,7 @@ java::lang::Runtime::_load (jstring path, jboolean do_search)
if (do_search)
{
ClassLoader *sys = ClassLoader::systemClassLoader;
ClassLoader *look = NULL;
gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(10);
try
{
for (int i = 0; i < 10; ++i)
{
jclass klass = t->classAt(i);
if (klass != NULL)
{
ClassLoader *loader = klass->getClassLoaderInternal();
if (loader != NULL && loader != sys)
{
look = loader;
break;
}
}
}
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader ();
if (look != NULL)
{

View file

@ -12,43 +12,18 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/lang/VMSecurityManager.h>
#include <java/lang/SecurityManager.h>
#include <java/lang/ClassLoader.h>
#include <java/lang/Class.h>
#include <gnu/gcj/runtime/StackTrace.h>
JArray<jclass> *
java::lang::VMSecurityManager::getClassContext ()
{
JArray<jclass> *result = NULL;
gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace();
if (t)
{
int maxlen = t->length();
int len = 0;
for (int i=0; i<maxlen; i++)
{
jclass klass = t->classAt(i);
if (klass != NULL && klass != &java::lang::VMSecurityManager::class$
&& klass != &java::lang::SecurityManager::class$)
++len;
}
result =
(JArray<jclass> *) _Jv_NewObjectArray (len, &java::lang::Class::class$,
NULL);
len = 0;
for (int i=0; i<maxlen; i++)
{
jclass klass = t->classAt(i);
if (klass != NULL && klass != &java::lang::VMSecurityManager::class$
&& klass != &java::lang::SecurityManager::class$)
elements(result)[len++] = klass;
}
}
JArray<jclass> *result =
_Jv_StackTrace::GetClassContext (&SecurityManager::class$);
return result;
}

View file

@ -0,0 +1,45 @@
// natVMThrowable.cc - Native part of VMThrowable class.
/* Copyright (C) 2003 Free Software Foundation
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. */
#include <config.h>
#include <stdlib.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/lang/Throwable.h>
#include <java/lang/VMThrowable.h>
using namespace gnu::gcj;
java::lang::VMThrowable *
java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable *)
{
using namespace java::lang;
// Don't trace stack during initialization of the runtime.
if (! trace_enabled)
return NULL;
_Jv_StackTrace *trace = _Jv_StackTrace::GetStackTrace ();
VMThrowable *vmthrowable = new VMThrowable ();
vmthrowable->data = (RawDataManaged *) trace;
return vmthrowable;
}
JArray< ::java::lang::StackTraceElement *> *
java::lang::VMThrowable::getStackTrace (java::lang::Throwable *throwable)
{
_Jv_StackTrace *trace = reinterpret_cast <_Jv_StackTrace *> (data);
return _Jv_StackTrace::GetStackTraceElements (trace, throwable);
}

View file

@ -14,6 +14,7 @@ details. */
#include <jvm.h>
#include <gcj/cni.h>
#include <java-stack.h>
#include <java/lang/reflect/Array.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/IllegalArgumentException.h>
@ -54,21 +55,10 @@ java::lang::reflect::Array::newInstance (jclass componentType,
if (ndims == 1)
return newInstance (componentType, dims[0]);
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
Class *caller = NULL;
Class *caller = _Jv_StackTrace::GetCallingClass (&Array::class$);
ClassLoader *caller_loader = NULL;
try
{
for (int i = 1; !caller; i++)
{
caller = t->classAt (i);
}
caller_loader = caller->getClassLoaderInternal();
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
if (caller)
caller_loader = caller->getClassLoaderInternal();
jclass arrayType = componentType;
for (int i = 0; i < ndims; i++)

View file

@ -12,6 +12,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/IllegalAccessException.h>
@ -55,20 +56,7 @@ java::lang::reflect::Constructor::newInstance (jobjectArray args)
// Check accessibility, if required.
if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
{
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
Class *caller = NULL;
try
{
for (int i = 1; !caller; i++)
{
caller = t->classAt (i);
}
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
Class *caller = _Jv_StackTrace::GetCallingClass (&Constructor::class$);
if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
throw new IllegalAccessException;
}

View file

@ -13,6 +13,7 @@ details. */
#include <stdlib.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/lang/reflect/Field.h>
#include <java/lang/reflect/Modifier.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
@ -78,18 +79,7 @@ getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj,
// Check accessibility, if required.
if (! (Modifier::isPublic (flags) || field->isAccessible()))
{
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(7);
try
{
// We want to skip all the frames on the stack from this class.
for (int i = 1; !caller || caller == &Field::class$; i++)
caller = t->classAt (i);
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
caller = _Jv_StackTrace::GetCallingClass (&Field::class$);
if (! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags))
throw new java::lang::IllegalAccessException;
}

View file

@ -13,6 +13,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <jni.h>
#include <java-stack.h>
#include <java/lang/reflect/Method.h>
#include <java/lang/reflect/Constructor.h>
@ -168,20 +169,7 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args)
// Check accessibility, if required.
if (! (Modifier::isPublic (meth->accflags) || this->isAccessible()))
{
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
Class *caller = NULL;
try
{
for (int i = 1; !caller; i++)
{
caller = t->classAt (i);
}
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$);
if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags))
throw new IllegalAccessException;
}

View file

@ -17,7 +17,7 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/lang/Object.h>
#include <java/lang/Class.h>
@ -25,31 +25,19 @@ details. */
#include <java/lang/StackTraceElement.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
using namespace java::util::logging;
java::lang::StackTraceElement*
java::util::logging::Logger::getCallerStackFrame ()
{
gnu::gcj::runtime::StackTrace *t
= new gnu::gcj::runtime::StackTrace(4);
java::lang::Class *klass = NULL;
int i = 2;
try
{
// skip until this class
while ((klass = t->classAt (i)) != getClass())
i++;
// skip the stackentries of this class
while ((klass = t->classAt (i)) == getClass() || klass == NULL)
i++;
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
// FIXME: RuntimeError
}
jclass klass = NULL;
_Jv_Method *meth = NULL;
_Jv_StackTrace::GetCallerInfo (&Logger::class$, &klass, &meth);
java::lang::StackTraceElement *e
= new java::lang::StackTraceElement
(JvNewStringUTF (""), 0,
klass->getName(), t->methodAt(i), false);
klass->getName(), _Jv_NewStringUtf8Const (meth->name), false);
return e;
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2002, 2003 Free Software Foundation
/* Copyright (C) 2002, 2003, 2005 Free Software Foundation
This file is part of libgcj.
@ -12,31 +12,18 @@ details. */
#include <gcj/cni.h>
#include <jvm.h>
#include <java-stack.h>
#include <java/util/ResourceBundle.h>
#include <java/lang/SecurityManager.h>
#include <java/lang/ClassLoader.h>
#include <java/lang/Class.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <gnu/gcj/runtime/StackTrace.h>
using namespace java::lang;
java::lang::ClassLoader *
java::util::ResourceBundle::getCallingClassLoader ()
{
gnu::gcj::runtime::StackTrace *t = new gnu::gcj::runtime::StackTrace(6);
try
{
/* Frame 0 is this method, frame 1 is getBundle, so starting at
frame 2 we might see the user's class. FIXME: should account
for reflection, JNI, etc, here. */
for (int i = 2; ; ++i)
{
jclass klass = t->classAt(i);
if (klass != NULL)
return klass->getClassLoaderInternal();
}
}
catch (::java::lang::ArrayIndexOutOfBoundsException *e)
{
}
jclass caller = _Jv_StackTrace::GetCallingClass (&ResourceBundle::class$);
if (caller)
return caller->getClassLoaderInternal();
return NULL;
}