This is the mail archive of the java-patches@gcc.gnu.org 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] Slightly More Robust Stacktraces on Windows


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

Hi,

  As discussed earlier, the current hack in fallback_backtrace()
in "sysdep/i386/backtrace.h" works only for static method
invocations, that too without -findirect-dispatch. The attached
patch attempts to make this function a bit more robust by looking
for the following function prologue in function bodies to
determine their respective beginning addresses:

  pushl %ebp
  movl %esp, %ebp

We can assume the presence of this prologue since
fallback_backtrace() anyway needs code compiled with
- -fno-omit-frame-pointer for it to work.

main() is a notable exception to this pattern since GCC
(for MinGW) emits code to first align the stack on a 16-byte
boundary (by default) before emitting the function prologue.

In any case, we do not need to unwind all the way back to
main() - stopping at JvRunMain() should suffice. This is not just
a nifty optimisation; it prevents us from following wild %ebp
values beyond the programme's initial call stack frame.

The attached patch makes stack traces work with static
and instance methods, compiled with or without -findirect-dispatch
(as far as a very light testing could tell). It was tested
using an i686-pc-linux-gnu to i686-pc-mingw32 cross-compiler.

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

iD8DBQFErUWbYb1hx2wRS48RAgxoAJ0TpEgewUUmMqaMYuWYt+/XPKG2vACgoqUM
81MwqDjjpNlbI3uo1V838Mc=
=RF2E
-----END PGP SIGNATURE-----
Index: ChangeLog
from  Ranjit Mathew  <rmathew@gcc.gnu.org>

	* sysdep/i386/backtrace.h (fallback_backtrace): Scan for a function's
	prologue to determine its beginning.  Stop unwinding when we reach
	JvRunMain().

Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 115200)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -20,14 +20,14 @@ details.  */
 void
 fallback_backtrace (_Jv_UnwindState *state)
 {
-  register void *_ebp __asm__ ("ebp");
-  register void *_esp __asm__ ("esp");
-  _Jv_uintptr_t *rfp;
+  register _Jv_uintptr_t *_ebp __asm__ ("ebp");
+  register _Jv_uintptr_t _esp __asm__ ("esp");
+  _Jv_uintptr_t rfp;
 
   int i = state->pos;
-  for (rfp = *(_Jv_uintptr_t **)_ebp;
+  for (rfp = *_ebp;
        rfp && i < state->length;
-       rfp = *(_Jv_uintptr_t **)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.
@@ -35,30 +35,44 @@ fallback_backtrace (_Jv_UnwindState *sta
          a value greater than the current value of the stack pointer, it
          should not be below the supposed next frame pointer and it should
          not be too far off from the supposed next frame pointer.  */
-      int diff = *rfp - (_Jv_uintptr_t)rfp;
-      if (((_Jv_uintptr_t)rfp & 0x00000003) != 0 || (void*)rfp < _esp
+      int diff = *(_Jv_uintptr_t *)rfp - rfp;
+      if ((rfp & 0x00000003) != 0 || rfp < _esp
           || diff > 4 * 1024 || diff < 0)
         break;
 
-      /* Use the return address in the calling function stored just before
-         the current frame pointer to locate the address operand part of the
-         "CALL <XYZ>" instruction in the calling function that called this
-         function.  */
-      void *ip = (void*)(rfp[1] - 4);
-
-      /* Verify that the instruction at this position is a "CALL <XYZ>" and
-         use its operand to determine the starting address of the function
-         that this function had called.  0xE8 is the opcode for this CALL
-         instruction variant.  */
-      if (*(unsigned char *)((_Jv_uintptr_t)ip - 1) == 0xE8 && i > state->pos
-          && state->frames[i-1].type == frame_native)
+      /* 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;
+
+      /* Try to locate a "pushl %ebp; movl %esp, %ebp" function prologue
+         by scanning backwards at even addresses below the return address.
+         This instruction sequence is encoded as 0x55 0x89 0xE5.  We give up
+         if we do not find this sequence even after scanning 1024K of memory.
+         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;
+      _Jv_uintptr_t limit_addr
+        = (scan_addr > 1024 * 1024) ? (scan_addr - 1024 * 1024) : 2;
+      for ( ; scan_addr >= limit_addr; scan_addr -= 2)
         {
-          state->frames[i-1].start_ip
-            = (void *)((_Jv_uintptr_t)ip + 4 + *(_Jv_uintptr_t *)ip);
+          unsigned char *scan_bytes = (unsigned char *)scan_addr;
+          if (scan_bytes[0] == 0x55 && scan_bytes[1] == 0x89
+              && scan_bytes[2] == 0xE5)
+            {
+              state->frames[i].start_ip = (void *)scan_addr;
+              break;
+            }
         }
 
-      state->frames[i].type = frame_native;
-      state->frames[i].ip = ip;
+      /* No need to unwind beyond JvRunMain().  */
+      if (state->frames[i].start_ip == (void *)JvRunMain)
+        break;
 
       i++;
     }

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