diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index b74f0edd7bd731e9cea5005ab24253ff6ade869f..b92bf687e695029ca0cff7685086ff0843f236de 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -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.
diff --git a/libjava/Makefile.am b/libjava/Makefile.am
index cd6f0b3aa6479f390f9cb9765c25d7ae56650cda..920b05bd9af2eb8234b9c0d85f78293cfa986aa6 100644
--- a/libjava/Makefile.am
+++ b/libjava/Makefile.am
@@ -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 \
diff --git a/libjava/Makefile.in b/libjava/Makefile.in
index 4e114c7dc97ada1aa4f67e1d9180400fb099a22b..4be41130c88a2ce71a4c38f56b817696b5d94cd6 100644
--- a/libjava/Makefile.in
+++ b/libjava/Makefile.in
@@ -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)
diff --git a/libjava/configure b/libjava/configure
index f8fb203b9f96e2145abaa887a81d733b4b442e39..980f4a4e567760900ef526e6b81e8aef4985f97b 100755
--- a/libjava/configure
+++ b/libjava/configure
@@ -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" ;;
diff --git a/libjava/configure.ac b/libjava/configure.ac
index 6fcfe6d143695029049693dc78a1e549c3e48028..2e40268038a24d35cce39a4ae03d985b4b72de5c 100644
--- a/libjava/configure.ac
+++ b/libjava/configure.ac
@@ -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.
diff --git a/libjava/configure.host b/libjava/configure.host
index 583b4e2e015908591994bd6cfbbe4a58d7027941..4d4c6e311bfabc7e0f12eaf77e30c95be26dd3c3 100644
--- a/libjava/configure.host
+++ b/libjava/configure.host
@@ -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}"
diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc
index 382b321f5918b55efed04a80d9ff6da8aacf9756..111b1fb2ca2fb83120b23cdb293c8f4531783524 100644
--- a/libjava/defineclass.cc
+++ b/libjava/defineclass.cc
@@ -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 (),
diff --git a/libjava/exception.cc b/libjava/exception.cc
index 088d48268e3da54e7749bce020f9e95379e11f2d..ef7292c3bf755d5b6e8583f7f7b7458fe89a1f85 100644
--- a/libjava/exception.cc
+++ b/libjava/exception.cc
@@ -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>
diff --git a/libjava/gnu/classpath/Configuration.java.in b/libjava/gnu/classpath/Configuration.java.in
index 5a4b97e803292cf6f1f81da82cbbe892b3dcf422..68d9a4782610e69e42355d98e236f17882eb8325 100644
--- a/libjava/gnu/classpath/Configuration.java.in
+++ b/libjava/gnu/classpath/Configuration.java.in
@@ -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;
diff --git a/libjava/gnu/gcj/runtime/NameFinder.java b/libjava/gnu/gcj/runtime/NameFinder.java
index b14bbf933273afd69933903cce57b7accfc7986d..5469f08168d6bd8979908176a52ad707d8d0efbd 100644
--- a/libjava/gnu/gcj/runtime/NameFinder.java
+++ b/libjava/gnu/gcj/runtime/NameFinder.java
@@ -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()
-	     );
-
-  private static final boolean use_addr2line
-	  = Boolean.valueOf(System.getProperty
-		("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
-	    ).booleanValue();
-
-  /**
-   * The name of the currently running executable.
-   */
-  private final String executable;
-
-  /**
-   * Process used for demangling names.
-   */
-  private Process cppfilt;
-
-  private BufferedWriter cppfiltOut;
-  private BufferedReader cppfiltIn;
-
   /**
-   * Process used for translating addresses to function/file names.
+   * The name of the binary to look up.
    */
-  private Process addr2line;
+  private String binaryFile;
+  private String sourceFile;
+  private int lineNum;
+  private HashMap procs = new HashMap();
 
-  private BufferedWriter addr2lineOut;
-  private BufferedReader addr2lineIn;
-
-  /**
-   * Flag set if using addr2name.awk instead of addr2line from binutils.
-   */
-  private boolean usingAddr2name = false;
+  private static final boolean use_addr2line
+          = Boolean.valueOf(System.getProperty
+                ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
+            ).booleanValue();
 
-  /**
-   * Creates a new NameFinder. Call close to get rid of any resources
-   * created while using the <code>lookup</code> methods.
-   */
-  public NameFinder()
+  class Addr2Line
   {
-    executable = getExecutable();
-    Runtime runtime = Runtime.getRuntime();
-    if (demangle)
+    Process proc;
+    BufferedWriter out;
+    BufferedReader in;
+
+    Addr2Line(String binaryFile)
     {
       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()));
-	}
+      {
+	String[] exec = new String[] {"addr2line", "-e", binaryFile};
+	Runtime runtime = Runtime.getRuntime();
+	proc = runtime.exec(exec);
+      }
       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.
