public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
@ 2006-07-09  9:19 Ranjit Mathew
  2006-07-11 17:59 ` Bryce McKinlay
  0 siblings, 1 reply; 8+ messages in thread
From: Ranjit Mathew @ 2006-07-09  9:19 UTC (permalink / raw)
  To: java-patches

[-- Attachment #1: Type: text/plain, Size: 2246 bytes --]

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

[-- Attachment #2: p2.txt --]
[-- Type: text/plain, Size: 4113 bytes --]

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-09  9:19 [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows Ranjit Mathew
@ 2006-07-11 17:59 ` Bryce McKinlay
  2006-07-11 18:34   ` Ranjit Mathew
  0 siblings, 1 reply; 8+ messages in thread
From: Bryce McKinlay @ 2006-07-11 17:59 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Hi Ranjit,

Ranjit Mathew wrote:
>   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.)
>   

Only the main thread will have JvRunMain on the stack - you probably 
also need to look for the thread-start routine to handle other threads.

Note that even then there are some situations (invocation API) where 
neither _Jv_RunMain or _Jv_ThreadStart will be on the stack.
> 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 part of the patch is a bit awkward - duplicating the 
interpreter-specific code is fragile and will make maintenance more 
difficult. Couldn't we instead have fallback_backtrace call the real 
UnwindTraceFn? I believe _Unwind_context is an opaque type, so it should 
be possible to have fallback_backtrace pass its own data there.
> (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.)
>   
Hmm. There shouldn't be any problems here (on Linux) - do you have a 
test case?

Bryce

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-11 17:59 ` Bryce McKinlay
@ 2006-07-11 18:34   ` Ranjit Mathew
  2006-07-11 21:34     ` Bryce McKinlay
  0 siblings, 1 reply; 8+ messages in thread
From: Ranjit Mathew @ 2006-07-11 18:34 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

[Apologies if you see this message twice. Gmail's SMTP server is
acting weird.]

Bryce McKinlay wrote:
> Ranjit Mathew wrote:
>>
>> 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.)
>>
>
> Only the main thread will have JvRunMain on the stack - you probably
> also need to look for the thread-start routine to handle other threads.

Good point. So I can stop unwinding when I see either
_Jv_RunMain() or _Jv_ThreadStart().

However...

> Note that even then there are some situations (invocation API) where
> neither _Jv_RunMain or _Jv_ThreadStart will be on the stack.

...would you happen to know what *will* be there on the call stack
in this case?


>> 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 part of the patch is a bit awkward - duplicating the
> interpreter-specific code is fragile and will make maintenance more
> difficult. Couldn't we instead have fallback_backtrace call the real
> UnwindTraceFn? I believe _Unwind_context is an opaque type, so it should
> be possible to have fallback_backtrace pass its own data there.

I sort of agree. However, if you look at the code there, it
calls _Unwind_GetRegionStart() and _Unwind_GetIPInfo() - I'll
have to #ifdef these out and somehow shoehorn the SJLJ EH
equivalents in there since the default implementations of
these functions provided by GCC for SJLJ EH are of no use to
us.

The bigger picture however is that I expect all this to be
unnecessary in 4.3 - we would hopefully switch to DW2 EH
for MinGW by then.


>> (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.)
>>
> Hmm. There shouldn't be any problems here (on Linux) - do you have a
> test case?

Yes. See:
- ---------------------------- 8< ----------------------------
 1 public class Ex {
 2   void snafu( ) throws Exception {
 3     throw new Exception( "I do not like you!");
 4   }
 5   void bar( ) throws Exception {
 6     snafu( );
 7   }
 8   void foo( ) throws Exception {
 9     bar( );
10   }
11   public static void main( String[] args) throws Exception {
12     new Ex( ).foo( );
13   }
14 }
- ---------------------------- 8< ----------------------------

- ---------------------------- 8< ----------------------------
~/src/tmp > $MYGCJ --version
gcj (GCC) 4.2.0 20060701 (experimental)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

