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

@ -1,3 +1,89 @@
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.
2005-03-10 Ranjit Mathew <rmathew@hotmail.com>
* testsuite/libjava.compile/PR20312.java: New file.

View File

@ -217,7 +217,7 @@ libgij_la_LDFLAGS = -rpath $(toolexeclibdir) \
# convenience library suddenly invokes the --whole-archive path instead.
# This allows the build to succeed for targets that allocate multiple got
# subsections in the linker, such as Alpha and MIPS.
libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc \
libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc stacktrace.cc \
link.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files) $(math_c_source_files) $(java_source_files) \
$(gnu_xml_source_files) $(built_java_source_files) \
@ -588,20 +588,12 @@ clean-nat:
SUFFIXES = .class .java .h .properties
## Note: we omit StackTrace here, since it has an explicit rule a bit
## later, and GNU make will warn in this case.
$(filter-out gnu/gcj/runtime/StackTrace.lo, $(javao_files)) $(xlib_javao_files): %.lo: %.java
$(javao_files) $(xlib_javao_files): %.lo: %.java
$(LTGCJCOMPILE) -o $@ -c $<
$(gtk_awt_peer_sources:.java=.lo) $(gnu_xml_source_files:.java=.lo): %.lo: %.java
$(LTGCJCOMPILE) -fjni -o $@ -c $<
## A special case. The sibcall optimization can change the number of
## frames on the stack, and StackTrace makes assumptions about this
## number.
gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/StackTrace.java
$(LTGCJCOMPILE) -fno-optimize-sibling-calls -o $@ -c $<
## Pass the list of object files to libtool in a temporary file to
## avoid tripping platform command line length limits.
libgcj.la: $(libgcj_la_OBJECTS) $(libgcj_la_DEPENDENCIES)
@ -2911,12 +2903,10 @@ gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
gnu/gcj/runtime/MethodRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java \
@ -3676,9 +3666,7 @@ gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc \
gnu/gcj/util/natDebug.cc \
@ -3708,6 +3696,7 @@ java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
java/lang/natVMSecurityManager.cc \
java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \

View File