-   */
-  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)
-  {
-    StackTraceElement result;
-
-    result = lookupInterp(addrs, n);
-    if (result == null)
-      result = dladdrLookup(addrs, n);
-    if (result == null)
+      if (proc != 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);
+	in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+	out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
+      }
+    }
+    
+    void close()
+    {
+      try
+      {
+	in.close();
+	out.close();
       }
+      catch (IOException x) {}
 
-    return result;
+      proc.destroy();
+    }
   }
 
   /**
-   * Given an Throwable and a native stacktrace returns an array of
-   * StackTraceElement containing class, method, file and linenumbers.
+   * 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 StackTraceElement[] lookup(Throwable t, StackTrace trace)
+  public NameFinder()
   {
-    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);
-    else
-      return elements;
   }
 
-  
   /**
-   * Removes calls to initialize exceptions and the runtime system from
-   * the stack trace including stack frames of which nothing usefull is known.
-   * Throw away the top of the stack till we find the constructor(s)
-   * of this Throwable or at least the contructors of java.lang.Throwable
-   * or the actual fillInStackTrace call.
-   * Also throw away from the top everything before and including a runtime
-   * _Jv_Throw call.
+   * Returns the source file name if lookup() was successful. If the source file could not be 
+   * determined, the binary name will be returned instead.
    */
-  private static StackTraceElement[] sanitizeStack(StackTraceElement[] elements,
-						   Throwable t)
+  public String getSourceFile()
   {
-    StackTraceElement[] stack;
-
-    String className = t.getClass().getName();
-    String consName;
-    int lastDot = className.lastIndexOf('.');
-    if (lastDot == -1)
-      consName = className + '(';
+    String file;
+    if (sourceFile != null)
+      file = sourceFile;
     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++)
-      {
-	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;
-	  }
-      }
-    int begin = last_throw+1;
-
-    // Now filter out everything at the start and the end that is not part
-    // of the "normal" user program including any elements that 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)
-      {
-	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;
-
-    return stack;
+      file = binaryFile;
+    
+    return file.substring(file.lastIndexOf(File.separator) + 1, file.length());
   }
 
   /**
-   * 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 lookup() was successful, returns the line number of addr. If the line number could not
+   * be determined, -1 is returned.
+   */  
+  public int getLineNum()
   {
-    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)
+    return lineNum;
+  }
+  
+  public void lookup (String file, long addr)
+  {
+    binaryFile = file;
+    sourceFile = null;
+    lineNum = -1;
+    
+    if (! use_addr2line)
+      return;
+    Addr2Line addr2line = (Addr2Line) procs.get(file);
+    if (addr2line == null)
       {
-	int dot = s.lastIndexOf('.', bracket);
-	if (dot > 0)
-	  {
-	    className = s.substring(0, dot);
-	    methodName = s.substring(dot+1, s.length());
-	  }
+      addr2line = new Addr2Line(file);
+      procs.put(file, addr2line);
       }
-
-    String fileName = file;
-    int line = -1;
-    if (fileName != null)
+    
+    if (addr2line.proc == null)      
+      return;
+    
+    String hexAddr = "0x" + Long.toHexString(addr);
+    String name;
+
+    try
       {
-	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 */ }
-	  }
+      addr2line.out.write(hexAddr);
+      addr2line.out.newLine();
+      addr2line.out.flush();
+      String result = addr2line.in.readLine();
 