~/src/tmp > $MYGCJ --main=Ex -g Ex.java
~/src/tmp > ./a.out
Exception in thread "main" java.lang.Exception: I do not like you!
   at Ex.snafu(Ex.java:2)
   at Ex.bar(Ex.java:6)
   at Ex.foo(Ex.java:9)
   at Ex.main(Ex.java:12)
~/src/tmp > $MYGCJ -C Ex.java
~/src/tmp > mygij Ex
Exception in thread "main" java.lang.Exception: I do not like you!
   at Ex.snafu(Ex.java)
   at Ex.bar(Ex.java:6)
   at Ex.foo(Ex.java:9)
   at Ex.main(Ex.java:12)
~/src/tmp > mygij --version
java version "1.4.2"
gij (GNU libgcj) version 4.2.0 20060701 (experimental)

Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
~/src/tmp >
- ---------------------------- 8< ----------------------------

Note that this is a slightly older build and does not have your
_UnwindGetIPInfo() changes, so the problem has very likely been
fixed in recent builds.

Thanks,
Ranjit.

-- 
Ranjit Mathew      Email: rmathew AT gmail DOT com

Bangalore, INDIA.    Web: http://rmathew.com/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-11 18:34   ` Ranjit Mathew
@ 2006-07-11 21:34     ` Bryce McKinlay
  2006-07-12 17:28       ` Ranjit Mathew
  0 siblings, 1 reply; 8+ messages in thread
From: Bryce McKinlay @ 2006-07-11 21:34 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
>> Note that even then there are some situations (invocation API) where
>> neither _Jv_RunMain or _Jv_ThreadStart will be on the stack.
>
> ...would you happen to know what *will* be there on the call stack
> in this case?

I don't think there is anything guaranteed in the invocation API case. 
For JNI you could look for the various JNI Call* functions, but even 
then it is tricky to figure out whether the frame you are looking at is 
the outermost JNI call.

>> This part of the patch is a bit awkward - duplicating the
>> interpreter-specific code is fragile and will make maintenance more
>> difficult. Couldn't we instead have fallback_backtrace call the real
>> UnwindTraceFn? I believe _Unwind_context is an opaque type, so it should
>> be possible to have fallback_backtrace pass its own data there.
>
> I sort of agree. However, if you look at the code there, it
> calls _Unwind_GetRegionStart() and _Unwind_GetIPInfo() - I'll
> have to #ifdef these out and somehow shoehorn the SJLJ EH
> equivalents in there since the default implementations of
> these functions provided by GCC for SJLJ EH are of no use to
> us.

I think you could just overload them with #defines in backtrace.h? 
Failing that, I think that adding a couple of #ifdef's in UnwindTraceFn 
is not as bad as the code duplication.

>> Hmm. There shouldn't be any problems here (on Linux) - do you have a
>> test case?
>
> Yes. See:
> - ---------------------------- 8< ----------------------------
> 1 public class Ex {
> 2   void snafu( ) throws Exception {
> 3     throw new Exception( "I do not like you!");
> 4   }
> 5   void bar( ) throws Exception {
> 6     snafu( );
> 7   }
> 8   void foo( ) throws Exception {
> 9     bar( );
> 10   }
> 11   public static void main( String[] args) throws Exception {
> 12     new Ex( ).foo( );
> 13   }
> 14 }
> - ---------------------------- 8< ----------------------------

Hmm, ok, I see this too. I've filed a bug:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28352

Bryce

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-11 21:34     ` Bryce McKinlay
@ 2006-07-12 17:28       ` Ranjit Mathew
  2006-07-12 20:05         ` Bryce McKinlay
  2006-07-12 20:10         ` Bryce McKinlay
  0 siblings, 2 replies; 8+ messages in thread
From: Ranjit Mathew @ 2006-07-12 17:28 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