@ -84,7 +84,8 @@ CONFIG_CLEAN_FILES = libgcj.pc libgcj.spec libgcj-test.spec \
gnu/java/net/natPlainSocketImpl.cc \
gnu/java/net/natPlainDatagramSocketImpl.cc \
gnu/java/nio/natPipeImpl.cc gnu/java/nio/natSelectorImpl.cc \
gnu/java/nio/channels/natFileChannelImpl.cc sysdep/locks.h
gnu/java/nio/channels/natFileChannelImpl.cc sysdep/locks.h \
sysdep/backtrace.h
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@ -331,7 +332,7 @@ am_libgcj_la_OBJECTS =
libgcj_la_OBJECTS = $(am_libgcj_la_OBJECTS)
libgcj0_convenience_la_LIBADD =
am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
link.cc defineclass.cc interpret.cc verify.cc \
stacktrace.cc link.cc defineclass.cc interpret.cc verify.cc \
gnu/gcj/natCore.cc gnu/gcj/convert/JIS0208_to_Unicode.cc \
gnu/gcj/convert/JIS0212_to_Unicode.cc \
gnu/gcj/convert/Unicode_to_JIS.cc gnu/gcj/convert/natIconv.cc \
@ -341,9 +342,7 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc gnu/gcj/util/natDebug.cc \
gnu/java/lang/natMainThread.cc \
@ -362,7 +361,7 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
java/lang/natString.cc java/lang/natStringBuffer.cc \
java/lang/natSystem.cc java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
java/lang/natVMSecurityManager.cc \
java/lang/natVMSecurityManager.cc java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
java/lang/reflect/natField.cc java/lang/reflect/natMethod.cc \
@ -555,12 +554,11 @@ am__libgcj0_convenience_la_SOURCES_DIST = prims.cc jni.cc exception.cc \
gnu/gcj/io/MimeTypes.java gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/JNIWeakRef.java gnu/gcj/runtime/MethodRef.java \
gnu/gcj/runtime/JNIWeakRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java gnu/gcj/util/Debug.java \
@ -2615,9 +2613,7 @@ am__objects_6 = gnu/gcj/natCore.lo \
gnu/gcj/convert/natOutput_SJIS.lo \
gnu/gcj/io/natSimpleSHSStream.lo gnu/gcj/io/shs.lo \
gnu/gcj/runtime/natFinalizerThread.lo \
gnu/gcj/runtime/natNameFinder.lo \
gnu/gcj/runtime/natSharedLibLoader.lo \
gnu/gcj/runtime/natStackTrace.lo \
gnu/gcj/runtime/natStringBuffer.lo \
gnu/gcj/runtime/natVMClassLoader.lo gnu/gcj/util/natDebug.lo \
gnu/java/lang/natMainThread.lo \
@ -2636,7 +2632,7 @@ am__objects_6 = gnu/gcj/natCore.lo \
java/lang/natString.lo java/lang/natStringBuffer.lo \
java/lang/natSystem.lo java/lang/natThread.lo \
java/lang/natVMClassLoader.lo \
java/lang/natVMSecurityManager.lo \
java/lang/natVMSecurityManager.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 \
@ -3996,12 +3992,11 @@ am__objects_15 = $(am__objects_9) gnu/classpath/ServiceFactory.lo \
gnu/gcj/io/DefaultMimeTypes.lo gnu/gcj/io/MimeTypes.lo \
gnu/gcj/io/SimpleSHSStream.lo gnu/gcj/runtime/FileDeleter.lo \
gnu/gcj/runtime/FinalizerThread.lo \
gnu/gcj/runtime/JNIWeakRef.lo gnu/gcj/runtime/MethodRef.lo \
gnu/gcj/runtime/NameFinder.lo \
gnu/gcj/runtime/JNIWeakRef.lo gnu/gcj/runtime/NameFinder.lo \
gnu/gcj/runtime/PersistentByteMap.lo \
gnu/gcj/runtime/SharedLibHelper.lo \
gnu/gcj/runtime/SharedLibLoader.lo \
gnu/gcj/runtime/StackTrace.lo gnu/gcj/runtime/StringBuffer.lo \
gnu/gcj/runtime/StringBuffer.lo \
gnu/gcj/runtime/SystemClassLoader.lo \
gnu/gcj/runtime/VMClassLoader.lo gnu/gcj/util/Debug.lo \
gnu/java/io/ASN1ParsingException.lo \
@ -4746,12 +4741,12 @@ am__objects_18 = java/lang/ConcreteProcess.lo \
@USING_WIN32_THREADS_TRUE@am__objects_27 = win32-threads.lo
@USING_NO_THREADS_TRUE@am__objects_28 = no-threads.lo
am_libgcj0_convenience_la_OBJECTS = prims.lo jni.lo exception.lo \
link.lo defineclass.lo interpret.lo verify.lo $(am__objects_6) \
$(am__objects_7) $(am__objects_16) $(am__objects_17) \
$(am__objects_18) $(am__objects_19) $(am__objects_20) \
$(am__objects_21) $(am__objects_22) $(am__objects_23) \
$(am__objects_24) $(am__objects_25) $(am__objects_26) \
$(am__objects_27) $(am__objects_28)
stacktrace.lo link.lo defineclass.lo interpret.lo verify.lo \
$(am__objects_6) $(am__objects_7) $(am__objects_16) \
$(am__objects_17) $(am__objects_18) $(am__objects_19) \
$(am__objects_20) $(am__objects_21) $(am__objects_22) \
$(am__objects_23) $(am__objects_24) $(am__objects_25) \
$(am__objects_26) $(am__objects_27) $(am__objects_28)
libgcj0_convenience_la_OBJECTS = $(am_libgcj0_convenience_la_OBJECTS)
am_libgij_la_OBJECTS = gij.lo
libgij_la_OBJECTS = $(am_libgij_la_OBJECTS)
@ -5163,7 +5158,7 @@ libgij_la_LDFLAGS = -rpath $(toolexeclibdir) \
# convenience library suddenly invokes the --whole-archive path instead.
# This allows the build to succeed for targets that allocate multiple got
# subsections in the linker, such as Alpha and MIPS.
libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc \
libgcj0_convenience_la_SOURCES = prims.cc jni.cc exception.cc stacktrace.cc \
link.cc defineclass.cc interpret.cc verify.cc \
$(nat_source_files) $(math_c_source_files) $(java_source_files) \
$(gnu_xml_source_files) $(built_java_source_files) \
@ -7306,12 +7301,10 @@ gnu/gcj/io/SimpleSHSStream.java \
gnu/gcj/runtime/FileDeleter.java \
gnu/gcj/runtime/FinalizerThread.java \
gnu/gcj/runtime/JNIWeakRef.java \
gnu/gcj/runtime/MethodRef.java \
gnu/gcj/runtime/NameFinder.java \
gnu/gcj/runtime/PersistentByteMap.java \
gnu/gcj/runtime/SharedLibHelper.java \
gnu/gcj/runtime/SharedLibLoader.java \
gnu/gcj/runtime/StackTrace.java \
gnu/gcj/runtime/StringBuffer.java \
gnu/gcj/runtime/SystemClassLoader.java \
gnu/gcj/runtime/VMClassLoader.java \
@ -8066,9 +8059,7 @@ gnu/gcj/convert/natOutput_SJIS.cc \
gnu/gcj/io/natSimpleSHSStream.cc \
gnu/gcj/io/shs.cc \
gnu/gcj/runtime/natFinalizerThread.cc \
gnu/gcj/runtime/natNameFinder.cc \
gnu/gcj/runtime/natSharedLibLoader.cc \
gnu/gcj/runtime/natStackTrace.cc \
gnu/gcj/runtime/natStringBuffer.cc \
gnu/gcj/runtime/natVMClassLoader.cc \
gnu/gcj/util/natDebug.cc \
@ -8098,6 +8089,7 @@ java/lang/natSystem.cc \
java/lang/natThread.cc \
java/lang/natVMClassLoader.cc \
java/lang/natVMSecurityManager.cc \
java/lang/natVMThrowable.cc \
java/lang/ref/natReference.cc \
java/lang/reflect/natArray.cc \
java/lang/reflect/natConstructor.cc \
@ -8783,13 +8775,9 @@ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp):
gnu/gcj/runtime/natFinalizerThread.lo: \
gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natNameFinder.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natSharedLibLoader.lo: \
gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natStackTrace.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natStringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/natVMClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
@ -8899,6 +8887,8 @@ java/lang/natVMClassLoader.lo: java/lang/$(am__dirstamp) \
java/lang/$(DEPDIR)/$(am__dirstamp)
java/lang/natVMSecurityManager.lo: java/lang/$(am__dirstamp) \
java/lang/$(DEPDIR)/$(am__dirstamp)
java/lang/natVMThrowable.lo: java/lang/$(am__dirstamp) \
java/lang/$(DEPDIR)/$(am__dirstamp)
java/lang/ref/$(am__dirstamp):
@$(mkdir_p) java/lang/ref
@: > java/lang/ref/$(am__dirstamp)
@ -9612,8 +9602,6 @@ gnu/gcj/runtime/FinalizerThread.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/JNIWeakRef.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/MethodRef.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/NameFinder.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/PersistentByteMap.lo: gnu/gcj/runtime/$(am__dirstamp) \
@ -9622,8 +9610,6 @@ gnu/gcj/runtime/SharedLibHelper.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/SharedLibLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/StringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \
gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp)
gnu/gcj/runtime/SystemClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \
@ -16363,8 +16349,6 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/FinalizerThread.lo
-rm -f gnu/gcj/runtime/JNIWeakRef.$(OBJEXT)
-rm -f gnu/gcj/runtime/JNIWeakRef.lo
-rm -f gnu/gcj/runtime/MethodRef.$(OBJEXT)
-rm -f gnu/gcj/runtime/MethodRef.lo
-rm -f gnu/gcj/runtime/NameFinder.$(OBJEXT)
-rm -f gnu/gcj/runtime/NameFinder.lo
-rm -f gnu/gcj/runtime/PersistentByteMap.$(OBJEXT)
@ -16373,8 +16357,6 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/SharedLibHelper.lo
-rm -f gnu/gcj/runtime/SharedLibLoader.$(OBJEXT)
-rm -f gnu/gcj/runtime/SharedLibLoader.lo
-rm -f gnu/gcj/runtime/StackTrace.$(OBJEXT)
-rm -f gnu/gcj/runtime/StackTrace.lo
-rm -f gnu/gcj/runtime/StringBuffer.$(OBJEXT)
-rm -f gnu/gcj/runtime/StringBuffer.lo
-rm -f gnu/gcj/runtime/SystemClassLoader.$(OBJEXT)
@ -16383,12 +16365,8 @@ mostlyclean-compile:
-rm -f gnu/gcj/runtime/VMClassLoader.lo
-rm -f gnu/gcj/runtime/natFinalizerThread.$(OBJEXT)
-rm -f gnu/gcj/runtime/natFinalizerThread.lo
-rm -f gnu/gcj/runtime/natNameFinder.$(OBJEXT)
-rm -f gnu/gcj/runtime/natNameFinder.lo
-rm -f gnu/gcj/runtime/natSharedLibLoader.$(OBJEXT)
-rm -f gnu/gcj/runtime/natSharedLibLoader.lo
-rm -f gnu/gcj/runtime/natStackTrace.$(OBJEXT)
-rm -f gnu/gcj/runtime/natStackTrace.lo
-rm -f gnu/gcj/runtime/natStringBuffer.$(OBJEXT)
-rm -f gnu/gcj/runtime/natStringBuffer.lo
-rm -f gnu/gcj/runtime/natVMClassLoader.$(OBJEXT)
@ -19002,6 +18980,8 @@ mostlyclean-compile:
-rm -f java/lang/natVMClassLoader.lo
-rm -f java/lang/natVMSecurityManager.$(OBJEXT)
-rm -f java/lang/natVMSecurityManager.lo
-rm -f java/lang/natVMThrowable.$(OBJEXT)
-rm -f java/lang/natVMThrowable.lo
-rm -f java/lang/ref/PhantomReference.$(OBJEXT)
-rm -f java/lang/ref/PhantomReference.lo
-rm -f java/lang/ref/Reference.$(OBJEXT)
@ -21926,6 +21906,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-threads.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prims.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-threads.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32.Plo@am__quote@
@ -21992,19 +21973,15 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/FileDeleter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/FinalizerThread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/JNIWeakRef.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/MethodRef.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/NameFinder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/PersistentByteMap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibHelper.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/StackTrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/StringBuffer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SystemClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/VMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natFinalizerThread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natNameFinder.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natSharedLibLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStackTrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStringBuffer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natVMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/Main.Po@am__quote@
@ -23312,6 +23289,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natThread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMClassLoader.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMSecurityManager.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/natVMThrowable.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_atan.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_ceil.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/s_copysign.Plo@am__quote@
@ -26677,15 +26655,12 @@ distclean-local:
clean-nat:
rm -f $(nat_files) $(xlib_nat_files)
$(filter-out gnu/gcj/runtime/StackTrace.lo, $(javao_files)) $(xlib_javao_files): %.lo: %.java
$(javao_files) $(xlib_javao_files): %.lo: %.java
$(LTGCJCOMPILE) -o $@ -c $<
$(gtk_awt_peer_sources:.java=.lo) $(gnu_xml_source_files:.java=.lo): %.lo: %.java
$(LTGCJCOMPILE) -fjni -o $@ -c $<
gnu/gcj/runtime/StackTrace.lo: gnu/gcj/runtime/StackTrace.java
$(LTGCJCOMPILE) -fno-optimize-sibling-calls -o $@ -c $<
libgcj.la: $(libgcj_la_OBJECTS) $(libgcj_la_DEPENDENCIES)
@echo Creating list of files to link...
@: $(call write_entries_to_file,$(libgcj_la_OBJECTS),libgcj.objectlist)

3
libjava/configure vendored
View File