-	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();
+      }
   }
 }
diff --git a/libjava/gnu/java/lang/MainThread.java b/libjava/gnu/java/lang/MainThread.java
index 14a00ca8d9b1be8e19d59ff5dfd9883f26c1e785..44c20ff94d25cd42d6445f159ee2fec35d10349d 100644
--- a/libjava/gnu/java/lang/MainThread.java
+++ b/libjava/gnu/java/lang/MainThread.java
@@ -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();
 }
diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h
index 4126c2f44cd036bca23174a702aa107141bedcd4..569286116ee5c4be1522f4e8990aee69301bd8f2 100644
--- a/libjava/include/java-interp.h
+++ b/libjava/include/java-interp.h
@@ -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;
   }
diff --git a/libjava/include/java-stack.h b/libjava/include/java-stack.h
index 6c3103ce05682d0eed6f003dadfed5bb18f58288..2d914cb9ba73d5461dd25eb6509ce8a2806a4c26 100644
--- a/libjava/include/java-stack.h
+++ b/libjava/include/java-stack.h
@@ -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__ */
diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h
index 7668703f54c2b2d22afe8a7eee1a0a42e5030e2f..4dfdb4d3767641a1f9e5d28733cde7cdfd043c83 100644
--- a/libjava/include/jvm.h
+++ b/libjava/include/jvm.h
@@ -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.
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
index 4c547b35dd6b5f3c34bdf1107f5e9dff61036f89..a2bcbb84084bd5937ee90ca56ac0a66790b64c70 100644
--- a/libjava/interpret.cc
+++ b/libjava/interpret.cc
@@ -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)
diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h
index d7b21e76b05bc613dbfa776a8e71719f8e7a5a00..46feff6280c2783928df8afdcf087202dabe7820 100644
--- a/libjava/java/lang/Class.h
+++ b/libjava/java/lang/Class.h
@@ -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;
diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java
index e21bb649542659b6fdad016b05f3502377c3dc6f..c0739ba7e7ccbaf52a9824f430214678866212d6 100644
--- a/libjava/java/lang/VMClassLoader.java
+++ b/libjava/java/lang/VMClassLoader.java
@@ -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;
diff --git a/libjava/java/lang/VMThrowable.java b/libjava/java/lang/VMThrowable.java
index 102916a5d7cbdf7925c76699a3bb88c50a8cc87f..f3b079a566ebfe1fbe399f1db6953be427f67740 100644
--- a/libjava/java/lang/VMThrowable.java
+++ b/libjava/java/lang/VMThrowable.java
@@ -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;
 }
diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc
index f29f66747649c7db984ab6309a769d24fd82bd5c..25343e38b056945b78184b76f2b5b26d7817ac37 100644
--- a/libjava/java/lang/natClass.cc
+++ b/libjava/java/lang/natClass.cc
@@ -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
diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc
index 97a69b27f282f2876a8b800f3a5c3a7234eb0fb5..d013878834dca5b0895ba2b95535d01eb848885a 100644
--- a/libjava/java/lang/natRuntime.cc
+++ b/libjava/java/lang/natRuntime.cc
@@ -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)
 	{
diff --git a/libjava/java/lang/natVMSecurityManager.cc b/libjava/java/lang/natVMSecurityManager.cc
index 8fd2875aedcd04c1eb45a4a30643b0678016f9c7..d55b7a54c3a938e5f2513aed49d8462fd69f0436 100644
--- a/libjava/java/lang/natVMSecurityManager.cc
+++ b/libjava/java/lang/natVMSecurityManager.cc
@@ -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;
 }