[-- Attachment #1: Type: text/plain, Size: 1475 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bryce McKinlay wrote:
> Ranjit Mathew wrote:
>>> Note that even then there are some situations (invocation API) where
>>> neither _Jv_RunMain or _Jv_ThreadStart will be on the stack.
>> ...would you happen to know what *will* be there on the call stack
>> in this case?
> 
> I don't think there is anything guaranteed in the invocation API case. 
> For JNI you could look for the various JNI Call* functions, but even 
> then it is tricky to figure out whether the frame you are looking at is 
> the outermost JNI call.

For now, I'm giving up when the unwinding reaches "close enough"
to main(). :-/


> I think you could just overload them with #defines in backtrace.h? 
> Failing that, I think that adding a couple of #ifdef's in UnwindTraceFn 
> is not as bad as the code duplication.

That worked pretty nicely, thank you. It reduces unnecessary
duplication of code too. The attached patch implements it and
was tested using a crossed-native compiler for i686-pc-mingw32.
I still get usable stack traces for compiled and interpreted
code.

OK?

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

iD8DBQFEtTFTYb1hx2wRS48RArjrAJ9mpsgaC7uv24LxehmpwLlxxAsnXQCgkwPf
Gm3Wb/KgCNNOVqZROV14tIU=
=pJ4u
-----END PGP SIGNATURE-----

[-- Attachment #2: p3.txt --]
[-- Type: text/plain, Size: 7421 bytes --]

Index: ChangeLog
from  Ranjit Mathew  <rmathew@gcc.gnu.org>

	* stacktrace.cc (_Jv_StackTrace::GetStackTrace): Pass UnwindTraceFn()
	to fallback_backtrace().
	(_Jv_StackTrace::GetCallerInfo): Enable even for targets using SJLJ
	EH and use fallback_backtrace() in that case.
	(_Jv_StackTrace::GetClassContext): Pass UnwindTraceFn() to
	fallback_backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.
	* sysdep/generic/backtrace.h (fallback_backtrace): Accept an
	additional unwind trace function argument.
	* sysdep/i386/backtrace.h (HAVE_FALLBACK_BACKTRACE): Do not define.
	(_Unwind_GetIPInfo): Define macro.
	(_Unwind_GetRegionStart): Likewise.
	(fallback_backtrace): Accept additional unwind trace function
	argument.  Call it during unwinding.  Stop when any of _Jv_RunMain(),
	_Jv_ThreadStart() or main() is seen during unwinding.

Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 115260)
+++ stacktrace.cc	(working copy)
@@ -156,7 +156,7 @@ _Jv_StackTrace::GetStackTrace(void)
 #ifdef SJLJ_EXCEPTIONS
   // The Unwind interface doesn't work with the SJLJ exception model.
   // Fall back to a platform-specific unwinder.
-  fallback_backtrace (&state);
+  fallback_backtrace (UnwindTraceFn, &state);
 #else /* SJLJ_EXCEPTIONS */  
   _Unwind_Backtrace (UnwindTraceFn, &state);
 #endif /* SJLJ_EXCEPTIONS */
@@ -421,7 +421,6 @@ 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);
@@ -439,15 +438,18 @@ _Jv_StackTrace::GetCallerInfo (jclass ch
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
 
+#ifdef SJLJ_EXCEPTIONS
+  // The Unwind interface doesn't work with the SJLJ exception model.
+  // Fall back to a platform-specific unwinder.
+  fallback_backtrace (UnwindTraceFn, &state);
+#else /* SJLJ_EXCEPTIONS */  
   _Unwind_Backtrace (UnwindTraceFn, &state);
+#endif /* SJLJ_EXCEPTIONS */
   
   if (caller_class)
     *caller_class = trace_data.foundClass;
   if (caller_meth)
     *caller_meth = trace_data.foundMeth;
-#else
-  return;
-#endif
 }
 
 // Return a java array containing the Java classes on the stack above CHECKCLASS.