@ -8454,6 +8454,8 @@ fi
if test -d sysdep; then true; else mkdir sysdep; fi
ac_config_links="$ac_config_links sysdep/locks.h:sysdep/$sysdeps_dir/locks.h"
ac_config_links="$ac_config_links sysdep/backtrace.h:$fallback_backtrace_h"
HASH_SYNC_SPEC=
# Hash synchronization is only useful with posix threads right now.
@ -16482,6 +16484,7 @@ do
"include/java-gc.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-gc.h:include/$GCHDR" ;;
"include/java-threads.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-threads.h:include/$THREADH" ;;
"sysdep/locks.h" ) CONFIG_LINKS="$CONFIG_LINKS sysdep/locks.h:sysdep/$sysdeps_dir/locks.h" ;;
"sysdep/backtrace.h" ) CONFIG_LINKS="$CONFIG_LINKS sysdep/backtrace.h:$fallback_backtrace_h" ;;
"include/java-signal.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-signal.h:$SIGNAL_HANDLER" ;;
"include/java-signal-aux.h" ) CONFIG_LINKS="$CONFIG_LINKS include/java-signal-aux.h:$SIGNAL_HANDLER_AUX" ;;
"depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;

View File

@ -710,6 +710,7 @@ AM_CONDITIONAL(USING_NO_THREADS, test "$THREADS" = none)
if test -d sysdep; then true; else mkdir sysdep; fi
AC_CONFIG_LINKS(sysdep/locks.h:sysdep/$sysdeps_dir/locks.h)
AC_CONFIG_LINKS(sysdep/backtrace.h:$fallback_backtrace_h)
HASH_SYNC_SPEC=
# Hash synchronization is only useful with posix threads right now.

View File

@ -30,6 +30,8 @@
# from a signal handler.
# disable_dladdr Set to "yes" if dladdr should not be used
# (i.e it is broken).
# fallback_backtrace_h Header to use for fallback backtrace implementation
# (only for targets that don't support DWARF2 unwind)
libgcj_flags=
libgcj_cflags=
@ -42,6 +44,7 @@ sysdeps_dir=generic
slow_pthread_self=
can_unwind_signal=no
disable_dladdr=
fallback_backtrace_h=sysdep/generic/backtrace.h
case "${target_optspace}:${host}" in
yes:*)
@ -258,6 +261,13 @@ EOF
;;
esac
case "${host}" in
*-cygwin* | *-mingw*)
fallback_backtrace_h=sysdep/i386/backtrace.h
;;
esac
libgcj_cflags="${libgcj_cflags} ${libgcj_flags}"
libgcj_cxxflags="${libgcj_cxxflags} ${libgcj_flags}"
libgcj_javaflags="${libgcj_javaflags} ${libgcj_flags}"

View File

