This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
- From: Ranjit Mathew <rmathew at gmail dot com>
- To: java-patches at gcc dot gnu dot org
- Date: Sun, 09 Jul 2006 14:49:53 +0530
- Subject: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
- Openpgp: url=http://ranjitmathew.hostingzero.com/aa_6C114B8F.txt
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hello,
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 configure.host, 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:
http://gcc.gnu.org/ml/java-patches/2006-q3/msg00098.html
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
i686-pc-linux-gnu.
OK to apply?
Thanks,
Ranjit.
- --
Ranjit Mathew Email: rmathew AT gmail DOT com
Bangalore, INDIA. Web: http://rmathew.com/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFEsMo5Yb1hx2wRS48RAmZmAJsHu0Iyx3r9W4ILKg27BMBDC1sOZwCgix8m
CFfW9c39jTSvqNxoH6lBLxY=
=wLCp
-----END PGP SIGNATURE-----
Index: ChangeLog
from Ranjit Mathew <rmathew@gcc.gnu.org>
* configure.host: 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().
Index: configure.host
===================================================================
--- configure.host (revision 115260)
+++ configure.host (working copy)
@@ -283,6 +283,7 @@ esac
case "${host}" in
*-cygwin* | *-mingw*)
fallback_backtrace_h=sysdep/i386/backtrace.h
+ libgcj_cxxflags="${libgcj_cxxflags} -DHAVE_FALLBACK_BACKTRACE"
# We need a frame pointer on Windows, so override BACKTRACESPEC
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;
+#ifdef HAVE_FALLBACK_BACKTRACE
+struct _Jv_UnwindState;
+extern "C" void fallback_backtrace (_Jv_UnwindState *);
+#endif
+
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;
+#ifdef HAVE_FALLBACK_BACKTRACE
+ friend void fallback_backtrace (_Jv_UnwindState *);
+#endif
+
#ifdef JV_MARKOBJ_DECL
friend JV_MARKOBJ_DECL;
#endif
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>
-#define HAVE_FALLBACK_BACKTRACE
-
/* Store return addresses of the current program stack in
STATE and return the exact number of values stored. */
void
@@ -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);
+
break;
}
}
- /* 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)
break;
i++;
+ state->pos = i;
}
- state->pos = i;
}
#endif