@@ -467,7 +469,7 @@ _Jv_StackTrace::GetClassContext (jclass 
 #ifdef SJLJ_EXCEPTIONS
   // The Unwind interface doesn't work with the SJLJ exception model.
   // Fall back to a platform-specific unwinder.
-  fallback_backtrace (&state);
+  fallback_backtrace (UnwindTraceFn, &state);
 #else /* SJLJ_EXCEPTIONS */  
   _Unwind_Backtrace (UnwindTraceFn, &state);
 #endif /* SJLJ_EXCEPTIONS */  
@@ -544,7 +546,7 @@ _Jv_StackTrace::GetFirstNonSystemClassLo
 #ifdef SJLJ_EXCEPTIONS
   // The Unwind interface doesn't work with the SJLJ exception model.
   // Fall back to a platform-specific unwinder.
-  fallback_backtrace (&state);
+  fallback_backtrace (UnwindTraceFn, &state);
 #else /* SJLJ_EXCEPTIONS */  
   _Unwind_Backtrace (UnwindTraceFn, &state);
 #endif /* SJLJ_EXCEPTIONS */  
Index: sysdep/generic/backtrace.h
===================================================================
--- sysdep/generic/backtrace.h	(revision 115260)
+++ sysdep/generic/backtrace.h	(working copy)
@@ -16,7 +16,7 @@ details.  */
 /* Store return addresses of the current program stack in
    STATE and return the exact number of values stored.  */
 void
-fallback_backtrace (_Jv_UnwindState *)
+fallback_backtrace (_Unwind_Trace_Fn, _Jv_UnwindState *)
 {
 }
 #endif
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 115261)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -13,21 +13,39 @@ details.  */
 
 #include <java-stack.h>
 
-#define HAVE_FALLBACK_BACKTRACE
+extern int main (int, char **);
+
+/* The context used to keep track of our position while unwinding through
+   the call stack.  */
+struct _Unwind_Context
+{
+  /* The starting address of the method.  */
+  _Jv_uintptr_t meth_addr;
+
+  /* The return address in the method.  */
+  _Jv_uintptr_t ret_addr;
+};
+
+#undef _Unwind_GetIPInfo
+#define _Unwind_GetIPInfo(ctx,ip_before_insn) \
+  (*(ip_before_insn) = 1, (ctx)->ret_addr)
+
+#undef _Unwind_GetRegionStart
+#define _Unwind_GetRegionStart(ctx) \
+  ((ctx)->meth_addr)
+
 
 /* Store return addresses of the current program stack in
    STATE and return the exact number of values stored.  */
 void
-fallback_backtrace (_Jv_UnwindState *state)
+fallback_backtrace (_Unwind_Trace_Fn trace_fn, _Jv_UnwindState *state)
 {
   register _Jv_uintptr_t *_ebp __asm__ ("ebp");
   register _Jv_uintptr_t _esp __asm__ ("esp");
   _Jv_uintptr_t rfp;
+  _Unwind_Context ctx;
 
-  int i = state->pos;
-  for (rfp = *_ebp;
-       rfp && i < state->length;
-       rfp = *(_Jv_uintptr_t *)rfp)
+  for (rfp = *_ebp; rfp; rfp = *(_Jv_uintptr_t *)rfp)
     {
       /* Sanity checks to eliminate dubious-looking frame pointer chains.
          The frame pointer should be a 32-bit word-aligned stack address.
@@ -42,12 +60,7 @@ fallback_backtrace (_Jv_UnwindState *sta
 
       /* Get the return address in the calling function.  This is stored on
          the stack just before the value of the old frame pointer.  */
-      _Jv_uintptr_t ret_addr
-        = *(_Jv_uintptr_t *)(rfp + sizeof (_Jv_uintptr_t));
-
-      state->frames[i].type = frame_native;
-      state->frames[i].ip = (void *)(ret_addr - 1);
-      state->frames[i].start_ip = NULL;
+      ctx.ret_addr = *(_Jv_uintptr_t *)(rfp + sizeof (_Jv_uintptr_t));
 
       /* Try to locate a "pushl %ebp; movl %esp, %ebp" function prologue
          by scanning backwards at even addresses below the return address.
@@ -56,7 +69,8 @@ fallback_backtrace (_Jv_UnwindState *sta
          FIXME: This is not robust and will probably give us false positives,
          but this is about the best we can do if we do not have DWARF-2 unwind
          information based exception handling.  */
-      _Jv_uintptr_t scan_addr = (ret_addr & 0xFFFFFFFE) - 2;
+      ctx.meth_addr = (_Jv_uintptr_t)NULL;
+      _Jv_uintptr_t scan_addr = (ctx.ret_addr & 0xFFFFFFFE) - 2;
       _Jv_uintptr_t limit_addr
         = (scan_addr > 1024 * 1024) ? (scan_addr - 1024 * 1024) : 2;
       for ( ; scan_addr >= limit_addr; scan_addr -= 2)
@@ -65,17 +79,24 @@ 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;
+              ctx.meth_addr = scan_addr;
               break;
             }
         }
 