@ -229,6 +229,7 @@ struct _Jv_ClassReader {
len = length;
pos = 0;
def = klass;
def->size_in_bytes = -1;
def->vtable_method_count = -1;
def->engine = &_Jv_soleInterpreterEngine;
@ -613,26 +614,54 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index)
}
}
void _Jv_ClassReader::read_one_code_attribute (int /*method*/)
void _Jv_ClassReader::read_one_code_attribute (int method_index)
{
/* ignore for now, ... later we may want to pick up
line number information, for debugging purposes;
in fact, the whole debugger issue is open! */
/* int name = */ read2u ();
int name = read2u ();
int length = read4 ();
skip (length);
if (is_attribute_name (name, "LineNumberTable"))
{
_Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *>
(def_interp->interpreted_methods[method_index]);
if (method->line_table != NULL)
throw_class_format_error ("Method already has LineNumberTable");
int table_len = read2u ();
_Jv_LineTableEntry* table
= (_Jv_LineTableEntry *) JvAllocBytes (table_len
* sizeof (_Jv_LineTableEntry));
for (int i = 0; i < table_len; i++)
{
table[i].bytecode_pc = read2u ();
table[i].line = read2u ();
}
method->line_table_len = table_len;
method->line_table = table;
}
else
{
/* ignore unknown code attributes */
skip (length);
}
}
void _Jv_ClassReader::read_one_class_attribute ()
{
/* we also ignore the class attributes, ...
some day we'll add inner-classes support. */
/* int name = */ read2u ();
int name = read2u ();
int length = read4 ();
skip (length);
if (is_attribute_name (name, "SourceFile"))
{
int source_index = read2u ();
check_tag (source_index, JV_CONSTANT_Utf8);
prepare_pool_entry (source_index, JV_CONSTANT_Utf8);
def_interp->source_file_name = _Jv_NewStringUtf8Const
(def->constants.data[source_index].utf8);
}
else
{
/* Currently, we ignore most class attributes.
FIXME: Add inner-classes attributes support. */
skip (length);
}
}
@ -1279,6 +1308,9 @@ void _Jv_ClassReader::handleCodeAttribute
method->defining_class = def;
method->self = &def->methods[method_index];
method->prepared = NULL;
method->line_table_len = 0;
method->line_table = NULL;
// grab the byte code!
memcpy ((void*) method->bytecode (),

View File

@ -15,7 +15,6 @@ details. */
#include <java/lang/Class.h>
#include <java/lang/NullPointerException.h>
#include <gnu/gcj/runtime/StackTrace.h>
#include <gnu/gcj/runtime/MethodRef.h>
#include <gnu/gcj/RawData.h>
#include <gcj/cni.h>

View File

@ -52,7 +52,7 @@ public interface Configuration
// For libgcj we never load the JNI libraries.
boolean INIT_LOAD_LIBRARY = false;
// For libgcj we have native methods for proxy support....
// For libgcj we have native methods for dynamic proxy support....
boolean HAVE_NATIVE_GET_PROXY_DATA = false;
boolean HAVE_NATIVE_GET_PROXY_CLASS = false;
boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = false;

View File

@ -9,6 +9,7 @@ details. */
package gnu.gcj.runtime;
import gnu.classpath.Configuration;
import gnu.gcj.RawData;
import java.lang.StringBuffer;
@ -19,456 +20,156 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.IOException;
import java.io.File;
import java.util.Iterator;
import java.util.HashMap;
/**
* Helper class that translates addresses (represented as longs) to a
* StackTraceElement array.
* Lookup addresses (represented as longs) to find source & line number info.
*
* There are a couple of system properties that can be set to manipulate the
* result (all default to true):
* The following system property is available (defaults 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>
* Whether 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.remove_internal</code>
* Whether runtime internal calls (methods in the internal _Jv_* classes
* and functions starting with 'ffi_') should be removed from the stack
* trace. Only done when the stack is sanitized.</ul>
* <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
* Whether 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>
* Whether an external process, addr2line, should be used to look up
* source file and line number info. Throwable.printStackTrace() will
* be faster if this property is set to 'false'.
* </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();
// The remove_interpreter name is an old 3.3/3.4 (deprecated) synonym.
private static final boolean remove_internal
= (Boolean.valueOf(System.getProperty
("gnu.gcj.runtime.NameFinder.remove_internal", "true")
).booleanValue()
||
Boolean.valueOf(System.getProperty
("gnu.gcj.runtime.NameFinder.remove_interpreter", "true")
).booleanValue()
);
/**
* The name of the binary to look up.
*/
private String binaryFile;
private String sourceFile;
private int lineNum;
private HashMap procs = new HashMap();
private static final boolean use_addr2line
= Boolean.valueOf(System.getProperty
("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
).booleanValue();
= Boolean.valueOf(System.getProperty
("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
).booleanValue();
class Addr2Line
{
Process proc;
BufferedWriter out;
BufferedReader in;
Addr2Line(String binaryFile)
{
try
{
String[] exec = new String[] {"addr2line", "-e", binaryFile};
Runtime runtime = Runtime.getRuntime();
proc = runtime.exec(exec);
}
catch (IOException ioe)
{
}
if (proc != null)
{
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
}
}
void close()
{
try
{
in.close();
out.close();
}
catch (IOException x) {}
proc.destroy();
}
}
/**
* 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;
/**
* Flag set if using addr2name.awk instead of addr2line from binutils.
*/
private boolean usingAddr2name = false;
/**
* Creates a new NameFinder. Call close to get rid of any resources
* created while using the <code>lookup</code> methods.
* Create a new NameFinder to lookup names in binaryFile. 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);
usingAddr2name = true;
}
catch (IOException ioe2) { addr2line = null; }
}
if (addr2line != null)
{
addr2lineIn = new BufferedReader
(new InputStreamReader(addr2line.getInputStream()));
addr2lineOut = new BufferedWriter
(new OutputStreamWriter(addr2line.getOutputStream()));
}
}
}
/**
* Returns the name of the currently running process.
* Returns the source file name if lookup() was successful. If the source file could not be
* determined, the binary name will be returned instead.
*/
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);
/**
* Returns the label that is exported for the given method name.
*/
native private String getExternalLabel(String name);
/**
* If nth element of stack is an interpreted frame, return the
* element representing the method being interpreted.
*/
native private StackTraceElement lookupInterp(RawData addrs, int n);
/**
* Creates the nth StackTraceElement from the given native stacktrace.
*/
private StackTraceElement lookup(RawData addrs, int n)
public String getSourceFile()
{
StackTraceElement result;
result = lookupInterp(addrs, n);
if (result == null)
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();
// addr2line uses symbolic debugging information instead
// of the actually exported labels as addr2name.awk does.
// This name might need some modification, depending on
// the system, to make it a label like that returned
// by addr2name.awk or dladdr.
if (! usingAddr2name)
if (name != null && ! "??".equals (name))
name = getExternalLabel (name);
}
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, StackTrace trace)
{
RawData addrs = trace.stackTraceAddrs();
int length = trace.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);
String file;
if (sourceFile != null)
file = sourceFile;
else
return elements;
file = binaryFile;
return file.substring(file.lastIndexOf(File.separator) + 1, file.length());
}
/**
* If lookup() was successful, returns the line number of addr. If the line number could not
* be determined, -1 is returned.
*/
public int getLineNum()
{
return lineNum;
}
/**
* 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)
public void lookup (String file, long addr)
{
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 internal = 0;
int last_throw = -1;
int length = elements.length;
int end = length-1;
for (int i = 0; i < length; i++)
binaryFile = file;
sourceFile = null;
lineNum = -1;
if (! use_addr2line)
return;
Addr2Line addr2line = (Addr2Line) procs.get(file);
if (addr2line == null)
{
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;
// Reset counting of unknown and internal frames.
unknown = 0;
internal = 0;
}
else if (remove_unknown && CName == null
&& (MName == null || MName.startsWith("0x")))
unknown++;
else if (remove_internal
&& ((CName == null
&& MName != null && MName.startsWith("ffi_"))
|| (CName != null && CName.startsWith("_Jv_"))
|| (CName == null && MName != null
&& MName.startsWith("_Jv_"))))
internal++;
else if (("java.lang.Thread".equals(CName)
|| "gnu.java.lang.MainThread".equals(CName))
&& "run()".equals(MName))
{
end = i;
break;
}
addr2line = new Addr2Line(file);
procs.put(file, addr2line);
}
int begin = last_throw+1;
if (addr2line.proc == null)
return;
String hexAddr = "0x" + Long.toHexString(addr);
String name;
// Now filter out everything at the start and the end that is not part
// of the "normal" user program including any elements that are internal
// calls or have no usefull information whatsoever.
// Unless that means we filter out all info.
int nr_elements = end - begin - unknown - internal + 1;
if ((begin > 0 || end < length-1 || unknown > 0 || internal > 0)
&& nr_elements > 0)
try
{
stack = new StackTraceElement[nr_elements];
int pos =0;
for (int i=begin; i<=end; i++)
{
String MName = elements[i].getMethodName();
String CName = elements[i].getClassName();
if (remove_unknown && CName == null
&& (MName == null || MName.startsWith("0x")))
; // Skip unknown frame
else if (remove_internal
&& ((CName == null
&& MName != null && MName.startsWith("ffi_"))
|| (CName != null && CName.startsWith("_Jv_"))
|| (CName == null && MName != null
&& MName.startsWith("_Jv_"))))
; // Skip internal runtime frame
else
{
// Null Class or Method name in elements are not allowed.
if (MName == null || CName == null)
{
MName = MName == null ? "" : MName;
CName = CName == null ? "" : CName;
stack[pos] = newElement(elements[i].getFileName(),
elements[i].getLineNumber(),
CName, MName,
elements[i].isNativeMethod());
}
else
stack[pos] = elements[i];
pos++;
}
}
}
else
stack = elements;
addr2line.out.write(hexAddr);
addr2line.out.newLine();
addr2line.out.flush();
String result = addr2line.in.readLine();
return stack;
}
/**
* Native helper method to create a StackTraceElement. Needed to work
* around normal Java access restrictions.
*/
native static private StackTraceElement newElement(String fileName,
int lineNumber,
String className,
String methName,
boolean isNative);
/**
* 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 newElement(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.lastIndexOf(':');
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 newElement(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
if (result.indexOf("??") == -1)
{
cppfiltOut.write(s);
cppfiltOut.newLine();
cppfiltOut.flush();
return cppfiltIn.readLine();
int split = result.lastIndexOf(':');
sourceFile = result.substring(0, split);
String lineNumStr = result.substring(split + 1, result.length());
lineNum = Integer.parseInt (lineNumStr);
}
catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
}
return s;
}
catch (IOException ioe)
{
addr2line = null;
}
catch (NumberFormatException x)
{
}
}
/**
@ -508,7 +209,7 @@ public class NameFinder
// Demangle the type arguments
int arrayDepth = 0;
char c = (index < length) ? m.charAt(index) : ')';
while (c != ')')
while (c != ')')
{
String type;
switch(c)
@ -581,18 +282,11 @@ public class 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();
Iterator itr = procs.values().iterator();
while (itr.hasNext())
{
Addr2Line proc = (Addr2Line) itr.next();
proc.close();
}
}
}

View File

@ -127,5 +127,7 @@ final class MainThread extends Thread
return mainName;
}
// Note: this function name is known to the stack tracing code.
// You shouldn't change this without also updating stacktrace.cc.
private native void call_main();
}

View File

@ -23,6 +23,11 @@ details. */
#include <java/lang/ClassLoader.h>
#include <java/lang/reflect/Modifier.h>
// Define this to get the direct-threaded interpreter. If undefined,
// we revert to a basic bytecode interpreter. The former is faster
// but uses more memory.
#define DIRECT_THREADED
extern "C" {
#include <ffi.h>
}
@ -95,6 +100,41 @@ public:
}
};
// The type of the PC depends on whether we're doing direct threading
// or a more ordinary bytecode interpreter.
#ifdef DIRECT_THREADED
// Slot in the "compiled" form of the bytecode.
union insn_slot
{
// Address of code.
void *insn;
// An integer value used by an instruction.
jint int_val;
// A pointer value used by an instruction.
void *datum;
};
typedef insn_slot *pc_t;
#else
typedef unsigned char *pc_t;
#endif
// This structure holds the bytecode pc and corresponding source code
// line number. An array (plus length field) of this structure is put
// in each _Jv_InterpMethod and used to resolve the (internal) program
// counter of the interpreted method to an actual java source file
// line.
struct _Jv_LineTableEntry
{
union
{
pc_t pc;
int bytecode_pc;
};
int line;
};
class _Jv_InterpMethod : public _Jv_MethodBase
{
_Jv_ushort max_stack;
@ -103,6 +143,10 @@ class _Jv_InterpMethod : public _Jv_MethodBase
_Jv_ushort exc_count;
// Length of the line_table - when this is zero then line_table is NULL.
int line_table_len;
_Jv_LineTableEntry *line_table;
void *prepared;
unsigned char* bytecode ()
@ -135,17 +179,19 @@ class _Jv_InterpMethod : public _Jv_MethodBase
static void run_class (ffi_cif*, void*, ffi_raw*, void*);
static void run_synch_class (ffi_cif*, void*, ffi_raw*, void*);
void run (void*, ffi_raw *);
static void run (void*, ffi_raw *, _Jv_InterpMethod *);
// Returns source file line number for given PC value, or -1 if line
// number info is unavailable.
int get_source_line(pc_t mpc);
public:
static void dump_object(jobject o);
friend class _Jv_ClassReader;
friend class _Jv_BytecodeVerifier;
friend class gnu::gcj::runtime::NameFinder;
friend class gnu::gcj::runtime::StackTrace;
friend class _Jv_StackTrace;
friend class _Jv_InterpreterEngine;
#ifdef JV_MARKOBJ_DECL
friend JV_MARKOBJ_DECL;
@ -155,11 +201,14 @@ class _Jv_InterpMethod : public _Jv_MethodBase
class _Jv_InterpClass
{
_Jv_MethodBase **interpreted_methods;
_Jv_ushort *field_initializers;
_Jv_ushort *field_initializers;
jstring source_file_name;
friend class _Jv_ClassReader;
friend class _Jv_InterpMethod;
friend class _Jv_StackTrace;
friend class _Jv_InterpreterEngine;
friend void _Jv_InitField (jobject, jclass, int);
#ifdef JV_MARKOBJ_DECL
friend JV_MARKOBJ_DECL;
@ -219,23 +268,24 @@ public:
}
};
// A structure of this type is used to link together interpreter
// invocations on the stack.
struct _Jv_MethodChain
// The interpreted call stack, represented by a linked list of frames.
struct _Jv_InterpFrame
{
const _Jv_InterpMethod *self;
_Jv_MethodChain **ptr;
_Jv_MethodChain *next;
_Jv_InterpMethod *self;
_Jv_InterpFrame **ptr;
_Jv_InterpFrame *next;
pc_t pc;
_Jv_MethodChain (const _Jv_InterpMethod *s, _Jv_MethodChain **n)
_Jv_InterpFrame (_Jv_InterpMethod *s, _Jv_InterpFrame **n)
{
self = s;
ptr = n;
next = *n;
*n = this;
pc = NULL;
}
~_Jv_MethodChain ()
~_Jv_InterpFrame ()
{
*ptr = next;
}

View File

@ -1,6 +1,6 @@
// java-stack.h - Definitions for unwinding & inspecting the call stack.
/* Copyright (C) 2003 Free Software Foundation
/* Copyright (C) 2005 Free Software Foundation
This file is part of libgcj.
@ -21,10 +21,12 @@ details. */
#include <java/lang/Class.h>
#include <java/lang/StackTraceElement.h>
#include <java/lang/Throwable.h>
#include <java/lang/Thread.h>
#include <gnu/gcj/runtime/NameFinder.h>
using namespace gnu::gcj::runtime;
using namespace java::lang;
enum _Jv_FrameType
{
@ -51,13 +53,44 @@ struct _Jv_StackFrame
#ifdef INTERPRETER
_Jv_InterpFrameInfo interp;
#endif
void *ip;
struct {
void *ip;
void *start_ip;
};
};
// _Jv_FrameInfo info; /* Frame-type specific data. */
jclass klass;
_Jv_Method *meth;
};
typedef struct _Jv_UnwindState;
typedef _Unwind_Reason_Code (*_Jv_TraceFn) (_Jv_UnwindState *);
struct _Jv_UnwindState
{
jint length; // length of FRAMES
jint pos; // current position in FRAMES
_Jv_StackFrame *frames; // array of stack frame data to be filled.
_Jv_InterpFrame *interp_frame; // current frame in the interpreter stack.
_Jv_TraceFn trace_function; // function to call back after each frame
// is enumerated. May be NULL.
void *trace_data; // additional state data for trace_function.
_Jv_UnwindState (jint ln)
{
length = ln;
pos = 0;
frames = NULL;
Thread *thread = Thread::currentThread();
// Check for NULL currentThread(), in case an exception is created
// very early during the runtime startup.
if (thread)
interp_frame = (_Jv_InterpFrame *) thread->interp_frame;
trace_function = NULL;
trace_data = NULL;
}
};
class _Jv_StackTrace
{
private:
@ -65,20 +98,28 @@ private:
_Jv_StackFrame frames[];
static void UpdateNCodeMap ();
static jclass ClassForIP (void *ip, void **ncode);
static jclass ClassForFrame (_Jv_StackFrame *frame);
static void FillInFrameInfo (_Jv_StackFrame *frame);
static void getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
jstring *sourceFileName, jint *lineNum);
static _Unwind_Reason_Code UnwindTraceFn (struct _Unwind_Context *context,
void *state_ptr);
static _Unwind_Reason_Code calling_class_trace_fn (_Jv_UnwindState *state);
static _Unwind_Reason_Code non_system_trace_fn (_Jv_UnwindState *state);
public:
static _Jv_StackTrace *GetStackTrace (void);
static JArray< ::java::lang::StackTraceElement *>*
GetStackTraceElements (_Jv_StackTrace *trace,
java::lang::Throwable *throwable);
static jclass GetCallingClass (void);
static jclass GetCallingClass (jclass);
static void GetCallerInfo (jclass checkClass, jclass *, _Jv_Method **);
static JArray<jclass> *GetClassContext (jclass checkClass);
static ClassLoader *GetFirstNonSystemClassLoader (void);
};
#endif /* __JV_STACKTRACE_H__ */