diff --git a/libjava/java/lang/natVMThrowable.cc b/libjava/java/lang/natVMThrowable.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6db1a1fd56d0a85fb1c4ddc4f3db4507a4f3fbbe
--- /dev/null
+++ b/libjava/java/lang/natVMThrowable.cc
@@ -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);
+}
diff --git a/libjava/java/lang/reflect/natArray.cc b/libjava/java/lang/reflect/natArray.cc
index ce76b9c92d4c7045d1e94f4d94ff4d0318e80a77..b7bc8beff88fada8ceaaa0aae211af53bad46d48 100644
--- a/libjava/java/lang/reflect/natArray.cc
+++ b/libjava/java/lang/reflect/natArray.cc
@@ -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++)
diff --git a/libjava/java/lang/reflect/natConstructor.cc b/libjava/java/lang/reflect/natConstructor.cc
index 3697332d1efb0e8d129654b059a58b5c914620ea..f4d95905bfc1a980d502c92b01783ae4180d3c57 100644
--- a/libjava/java/lang/reflect/natConstructor.cc
+++ b/libjava/java/lang/reflect/natConstructor.cc
@@ -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;
     }
diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc
index 9a8107b795d38c4f48130a8cc8d54e30c957f949..33a5717f4b3805b05775f9ec30c1f83536cf51d1 100644
--- a/libjava/java/lang/reflect/natField.cc
+++ b/libjava/java/lang/reflect/natField.cc
@@ -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;
     }
diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc
index 27c26e19ac740fc588fc5e9a278172d6ff41ec7b..4329443146cd270dd685e4fac77ec8bbd4361b70 100644
--- a/libjava/java/lang/reflect/natMethod.cc
+++ b/libjava/java/lang/reflect/natMethod.cc
@@ -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;
     }
diff --git a/libjava/java/util/logging/natLogger.cc b/libjava/java/util/logging/natLogger.cc
index 15d1ab70efd0c1a78f5cc8ce9c0f98dfac69f3a3..e92c487c66f387c8a8566cc7cf4edf9c398180c6 100644
--- a/libjava/java/util/logging/natLogger.cc
+++ b/libjava/java/util/logging/natLogger.cc
@@ -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;
 }
diff --git a/libjava/java/util/natResourceBundle.cc b/libjava/java/util/natResourceBundle.cc
index 35e90ee23d35a9b64b9e09eba0c3b9ade3ae8a93..e8d4fb4fd43a30a1f5bc23e69ffad17047f6a3c4 100644
--- a/libjava/java/util/natResourceBundle.cc
+++ b/libjava/java/util/natResourceBundle.cc
@@ -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;
 }
diff --git a/libjava/prims.cc b/libjava/prims.cc
index cf0fed10dd4654407871b573c692bcc8ceaa07bb..9281711ae89ca025f46d044a5b9ecb1ec1b24fdd 100644
--- a/libjava/prims.cc
+++ b/libjava/prims.cc
@@ -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
diff --git a/libjava/stacktrace.cc b/libjava/stacktrace.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0777d903a2173fa48dedd18252f6ee0761f0aa99
--- /dev/null
+++ b/libjava/stacktrace.cc
@@ -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;
+}
diff --git a/libjava/sysdep/generic/backtrace.h b/libjava/sysdep/generic/backtrace.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe9d68f1b70b732dcbb7d33b59ee639a7663f026
--- /dev/null
+++ b/libjava/sysdep/generic/backtrace.h
@@ -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
diff --git a/libjava/sysdep/i386/backtrace.h b/libjava/sysdep/i386/backtrace.h
new file mode 100644
index 0000000000000000000000000000000000000000..b10840213a4448d2bdb12a7418c9197ef832fc4a
--- /dev/null
+++ b/libjava/sysdep/i386/backtrace.h
@@ -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