-      /* No need to unwind beyond JvRunMain().  */
-      if (state->frames[i].start_ip == (void *)JvRunMain)
+      /* Now call the unwinder callback function. */
+      if (trace_fn != NULL)
+        (*trace_fn) (&ctx, state);
+
+      /* No need to unwind beyond _Jv_RunMain(), _Jv_ThreadStart or
+         main().  */
+      void *jv_runmain
+        = (void *)(void (*)(JvVMInitArgs *, jclass, const char *, int,
+                            const char **, bool))_Jv_RunMain;
+      if (ctx.meth_addr == (_Jv_uintptr_t)jv_runmain
+          || ctx.meth_addr == (_Jv_uintptr_t)_Jv_ThreadStart
+          || (ctx.meth_addr - (_Jv_uintptr_t)main) < 16)
         break;
-
-      i++;
     }
-  state->pos = i;
 }
 #endif

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-12 17:28       ` Ranjit Mathew
@ 2006-07-12 20:05         ` Bryce McKinlay
  2006-07-14 17:26           ` Ranjit Mathew
  2006-07-12 20:10         ` Bryce McKinlay
  1 sibling, 1 reply; 8+ messages in thread
From: Bryce McKinlay @ 2006-07-12 20:05 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
>> I think you could just overload them with #defines in backtrace.h? 
>> Failing that, I think that adding a couple of #ifdef's in UnwindTraceFn 
>> is not as bad as the code duplication.
>>     
>
> That worked pretty nicely, thank you. It reduces unnecessary
> duplication of code too. The attached patch implements it and
> was tested using a crossed-native compiler for i686-pc-mingw32.
> I still get usable stack traces for compiled and interpreted
> code.
>
> OK?
>   

It occurs to me that you could now actually #define fallback_backtrace 
as _Unwind_Backtrace, and get rid of some #ifdefs in stacktrace.cc. Do 
you think that is worth doing? Otherwise, this is OK for trunk.

Bryce

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-12 17:28       ` Ranjit Mathew
  2006-07-12 20:05         ` Bryce McKinlay
@ 2006-07-12 20:10         ` Bryce McKinlay
  1 sibling, 0 replies; 8+ messages in thread
From: Bryce McKinlay @ 2006-07-12 20:10 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
>  /* Store return addresses of the current program stack in
>     STATE and return the exact number of values stored.  */
>  void
> -fallback_backtrace (_Jv_UnwindState *state)
> +fallback_backtrace (_Unwind_Trace_Fn trace_fn, _Jv_UnwindState *state)
>  {
>   


The comment here should also be updated.

Bryce

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows
  2006-07-12 20:05         ` Bryce McKinlay
