This is the mail archive of the mailing list for the Java project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows

Hash: SHA1


  When run under the interpreter, an exception-throwing programme
crashes the interpreter on Windows since JvRunMain() does not
occur in the call stack and we once again roam the wilderness of
arbitrary EBP values.

The fix was to change fallback_backtrace() in
"sysdep/i386/backtrace.h" to stop on _Jv_RunMain() instead since
this does occur in both interpreted and natively-executed call
stacks. (Since this function is overloaded, I needed to use an
interim variable with the appropriate cast to tell the compiler
which of these function variants to pick up.)

fallback_backtrace() also does not correctly handle unwinding
through interpreted code. The fix was as simple as copying the
relevant bits of code from _Jv_StackTrace::Unwind_TraceFn() and
adjusting it a little bit.

This exposed the fact that _Jv_InterpMethod::run() is a private
method. Therefore I had to declare fallback_backtrace() as
a friend function for this class (similar to that for the
_Jv_StackTrace class). This declaration is done only if
HAVE_FALLBACK_BACKTRACE is defined. This definition in turn was
moved out of "sysdep/i386/backtrace.h" to, where
it is added to libgcj_cxxflags (this jugglery avoids having to deal
with included file ordering issues).

The attached patch contains all these changes. Note that it also
contains the "sysdep/i386/backtrace.h" changes from:

purely as a matter of convenience for yours truly.

With this patch, we now get proper stack traces for interpreted
code also on Windows. (I note that under the interpreter we do
not get line numbers for the innermost call frame, even on Linux.
I haven't investigated this issue yet.)

Tested via a crossed-native i686-pc-mingw32 compiler built on

OK to apply?


- --
Ranjit Mathew       Email: rmathew AT gmail DOT com

Bangalore, INDIA.     Web:

Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Using GnuPG with Mozilla -

Index: ChangeLog
from  Ranjit Mathew  <>

	* Add a definition of HAVE_FALLBACK_BACKTRACE to
	libgcj_cxxflags for Windows.
	* include/java-interp.h (_Jv_InterpMethod): Declare
	fallback_backtrace() as a friend function.
	* sysdep/i386/backtrace.h: Do not define HAVE_FALLBACK_BACKTRACE.
	(fallback_backtrace): If we see _Jv_InterpMethod::run(), make sure
	the trace goes through the interpreted java stack.
	Stop unwinding when we see _Jv_RunMain().

---	(revision 115260)
+++	(working copy)
@@ -283,6 +283,7 @@ esac
 case "${host}" in
   *-cygwin* | *-mingw*)
+	libgcj_cxxflags="${libgcj_cxxflags} -DHAVE_FALLBACK_BACKTRACE"
 	# We need a frame pointer on Windows, so override BACKTRACESPEC
Index: include/java-interp.h
--- include/java-interp.h	(revision 115260)
+++ include/java-interp.h	(working copy)
@@ -34,6 +34,11 @@ details.  */
 struct _Jv_ResolvedMethod;
+struct _Jv_UnwindState;
+extern "C" void fallback_backtrace (_Jv_UnwindState *);
 void _Jv_InitInterpreter ();
 void _Jv_DefineClass (jclass, jbyteArray, jint, jint,
 		      java::security::ProtectionDomain *,
@@ -209,6 +214,10 @@ class _Jv_InterpMethod : public _Jv_Meth
   friend class _Jv_StackTrace;
   friend class _Jv_InterpreterEngine;
+  friend void fallback_backtrace (_Jv_UnwindState *);
   friend JV_MARKOBJ_DECL;
Index: sysdep/i386/backtrace.h
--- sysdep/i386/backtrace.h	(revision 115261)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -13,8 +13,6 @@ details.  */
 #include <java-stack.h>
 /* Store return addresses of the current program stack in
    STATE and return the exact number of values stored.  */
@@ -65,17 +63,44 @@ fallback_backtrace (_Jv_UnwindState *sta
           if (scan_bytes[0] == 0x55 && scan_bytes[1] == 0x89
               && scan_bytes[2] == 0xE5)
-              state->frames[i].start_ip = (void *)scan_addr;
+              // 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.
+            #ifdef INTERPRETER
+              void *interp_run = (void *) &_Jv_InterpMethod::run;
+              if ((void *)scan_addr == interp_run)
+                {
+                  state->frames[i].type = frame_interpreter;
+                  state->frames[i].interp.meth = state->interp_frame->self;
+                  state->frames[i].interp.pc = state->interp_frame->pc;
+                  state->interp_frame = state->interp_frame->next;
+                }
+              else
+            #endif /* INTERPRETER */
+                {
+                  state->frames[i].start_ip = (void *)scan_addr;
+                }
+              // If we have a trace callback function, call it now.
+              if (state->trace_function != NULL)
+                (state->trace_function) (state);
-      /* No need to unwind beyond JvRunMain().  */
-      if (state->frames[i].start_ip == (void *)JvRunMain)
+      /* No need to unwind beyond _Jv_RunMain().  */
+      void *jv_runmain
+        = (void *)(void (*)(JvVMInitArgs *, jclass, const char *, int,
+                            const char **, bool))_Jv_RunMain;
+      if (state->frames[i].start_ip == jv_runmain)
+      state->pos = i;
-  state->pos = i;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]