View File

@ -120,20 +120,6 @@ union _Jv_value
jobject object_value;
};
// An instance of this type is used to represent a single frame in a
// backtrace. If the interpreter has been built, we also include
// information about the interpreted method.
struct _Jv_frame_info
{
// PC value.
void *addr;
#ifdef INTERPRETER
// Actually a _Jv_InterpMethod, but we don't want to include
// java-interp.h everywhere.
void *interp;
#endif // INTERPRETER
};
/* Extract a character from a Java-style Utf8 string.
* PTR points to the current character.
* LIMIT points to the end of the Utf8 string.

View File

@ -13,11 +13,6 @@ details. */
#include <config.h>
#include <platform.h>
// Define this to get the direct-threaded interpreter. If undefined,
// we revert to a basic bytecode interpreter. The former is faster
// but uses more memory.
#define DIRECT_THREADED
#pragma implementation "java-interp.h"
#include <jvm.h>
@ -83,26 +78,6 @@ void _Jv_InitInterpreter() {}
extern "C" double __ieee754_fmod (double,double);
// This represents a single slot in the "compiled" form of the
// bytecode.
union insn_slot
{
// Address of code.
void *insn;
// An integer value used by an instruction.
jint int_val;
// A pointer value used by an instruction.
void *datum;
};
// The type of the PC depends on whether we're doing direct threading
// or a more ordinary bytecode interpreter.
#ifdef DIRECT_THREADED
typedef insn_slot *pc_t;
#else
typedef unsigned char *pc_t;
#endif
static inline void dupx (_Jv_word *sp, int n, int x)
{
// first "slide" n+x elements n to the right
@ -117,7 +92,6 @@ static inline void dupx (_Jv_word *sp, int n, int x)
{
sp[top-(n+x)-i] = sp[top-i];
}
}
// Used to convert from floating types to integral types.
@ -248,15 +222,16 @@ static jint get4(unsigned char* loc) {
| (((jint)(loc[3])) << 0);
}
#define SAVE_PC() frame_desc.pc = pc
#ifdef HANDLE_SEGV
#define NULLCHECK(X)
#define NULLARRAYCHECK(X)
#define NULLCHECK(X) SAVE_PC()
#define NULLARRAYCHECK(X) SAVE_PC()
#else
#define NULLCHECK(X) \
do { if ((X)==NULL) throw_null_pointer_exception (); } while (0)
do { SAVE_PC(); if ((X)==NULL) throw_null_pointer_exception (); } while (0)
#define NULLARRAYCHECK(X) \
do { if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
do { SAVE_PC(); if ((X)==NULL) { throw_null_pointer_exception (); } } while (0)
#endif
#define ARRAYBOUNDSCHECK(array, index) \
@ -274,7 +249,7 @@ _Jv_InterpMethod::run_normal (ffi_cif *,
void* __this)
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_this->run (ret, args);
run (ret, args, _this);
}
void
@ -288,7 +263,7 @@ _Jv_InterpMethod::run_synch_object (ffi_cif *,
jobject rcv = (jobject) args[0].ptr;
JvSynchronize mutex (rcv);
_this->run (ret, args);
run (ret, args, _this);
}
void
@ -299,7 +274,7 @@ _Jv_InterpMethod::run_class (ffi_cif *,
{
_Jv_InterpMethod *_this = (_Jv_InterpMethod *) __this;
_Jv_InitClass (_this->defining_class);
_this->run (ret, args);
run (ret, args, _this);
}
void
@ -314,7 +289,7 @@ _Jv_InterpMethod::run_synch_class (ffi_cif *,
_Jv_InitClass (sync);
JvSynchronize mutex (sync);
_this->run (ret, args);
run (ret, args, _this);
}
#ifdef DIRECT_THREADED
@ -783,29 +758,23 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
exc[i].handler_type.p = handler;
}
// Translate entries in the LineNumberTable from bytecode PC's to direct
// threaded interpreter instruction values.
for (int i = 0; i < line_table_len; i++)
{
int byte_pc = line_table[i].bytecode_pc;
line_table[i].pc = &insns[pc_mapping[byte_pc]];
}
prepared = insns;
}
#endif /* DIRECT_THREADED */
// These exist so that the stack-tracing code can find the boundaries
// of the interpreter.
void *_Jv_StartOfInterpreter;
void *_Jv_EndOfInterpreter;
extern "C" void *_Unwind_FindEnclosingFunction (void *pc);
void
_Jv_InterpMethod::run (void *retp, ffi_raw *args)
_Jv_InterpMethod::run (void *retp, ffi_raw *args, _Jv_InterpMethod *meth)
{
using namespace java::lang::reflect;
// Record the address of the start of this member function in
// _Jv_StartOfInterpreter. Such a write to a global variable
// without acquiring a lock is correct iff reads and writes of words
// in memory are atomic, but Java requires that anyway.
foo:
if (_Jv_StartOfInterpreter == NULL)
_Jv_StartOfInterpreter = _Unwind_FindEnclosingFunction (&&foo);
// FRAME_DESC registers this particular invocation as the top-most
// interpreter frame. This lets the stack tracing code (for
// Throwable) print information about the method being interpreted
@ -813,20 +782,20 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// destructor so it cleans up automatically when the interpreter
// returns.
java::lang::Thread *thread = java::lang::Thread::currentThread();
_Jv_MethodChain frame_desc (this,
(_Jv_MethodChain **) &thread->interp_frame);
_Jv_InterpFrame frame_desc (meth,
(_Jv_InterpFrame **) &thread->interp_frame);
_Jv_word stack[max_stack];
_Jv_word stack[meth->max_stack];
_Jv_word *sp = stack;
_Jv_word locals[max_locals];
_Jv_word locals[meth->max_locals];
/* Go straight at it! the ffi raw format matches the internal
stack representation exactly. At least, that's the idea.
*/
memcpy ((void*) locals, (void*) args, args_raw_size);
memcpy ((void*) locals, (void*) args, meth->args_raw_size);
_Jv_word *pool_data = defining_class->constants.data;
_Jv_word *pool_data = meth->defining_class->constants.data;
/* These three are temporaries for common code used by several
instructions. */
@ -1068,14 +1037,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#define AMPAMP(label) &&label
// Compile if we must. NOTE: Double-check locking.
if (prepared == NULL)
if (meth->prepared == NULL)
{
_Jv_MutexLock (&compile_mutex);
if (prepared == NULL)
compile (insn_target);
if (meth->prepared == NULL)
meth->compile (insn_target);
_Jv_MutexUnlock (&compile_mutex);
}
pc = (insn_slot *) prepared;
pc = (insn_slot *) meth->prepared;
#else
@ -1132,7 +1101,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
* the corresponding bit JV_CONSTANT_ResolvedFlag in the tag
* directly. For now, I don't think it is worth it. */
rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
SAVE_PC();
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@ -1140,7 +1110,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// working if the method is final. So instead we do an
// explicit test.
if (! sp[0].o)
throw new java::lang::NullPointerException;
{
//printf("invokevirtual pc = %p/%i\n", pc, meth->get_pc_val(pc));
throw new java::lang::NullPointerException;
}
if (rmeth->vtable_index == -1)
{
@ -1173,7 +1146,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// working if the method is final. So instead we do an
// explicit test.
if (! sp[0].o)
throw new java::lang::NullPointerException;
{
SAVE_PC();
throw new java::lang::NullPointerException;
}
if (rmeth->vtable_index == -1)
{
@ -1193,6 +1169,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
perform_invoke:
{
SAVE_PC();
/* here goes the magic again... */
ffi_cif *cif = &rmeth->cif;
ffi_raw *raw = (ffi_raw*) sp;
@ -2423,7 +2401,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getstatic:
{
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
SAVE_PC(); // Constant pool resolution could throw.
_Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) == 0)
@ -2510,7 +2489,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getfield:
{
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) != 0)
@ -2626,7 +2605,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putstatic:
{
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@ -2713,7 +2692,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putfield:
{
jint fieldref_index = GET2U ();
_Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Linker::resolve_pool_entry (meth->defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@ -2839,7 +2818,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@ -2847,7 +2826,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
throw new java::lang::NullPointerException;
{
SAVE_PC();
throw new java::lang::NullPointerException;
}
fun = (void (*)()) rmeth->method->ncode;
@ -2868,7 +2850,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
// We don't use NULLCHECK here because we can't rely on that
// working for <init>. So instead we do an explicit test.
if (! sp[0].o)
throw new java::lang::NullPointerException;
{
SAVE_PC();
throw new java::lang::NullPointerException;
}
fun = (void (*)()) rmeth->method->ncode;
}
goto perform_invoke;
@ -2878,7 +2863,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@ -2908,7 +2893,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
rmeth = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).rmethod;
sp -= rmeth->stack_item_count;
@ -2952,7 +2937,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_new:
{
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
@ -2986,7 +2971,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_anewarray:
{
int index = GET2U ();
jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
jclass klass = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
int size = POPI();
jobject result = _Jv_NewObjectArray (size, klass, 0);
@ -3027,9 +3012,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_checkcast:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
if (value != NULL && ! to->isInstance (value))
@ -3047,6 +3033,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#ifdef DIRECT_THREADED
checkcast_resolved:
{
SAVE_PC();
jobject value = POPA ();
jclass to = (jclass) AVAL ();
if (value != NULL && ! to->isInstance (value))
@ -3058,9 +3045,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_instanceof:
{
SAVE_PC();
jobject value = POPA();
jint index = GET2U ();
jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
jclass to = (_Jv_Linker::resolve_pool_entry (meth->defining_class,
index)).clazz;
PUSHI (to->isInstance (value));
@ -3123,7 +3111,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
int dim = GET1U ();
jclass type
= (_Jv_Linker::resolve_pool_entry (defining_class,
= (_Jv_Linker::resolve_pool_entry (meth->defining_class,
kind_index)).clazz;
jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim);
@ -3212,10 +3200,10 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#else
int logical_pc = pc - 1 - bytecode ();
#endif
_Jv_InterpException *exc = exceptions ();
_Jv_InterpException *exc = meth->exceptions ();
jclass exc_class = ex->getClass ();
for (int i = 0; i < exc_count; i++)
for (int i = 0; i < meth->exc_count; i++)
{
if (PCVAL (exc[i].start_pc) <= logical_pc
&& logical_pc < PCVAL (exc[i].end_pc))
@ -3272,6 +3260,21 @@ throw_null_pointer_exception ()
}
#endif
/* Look up source code line number for given bytecode (or direct threaded
interpreter) PC. */
int
_Jv_InterpMethod::get_source_line(pc_t mpc)
{
int line = line_table_len > 0 ? line_table[0].line : -1;
for (int i = 1; i < line_table_len; i++)
if (line_table[i].pc > mpc)
break;
else
line = line_table[i].line;
return line;
}
/** Do static initialization for fields with a constant initializer */
void
_Jv_InitField (jobject obj, jclass klass, int index)

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

View File

@ -147,10 +147,10 @@ unblock_signal (int signum __attribute__ ((__unused__)))
#ifdef HANDLE_SEGV
SIGNAL_HANDLER (catch_segv)
{
java::lang::NullPointerException *nullp
= new java::lang::NullPointerException;
unblock_signal (SIGSEGV);
MAKE_THROW_FRAME (nullp);
java::lang::NullPointerException *nullp
= new java::lang::NullPointerException;
throw nullp;
}
#endif
@ -158,14 +158,14 @@ SIGNAL_HANDLER (catch_segv)
#ifdef HANDLE_FPE
SIGNAL_HANDLER (catch_fpe)
{
java::lang::ArithmeticException *arithexception
= new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
unblock_signal (SIGFPE);
#ifdef HANDLE_DIVIDE_OVERFLOW
HANDLE_DIVIDE_OVERFLOW;
#else
MAKE_THROW_FRAME (arithexception);
#endif
java::lang::ArithmeticException *arithexception
= new java::lang::ArithmeticException (JvNewStringLatin1 ("/ by zero"));
throw arithexception;
}
#endif

527
libjava/stacktrace.cc Normal file
View File

@ -0,0 +1,527 @@
// stacktrace.cc - Functions for unwinding & inspecting the call stack.
/* Copyright (C) 2005 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 <jvm.h>
#include <gcj/cni.h>
#include <java-interp.h>
#include <java-stack.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <java/lang/Class.h>
#include <java/lang/Long.h>
#include <java/util/ArrayList.h>
#include <java/util/IdentityHashMap.h>
#include <gnu/java/lang/MainThread.h>
#include <gnu/gcj/runtime/NameFinder.h>
#include <sysdep/backtrace.h>
using namespace java::lang;
using namespace java::lang::reflect;
using namespace java::util;
using namespace gnu::gcj::runtime;
struct _Jv_FindCallingClassState: _Jv_UnwindState
{
jclass result;
};
// Maps ncode values to their containing native class.
// NOTE: Currently this Map contradicts class GC for native classes. This map
// (and the "new class stack") will need to use WeakReferences in order to
// enable native class GC.
static java::util::IdentityHashMap *ncodeMap;
// Check the "class stack" for any classes initialized since we were last
// called, and add them to ncodeMap.
void
_Jv_StackTrace::UpdateNCodeMap ()
{
// The Map should be large enough so that a typical Java app doesn't cause
// it to rehash, without using too much memory. ~5000 entries should be
// enough.
if (ncodeMap == NULL)
ncodeMap = new java::util::IdentityHashMap (5087);
jclass klass;
while ((klass = _Jv_PopClass ()))
{
//printf ("got %s\n", klass->name->data);
#ifdef INTERPRETER
JvAssert (! _Jv_IsInterpretedClass (klass));
#endif
for (int i=0; i < klass->method_count; i++)
{
_Jv_Method *method = &klass->methods[i];
// Add non-abstract methods to ncodeMap.
if (method->ncode)
{
//printf("map->put 0x%x / %s.%s\n", method->ncode, klass->name->data,
// method->name->data);
ncodeMap->put ((java::lang::Object *) method->ncode, klass);
}
}
}
}
// Given a native frame, return the class which this code belongs
// to. Returns NULL if this IP is not associated with a native Java class.
// If NCODE is supplied, it will be set with the ip for the entry point of the
// enclosing method.
jclass
_Jv_StackTrace::ClassForFrame (_Jv_StackFrame *frame)
{
JvAssert (frame->type == frame_native);
jclass klass = NULL;
// use _Unwind_FindEnclosingFunction to find start of method
//void *entryPoint = _Unwind_FindEnclosingFunction (ip);
// look it up in ncodeMap
if (frame->start_ip)
klass = (jclass) ncodeMap->get ((jobject) frame->start_ip);
return klass;
}
_Unwind_Reason_Code
_Jv_StackTrace::UnwindTraceFn (struct _Unwind_Context *context, void *state_ptr)
{
_Jv_UnwindState *state = (_Jv_UnwindState *) state_ptr;
jint pos = state->pos;
// Check if the trace buffer needs to be extended.
if (pos == state->length)
{
int newLength = state->length *= 2;
void *newFrames = _Jv_AllocBytes (newLength * sizeof(_Jv_StackFrame));
memcpy (newFrames, state->frames, state->length * sizeof(_Jv_StackFrame));
state->frames = (_Jv_StackFrame *) newFrames;
state->length = newLength;
}
_Unwind_Ptr func_addr = _Unwind_GetRegionStart (context);
// If we see the interpreter's main function, "pop" an entry off the
// interpreter stack and use that instead, so that the trace goes through
// the java code and not the interpreter itself. This assumes a 1:1
// correspondance between call frames in the interpreted stack and occurances
// of _Jv_InterpMethod::run() on the native stack.
if (func_addr == (_Unwind_Ptr) &_Jv_InterpMethod::run)
{
state->frames[pos].type = frame_interpreter;
state->frames[pos].interp.meth = state->interp_frame->self;
state->frames[pos].interp.pc = state->interp_frame->pc;
state->interp_frame = state->interp_frame->next;
}
else
{
state->frames[pos].type = frame_native;
state->frames[pos].ip = (void *) _Unwind_GetIP (context);
state->frames[pos].start_ip = (void *) func_addr;
}
//printf ("unwind ip: %p\n", _Unwind_GetIP (context));
_Unwind_Reason_Code result = _URC_NO_REASON;
if (state->trace_function != NULL)
result = (state->trace_function) (state);
state->pos++;
return result;
}
// Return a raw stack trace from the current point of execution. The raw
// trace will include all functions that have unwind info.
_Jv_StackTrace *
_Jv_StackTrace::GetStackTrace(void)
{
int trace_size = 100;
_Jv_StackFrame frames[trace_size];
_Jv_UnwindState state (trace_size);
state.frames = (_Jv_StackFrame *) &frames;
#ifdef SJLJ_EXCEPTIONS
// The Unwind interface doesn't work with the SJLJ exception model.
// Fall back to a platform-specific unwinder.
fallback_backtrace (&state);
#else /* SJLJ_EXCEPTIONS */
_Unwind_Backtrace (UnwindTraceFn, &state);
#endif /* SJLJ_EXCEPTIONS */
// Copy the trace and return it.
int traceSize = sizeof (_Jv_StackTrace) +
(sizeof (_Jv_StackFrame) * state.pos);
_Jv_StackTrace *trace = (_Jv_StackTrace *) _Jv_AllocBytes (traceSize);
trace->length = state.pos;
memcpy (trace->frames, state.frames, sizeof (_Jv_StackFrame) * state.pos);
return trace;
}
void
_Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
jstring *sourceFileName, jint *lineNum)
{
if (frame->type == frame_interpreter)
{
_Jv_InterpMethod *interp_meth = frame->interp.meth;
_Jv_InterpClass *interp_class =
(_Jv_InterpClass *) interp_meth->defining_class->aux_info;
*sourceFileName = interp_class->source_file_name;
*lineNum = interp_meth->get_source_line(frame->interp.pc);
return;
}
// Use dladdr() to determine in which binary the address IP resides.
#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
extern char **_Jv_argv;
Dl_info info;
jstring binaryName = NULL;
void *ip = frame->ip;
_Unwind_Ptr offset = 0;
if (dladdr (ip, &info))
{
if (info.dli_fname)
binaryName = JvNewStringUTF (info.dli_fname);
else
return;
// addr2line expects relative addresses for shared libraries.
if (strcmp (info.dli_fname, _Jv_argv[0]) == 0)
offset = (_Unwind_Ptr) ip;
else
offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
//printf ("linenum ip: %p\n", ip);
//printf ("%s: 0x%x\n", info.dli_fname, offset);
//offset -= sizeof(void *);
// The unwinder gives us the return address. In order to get the right
// line number for the stack trace, roll it back a little.
offset -= 1;
// printf ("%s: 0x%x\n", info.dli_fname, offset);
finder->lookup (binaryName, (jlong) offset);
*sourceFileName = finder->getSourceFile();
*lineNum = finder->getLineNum();
}
#endif
}
// Look up class and method info for the given stack frame, setting
// frame->klass and frame->meth if they are known.
void
_Jv_StackTrace::FillInFrameInfo (_Jv_StackFrame *frame)
{
jclass klass = NULL;
_Jv_Method *meth = NULL;
if (frame->type == frame_native)
{
klass = _Jv_StackTrace::ClassForFrame (frame);
if (klass != NULL)
// Find method in class
for (int j = 0; j < klass->method_count; j++)
{
if (klass->methods[j].ncode == frame->start_ip)
{
meth = &klass->methods[j];
break;
}
}
}
else if (frame->type == frame_interpreter)
{
_Jv_InterpMethod *interp_meth = frame->interp.meth;
klass = interp_meth->defining_class;
meth = interp_meth->self;
}
else
JvFail ("Unknown frame type");
frame->klass = klass;
frame->meth = meth;
}
// Convert raw stack frames to a Java array of StackTraceElement objects.
JArray< ::java::lang::StackTraceElement *>*
_Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
Throwable *throwable __attribute__((unused)))
{
ArrayList *list = new ArrayList ();
#ifdef SJLJ_EXCEPTIONS
// We can't use the nCodeMap without unwinder support. Instead,
// fake the method name by giving the IP in hex - better than nothing.
jstring hex = JvNewStringUTF ("0x");
for (int i = 0; i < trace->length; i++)
{
jstring sourceFileName = NULL;
jint lineNum = -1;
_Jv_StackFrame *frame = &trace->frames[i];
jstring className = NULL;
jstring methodName = hex->concat (Long::toHexString ((jlong) frame->ip));
StackTraceElement *element = new StackTraceElement (sourceFileName,
lineNum, className, methodName, 0);
list->add (element);
}
#else /* SJLJ_EXCEPTIONS */
//JvSynchronized (ncodeMap);
UpdateNCodeMap ();
NameFinder *finder = new NameFinder();
int start_idx = 0;
int end_idx = trace->length - 1;
// First pass: strip superfluous frames from beginning and end of the trace.
for (int i = 0; i < trace->length; i++)
{
_Jv_StackFrame *frame = &trace->frames[i];
FillInFrameInfo (frame);
if (!frame->klass || !frame->meth)
// Not a Java frame.
continue;
// Throw away the top of the stack till we see:
// - the constructor(s) of this Throwable, or
// - the Throwable.fillInStackTrace call.
if (frame->klass == throwable->getClass()
&& strcmp (frame->meth->name->chars(), "<init>") == 0)
start_idx = i + 1;
if (frame->klass == &Throwable::class$
&& strcmp (frame->meth->name->chars(), "fillInStackTrace") == 0)
start_idx = i + 1;
// End the trace at the application's main() method if we see call_main.
if (frame->klass == &gnu::java::lang::MainThread::class$
&& strcmp (frame->meth->name->chars(), "call_main") == 0)
end_idx = i - 1;
}
// Second pass: Look up line-number info for remaining frames.
for (int i = start_idx; i <= end_idx; i++)
{
_Jv_StackFrame *frame = &trace->frames[i];
if (frame->klass == NULL)
// Not a Java frame.
continue;
jstring className = frame->klass->getName ();
jstring methodName = NULL;
if (frame->meth)
methodName = JvNewStringUTF (frame->meth->name->chars());
jstring sourceFileName = NULL;
jint lineNum = -1;
getLineNumberForFrame(frame, finder, &sourceFileName, &lineNum);
StackTraceElement *element = new StackTraceElement (sourceFileName, lineNum,
className, methodName, 0);
list->add (element);
}
finder->close();
#endif /* SJLJ_EXCEPTIONS */
JArray<Object *> *array = JvNewObjectArray (list->size (),
&StackTraceElement::class$, NULL);
return (JArray<StackTraceElement *>*) list->toArray (array);
}
struct CallingClassTraceData
{
jclass checkClass;
jclass foundClass;
_Jv_Method *foundMeth;
bool seen_checkClass;
};
_Unwind_Reason_Code
_Jv_StackTrace::calling_class_trace_fn (_Jv_UnwindState *state)
{
CallingClassTraceData *trace_data = (CallingClassTraceData *)
state->trace_data;
_Jv_StackFrame *frame = &state->frames[state->pos];
FillInFrameInfo (frame);
if (trace_data->seen_checkClass
&& frame->klass
&& frame->klass != trace_data->checkClass)
{
trace_data->foundClass = frame->klass;
trace_data->foundMeth = frame->meth;
return _URC_NORMAL_STOP;
}
if (frame->klass == trace_data->checkClass)
trace_data->seen_checkClass = true;
return _URC_NO_REASON;
}
// Find the class immediately above the given class on the call stack. Any
// intermediate non-Java
// frames are ignored. If the calling class could not be determined (eg because
// the unwinder is not supported on this platform), NULL is returned.
// This function is used to implement calling-classloader checks and reflection
// accessibility checks.
// CHECKCLASS is typically the class calling GetCallingClass. The first class
// above CHECKCLASS on the call stack will be returned.
jclass
_Jv_StackTrace::GetCallingClass (jclass checkClass)
{
jclass result = NULL;
GetCallerInfo (checkClass, &result, NULL);
return result;
}
void
_Jv_StackTrace::GetCallerInfo (jclass checkClass, jclass *caller_class,
_Jv_Method **caller_meth)
{
#ifndef SJLJ_EXCEPTIONS
int trace_size = 20;
_Jv_StackFrame frames[trace_size];
_Jv_UnwindState state (trace_size);
state.frames = (_Jv_StackFrame *) &frames;
CallingClassTraceData trace_data;
trace_data.checkClass = checkClass;
trace_data.seen_checkClass = false;
trace_data.foundClass = NULL;
trace_data.foundMeth = NULL;
state.trace_function = calling_class_trace_fn;
state.trace_data = (void *) &trace_data;
//JvSynchronized (ncodeMap);
UpdateNCodeMap ();
_Unwind_Backtrace (UnwindTraceFn, &state);
if (caller_class)
*caller_class = trace_data.foundClass;
if (caller_meth)
*caller_meth = trace_data.foundMeth;
#else
return NULL;
#endif
}
// Return a java array containing the Java classes on the stack above CHECKCLASS.
JArray<jclass> *
_Jv_StackTrace::GetClassContext (jclass checkClass)
{
JArray<jclass> *result = NULL;
int trace_size = 100;
_Jv_StackFrame frames[trace_size];
_Jv_UnwindState state (trace_size);
state.frames = (_Jv_StackFrame *) &frames;
//JvSynchronized (ncodeMap);
UpdateNCodeMap ();
_Unwind_Backtrace (UnwindTraceFn, &state);
// Count the number of Java frames on the stack.
int jframe_count = 0;
bool seen_checkClass = false;
int start_pos = -1;
for (int i = 0; i < state.pos; i++)
{
_Jv_StackFrame *frame = &state.frames[i];
FillInFrameInfo (frame);
if (seen_checkClass
&& frame->klass
&& frame->klass != checkClass)
{
jframe_count++;
if (start_pos == -1)
start_pos = i;
}
if (!seen_checkClass
&& frame->klass
&& frame->klass == checkClass)
seen_checkClass = true;
}
result = (JArray<jclass> *) _Jv_NewObjectArray (jframe_count, &Class::class$, NULL);
int pos = 0;
for (int i = start_pos; i < state.pos; i++)
{
_Jv_StackFrame *frame = &state.frames[i];
if (frame->klass)
elements(result)[pos++] = frame->klass;
}
return result;
}
_Unwind_Reason_Code
_Jv_StackTrace::non_system_trace_fn (_Jv_UnwindState *state)
{
_Jv_StackFrame *frame = &state->frames[state->pos];
FillInFrameInfo (frame);
ClassLoader *classLoader = NULL;
if (frame->klass)
{
classLoader = frame->klass->getClassLoaderInternal();
if (classLoader != NULL && classLoader != ClassLoader::systemClassLoader)
{
state->trace_data = (void *) classLoader;
return _URC_NORMAL_STOP;
}
}
return _URC_NO_REASON;
}
ClassLoader *
_Jv_StackTrace::GetFirstNonSystemClassLoader ()
{
int trace_size = 32;
_Jv_StackFrame frames[trace_size];
_Jv_UnwindState state (trace_size);
state.frames = (_Jv_StackFrame *) &frames;
state.trace_function = non_system_trace_fn;
state.trace_data = NULL;
//JvSynchronized (ncodeMap);
UpdateNCodeMap ();
_Unwind_Backtrace (UnwindTraceFn, &state);
if (state.trace_data)
return (ClassLoader *) state.trace_data;
return NULL;
}

View File

@ -0,0 +1,22 @@
// backtrace.h - Fallback backtrace implementation. default implementation.
/* Copyright (C) 2005 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. */
#ifndef __SYSDEP_BACKTRACE_H__
#define __SYSDEP_BACKTRACE_H__
#include <java-stack.h>
/* Store return addresses of the current program stack in
STATE and return the exact number of values stored. */
void
fallback_backtrace (_Jv_UnwindState *)
{
}
#endif

View File

@ -0,0 +1,42 @@
// backtrace.h - Fallback backtrace implementation. i386 implementation.
/* Copyright (C) 2005 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. */
#ifndef __SYSDEP_BACKTRACE_H__
#define __SYSDEP_BACKTRACE_H__
#include <java-stack.h>
#define HAVE_FALLBACK_BACKTRACE
/* Store return addresses of the current program stack in
STATE and return the exact number of values stored. */
void
fallback_backtrace (_Jv_UnwindState *state)
{
register void *_ebp __asm__ ("ebp");
register void *_esp __asm__ ("esp");
unsigned int *rfp;
int i = state->pos;
for (rfp = *(unsigned int**)_ebp;
rfp && i < state->length;
rfp = *(unsigned int **)rfp)
{
int diff = *rfp - (unsigned int)rfp;
if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
break;
state->frames[i].type = frame_native;
state->frames[i].ip = (void*)(rfp[1]-4);
i++;
}
state->pos = i;
}
#endif