@ 2006-07-14 17:26           ` Ranjit Mathew
  0 siblings, 0 replies; 8+ messages in thread
From: Ranjit Mathew @ 2006-07-14 17:26 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

[-- Attachment #1: Type: text/plain, Size: 3008 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bryce McKinlay wrote:
> Ranjit Mathew wrote:
>>> I think you could just overload them with #defines in backtrace.h? 
>>> Failing that, I think that adding a couple of #ifdef's in UnwindTraceFn 
>>> is not as bad as the code duplication.
>>>     
>> That worked pretty nicely, thank you. It reduces unnecessary
>> duplication of code too. The attached patch implements it and
>> was tested using a crossed-native compiler for i686-pc-mingw32.
>> I still get usable stack traces for compiled and interpreted
>> code.
>>
>> OK?
> 
> It occurs to me that you could now actually #define fallback_backtrace 
> as _Unwind_Backtrace, and get rid of some #ifdefs in stacktrace.cc. Do 
> you think that is worth doing? Otherwise, this is OK for trunk.

I've applied the attached patch to trunk. It defines _Unwind_Backtrace()
as fallback_backtrace() if SJLJ EH is in use. It was tested on
i686-pc-mingw32.

Even after this patch everything is not OK with the interpreter
and unwinding. While I get proper stack traces for programmes
that throw uncaught exceptions, I get a crashed interpreter for
programmes where the exception is caught. Some of the frames just
before _Jv_InterpMethod::run() have wild return addresses (even within
GDB) and I do not immediately understand why. I'll investigate this
further.
- -------------------------------- 8< --------------------------------
#13 0x0043bcd0 in _Jv_InterpMethod::run (retp=0x22fd80, args=0x22fda0,
    meth=0x2cd6f60) at /extra/src/gcc/gcc/libjava/interpret.cc:1221
#14 0xf8836606 in ?? ()
#15 0x0022fd80 in ?? ()
#16 0x0022fda0 in ?? ()
#17 0x02cd6f60 in ?? ()
#18 0x02cd6f60 in ?? ()
#19 0x02a1f098 in ?? ()
#20 0x02a139d0 in ?? ()
#21 0x0022fd98 in ?? ()
#22 0x00567e02 in _ZN4java4lang7reflect8Modifier8isPublicEJbi (mod=44138424)
    at /extra/src/gcc/gcc/libjava/java/lang/reflect/Modifier.java:257
#23 0x005e2be8 in gnu::java::lang::MainThread::call_main (this=0x2cc0fa0)
    at /extra/src/gcc/gcc/libjava/gnu/java/lang/natMainThread.cc:50
#24 0x0042fdff in _ZN3gnu4java4lang10MainThread3runEJvv (this=0x2cc0fa0)
    at /extra/src/gcc/gcc/libjava/gnu/java/lang/MainThread.java:108
#25 0x004550f4 in _Jv_ThreadRun (thread=0x2cc0fa0)
    at /extra/src/gcc/gcc/libjava/java/lang/natThread.cc:302
#26 0x00405136 in _Jv_RunMain (vm_args=0x22ff48, klass=0x0,
    name=0x3f2488 "Ex12", argc=1, argv=0x3f2504, is_jar=false)
    at /extra/src/gcc/gcc/libjava/prims.cc:1542
#27 0x004015e8 in main (argc=12, argv=0x7801392e)
    at /extra/src/gcc/gcc/libjava/gij.cc:333
- -------------------------------- 8< --------------------------------

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

iD8DBQFEt9O4Yb1hx2wRS48RAgyMAJ92tLmo2x3Q3t6jDGrLAEZriwGD5wCfTik8
4tPj7wleovKU8ZLejmbWOpU=
=BJrv
-----END PGP SIGNATURE-----

[-- Attachment #2: p4.txt --]
[-- Type: text/plain, Size: 8171 bytes --]

Index: ChangeLog
from  Ranjit Mathew  <rmathew@gcc.gnu.org>

	* stacktrace.cc (_Jv_StackTrace::GetStackTrace): Unconditionally use
	_Unwind_Backtrace().
	(_Jv_StackTrace::GetCallerInfo): Enable even for targets using SJLJ
	EH.
	(_Jv_StackTrace::GetClassContext): Unconditionally use
	_Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.
	* sysdep/i386/backtrace.h (HAVE_FALLBACK_BACKTRACE): Do not define.
	(_Unwind_GetIPInfo): Define macro if SJLJ EH is in use.
	(_Unwind_GetRegionStart): Likewise.
	(_Unwind_Backtrace): Likewise.
	(fallback_backtrace): Accept additional unwind trace function
	argument.  Call it during unwinding.  Stop when any of _Jv_RunMain(),
	_Jv_ThreadStart() or main() is seen during unwinding.
	* sysdep/generic/backtrace.h (fallback_backtrace): Accept an
	additional unwind trace function argument.

Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 115260)
+++ stacktrace.cc	(working copy)
@@ -153,13 +153,7 @@ _Jv_StackTrace::GetStackTrace(void)
   _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) + 
@@ -421,7 +415,6 @@ 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);
@@ -445,9 +438,6 @@ _Jv_StackTrace::GetCallerInfo (jclass ch
     *caller_class = trace_data.foundClass;
   if (caller_meth)
     *caller_meth = trace_data.foundMeth;
-#else
-  return;
-#endif
 }
 
 // Return a java array containing the Java classes on the stack above CHECKCLASS.
@@ -464,13 +454,7 @@ _Jv_StackTrace::GetClassContext (jclass 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
 
-#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 */  
 
   // Count the number of Java frames on the stack.
   int jframe_count = 0;
@@ -541,13 +525,7 @@ _Jv_StackTrace::GetFirstNonSystemClassLo
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
   
-#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 */  
 
   if (state.trace_data)
     return (ClassLoader *) state.trace_data;
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 115261)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -13,21 +13,46 @@ details.  */
 
 #include <java-stack.h>
 
-#define HAVE_FALLBACK_BACKTRACE
+extern int main (int, char **);
 
-/* Store return addresses of the current program stack in
-   STATE and return the exact number of values stored.  */
-void
-fallback_backtrace (_Jv_UnwindState *state)
+/* The context used to keep track of our position while unwinding through
+   the call stack.  */
+struct _Unwind_Context
+{
+  /* The starting address of the method.  */
+  _Jv_uintptr_t meth_addr;
+
+  /* The return address in the method.  */
+  _Jv_uintptr_t ret_addr;
+};
+
+#ifdef SJLJ_EXCEPTIONS
+
+#undef _Unwind_GetIPInfo
+#define _Unwind_GetIPInfo(ctx,ip_before_insn) \
+  (*(ip_before_insn) = 1, (ctx)->ret_addr)
+
+#undef _Unwind_GetRegionStart
+#define _Unwind_GetRegionStart(ctx) \
+  ((ctx)->meth_addr)
+
+#undef _Unwind_Backtrace
+#define _Unwind_Backtrace(trace_fn,state_ptr) \
+  (fallback_backtrace (trace_fn, state_ptr))
+
+#endif /* SJLJ_EXCEPTIONS */
+
+/* Unwind through the call stack calling TRACE_FN with STATE for each stack
+   frame.  Returns the reason why the unwinding was stopped.  */
+_Unwind_Reason_Code
+fallback_backtrace (_Unwind_Trace_Fn trace_fn, _Jv_UnwindState *state)
 {
   register _Jv_uintptr_t *_ebp __asm__ ("ebp");
   register _Jv_uintptr_t _esp __asm__ ("esp");
   _Jv_uintptr_t rfp;
+  _Unwind_Context ctx;
 
-  int i = state->pos;
-  for (rfp = *_ebp;
-       rfp && i < state->length;
-       rfp = *(_Jv_uintptr_t *)rfp)
+  for (rfp = *_ebp; rfp; rfp = *(_Jv_uintptr_t *)rfp)
     {
       /* Sanity checks to eliminate dubious-looking frame pointer chains.
          The frame pointer should be a 32-bit word-aligned stack address.
@@ -42,12 +67,7 @@ fallback_backtrace (_Jv_UnwindState *sta
 
       /* Get the return address in the calling function.  This is stored on
          the stack just before the value of the old frame pointer.  */
-      _Jv_uintptr_t ret_addr
-        = *(_Jv_uintptr_t *)(rfp + sizeof (_Jv_uintptr_t));
-
-      state->frames[i].type = frame_native;
-      state->frames[i].ip = (void *)(ret_addr - 1);
-      state->frames[i].start_ip = NULL;
+      ctx.ret_addr = *(_Jv_uintptr_t *)(rfp + sizeof (_Jv_uintptr_t));
 
       /* Try to locate a "pushl %ebp; movl %esp, %ebp" function prologue
          by scanning backwards at even addresses below the return address.
@@ -56,7 +76,8 @@ fallback_backtrace (_Jv_UnwindState *sta
          FIXME: This is not robust and will probably give us false positives,
          but this is about the best we can do if we do not have DWARF-2 unwind
          information based exception handling.  */
-      _Jv_uintptr_t scan_addr = (ret_addr & 0xFFFFFFFE) - 2;
+      ctx.meth_addr = (_Jv_uintptr_t)NULL;
+      _Jv_uintptr_t scan_addr = (ctx.ret_addr & 0xFFFFFFFE) - 2;
       _Jv_uintptr_t limit_addr
         = (scan_addr > 1024 * 1024) ? (scan_addr - 1024 * 1024) : 2;
       for ( ; scan_addr >= limit_addr; scan_addr -= 2)
@@ -65,17 +86,26 @@ 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;
+              ctx.meth_addr = scan_addr;
               break;
             }
         }
 
-      /* No need to unwind beyond JvRunMain().  */
-      if (state->frames[i].start_ip == (void *)JvRunMain)
+      /* Now call the unwinder callback function. */
+      if (trace_fn != NULL)
+        (*trace_fn) (&ctx, state);
+
+      /* No need to unwind beyond _Jv_RunMain(), _Jv_ThreadStart or
+         main().  */
+      void *jv_runmain
+        = (void *)(void (*)(JvVMInitArgs *, jclass, const char *, int,
+                            const char **, bool))_Jv_RunMain;
+      if (ctx.meth_addr == (_Jv_uintptr_t)jv_runmain
+          || ctx.meth_addr == (_Jv_uintptr_t)_Jv_ThreadStart
+          || (ctx.meth_addr - (_Jv_uintptr_t)main) < 16)
         break;
-
-      i++;
     }
-  state->pos = i;
+
+  return _URC_NO_REASON;
 }
 #endif
Index: sysdep/generic/backtrace.h
===================================================================
--- sysdep/generic/backtrace.h	(revision 115260)
+++ sysdep/generic/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. default implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -13,10 +13,11 @@ details.  */
 
 #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 *)
+/* Unwind through the call stack calling TRACE_FN with STATE for every stack
+   frame.  Returns the reason why the unwinding was stopped.  */
+_Unwind_Reason_Code
+fallback_backtrace (_Unwind_Trace_Fn, _Jv_UnwindState *)
 {
+  return _URC_NO_REASON;
 }
 #endif

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-07-14 17:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-07-09  9:19 [MinGW] RFA: Make Stack Traces Work for Interpreted Code on Windows Ranjit Mathew
2006-07-11 17:59 ` Bryce McKinlay
2006-07-11 18:34   ` Ranjit Mathew
2006-07-11 21:34     ` Bryce McKinlay
2006-07-12 17:28       ` Ranjit Mathew
2006-07-12 20:05         ` Bryce McKinlay
2006-07-14 17:26           ` Ranjit Mathew
2006-07-12 20:10         ` Bryce McKinlay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).