This is the mail archive of the
java@gcc.gnu.org
mailing list for the Java project.
resurrection: reflection-data stack traces [request 3.1.1 branch approval]
- From: Adam Megacz <gcj at lists dot megacz dot com>
- To: java at gcc dot gnu dot org, mitchell at mail dot codesourcery dot com
- Date: 05 Jun 2002 15:07:12 -0700
- Subject: resurrection: reflection-data stack traces [request 3.1.1 branch approval]
- Organization: Myself
I'd like to resurrect this patch; it was offered in the 11th hour
before 3.1 went out the door, which wasn't such a great time for
people to be considering patches =)
The code path modified by this patch should only be encountered if
CPlusPlusDemangler or printRawStackTrace fails (ie addr2line or
c++filt is not present). This is mainly advantageous on Win32, where
these tools are often not around.
Binary compatability is not affected since no per-instance members or
methods are added or removed.
Ok for branch and trunk?
- a
Index: Class.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Class.h,v
retrieving revision 1.43
diff -u -r1.43 Class.h
--- Class.h 21 Dec 2001 19:47:50 -0000 1.43
+++ Class.h 24 Apr 2002 03:06:14 -0000
@@ -308,6 +308,7 @@
friend void _Jv_LayoutVTableMethods (jclass klass);
friend void _Jv_SetVTableEntries (jclass, _Jv_VTable *);
friend void _Jv_MakeVTable (jclass);
+ friend JArray<java::lang::reflect::Method*>* _Jv_GetAllMethods();
// Return array class corresponding to element type KLASS, creating it if
// necessary.
Index: ClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/ClassLoader.java,v
retrieving revision 1.16
diff -u -r1.16 ClassLoader.java
--- ClassLoader.java 7 Dec 2001 23:34:12 -0000 1.16
+++ ClassLoader.java 24 Apr 2002 03:06:14 -0000
@@ -577,4 +577,8 @@
// Default to returning null. Derived classes implement this.
return null;
}
+
+ static native java.lang.reflect.Method[] getAllMethods();
+ static native long[] getAllMethodAddrs();
+
}
Index: Throwable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Throwable.java,v
retrieving revision 1.10
diff -u -r1.10 Throwable.java
--- Throwable.java 24 Feb 2001 03:52:49 -0000 1.10
+++ Throwable.java 24 Apr 2002 03:06:14 -0000
@@ -123,21 +123,64 @@
printStackTrace (writer);
}
+ private native static long longFromStackTraceBytes(byte[] stackTrace, int i);
+
public void printStackTrace (PrintWriter wr)
{
- try
- {
- CPlusPlusDemangler cPlusPlusFilter = new CPlusPlusDemangler (wr);
- PrintWriter writer = new PrintWriter (cPlusPlusFilter);
- printRawStackTrace (writer);
- writer.close ();
- if (cPlusPlusFilter.written == 0) // The demangler has failed...
- printRawStackTrace (wr);
+ try
+ {
+ CPlusPlusDemangler cPlusPlusFilter = new CPlusPlusDemangler (wr);
+ PrintWriter writer = new PrintWriter (cPlusPlusFilter);
+ printRawStackTrace (writer);
+ writer.close ();
+ if (cPlusPlusFilter.written > 0) return;
+ }
+ catch (Exception e1)
+ {
+ }
+
+ wr.println(toString());
+ if (stackTrace == null) {
+ wr.flush();
+ return;
}
- catch (Exception e1)
- {
- printRawStackTrace (wr);
+
+ long[] allAddrs = ClassLoader.getAllMethodAddrs();
+ java.lang.reflect.Method[] meths = ClassLoader.getAllMethods();
+
+ // FIXME: assumes little endian
+ for(int i=0; i<stackTrace.length; i++) {
+ long addr = longFromStackTraceBytes(stackTrace, i);
+ if (addr == 0) break;
+
+ int whichMethod = -1;
+ for(int j=0; j<allAddrs.length; j++) {
+ if (allAddrs[j] <= addr &&
+ (whichMethod == -1 || allAddrs[whichMethod] < allAddrs[j])) {
+ whichMethod = j;
+ }
+ }
+
+ if (whichMethod == -1) {
+ wr.println("[" + Long.toString(addr, 16) + "] " + "??");
+ continue;
+ }
+
+ if (meths[whichMethod].getDeclaringClass().getName().equals("gnu.gcj.runtime.FirstThread") &&
+ meths[whichMethod].getName().equals("call_main"))
+ break;
+
+ wr.println(" [" + Long.toString(addr, 16) + "] " +
+ meths[whichMethod].getDeclaringClass().getName() + "." +
+ meths[whichMethod].getName() + "() " +
+ "+" + (addr - allAddrs[whichMethod])
+ );
+
+ if (java.lang.Thread.class.isAssignableFrom(meths[whichMethod].getDeclaringClass()) &&
+ meths[whichMethod].getName().equals("run"))
+ break;
}
+ wr.flush();
}
public Throwable ()
Index: natClassLoader.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natClassLoader.cc,v
retrieving revision 1.47.8.1
diff -u -r1.47.8.1 natClassLoader.cc
--- natClassLoader.cc 2 Apr 2002 22:19:55 -0000 1.47.8.1
+++ natClassLoader.cc 24 Apr 2002 03:06:14 -0000
@@ -40,6 +40,10 @@
#include <java/lang/StringBuffer.h>
#include <java/io/Serializable.h>
#include <java/lang/Cloneable.h>
+#include <java/lang/reflect/Method.h>
+
+#include<java/lang/reflect/Constructor.h>
+#include<gcj/method.h>
// FIXME: remove these.
#define CloneableClass java::lang::Cloneable::class$
@@ -347,6 +351,50 @@
static jclass loaded_classes[HASH_LEN];
// This is the root of a linked list of classes
+
+JArray<java::lang::reflect::Method*>*
+java::lang::ClassLoader::getAllMethods()
+{
+ return _Jv_GetAllMethods();
+}
+
+JArray<jlong>*
+java::lang::ClassLoader::getAllMethodAddrs()
+{
+ JArray<java::lang::reflect::Method*>* arr = _Jv_GetAllMethods();
+ java::lang::reflect::Method** el = (java::lang::reflect::Method**)elements(arr);
+ JArray<jlong>* ret = JvNewLongArray(arr->length);
+ jlong* retel = (jlong*)elements(ret);
+ for(int i=0; i<arr->length; i++)
+ retel[i] = (jlong)((unsigned int)(_Jv_FromReflectedMethod (el[i])->ncode));
+ return ret;
+}
+
+JArray<java::lang::reflect::Method*>*
+_Jv_GetAllMethods()
+{
+ int numMethods = 0;
+
+ for(int i=0; i<HASH_LEN; i++)
+ for(jclass c = loaded_classes[i]; c; c = c->next)
+ numMethods += c->getDeclaredMethods()->length;
+
+ JArray<java::lang::reflect::Method*>* ret =
+ (JArray<java::lang::reflect::Method*>*)
+ JvNewObjectArray(numMethods, &java::lang::reflect::Method::class$, NULL);
+
+ java::lang::reflect::Method** el = (java::lang::reflect::Method**)elements(ret);
+
+ for(int i=0; i<HASH_LEN; i++)
+ for(jclass c = loaded_classes[i]; c; c = c->next) {
+ JArray<java::lang::reflect::Method*>* methods = c->getDeclaredMethods();
+ jint len = methods->length;
+ java::lang::reflect::Method** meths = (java::lang::reflect::Method**)elements(methods);
+ for(int j=0; j<len; j++) el[--numMethods] = meths[j];
+ }
+
+ return ret;
+}
^L
Index: natThrowable.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natThrowable.cc,v
retrieving revision 1.11
diff -u -r1.11 natThrowable.cc
--- natThrowable.cc 7 Feb 2002 19:26:06 -0000 1.11
+++ natThrowable.cc 24 Apr 2002 03:06:14 -0000
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <unistd.h>
+#include <platform.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
@@ -102,3 +103,18 @@
#endif /* HAVE_BACKTRACE */
wr->flush ();
}
+
+// Returns the i^th call address in the stackTrace member, or 0 if i
+// is beyond the end of the trace. This has to be done in C++ because
+// the addresses in stackTrace are the same width as the platform's
+// pointers (which is unknown to Java code), and stackTrace is a
+// byte[] using the platform's endianness (which is unknown to Java
+// code).
+jlong
+java::lang::Throwable::longFromStackTraceBytes(jbyteArray stackArr, jint i)
+{
+ if (i * sizeof(void*) > stackArr->length) return 0;
+ unsigned int* stack = (unsigned int*)elements(stackArr);
+ return (jlong)stack[i];
+}
+