public inbox for java-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
@ 2006-06-26 18:16 Ranjit Mathew
  2006-06-26 18:38 ` Bryce McKinlay
                   ` (3 more replies)
  0 siblings, 4 replies; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-26 18:16 UTC (permalink / raw)
  To: GCJ Patches; +Cc: mckinlay

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

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

[Bryce, CC-ing you explicitly to get your opinion on the
fallback_backtrace() changes.]

Hello,

  For targets like Windows that use SJLJ EH, GCJ-compiled
programmes only get hexadecimal addresses in stacktraces and
also crash on some exceptions as shown in:

  http://gcc.gnu.org/ml/java/2006-04/msg00025.html

The attached patch restores minimal stack traces on Windows.

I now get:
- --------------------------- 8< ---------------------------
Exception in thread "main" java.lang.Exception: I don't like you!
   at Hello.snafu(a.exe)
   at Hello.bar(a.exe)
   at Hello.foo(a.exe)
- --------------------------- 8< ---------------------------
(The sequence was main()->foo()->bar()->snafu() - I don't
know yet why main() is not listed in the trace. :-( )

The crux of the patch is the change to fallback_backtrace()
that uses the fact that a "CALL <XYZ>" instruction can be
used to determine the starting address of the called function.
(The operand is the offset of the called function relative
to the address of the *next* instruction after the CALL.)

Since it took me a while to understand what was going on in
this function, I took the liberty of adding copious comments
to this function to explain what is going on for the benefit
of lesser mortals like yours truly. I also added another sanity
test for a frame pointer value - it should be aligned on a
word boundary.

The second part of the patch uses a VirtualQuery()-based trick
shown by Matt Pietrek in his "Under The Hood" column for the
April '97 issue of MSJ to determine the module that contains
a given address. This is because Windows does not have a direct
equivalent of dladdr() as far as I can tell (I'm not a Windows
programmer, so I might be quite wrong on this).

The third part of the patch just ensures that we do not
call _Unwind_Backtrace() for non-SJLJ targets as shown by
the message linked above.

Tested lightly using an i686-pc-linux-gnu to i686-pc-mingw32
cross-compiler.

Comments? Suggestions? Approvals? ;-)

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

iD8DBQFEoCSBYb1hx2wRS48RAqBeAJ4+nJapJ8bjLC3WS8v2YiM0UHHXRQCgiC4o
Iay49ETYGKAZocPmjAmujvo=
=mGTH
-----END PGP SIGNATURE-----

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

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

	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Include platform.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use VirtualQuery() trick on
	Windows to find the module containing a given address.
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 114838)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -29,12 +29,37 @@ fallback_backtrace (_Jv_UnwindState *sta
        rfp && i < state->length;
        rfp = *(unsigned int **)rfp)
     {
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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 - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)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 *)((unsigned int)ip - 1) == 0xE8 && i > state->pos
+          && state->frames[i-1].type == frame_native)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((unsigned int)ip + 4 + *(unsigned int *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 114838)
+++ stacktrace.cc	(working copy)
@@ -9,6 +9,7 @@ Libgcj License.  Please consult the file
 details.  */
 
 #include <config.h>
+#include <platform.h>
 
 #include <jvm.h>
 #include <gcj/cni.h>
@@ -235,6 +236,68 @@ _Jv_StackTrace::getLineNumberForFrame(_J
         }
     }
 #endif
+
+#ifdef WIN32
+  void *ip = frame->ip;
+
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+
+  if (!VirtualQuery (ip, &mbi, sizeof (mbi)))
+  {
+    return;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return;
+  }
+
+  jstring binaryName = JvNewStringUTF (moduleName);
+  const char *argv0 = _Jv_GetSafeArg(0);
+
+  _Unwind_Ptr offset = 0;
+
+  // FIXME: Uncomment the following when we figure out how to handle these
+  // for Windows.
+  //
+  // if (*methodName == NULL && info.dli_sname)
+  //   *methodName = JvNewStringUTF (info.dli_sname);
+  // 
+  // // addr2line expects relative addresses for shared libraries.
+  // if (strcmp (info.dli_fname, argv0) == 0)
+  //   offset = (_Unwind_Ptr) ip;
+  // else
+  //   offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+
+  // 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;
+
+  finder->lookup (binaryName, (jlong) offset);
+  *sourceFileName = finder->getSourceFile();
+  *lineNum = finder->getLineNum();
+  if (*lineNum == -1 && NameFinder::showRaw())
+    {
+      gnu::gcj::runtime::StringBuffer *t =
+        new gnu::gcj::runtime::StringBuffer(binaryName);
+      t->append ((jchar)' ');
+      t->append ((jchar)'[');
+      // + 1 to compensate for the - 1 adjustment above;
+      t->append (Long::toHexString (offset + 1));
+      t->append ((jchar)']');
+      *sourceFileName = t->toString();
+    }
+#endif /* WIN32 */
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +346,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +365,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +433,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +535,13 @@ _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;
@@ -543,7 +612,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 18:16 [MinGW] RFC/RFA: Get Partial Stack Traces on Windows Ranjit Mathew
@ 2006-06-26 18:38 ` Bryce McKinlay
  2006-06-27  2:23   ` Ranjit Mathew
  2006-06-26 19:06 ` Andrew Haley
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-26 18:38 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches

Ranjit Mathew wrote:
> The second part of the patch uses a VirtualQuery()-based trick
> shown by Matt Pietrek in his "Under The Hood" column for the
> April '97 issue of MSJ to determine the module that contains
> a given address. This is because Windows does not have a direct
> equivalent of dladdr() as far as I can tell (I'm not a Windows
> programmer, so I might be quite wrong on this).
>
> The third part of the patch just ensures that we do not
> call _Unwind_Backtrace() for non-SJLJ targets as shown by
> the message linked above.
>
> Tested lightly using an i686-pc-linux-gnu to i686-pc-mingw32
> cross-compiler.
>
> Comments? Suggestions? Approvals? ;-)
>   

Looks good! Could the win32 part of getLineNumberForFrame() be split out 
into its own function, perhaps in win32.cc? It would be nice to avoid 
adding yet more #ifdef's in here.

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 18:16 [MinGW] RFC/RFA: Get Partial Stack Traces on Windows Ranjit Mathew
  2006-06-26 18:38 ` Bryce McKinlay
@ 2006-06-26 19:06 ` Andrew Haley
  2006-06-26 19:15   ` Tom Tromey
  2006-06-27  1:29   ` Ranjit Mathew
  2006-06-27 15:28 ` Ranjit Mathew
  2006-06-28  2:51 ` Ranjit Mathew
  3 siblings, 2 replies; 36+ messages in thread
From: Andrew Haley @ 2006-06-26 19:06 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches, mckinlay

Ranjit Mathew writes:
 > -----BEGIN PGP SIGNED MESSAGE-----
 > Hash: SHA1
 > 
 > [Bryce, CC-ing you explicitly to get your opinion on the
 > fallback_backtrace() changes.]
 > 
 > iD8DBQFEoCSBYb1hx2wRS48RAqBeAJ4+nJapJ8bjLC3WS8v2YiM0UHHXRQCgiC4o
 > Iay49ETYGKAZocPmjAmujvo=
 > =mGTH
 > -----END PGP SIGNATURE-----
 > Index: ChangeLog
 > from  Ranjit Mathew  <rmathew@gcc.gnu.org>
 > 
 > 	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
 > 	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
 > 	instruction calling the current function to find its starting address.
 > 	* stacktrace.cc: Include platform.h.
 > 	(_Jv_StackTrace::getLineNumberForFrame): Use VirtualQuery() trick on
 > 	Windows to find the module containing a given address.
 > 	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
 > 	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
 > 	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
 > 	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

What happens with -findirect-dispatch?

 > Index: sysdep/i386/backtrace.h
 > ===================================================================
 > --- sysdep/i386/backtrace.h	(revision 114838)
 > +++ sysdep/i386/backtrace.h	(working copy)
 > @@ -1,6 +1,6 @@
 >  // backtrace.h - Fallback backtrace implementation. i386 implementation.
 >  
 > -/* Copyright (C) 2005  Free Software Foundation
 > +/* Copyright (C) 2005, 2006  Free Software Foundation
 >  
 >     This file is part of libgcj.
 >  
 > @@ -29,12 +29,37 @@ fallback_backtrace (_Jv_UnwindState *sta
 >         rfp && i < state->length;
 >         rfp = *(unsigned int **)rfp)
 >      {
 > +      /* Sanity checks to eliminate dubious-looking frame pointer chains.
 > +         The frame pointer should be a 32-bit word-aligned stack address.
 > +         Since the stack grows downwards on x86, the frame pointer must have
 > +         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 - (unsigned int)rfp;
 > -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
 > +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp

Don't use unsigned int for a pointer; instead use 
int __attribute__((mode(pointer))).  This is an int that is exactly the
same size as a pointer.

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 19:06 ` Andrew Haley
@ 2006-06-26 19:15   ` Tom Tromey
  2006-06-26 19:20     ` Andrew Haley
  2006-06-27  1:29   ` Ranjit Mathew
  1 sibling, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2006-06-26 19:15 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ranjit Mathew, GCJ Patches, mckinlay

>>>>> "Andrew" == Andrew Haley <aph@redhat.com> writes:

>> -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
>> +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp

Andrew> Don't use unsigned int for a pointer; instead use 
Andrew> int __attribute__((mode(pointer))).  This is an int that is exactly the
Andrew> same size as a pointer.

Maybe we ought to add a _Jv_intptr_t typedef somewhere.

Tom

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 19:15   ` Tom Tromey
@ 2006-06-26 19:20     ` Andrew Haley
  0 siblings, 0 replies; 36+ messages in thread
From: Andrew Haley @ 2006-06-26 19:20 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Ranjit Mathew, GCJ Patches, mckinlay

Tom Tromey writes:
 > >>>>> "Andrew" == Andrew Haley <aph@redhat.com> writes:
 > 
 > >> -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
 > >> +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp
 > 
 > Andrew> Don't use unsigned int for a pointer; instead use 
 > Andrew> int __attribute__((mode(pointer))).  This is an int that is exactly the
 > Andrew> same size as a pointer.
 > 
 > Maybe we ought to add a _Jv_intptr_t typedef somewhere.

Mmm.  It's used in a few places.

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 19:06 ` Andrew Haley
  2006-06-26 19:15   ` Tom Tromey
@ 2006-06-27  1:29   ` Ranjit Mathew
  2006-06-27  8:33     ` Andrew Haley
  2006-07-05  9:22     ` Ranjit Mathew
  1 sibling, 2 replies; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27  1:29 UTC (permalink / raw)
  To: Andrew Haley; +Cc: GCJ Patches

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

Andrew Haley wrote:
> What happens with -findirect-dispatch?

The stack-trace changes to:
- --------------------------- 8< ---------------------------
Exception in thread "main" java.lang.Exception: I don't like you!
   at java.lang.VMThrowable.fillInStackTrace(a.exe)
   at java.lang.Throwable.<init>(a.exe)
- --------------------------- 8< ---------------------------

However, I don't think the BC-ABI works on Windows as of
now - I was actually expecting an ICE or a segfault somewhere
and was quite surprised when neither of them happened. :-)


- -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp

> Don't use unsigned int for a pointer; instead use 
> int __attribute__((mode(pointer))).  This is an int that is exactly the
> same size as a pointer.

I was just following in the illustrious footsteps of Bryce. ;-)

Considering that this file (sysdep/i386/backtrace.h) is x86-specific
and is anyway full of otherwise utterly-non-portable-C stuff, does
it matter? (The glibc 2.3.6 stdint.h header on my system just
defines uintptr_t as "unsigned int" for non-64-bit systems.)

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

iD8DBQFEoIoGYb1hx2wRS48RAlLOAJ90dc0jwWgqTQW2xS7OcNz/atge1wCeJkz6
7h647AkFvcbzVpehwJcS3MM=
=crhd
-----END PGP SIGNATURE-----

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 18:38 ` Bryce McKinlay
@ 2006-06-27  2:23   ` Ranjit Mathew
  2006-06-27 11:27     ` Marco Trudel
  2006-06-27 21:20     ` Bryce McKinlay
  0 siblings, 2 replies; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27  2:23 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: GCJ Patches

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

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

Bryce McKinlay wrote:
> 
> Looks good! Could the win32 part of getLineNumberForFrame() be split out 
> into its own function, perhaps in win32.cc? It would be nice to avoid 
> adding yet more #ifdef's in here.

That function has just three independent sections (with my patch):

  1. If the frame is from the interpreter.
  2. If the target has a working dladdr().
  3. If the target is Windows.

It's neatly separated in my opinion but I can change it if you
want me to. The problem is that I will have to anyway copy over
the code for #1 above, so I can't escape the #ifdef-ing. Moreover,
since this is stack tracing code, it belongs (again, in my opinion)
to stacktrace.cc more than it does elsewhere.

(The lengths some people would go to avoid doing work... ;-))

By the way Bryce, in fallback_backtrace() why do you set the IP of
the faulting instruction to be the operand part of a "CALL <XYZ>"
instruction instead of the actual beginning of the instruction? You
then compensate for it in getLineNumberForFrame() by decrementing
the offset by one. Is it because the DWARF-2 unwinder has the
same curious behaviour?

In any case, I had commented out a bit too much in
getLineNumberForFrame() in my last patch with the result that
offset was always set to 0. With that rectified as in the attached
patch, I now get file and line number information as well in the
stack trace (if addr2line is in the PATH, of course):
- ------------------------------- 8< -------------------------------
Exception in thread "main" java.lang.Exception: I don't like you!
   at Hello.snafu(/home/rmathew/src/tmp/Hello.java:4)
   at Hello.bar(/home/rmathew/src/tmp/Hello.java:10)
   at Hello.foo(/home/rmathew/src/tmp/Hello.java:15)
- ------------------------------- 8< -------------------------------

This seems usable.

Just for reference, here's the source file in question:
- ------------------------------- 8< -------------------------------
      1 public class Hello
      2 {
      3   static void snafu( ) throws Exception
      4   {
      5     throw new Exception( "I don't like you!");
      6   }
      7
      8   static void bar( ) throws Exception
      9   {
     10     snafu( );
     11   }
     12
     13   static void foo( ) throws Exception
     14   {
     15     bar( );
     16   }
     17
     18   public static void main( String[] args) throws Exception
     19   {
     20     System.out.println( "Hello World!");
     21     foo( );
     22   }
     23 }
- ------------------------------- 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

iD8DBQFEoJalYb1hx2wRS48RAtO9AJ4wvHoPt90p7Rli2D1CFF7u+3FKqwCggOyG
R2C7d9jfecNyfNluwz/glMs=
=AeZr
-----END PGP SIGNATURE-----

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

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

	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Include platform.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use VirtualQuery() trick on
	Windows to find the module containing a given address.
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 114838)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -29,12 +29,37 @@ fallback_backtrace (_Jv_UnwindState *sta
        rfp && i < state->length;
        rfp = *(unsigned int **)rfp)
     {
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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 - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)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 *)((unsigned int)ip - 1) == 0xE8 && i > state->pos
+          && state->frames[i-1].type == frame_native)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((unsigned int)ip + 4 + *(unsigned int *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 114838)
+++ stacktrace.cc	(working copy)
@@ -9,6 +9,7 @@ Libgcj License.  Please consult the file
 details.  */
 
 #include <config.h>
+#include <platform.h>
 
 #include <jvm.h>
 #include <gcj/cni.h>
@@ -184,6 +185,7 @@ _Jv_StackTrace::getLineNumberForFrame(_J
       return;
     }
 #endif
+
   // Use dladdr() to determine in which binary the address IP resides.
 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
   Dl_info info;
@@ -235,6 +237,71 @@ _Jv_StackTrace::getLineNumberForFrame(_J
         }
     }
 #endif
+
+#ifdef WIN32
+  void *ip = frame->ip;
+
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+
+  if (!VirtualQuery (ip, &mbi, sizeof (mbi)))
+  {
+    return;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return;
+  }
+
+  jstring binaryName = JvNewStringUTF (moduleName);
+  const char *argv0 = _Jv_GetSafeArg(0);
+
+  _Unwind_Ptr offset = 0;
+
+  // FIXME: Uncomment the following when we figure out how to handle these
+  // for Windows.
+  //
+  // if (*methodName == NULL && info.dli_sname)
+  //   *methodName = JvNewStringUTF (info.dli_sname);
+  // 
+  // // addr2line expects relative addresses for shared libraries.
+  // if (strcmp (info.dli_fname, argv0) == 0)
+  //   offset = (_Unwind_Ptr) ip;
+  // else
+  //   offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+
+  offset = (_Unwind_Ptr) ip;
+
+
+  // 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;
+
+  finder->lookup (binaryName, (jlong) offset);
+  *sourceFileName = finder->getSourceFile();
+  *lineNum = finder->getLineNum();
+  if (*lineNum == -1 && NameFinder::showRaw())
+    {
+      gnu::gcj::runtime::StringBuffer *t =
+        new gnu::gcj::runtime::StringBuffer(binaryName);
+      t->append ((jchar)' ');
+      t->append ((jchar)'[');
+      // + 1 to compensate for the - 1 adjustment above;
+      t->append (Long::toHexString (offset + 1));
+      t->append ((jchar)']');
+      *sourceFileName = t->toString();
+    }
+#endif /* WIN32 */
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +350,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +369,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +437,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +539,13 @@ _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;
@@ -543,7 +616,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  1:29   ` Ranjit Mathew
@ 2006-06-27  8:33     ` Andrew Haley
  2006-06-27  9:11       ` Ranjit Mathew
  2006-07-05  9:22     ` Ranjit Mathew
  1 sibling, 1 reply; 36+ messages in thread
From: Andrew Haley @ 2006-06-27  8:33 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches

Ranjit Mathew writes:
 > -----BEGIN PGP SIGNED MESSAGE-----
 > Hash: SHA1
 > 
 > Andrew Haley wrote:
 > > What happens with -findirect-dispatch?
 > 
 > The stack-trace changes to:
 > - --------------------------- 8< ---------------------------
 > Exception in thread "main" java.lang.Exception: I don't like you!
 >    at java.lang.VMThrowable.fillInStackTrace(a.exe)
 >    at java.lang.Throwable.<init>(a.exe)
 > - --------------------------- 8< ---------------------------
 > 
 > However, I don't think the BC-ABI works on Windows as of
 > now - I was actually expecting an ICE or a segfault somewhere
 > and was quite surprised when neither of them happened. :-)

OK.  Fair enough.

 > 
 > - -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
 > +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp
 > 
 > > Don't use unsigned int for a pointer; instead use 
 > > int __attribute__((mode(pointer))).  This is an int that is exactly the
 > > same size as a pointer.
 > 
 > I was just following in the illustrious footsteps of Bryce. ;-)

Everything can be improved, y'know!

 > Considering that this file (sysdep/i386/backtrace.h) is x86-specific
 > and is anyway full of otherwise utterly-non-portable-C stuff, does
 > it matter?

It deson't affect correctness, it's just a matter of clarity.  It's
effectively saying "this is a pointer that holds an int."

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  8:33     ` Andrew Haley
@ 2006-06-27  9:11       ` Ranjit Mathew
  2006-06-27  9:29         ` Andrew Haley
  2006-06-27 21:57         ` Bryce McKinlay
  0 siblings, 2 replies; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27  9:11 UTC (permalink / raw)
  To: Andrew Haley; +Cc: GCJ Patches

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

Andrew Haley wrote:
> Ranjit Mathew writes:
>  > - -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
>  > +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp
>  > 
>  > > Don't use unsigned int for a pointer; instead use 
>  > > int __attribute__((mode(pointer))).  This is an int that is exactly the
>  > > same size as a pointer.
>  > 
>  > I was just following in the illustrious footsteps of Bryce. ;-)
> 
> Everything can be improved, y'know!

I was just kidding.


>  > Considering that this file (sysdep/i386/backtrace.h) is x86-specific
>  > and is anyway full of otherwise utterly-non-portable-C stuff, does
>  > it matter?
> 
> It deson't affect correctness, it's just a matter of clarity.  It's
> effectively saying "this is a pointer that holds an int."

Should I add something like the following for use everywhere or
do you prefer something more localised to "sysdep/i386/backtrace.h"?
- ---------------------------- 8< ----------------------------
Index: gcj/javaprims.h
===================================================================
- --- gcj/javaprims.h	(revision 115032)
+++ gcj/javaprims.h	(working copy)
@@ -623,6 +623,8 @@ extern "C" void _Jv_RegisterClassHookDef
 typedef unsigned short _Jv_ushort __attribute__((__mode__(__HI__)));
 typedef unsigned int _Jv_uint __attribute__((__mode__(__SI__)));
 typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__)));
+typedef int _Jv_intptr __attribute__((mode(pointer)));
+typedef unsigned int _Jv_uintptr __attribute__((mode(pointer)));

 class _Jv_Utf8Const
 {
- ---------------------------- 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.2 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEoPYYYb1hx2wRS48RAir0AJ9x8+yJAmVdUuxJc1B31cVx338zUQCfZWiQ
h54R+/XAyAXxs316yqRr6dw=
=KEl+
-----END PGP SIGNATURE-----

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  9:11       ` Ranjit Mathew
@ 2006-06-27  9:29         ` Andrew Haley
  2006-06-27 21:57         ` Bryce McKinlay
  1 sibling, 0 replies; 36+ messages in thread
From: Andrew Haley @ 2006-06-27  9:29 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches

Ranjit Mathew writes:
 > -----BEGIN PGP SIGNED MESSAGE-----
 > Hash: SHA1
 > 
 > Andrew Haley wrote:
 > > Ranjit Mathew writes:
 > >  > - -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
 > >  > +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp
 > >  > 
 > >  > > Don't use unsigned int for a pointer; instead use 
 > >  > > int __attribute__((mode(pointer))).  This is an int that is exactly the
 > >  > > same size as a pointer.
 > >  > 
 > >  > I was just following in the illustrious footsteps of Bryce. ;-)
 > > 
 > > Everything can be improved, y'know!
 > 
 > I was just kidding.

OK.  I guessed so.

 > >  > Considering that this file (sysdep/i386/backtrace.h) is x86-specific
 > >  > and is anyway full of otherwise utterly-non-portable-C stuff, does
 > >  > it matter?
 > > 
 > > It deson't affect correctness, it's just a matter of clarity.  It's
 > > effectively saying "this is a pointer that holds an int."
 > 
 > Should I add something like the following for use everywhere 

Sure.  tromey suggested that, and I agree.

 > or do you prefer something more localised to
 > "sysdep/i386/backtrace.h"?

I think tromey's suggestion of _Jv_intptr_t was better, as it
emphasizes the link with the optional intptr_t.  

Having said that, is there any need for a signed pointer?  I don't
think so.  It makes the most sense to define _Jv_uintptr_t.  But we're
in danger of arguing about what colour to paint the bicycle shed...

I've caused enough trouble already; I'm outta here!  :-)

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  2:23   ` Ranjit Mathew
@ 2006-06-27 11:27     ` Marco Trudel
  2006-06-27 11:38       ` Ranjit Mathew
  2006-06-27 21:20     ` Bryce McKinlay
  1 sibling, 1 reply; 36+ messages in thread
From: Marco Trudel @ 2006-06-27 11:27 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches

Hello Ranjit

Great Work! Thank you for that.
With this stacktraces and reflection rewritten to not use the stack 
unwinder, windows becomes more and more useful.


 > In any case, I had commented out a bit too much in
 > getLineNumberForFrame() in my last patch with the result that
 > offset was always set to 0. With that rectified as in the attached
 > patch, I now get file and line number information as well in the
 > stack trace (if addr2line is in the PATH, of course):

Question to that: I assume this only applies when classes aren't 
compiled into an executable? For compiled classes, I get:
    at Hello.foo(outWin.exe)
instead your mentioned
    at Hello.foo(/home/rmathew/src/tmp/Hello.java:15)

just curious...

regards
Marco


Ranjit Mathew wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Bryce McKinlay wrote:
> 
>>Looks good! Could the win32 part of getLineNumberForFrame() be split out 
>>into its own function, perhaps in win32.cc? It would be nice to avoid 
>>adding yet more #ifdef's in here.
> 
> 
> That function has just three independent sections (with my patch):
> 
>   1. If the frame is from the interpreter.
>   2. If the target has a working dladdr().
>   3. If the target is Windows.
> 
> It's neatly separated in my opinion but I can change it if you
> want me to. The problem is that I will have to anyway copy over
> the code for #1 above, so I can't escape the #ifdef-ing. Moreover,
> since this is stack tracing code, it belongs (again, in my opinion)
> to stacktrace.cc more than it does elsewhere.
> 
> (The lengths some people would go to avoid doing work... ;-))
> 
> By the way Bryce, in fallback_backtrace() why do you set the IP of
> the faulting instruction to be the operand part of a "CALL <XYZ>"
> instruction instead of the actual beginning of the instruction? You
> then compensate for it in getLineNumberForFrame() by decrementing
> the offset by one. Is it because the DWARF-2 unwinder has the
> same curious behaviour?
> 
> In any case, I had commented out a bit too much in
> getLineNumberForFrame() in my last patch with the result that
> offset was always set to 0. With that rectified as in the attached
> patch, I now get file and line number information as well in the
> stack trace (if addr2line is in the PATH, of course):
> - ------------------------------- 8< -------------------------------
> Exception in thread "main" java.lang.Exception: I don't like you!
>    at Hello.snafu(/home/rmathew/src/tmp/Hello.java:4)
>    at Hello.bar(/home/rmathew/src/tmp/Hello.java:10)
>    at Hello.foo(/home/rmathew/src/tmp/Hello.java:15)
> - ------------------------------- 8< -------------------------------
> 
> This seems usable.
> 
> Just for reference, here's the source file in question:
> - ------------------------------- 8< -------------------------------
>       1 public class Hello
>       2 {
>       3   static void snafu( ) throws Exception
>       4   {
>       5     throw new Exception( "I don't like you!");
>       6   }
>       7
>       8   static void bar( ) throws Exception
>       9   {
>      10     snafu( );
>      11   }
>      12
>      13   static void foo( ) throws Exception
>      14   {
>      15     bar( );
>      16   }
>      17
>      18   public static void main( String[] args) throws Exception
>      19   {
>      20     System.out.println( "Hello World!");
>      21     foo( );
>      22   }
>      23 }
> - ------------------------------- 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
> 
> iD8DBQFEoJalYb1hx2wRS48RAtO9AJ4wvHoPt90p7Rli2D1CFF7u+3FKqwCggOyG
> R2C7d9jfecNyfNluwz/glMs=
> =AeZr
> -----END PGP SIGNATURE-----
> 
> 
> ------------------------------------------------------------------------
> 
> Index: ChangeLog
> from  Ranjit Mathew  <rmathew@gcc.gnu.org>
> 
> 	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
> 	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
> 	instruction calling the current function to find its starting address.
> 	* stacktrace.cc: Include platform.h.
> 	(_Jv_StackTrace::getLineNumberForFrame): Use VirtualQuery() trick on
> 	Windows to find the module containing a given address.
> 	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
> 	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
> 	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
> 	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.
> 
> Index: sysdep/i386/backtrace.h
> ===================================================================
> --- sysdep/i386/backtrace.h	(revision 114838)
> +++ sysdep/i386/backtrace.h	(working copy)
> @@ -1,6 +1,6 @@
>  // backtrace.h - Fallback backtrace implementation. i386 implementation.
>  
> -/* Copyright (C) 2005  Free Software Foundation
> +/* Copyright (C) 2005, 2006  Free Software Foundation
>  
>     This file is part of libgcj.
>  
> @@ -29,12 +29,37 @@ fallback_backtrace (_Jv_UnwindState *sta
>         rfp && i < state->length;
>         rfp = *(unsigned int **)rfp)
>      {
> +      /* Sanity checks to eliminate dubious-looking frame pointer chains.
> +         The frame pointer should be a 32-bit word-aligned stack address.
> +         Since the stack grows downwards on x86, the frame pointer must have
> +         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 - (unsigned int)rfp;
> -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
> +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)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 *)((unsigned int)ip - 1) == 0xE8 && i > state->pos
> +          && state->frames[i-1].type == frame_native)
> +        {
> +          state->frames[i-1].start_ip
> +            = (void *)((unsigned int)ip + 4 + *(unsigned int *)ip);
> +        }
> +
>        state->frames[i].type = frame_native;
> -      state->frames[i].ip = (void*)(rfp[1]-4);
> +      state->frames[i].ip = ip;
> +
>        i++;
>      }
>    state->pos = i;
> Index: stacktrace.cc
> ===================================================================
> --- stacktrace.cc	(revision 114838)
> +++ stacktrace.cc	(working copy)
> @@ -9,6 +9,7 @@ Libgcj License.  Please consult the file
>  details.  */
>  
>  #include <config.h>
> +#include <platform.h>
>  
>  #include <jvm.h>
>  #include <gcj/cni.h>
> @@ -184,6 +185,7 @@ _Jv_StackTrace::getLineNumberForFrame(_J
>        return;
>      }
>  #endif
> +
>    // Use dladdr() to determine in which binary the address IP resides.
>  #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
>    Dl_info info;
> @@ -235,6 +237,71 @@ _Jv_StackTrace::getLineNumberForFrame(_J
>          }
>      }
>  #endif
> +
> +#ifdef WIN32
> +  void *ip = frame->ip;
> +
> +  // Since we do not have dladdr() on Windows, we use a trick involving
> +  // VirtualQuery() to find the module (EXE or DLL) that contains a given
> +  // address.  This was taken from Matt Pietrek's "Under the Hood" column
> +  // for the April 1997 issue of Microsoft Systems Journal.
> +
> +  MEMORY_BASIC_INFORMATION mbi;
> +
> +  if (!VirtualQuery (ip, &mbi, sizeof (mbi)))
> +  {
> +    return;
> +  }
> +  
> +  HMODULE hMod = (HMODULE) mbi.AllocationBase;
> +
> +  char moduleName[MAX_PATH];
> +
> +  // FIXME: We explicitly use the ANSI variant of the function here.
> +  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
> +  {
> +    return;
> +  }
> +
> +  jstring binaryName = JvNewStringUTF (moduleName);
> +  const char *argv0 = _Jv_GetSafeArg(0);
> +
> +  _Unwind_Ptr offset = 0;
> +
> +  // FIXME: Uncomment the following when we figure out how to handle these
> +  // for Windows.
> +  //
> +  // if (*methodName == NULL && info.dli_sname)
> +  //   *methodName = JvNewStringUTF (info.dli_sname);
> +  // 
> +  // // addr2line expects relative addresses for shared libraries.
> +  // if (strcmp (info.dli_fname, argv0) == 0)
> +  //   offset = (_Unwind_Ptr) ip;
> +  // else
> +  //   offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
> +
> +  offset = (_Unwind_Ptr) ip;
> +
> +
> +  // 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;
> +
> +  finder->lookup (binaryName, (jlong) offset);
> +  *sourceFileName = finder->getSourceFile();
> +  *lineNum = finder->getLineNum();
> +  if (*lineNum == -1 && NameFinder::showRaw())
> +    {
> +      gnu::gcj::runtime::StringBuffer *t =
> +        new gnu::gcj::runtime::StringBuffer(binaryName);
> +      t->append ((jchar)' ');
> +      t->append ((jchar)'[');
> +      // + 1 to compensate for the - 1 adjustment above;
> +      t->append (Long::toHexString (offset + 1));
> +      t->append ((jchar)']');
> +      *sourceFileName = t->toString();
> +    }
> +#endif /* WIN32 */
>  }
>  
>  // Look up class and method info for the given stack frame, setting 
> @@ -283,7 +350,7 @@ _Jv_StackTrace::GetStackTraceElements (_
>  {
>    ArrayList *list = new ArrayList ();
>  
> -#ifdef SJLJ_EXCEPTIONS
> +#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
>    // 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");
> @@ -302,7 +369,7 @@ _Jv_StackTrace::GetStackTraceElements (_
>        list->add (element);
>      }
>  
> -#else /* SJLJ_EXCEPTIONS */
> +#else /* SJLJ_EXCEPTIONS && !WIN32 */
>  
>    //JvSynchronized (ncodeMap);
>    UpdateNCodeMap ();
> @@ -370,7 +437,7 @@ _Jv_StackTrace::GetStackTraceElements (_
>      }
>    
>    finder->close();
> -#endif /* SJLJ_EXCEPTIONS */
> +#endif /* SJLJ_EXCEPTIONS && !WIN32 */
>  
>    JArray<Object *> *array = JvNewObjectArray (list->size (), 
>      &StackTraceElement::class$, NULL);
> @@ -472,7 +539,13 @@ _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;
> @@ -543,7 +616,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27 11:27     ` Marco Trudel
@ 2006-06-27 11:38       ` Ranjit Mathew
  2006-06-27 12:37         ` Marco Trudel
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27 11:38 UTC (permalink / raw)
  To: Marco Trudel; +Cc: GCJ Patches

On 6/27/06, Marco Trudel <mtrudel@gmx.ch> wrote:
>  > In any case, I had commented out a bit too much in
>  > getLineNumberForFrame() in my last patch with the result that
>  > offset was always set to 0. With that rectified as in the attached
>  > patch, I now get file and line number information as well in the
>  > stack trace (if addr2line is in the PATH, of course):
>
> Question to that: I assume this only applies when classes aren't
> compiled into an executable? For compiled classes, I get:
>     at Hello.foo(outWin.exe)
> instead your mentioned
>     at Hello.foo(/home/rmathew/src/tmp/Hello.java:15)

You need to have compiled "Hello.java" with debugging
information turned on. For example:

  gcj -g --main=Hello Hello.java

You also need to ensure that "addr2line" (from binutils)
is accessible from your PATH. If you have the MinGW
"bin" folder in your PATH, that should suffice.

HTH,
Ranjit.

-- 
Ranjit Mathew      Email: rmathew AT gmail DOT com

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

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27 11:38       ` Ranjit Mathew
@ 2006-06-27 12:37         ` Marco Trudel
  2006-06-27 13:14           ` Ranjit Mathew
  0 siblings, 1 reply; 36+ messages in thread
From: Marco Trudel @ 2006-06-27 12:37 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches



Ranjit Mathew wrote:
> On 6/27/06, Marco Trudel <mtrudel@gmx.ch> wrote:
> 
>>  > In any case, I had commented out a bit too much in
>>  > getLineNumberForFrame() in my last patch with the result that
>>  > offset was always set to 0. With that rectified as in the attached
>>  > patch, I now get file and line number information as well in the
>>  > stack trace (if addr2line is in the PATH, of course):
>>
>> Question to that: I assume this only applies when classes aren't
>> compiled into an executable? For compiled classes, I get:
>>     at Hello.foo(outWin.exe)
>> instead your mentioned
>>     at Hello.foo(/home/rmathew/src/tmp/Hello.java:15)
> 
> 
> You need to have compiled "Hello.java" with debugging
> information turned on. For example:
> 
>  gcj -g --main=Hello Hello.java
> 
> You also need to ensure that "addr2line" (from binutils)
> is accessible from your PATH. If you have the MinGW
> "bin" folder in your PATH, that should suffice.

Ah, yes. It works as long as I do not strip the final executable.
What does -g do? jc1 only tells me "Generate debug information in 
default format" and the executables keep the same size as withhout -g...
Will it be slower?

regards
Marco

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27 12:37         ` Marco Trudel
@ 2006-06-27 13:14           ` Ranjit Mathew
  0 siblings, 0 replies; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27 13:14 UTC (permalink / raw)
  To: Marco Trudel; +Cc: GCJ Patches

On 6/27/06, Marco Trudel <mtrudel@gmx.ch> wrote:
>
> Ah, yes. It works as long as I do not strip the final executable.
> What does -g do? jc1 only tells me "Generate debug information in
> default format" and the executables keep the same size as withhout -g...

"-g" asks the compiler to include debugging information that you
can use in a debugger like GDB. You should compare the output
(the "Hello.s" file) of these two commands:

  gcj -g -S Hello.java
  gcj -S Hello.java

to see the difference. GCC/MinGW uses the "stabs" debugging format
while GCC/Linux uses the DWARF-2 debugging format.

Since the debugging information maps programme instructions to
source files and line numbers, GCJ uses this information (via
addr2line) to show the source files and line numbers in an exception
stack trace.


> Will it be slower?

As far as I know, no.

HTH,
Ranjit.

-- 
Ranjit Mathew      Email: rmathew AT gmail DOT com

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

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 18:16 [MinGW] RFC/RFA: Get Partial Stack Traces on Windows Ranjit Mathew
  2006-06-26 18:38 ` Bryce McKinlay
  2006-06-26 19:06 ` Andrew Haley
@ 2006-06-27 15:28 ` Ranjit Mathew
  2006-06-27 19:57   ` Tom Tromey
  2006-06-28  2:51 ` Ranjit Mathew
  3 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-27 15:28 UTC (permalink / raw)
  To: java-patches

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

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

Ranjit Mathew wrote:
> 
> The attached patch restores minimal stack traces on Windows.

Here's the third revision of this patch that implements Andrew's
suggestion. Since the other typedefs in javaprims.h seem to
omit the "_t" suffix, I've omitted it here as well.

By the way, the reason main() does not appear in the stack trace
is because it is called indirectly by call_main() in
"gnu/java/lang/natMainThread.cc". The generated code is something
like "CALL %8(%EBX)" instead of the normal "CALL xyz".

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

iD8DBQFEoU6nYb1hx2wRS48RAlL3AKCL2bZAXXmfr0fjtRtBHaHXUgHs7ACgk1bm
UE/CpplrZchC5MEZNgZjH+s=
=vUSs
-----END PGP SIGNATURE-----

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

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

	* gcj/javaprims.h (_Jv_intptr, _Jv_uintptr): New typedefs similar to
	intptr_t and uintptr_t in C99.
	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Include platform.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use VirtualQuery() trick on
	Windows to find the module containing a given address.
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: gcj/javaprims.h
===================================================================
--- gcj/javaprims.h	(revision 114838)
+++ gcj/javaprims.h	(working copy)
@@ -624,6 +624,11 @@ typedef unsigned short _Jv_ushort __attr
 typedef unsigned int _Jv_uint __attribute__((__mode__(__SI__)));
 typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__)));
 
+// Types to use when treating a pointer as an integer.  Similar to
+// intptr_t and uintptr_t in C99.
+typedef int _Jv_intptr __attribute__((__mode__(__pointer__)));
+typedef unsigned int _Jv_uintptr __attribute__((__mode__(__pointer__)));
+
 class _Jv_Utf8Const
 {
   _Jv_ushort hash;
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 114838)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -22,19 +22,44 @@ fallback_backtrace (_Jv_UnwindState *sta
 {
   register void *_ebp __asm__ ("ebp");
   register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
+  _Jv_uintptr *rfp;
 
   int i = state->pos;
-  for (rfp = *(unsigned int**)_ebp;
+  for (rfp = *(_Jv_uintptr **)_ebp;
        rfp && i < state->length;
-       rfp = *(unsigned int **)rfp)
+       rfp = *(_Jv_uintptr **)rfp)
     {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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)rfp;
+      if (((_Jv_uintptr)rfp & 0x00000003) != 0 || (void*)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)ip - 1) == 0xE8 && i > state->pos
+          && state->frames[i-1].type == frame_native)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((_Jv_uintptr)ip + 4 + *(_Jv_uintptr *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 114838)
+++ stacktrace.cc	(working copy)
@@ -9,6 +9,7 @@ Libgcj License.  Please consult the file
 details.  */
 
 #include <config.h>
+#include <platform.h>
 
 #include <jvm.h>
 #include <gcj/cni.h>
@@ -184,6 +185,7 @@ _Jv_StackTrace::getLineNumberForFrame(_J
       return;
     }
 #endif
+
   // Use dladdr() to determine in which binary the address IP resides.
 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
   Dl_info info;
@@ -235,6 +237,71 @@ _Jv_StackTrace::getLineNumberForFrame(_J
         }
     }
 #endif
+
+#ifdef WIN32
+  void *ip = frame->ip;
+
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+
+  if (!VirtualQuery (ip, &mbi, sizeof (mbi)))
+  {
+    return;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return;
+  }
+
+  jstring binaryName = JvNewStringUTF (moduleName);
+  const char *argv0 = _Jv_GetSafeArg(0);
+
+  _Unwind_Ptr offset = 0;
+
+  // FIXME: Uncomment the following when we figure out how to handle these
+  // for Windows.
+  //
+  // if (*methodName == NULL && info.dli_sname)
+  //   *methodName = JvNewStringUTF (info.dli_sname);
+  // 
+  // // addr2line expects relative addresses for shared libraries.
+  // if (strcmp (info.dli_fname, argv0) == 0)
+  //   offset = (_Unwind_Ptr) ip;
+  // else
+  //   offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+
+  offset = (_Unwind_Ptr) ip;
+
+
+  // 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;
+
+  finder->lookup (binaryName, (jlong) offset);
+  *sourceFileName = finder->getSourceFile();
+  *lineNum = finder->getLineNum();
+  if (*lineNum == -1 && NameFinder::showRaw())
+    {
+      gnu::gcj::runtime::StringBuffer *t =
+        new gnu::gcj::runtime::StringBuffer(binaryName);
+      t->append ((jchar)' ');
+      t->append ((jchar)'[');
+      // + 1 to compensate for the - 1 adjustment above;
+      t->append (Long::toHexString (offset + 1));
+      t->append ((jchar)']');
+      *sourceFileName = t->toString();
+    }
+#endif /* WIN32 */
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +350,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +369,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +437,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +539,13 @@ _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;
@@ -543,7 +616,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27 15:28 ` Ranjit Mathew
@ 2006-06-27 19:57   ` Tom Tromey
  0 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2006-06-27 19:57 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

>>>>> "Ranjit" == Ranjit Mathew <rmathew@gmail.com> writes:

Ranjit> Here's the third revision of this patch that implements Andrew's
Ranjit> suggestion. Since the other typedefs in javaprims.h seem to
Ranjit> omit the "_t" suffix, I've omitted it here as well.

Either is fine by me.  The comment helps, thanks.

Ranjit> By the way, the reason main() does not appear in the stack trace
Ranjit> is because it is called indirectly by call_main() in
Ranjit> "gnu/java/lang/natMainThread.cc". The generated code is something
Ranjit> like "CALL %8(%EBX)" instead of the normal "CALL xyz".

Weird.  We do this in at least one other place as well --
Class.newInstance.

Ranjit> +// Types to use when treating a pointer as an integer.  Similar to
Ranjit> +// intptr_t and uintptr_t in C99.
Ranjit> +typedef int _Jv_intptr __attribute__((__mode__(__pointer__)));
Ranjit> +typedef unsigned int _Jv_uintptr __attribute__((__mode__(__pointer__)));

I tend to think we just want one of these.  I couldn't think of a
situation where I'd need both.

Ranjit> OK to apply?

I'm going to defer to Bryce and/or Andrew on this one.

Tom

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  2:23   ` Ranjit Mathew
  2006-06-27 11:27     ` Marco Trudel
@ 2006-06-27 21:20     ` Bryce McKinlay
  1 sibling, 0 replies; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-27 21:20 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: GCJ Patches

Ranjit Mathew wrote:
> That function has just three independent sections (with my patch):
>
>   1. If the frame is from the interpreter.
>   2. If the target has a working dladdr().
>   3. If the target is Windows.
>
> It's neatly separated in my opinion but I can change it if you
> want me to. The problem is that I will have to anyway copy over
> the code for #1 above, so I can't escape the #ifdef-ing. Moreover,
> since this is stack tracing code, it belongs (again, in my opinion)
> to stacktrace.cc more than it does elsewhere.
>   

I was thinking you'd just move out the windows-specific part to a 
"platform_getLineNumberForFrame()" (or whatever), which would be called 
from getLineNumberForFrame() after the interpreter-specific code. I 
agree, we don't want to duplicate the interpreter part of the code.
> By the way Bryce, in fallback_backtrace() why do you set the IP of
> the faulting instruction to be the operand part of a "CALL <XYZ>"
> instruction instead of the actual beginning of the instruction? You
> then compensate for it in getLineNumberForFrame() by decrementing
> the offset by one. Is it because the DWARF-2 unwinder has the
> same curious behaviour?
>   

Actually I didn't write fallback_backtrace(), that code was already 
there - but this sounds about right. The Dwarf-2 unwinder normally gives 
us the return address, which needs to be rolled back in order to get the 
correct line number. But, in the case of a frame where a fault occurred, 
it gives the address of the faulting instruction. I think there is 
actually a slight bug with this on Dwarf-2 since the "decrement the 
offset by one" isn't correct for a segfault/NullPointerException frame, 
so sometimes we get the wrong line number.

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  9:11       ` Ranjit Mathew
  2006-06-27  9:29         ` Andrew Haley
@ 2006-06-27 21:57         ` Bryce McKinlay
  1 sibling, 0 replies; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-27 21:57 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: Andrew Haley, GCJ Patches

Ranjit Mathew wrote:
> Andrew Haley wrote:
>   
>> Ranjit Mathew writes:
>>  > - -      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
>>  > +      if (((unsigned int)rfp & 0x00000003) != 0 || (void*)rfp < _esp
>>  > 
>>  > > Don't use unsigned int for a pointer; instead use 
>>  > > int __attribute__((mode(pointer))).  This is an int that is exactly the
>>  > > same size as a pointer.
>>  > 
>>  > I was just following in the illustrious footsteps of Bryce. ;-)
>>
>> Everything can be improved, y'know!
>>     
>
> I was just kidding.
>   

FWIW, I didn't write that (fallback_backtrace) code - it was just 
copied/moved from win32.cc. Actually, I think the old backtrace() in 
win32.cc can be deleted now.

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-26 18:16 [MinGW] RFC/RFA: Get Partial Stack Traces on Windows Ranjit Mathew
                   ` (2 preceding siblings ...)
  2006-06-27 15:28 ` Ranjit Mathew
@ 2006-06-28  2:51 ` Ranjit Mathew
  2006-06-28 13:56   ` Ranjit Mathew
  3 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-28  2:51 UTC (permalink / raw)
  To: GCJ Patches; +Cc: mckinlay

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

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

Ranjit Mathew wrote:
> 
> The attached patch restores minimal stack traces on Windows.

I'm attaching the fourth revision of this patch with this
message.

gcj/javaprims.h now defines just a single _Jv_uintptr type.

include/java-stack.h now defines a _Jv_AddrInfo structure
similar to Dl_info and a corresponding _Jv_platform_dladdr()
function similar to dladdr(). This function is then defined
in posix.cc and win32.cc using dladdr() and VirtualQuery()
respectively. stacktrace.cc now uses _Jv_platform_dladdr()
unconditionally and does not have to include either
dlfcn.h or platform.h.

I could be wrong, but I think we are leaking memory with
every call to dladdr(). The destructor for _Jv_AddrInfo
seeks to remedy this.

I've removed backtrace() from win32.cc as it has been
superseded by fallback_backtrace() in sysdep/i386/backtrace.h.

Tested via an i686-pc-linux-gnu to i686-pc-mingw32 cross-compiler.
I will also test a native configuration on i686-pc-linux-gnu
to exercise the POSIX code path.

OK to apply if that testing succeeds?

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

iD8DBQFEoe7PYb1hx2wRS48RAkfXAKCIxk/aY3XmuxBzqLaatWm+LTW6aACfTFfR
j9m8kxb3K/EeRQa57qX+q9E=
=uq9r
-----END PGP SIGNATURE-----

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

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

	* gcj/javaprims.h (_Jv_uintptr): New typedef similar to uintptr_t in
	C99.
	* include/java-stack.h: Include stdlib.h.
	(_Jv_AddrInfo): New structure to hold address information.
	(_Jv_platform_dladdr): Declare.
	* posix.cc: Include dlfcn.h if available.  Include java-stack.h.
	(_Jv_platform_dladdr): Define.
	* win32.cc: Include string.h.  Include java-stack.h.
	(backtrace): Remove.
	(_Jv_platform_dladdr): Define.
	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Do not include dlfcn.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use _Jv_platform_dladdr()
	instead of dladdr().
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: gcj/javaprims.h
===================================================================
--- gcj/javaprims.h	(revision 114838)
+++ gcj/javaprims.h	(working copy)
@@ -624,6 +624,10 @@ typedef unsigned short _Jv_ushort __attr
 typedef unsigned int _Jv_uint __attribute__((__mode__(__SI__)));
 typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__)));
 
+// The type to use when treating a pointer as an integer.  Similar to
+// uintptr_t in C99.
+typedef unsigned int _Jv_uintptr __attribute__((__mode__(__pointer__)));
+
 class _Jv_Utf8Const
 {
   _Jv_ushort hash;
Index: include/java-stack.h
===================================================================
--- include/java-stack.h	(revision 114838)
+++ include/java-stack.h	(working copy)
@@ -1,6 +1,6 @@
 // java-stack.h - Definitions for unwinding & inspecting the call stack.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -11,6 +11,7 @@ details.  */
 #ifndef __JV_STACKTRACE_H__
 #define __JV_STACKTRACE_H__
 
+#include <stdlib.h>
 #include <unwind.h>
 
 #include <gcj/cni.h>
@@ -126,5 +127,30 @@ public:
   
 };
 
+// Information about a given address.
+struct _Jv_AddrInfo
+{
+  // File name of the defining module.
+  char *file_name;
+  // Base address of the loaded module.
+  void *base;
+  // Name of the nearest symbol.
+  char *sym_name;
+  // Address of the nearest symbol.
+  void *sym_addr;
+
+  ~_Jv_AddrInfo (void)
+    {
+      if (file_name)
+        free (file_name);
+
+      if (sym_name)
+        free (sym_name);
+    }
+};
+
+// Given an address, determine the executable or shared object that defines
+// it and the nearest named symbol.
+extern int _Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info);
 
 #endif /* __JV_STACKTRACE_H__ */
Index: posix.cc
===================================================================
--- posix.cc	(revision 114838)
+++ posix.cc	(working copy)
@@ -17,7 +17,12 @@ details.  */
 #include <signal.h>
 #include <stdio.h>
 
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
 #include <jvm.h>
+#include <java-stack.h>
 #include <java/lang/Thread.h>
 #include <java/io/InterruptedIOException.h>
 #include <java/util/Properties.h>
@@ -203,3 +208,31 @@ _Jv_select (int n, fd_set *readfds, fd_s
   return 0;
 #endif
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  int ret_val = 0;
+
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+  Dl_info addr_info;
+  ret_val = dladdr (addr, &addr_info);
+  if (ret_val != 0)
+    {
+      info->file_name = addr_info.dli_fname;
+      info->base = addr_info.dli_fbase;
+      info->sym_name = addr_info.dli_sname;
+      info->sym_addr = addr_info.dli_saddr;
+    }
+#else
+  info->file_name = NULL;
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+#endif
+
+  return ret_val;
+}
Index: win32.cc
===================================================================
--- win32.cc	(revision 114838)
+++ win32.cc	(working copy)
@@ -12,8 +12,11 @@ details.  */
 #include <platform.h>
 #include <sys/timeb.h>
 #include <stdlib.h>
+#include <string.h>
 #include <fcntl.h>
 
+#include <java-stack.h>
+
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/UnsupportedOperationException.h>
 #include <java/io/IOException.h>
@@ -442,28 +445,6 @@ _Jv_platform_initProperties (java::util:
     }
 }
 
-/* Store up to SIZE return address of the current program state in
-   ARRAY and return the exact number of values stored.  */
-int
-backtrace (void **__array, int __size)
-{
-  register void *_ebp __asm__ ("ebp");
-  register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
-
-  int i=0;
-  for (rfp = *(unsigned int**)_ebp;
-       rfp && i < __size;
-       rfp = *(unsigned int **)rfp)
-    {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
-
-    __array[i++] = (void*)(rfp[1]-4);
-  }
-  return i;
-}
-
 int
 _Jv_pipe (int filedes[2])
 {
@@ -477,3 +458,41 @@ _Jv_platform_close_on_exec (HANDLE h)
   // no effect under Win9X.
   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+  if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
+  {
+    return 0;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return 0;
+  }
+
+  info->file_name = (char *)(malloc (strlen (moduleName) + 1));
+  strcpy (info->file_name, moduleName);
+
+  // FIXME.
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+
+  return 1;
+}
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 114838)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -22,19 +22,44 @@ fallback_backtrace (_Jv_UnwindState *sta
 {
   register void *_ebp __asm__ ("ebp");
   register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
+  _Jv_uintptr *rfp;
 
   int i = state->pos;
-  for (rfp = *(unsigned int**)_ebp;
+  for (rfp = *(_Jv_uintptr **)_ebp;
        rfp && i < state->length;
-       rfp = *(unsigned int **)rfp)
+       rfp = *(_Jv_uintptr **)rfp)
     {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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)rfp;
+      if (((_Jv_uintptr)rfp & 0x00000003) != 0 || (void*)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)ip - 1) == 0xE8 && i > state->pos
+          && state->frames[i-1].type == frame_native)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((_Jv_uintptr)ip + 4 + *(_Jv_uintptr *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 114838)
+++ stacktrace.cc	(working copy)
@@ -15,10 +15,6 @@ details.  */
 #include <java-interp.h>
 #include <java-stack.h>
 
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
 #include <stdio.h>
 
 #include <java/lang/Class.h>
@@ -184,41 +180,36 @@ _Jv_StackTrace::getLineNumberForFrame(_J
       return;
     }
 #endif
-  // Use dladdr() to determine in which binary the address IP resides.
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
-  Dl_info info;
+
+  // Use _Jv_platform_dladdr() to determine in which binary the address IP
+  // resides.
+  _Jv_AddrInfo info;
   jstring binaryName = NULL;
   const char *argv0 = _Jv_GetSafeArg(0);
 
   void *ip = frame->ip;
   _Unwind_Ptr offset = 0;
 
-  if (dladdr (ip, &info))
+  if (_Jv_platform_dladdr (ip, &info))
     {
-      if (info.dli_fname)
-	binaryName = JvNewStringUTF (info.dli_fname);
+      if (info.file_name)
+	binaryName = JvNewStringUTF (info.file_name);
       else
         return;
 
-      if (*methodName == NULL && info.dli_sname)
-	*methodName = JvNewStringUTF (info.dli_sname);
+      if (*methodName == NULL && info.sym_name)
+	*methodName = JvNewStringUTF (info.sym_name);
 
       // addr2line expects relative addresses for shared libraries.
-      if (strcmp (info.dli_fname, argv0) == 0)
+      if (strcmp (info.file_name, argv0) == 0)
         offset = (_Unwind_Ptr) ip;
       else
-        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.base;
 
-      //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();
@@ -234,7 +225,6 @@ _Jv_StackTrace::getLineNumberForFrame(_J
           *sourceFileName = t->toString();
         }
     }
-#endif
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +273,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +292,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +360,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +462,13 @@ _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;
@@ -543,7 +539,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28  2:51 ` Ranjit Mathew
@ 2006-06-28 13:56   ` Ranjit Mathew
  2006-06-28 15:02     ` Bryce McKinlay
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-28 13:56 UTC (permalink / raw)
  To: java-patches

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

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

Ranjit Mathew wrote:
> I will also test a native configuration on i686-pc-linux-gnu
> to exercise the POSIX code path.
> 
> OK to apply if that testing succeeds?

That testing did not succeed as-is. :-(

First off, I needed to add "const" qualifiers to file_name
and sym_name in _Jv_AddrInfo. Then I needed to cast the
arguments to the free() calls in the destructor for _Jv_AddrInfo
to "void *" to avoid errors complaining about invalid casts
from "const void *" to "void *".

More seriously, it appears that the free() calls in the
destructor are misguided - the effect ranges from a message
from glibc like "free(): invalid pointer 0x12345678!" to a
cryptic "Aborted".

There is no manual page for dladdr() on my system (though
there are for dlopen(), dlsym(), etc.) and online searches
didn't help much. Are the names not dynamically allocated
on all systems? I mean, is free() in this case non-kosher
on just glibc systems or is it the case for Solaris, etc.
as well?

Anyway, adding the "const" qualifiers and removing the
misguided free() calls make things work again on Linux.
I'm attaching the latest revision of this patch.

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.2 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEoopdYb1hx2wRS48RArq4AJ9SWhRYXcrp0P8Rhu1641v3OzQsVACfVnJS
9+usACwUUsq313icqsB7Gpg=
=xkhq
-----END PGP SIGNATURE-----

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

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

	* gcj/javaprims.h (_Jv_uintptr): New typedef similar to uintptr_t in
	C99.
	* include/java-stack.h: Include stdlib.h.
	(_Jv_AddrInfo): New structure to hold address information.
	(_Jv_platform_dladdr): Declare.
	* posix.cc: Include dlfcn.h if available.  Include java-stack.h.
	(_Jv_platform_dladdr): Define.
	* win32.cc: Include string.h.  Include java-stack.h.
	(backtrace): Remove.
	(_Jv_platform_dladdr): Define.
	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Do not include dlfcn.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use _Jv_platform_dladdr()
	instead of dladdr().
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: gcj/javaprims.h
===================================================================
--- gcj/javaprims.h	(revision 115049)
+++ gcj/javaprims.h	(working copy)
@@ -624,6 +624,10 @@ typedef unsigned short _Jv_ushort __attr
 typedef unsigned int _Jv_uint __attribute__((__mode__(__SI__)));
 typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__)));
 
+// The type to use when treating a pointer as an integer.  Similar to
+// uintptr_t in C99.
+typedef unsigned int _Jv_uintptr __attribute__((__mode__(__pointer__)));
+
 class _Jv_Utf8Const
 {
   _Jv_ushort hash;
Index: include/java-stack.h
===================================================================
--- include/java-stack.h	(revision 115049)
+++ include/java-stack.h	(working copy)
@@ -1,6 +1,6 @@
 // java-stack.h - Definitions for unwinding & inspecting the call stack.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -11,6 +11,7 @@ details.  */
 #ifndef __JV_STACKTRACE_H__
 #define __JV_STACKTRACE_H__
 
+#include <stdlib.h>
 #include <unwind.h>
 
 #include <gcj/cni.h>
@@ -126,5 +127,21 @@ public:
   
 };
 
+// Information about a given address.
+struct _Jv_AddrInfo
+{
+  // File name of the defining module.
+  const char *file_name;
+  // Base address of the loaded module.
+  void *base;
+  // Name of the nearest symbol.
+  const char *sym_name;
+  // Address of the nearest symbol.
+  void *sym_addr;
+};
+
+// Given an address, determine the executable or shared object that defines
+// it and the nearest named symbol.
+extern int _Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info);
 
 #endif /* __JV_STACKTRACE_H__ */
Index: posix.cc
===================================================================
--- posix.cc	(revision 115049)
+++ posix.cc	(working copy)
@@ -17,7 +17,12 @@ details.  */
 #include <signal.h>
 #include <stdio.h>
 
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
 #include <jvm.h>
+#include <java-stack.h>
 #include <java/lang/Thread.h>
 #include <java/io/InterruptedIOException.h>
 #include <java/util/Properties.h>
@@ -203,3 +208,31 @@ _Jv_select (int n, fd_set *readfds, fd_s
   return 0;
 #endif
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  int ret_val = 0;
+
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+  Dl_info addr_info;
+  ret_val = dladdr (addr, &addr_info);
+  if (ret_val != 0)
+    {
+      info->file_name = addr_info.dli_fname;
+      info->base = addr_info.dli_fbase;
+      info->sym_name = addr_info.dli_sname;
+      info->sym_addr = addr_info.dli_saddr;
+    }
+#else
+  info->file_name = NULL;
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+#endif
+
+  return ret_val;
+}
Index: win32.cc
===================================================================
--- win32.cc	(revision 115049)
+++ win32.cc	(working copy)
@@ -12,8 +12,11 @@ details.  */
 #include <platform.h>
 #include <sys/timeb.h>
 #include <stdlib.h>
+#include <string.h>
 #include <fcntl.h>
 
+#include <java-stack.h>
+
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/UnsupportedOperationException.h>
 #include <java/io/IOException.h>
@@ -442,28 +445,6 @@ _Jv_platform_initProperties (java::util:
     }
 }
 
-/* Store up to SIZE return address of the current program state in
-   ARRAY and return the exact number of values stored.  */
-int
-backtrace (void **__array, int __size)
-{
-  register void *_ebp __asm__ ("ebp");
-  register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
-
-  int i=0;
-  for (rfp = *(unsigned int**)_ebp;
-       rfp && i < __size;
-       rfp = *(unsigned int **)rfp)
-    {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
-
-    __array[i++] = (void*)(rfp[1]-4);
-  }
-  return i;
-}
-
 int
 _Jv_pipe (int filedes[2])
 {
@@ -477,3 +458,41 @@ _Jv_platform_close_on_exec (HANDLE h)
   // no effect under Win9X.
   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+  if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
+  {
+    return 0;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return 0;
+  }
+
+  info->file_name = (char *)(malloc (strlen (moduleName) + 1));
+  strcpy (info->file_name, moduleName);
+
+  // FIXME.
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+
+  return 1;
+}
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 115049)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -22,19 +22,44 @@ fallback_backtrace (_Jv_UnwindState *sta
 {
   register void *_ebp __asm__ ("ebp");
   register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
+  _Jv_uintptr *rfp;
 
   int i = state->pos;
-  for (rfp = *(unsigned int**)_ebp;
+  for (rfp = *(_Jv_uintptr **)_ebp;
        rfp && i < state->length;
-       rfp = *(unsigned int **)rfp)
+       rfp = *(_Jv_uintptr **)rfp)
     {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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)rfp;
+      if (((_Jv_uintptr)rfp & 0x00000003) != 0 || (void*)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)ip - 1) == 0xE8 && i > state->pos
+          && state->frames[i-1].type == frame_native)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((_Jv_uintptr)ip + 4 + *(_Jv_uintptr *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 115049)
+++ stacktrace.cc	(working copy)
@@ -15,10 +15,6 @@ details.  */
 #include <java-interp.h>
 #include <java-stack.h>
 
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
 #include <stdio.h>
 
 #include <java/lang/Class.h>
@@ -184,41 +180,36 @@ _Jv_StackTrace::getLineNumberForFrame(_J
       return;
     }
 #endif
-  // Use dladdr() to determine in which binary the address IP resides.
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
-  Dl_info info;
+
+  // Use _Jv_platform_dladdr() to determine in which binary the address IP
+  // resides.
+  _Jv_AddrInfo info;
   jstring binaryName = NULL;
   const char *argv0 = _Jv_GetSafeArg(0);
 
   void *ip = frame->ip;
   _Unwind_Ptr offset = 0;
 
-  if (dladdr (ip, &info))
+  if (_Jv_platform_dladdr (ip, &info))
     {
-      if (info.dli_fname)
-	binaryName = JvNewStringUTF (info.dli_fname);
+      if (info.file_name)
+	binaryName = JvNewStringUTF (info.file_name);
       else
         return;
 
-      if (*methodName == NULL && info.dli_sname)
-	*methodName = JvNewStringUTF (info.dli_sname);
+      if (*methodName == NULL && info.sym_name)
+	*methodName = JvNewStringUTF (info.sym_name);
 
       // addr2line expects relative addresses for shared libraries.
-      if (strcmp (info.dli_fname, argv0) == 0)
+      if (strcmp (info.file_name, argv0) == 0)
         offset = (_Unwind_Ptr) ip;
       else
-        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.base;
 
-      //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();
@@ -234,7 +225,6 @@ _Jv_StackTrace::getLineNumberForFrame(_J
           *sourceFileName = t->toString();
         }
     }
-#endif
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +273,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +292,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +360,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +462,13 @@ _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;
@@ -543,7 +539,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 13:56   ` Ranjit Mathew
@ 2006-06-28 15:02     ` Bryce McKinlay
  2006-06-28 15:15       ` Andrew Haley
  2006-06-29  4:06       ` Ranjit Mathew
  0 siblings, 2 replies; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-28 15:02 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
> There is no manual page for dladdr() on my system (though
> there are for dlopen(), dlsym(), etc.) and online searches
> didn't help much. Are the names not dynamically allocated
> on all systems? I mean, is free() in this case non-kosher
> on just glibc systems or is it the case for Solaris, etc.
> as well?
>   

Yes, there does seem to be a lack of docs for dladdr(). But, I found this:

http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=/usr/share/catman/p_man/cat3/libdl/dladdr.z

In particular:
"The memory pointed to by *dli_fname* and *dli_sname* is within the 
mapped object. If the object is closed with *dlclose()*, the pointers 
become invalid."

So, its safe to assume you don't need a free().
> Anyway, adding the "const" qualifiers and removing the
> misguided free() calls make things work again on Linux.
> I'm attaching the latest revision of this patch.
>
> OK to apply?
>
> Thanks,
> Ranjit.
>
> - --
> Ranjit Mathew      Email: rmathew AT gmail DOT com
>
> Bangalore, INDIA.    Web: http://rmathew.com/
>
>   
> ------------------------------------------------------------------------
>
> Index: ChangeLog
> from  Ranjit Mathew  <rmathew@gcc.gnu.org>
>
> 	* gcj/javaprims.h (_Jv_uintptr): New typedef similar to uintptr_t in
> 	C99.
>   

Hmm, is there some reason we can't just use uintptr_t? Doesn't GCC 
ensure it is always available?
> 	* include/java-stack.h: Include stdlib.h.
> 	(_Jv_AddrInfo): New structure to hold address information.
> 	(_Jv_platform_dladdr): Declare.
> 	* posix.cc: Include dlfcn.h if available.  Include java-stack.h.
> 	(_Jv_platform_dladdr): Define.
> 	* win32.cc: Include string.h.  Include java-stack.h.
> 	(backtrace): Remove.
> 	(_Jv_platform_dladdr): Define.
>   

Cool. Splitting out _Jv_platform_dladdr really cleans up the 
stacktrace.cc code - this looks perfect, almost - stylistically I think 
it would be better to declare _Jv_platform_dladdr in platform.h along 
with the other _Jv_platform_* functions. I realize this means platform.h 
will have to typedef _Jv_AddrInfo, or include java-stack.h, but I don't 
think that is a significant problem.

Otherwise, this is ok to commit. TVM!

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 15:02     ` Bryce McKinlay
@ 2006-06-28 15:15       ` Andrew Haley
  2006-06-28 15:45         ` Bryce McKinlay
  2006-06-28 15:49         ` Bryce McKinlay
  2006-06-29  4:06       ` Ranjit Mathew
  1 sibling, 2 replies; 36+ messages in thread
From: Andrew Haley @ 2006-06-28 15:15 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: Ranjit Mathew, java-patches

Bryce McKinlay writes:
 > 
 > Hmm, is there some reason we can't just use uintptr_t? Doesn't GCC 
 > ensure it is always available?

No.  It isn't part of gcc, it's part of whatever C library is being
used, and it's not guaranteed to be there.  It's safer to do it this
way.

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 15:15       ` Andrew Haley
@ 2006-06-28 15:45         ` Bryce McKinlay
  2006-06-28 15:49         ` Bryce McKinlay
  1 sibling, 0 replies; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-28 15:45 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ranjit Mathew, java-patches

Andrew Haley wrote:
> Bryce McKinlay writes:
>  > 
>  > Hmm, is there some reason we can't just use uintptr_t? Doesn't GCC 
>  > ensure it is always available?
>
> No.  It isn't part of gcc, it's part of whatever C library is being
> used, and it's not guaranteed to be there.  It's safer to do it this
> way.
>   

Fair enough. Ranjit, can we call it _Jv_uintptr_t, then?

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 15:15       ` Andrew Haley
  2006-06-28 15:45         ` Bryce McKinlay
@ 2006-06-28 15:49         ` Bryce McKinlay
  2006-06-28 16:11           ` Andrew Haley
  1 sibling, 1 reply; 36+ messages in thread
From: Bryce McKinlay @ 2006-06-28 15:49 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Ranjit Mathew, java-patches

Andrew Haley wrote:
> Bryce McKinlay writes:
>  > 
>  > Hmm, is there some reason we can't just use uintptr_t? Doesn't GCC 
>  > ensure it is always available?
>
> No.  It isn't part of gcc, it's part of whatever C library is being
> used, and it's not guaranteed to be there.  It's safer to do it this
> way.

We could also do something like:

#if !defined HAVE_UINTPTR_T
typedef unsigned int uintptr_t __attribute__((__mode__(__pointer__)));
#endif

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 15:49         ` Bryce McKinlay
@ 2006-06-28 16:11           ` Andrew Haley
  0 siblings, 0 replies; 36+ messages in thread
From: Andrew Haley @ 2006-06-28 16:11 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: Ranjit Mathew, java-patches

Bryce McKinlay writes:
 > Andrew Haley wrote:
 > > Bryce McKinlay writes:
 > >  > 
 > >  > Hmm, is there some reason we can't just use uintptr_t? Doesn't GCC 
 > >  > ensure it is always available?
 > >
 > > No.  It isn't part of gcc, it's part of whatever C library is being
 > > used, and it's not guaranteed to be there.  It's safer to do it this
 > > way.
 > 
 > We could also do something like:
 > 
 > #if !defined HAVE_UINTPTR_T
 > typedef unsigned int uintptr_t __attribute__((__mode__(__pointer__)));
 > #endif

I suppose we could, but it seems a bit fussy for something we can
define so easily.  I think perhaps we have enough configury already.
As I mentioned to Ranjit, this is turning into someting of a "what
colour shall we paint the bike shed" issue...  :-)

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-28 15:02     ` Bryce McKinlay
  2006-06-28 15:15       ` Andrew Haley
@ 2006-06-29  4:06       ` Ranjit Mathew
  2006-06-29 16:27         ` Ranjit Mathew
  1 sibling, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-29  4:06 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

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

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

Bryce McKinlay wrote:
> 
> Yes, there does seem to be a lack of docs for dladdr(). But, I found this:
> 
> http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=/usr/share/catman/p_man/cat3/libdl/dladdr.z
> 
> In particular:
> "The memory pointed to by *dli_fname* and *dli_sname* is within the 
> mapped object. If the object is closed with *dlclose()*, the pointers 
> become invalid."
> 
> So, its safe to assume you don't need a free().

Thanks a lot for confirming this. Since on Windows these are
still dynamically allocated, we need to free() them there.

The sixth revision of this patch (attached with this message)
takes care of this bit.

_Jv_uintptr has also been changed to _Jv_uintptr_t. The
_Jv_AddrInfo structure is still defined in java-stack.h,
but the _Jv_platform_dladdr() function is declared in the
respective platform.h. java-stack.h was pulling in a lot
of other headers, so I just forward-declare the _Jv_AddrInfo
structure and use it in the declaration.

I've tested this revision with an i686-pc-linux-gnu to
i686-pc-mingw32 cross-compiler. I hope to commit it
after testing with an i686-pc-linux-gnu native compiler
finishes successfully.

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

iD8DBQFEo1FxYb1hx2wRS48RAqa0AJ0a9yWkJDkU35jd2q0gIRezYq8/CACgjeG+
p6VJjuM3SoOYc2TaX0DRmF0=
=5uoN
-----END PGP SIGNATURE-----

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

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

	* gcj/javaprims.h (_Jv_uintptr_t): New typedef similar to uintptr_t in
	C99.
	* include/java-stack.h: Include stdlib.h.
	(_Jv_AddrInfo): New structure to hold address information.
	* include/posix.h (_Jv_platform_dladdr): Declare.
	* include/win32.h (_Jv_platform_dladdr): Declare.
	(backtrace): Remove declaration.
	* posix.cc: Include dlfcn.h if available.  Include java-stack.h.
	(_Jv_platform_dladdr): Define.
	* win32.cc: Include string.h.  Include java-stack.h.
	(backtrace): Remove.
	(_Jv_platform_dladdr): Define.
	* sysdep/i386/backtrace.h (fallback_backtrace): Check that a potential
	frame pointer value is 32-bit word-aligned.  Use operand of the CALL
	instruction calling the current function to find its starting address.
	* stacktrace.cc: Do not include dlfcn.h.  Include platform.h.
	(_Jv_StackTrace::getLineNumberForFrame): Use _Jv_platform_dladdr()
	instead of dladdr().
	(_Jv_StackTrace::GetStackTraceElements): Use nCodeMap even for Windows.
	(_Jv_StackTrace::GetClassContext): Use fallback_backtrace() for
	targets with SJLJ exceptions instead of using _Unwind_Backtrace().
	(_Jv_StackTrace::GetFirstNonSystemClassLoader): Likewise.

Index: gcj/javaprims.h
===================================================================
--- gcj/javaprims.h	(revision 114838)
+++ gcj/javaprims.h	(working copy)
@@ -624,6 +624,10 @@ typedef unsigned short _Jv_ushort __attr
 typedef unsigned int _Jv_uint __attribute__((__mode__(__SI__)));
 typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__)));
 
+// The type to use when treating a pointer as an integer.  Similar to
+// uintptr_t in C99.
+typedef unsigned int _Jv_uintptr_t __attribute__((__mode__(__pointer__)));
+
 class _Jv_Utf8Const
 {
   _Jv_ushort hash;
Index: include/java-stack.h
===================================================================
--- include/java-stack.h	(revision 114838)
+++ include/java-stack.h	(working copy)
@@ -1,6 +1,6 @@
 // java-stack.h - Definitions for unwinding & inspecting the call stack.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -11,6 +11,7 @@ details.  */
 #ifndef __JV_STACKTRACE_H__
 #define __JV_STACKTRACE_H__
 
+#include <stdlib.h>
 #include <unwind.h>
 
 #include <gcj/cni.h>
@@ -126,5 +127,35 @@ public:
   
 };
 
+// Information about a given address.
+struct _Jv_AddrInfo
+{
+  // File name of the defining module.
+  const char *file_name;
+
+  // Base address of the loaded module.
+  void *base;
+
+  // Name of the nearest symbol.
+  const char *sym_name;
+
+  // Address of the nearest symbol.
+  void *sym_addr;
+
+  ~_Jv_AddrInfo (void)
+    {
+      // On systems with a real dladdr(), the file and symbol names given by
+      // _Jv_platform_dladdr() are not dynamically allocated.  On Windows,
+      // they are.
+
+#ifdef WIN32
+      if (file_name)
+        free ((void *)file_name);
+
+      if (sym_name)
+        free ((void *)sym_name);
+#endif /* WIN32 */
+    }
+};
 
 #endif /* __JV_STACKTRACE_H__ */
Index: include/posix.h
===================================================================
--- include/posix.h	(revision 114838)
+++ include/posix.h	(working copy)
@@ -194,4 +194,11 @@ _Jv_pipe (int filedes[2])
   return ::pipe (filedes);
 }
 
+// Forward declaration.  See java-stack.h for definition.
+struct _Jv_AddrInfo;
+
+// Given an address, determine the executable or shared object that defines
+// it and the nearest named symbol.
+extern int _Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info);
+
 #endif /* __JV_POSIX_H__ */
Index: include/win32.h
===================================================================
--- include/win32.h	(revision 114838)
+++ include/win32.h	(working copy)
@@ -11,7 +11,7 @@ details.  */
 #ifndef __JV_WIN32_H__
 #define __JV_WIN32_H__
 
-// Enable UNICODE Support.?
+// Enable UNICODE support?
 
 #ifdef MINGW_LIBGCJ_UNICODE
 #define UNICODE
@@ -175,8 +175,11 @@ _Jv_platform_usleep (unsigned long usecs
 }
 #endif /* JV_HASH_SYNCHRONIZATION */
 
-/* Store up to SIZE return address of the current program state in
-   ARRAY and return the exact number of values stored.  */
-extern int backtrace (void **__array, int __size);
+// Forward declaration.  See java-stack.h for definition.
+struct _Jv_AddrInfo;
+
+// Given an address, determine the executable or shared object that defines
+// it and the nearest named symbol.
+extern int _Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info);
 
 #endif /* __JV_WIN32_H__ */
Index: posix.cc
===================================================================
--- posix.cc	(revision 114838)
+++ posix.cc	(working copy)
@@ -17,7 +17,12 @@ details.  */
 #include <signal.h>
 #include <stdio.h>
 
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
 #include <jvm.h>
+#include <java-stack.h>
 #include <java/lang/Thread.h>
 #include <java/io/InterruptedIOException.h>
 #include <java/util/Properties.h>
@@ -203,3 +208,31 @@ _Jv_select (int n, fd_set *readfds, fd_s
   return 0;
 #endif
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  int ret_val = 0;
+
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+  Dl_info addr_info;
+  ret_val = dladdr (addr, &addr_info);
+  if (ret_val != 0)
+    {
+      info->file_name = addr_info.dli_fname;
+      info->base = addr_info.dli_fbase;
+      info->sym_name = addr_info.dli_sname;
+      info->sym_addr = addr_info.dli_saddr;
+    }
+#else
+  info->file_name = NULL;
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+#endif
+
+  return ret_val;
+}
Index: win32.cc
===================================================================
--- win32.cc	(revision 114838)
+++ win32.cc	(working copy)
@@ -12,8 +12,11 @@ details.  */
 #include <platform.h>
 #include <sys/timeb.h>
 #include <stdlib.h>
+#include <string.h>
 #include <fcntl.h>
 
+#include <java-stack.h>
+
 #include <java/lang/ArithmeticException.h>
 #include <java/lang/UnsupportedOperationException.h>
 #include <java/io/IOException.h>
@@ -442,28 +445,6 @@ _Jv_platform_initProperties (java::util:
     }
 }
 
-/* Store up to SIZE return address of the current program state in
-   ARRAY and return the exact number of values stored.  */
-int
-backtrace (void **__array, int __size)
-{
-  register void *_ebp __asm__ ("ebp");
-  register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
-
-  int i=0;
-  for (rfp = *(unsigned int**)_ebp;
-       rfp && i < __size;
-       rfp = *(unsigned int **)rfp)
-    {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) break;
-
-    __array[i++] = (void*)(rfp[1]-4);
-  }
-  return i;
-}
-
 int
 _Jv_pipe (int filedes[2])
 {
@@ -477,3 +458,42 @@ _Jv_platform_close_on_exec (HANDLE h)
   // no effect under Win9X.
   SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
 }
+
+// Given an address, find the object that defines it and the nearest
+// defined symbol to that address.  Returns 0 if no object defines this
+// address.
+int
+_Jv_platform_dladdr (const void *addr, _Jv_AddrInfo *info)
+{
+  // Since we do not have dladdr() on Windows, we use a trick involving
+  // VirtualQuery() to find the module (EXE or DLL) that contains a given
+  // address.  This was taken from Matt Pietrek's "Under the Hood" column
+  // for the April 1997 issue of Microsoft Systems Journal.
+
+  MEMORY_BASIC_INFORMATION mbi;
+  if (!VirtualQuery (addr, &mbi, sizeof (mbi)))
+  {
+    return 0;
+  }
+  
+  HMODULE hMod = (HMODULE) mbi.AllocationBase;
+
+  char moduleName[MAX_PATH];
+
+  // FIXME: We explicitly use the ANSI variant of the function here.
+  if (!GetModuleFileNameA (hMod, moduleName, sizeof (moduleName)))
+  {
+    return 0;
+  }
+
+  char *file_name = (char *)(malloc (strlen (moduleName) + 1));
+  strcpy (file_name, moduleName);
+  info->file_name = file_name;
+
+  // FIXME.
+  info->base = NULL;
+  info->sym_name = NULL;
+  info->sym_addr = NULL;
+
+  return 1;
+}
Index: sysdep/i386/backtrace.h
===================================================================
--- sysdep/i386/backtrace.h	(revision 114838)
+++ sysdep/i386/backtrace.h	(working copy)
@@ -1,6 +1,6 @@
 // backtrace.h - Fallback backtrace implementation. i386 implementation.
 
-/* Copyright (C) 2005  Free Software Foundation
+/* Copyright (C) 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -22,19 +22,44 @@ fallback_backtrace (_Jv_UnwindState *sta
 {
   register void *_ebp __asm__ ("ebp");
   register void *_esp __asm__ ("esp");
-  unsigned int *rfp;
+  _Jv_uintptr_t *rfp;
 
   int i = state->pos;
-  for (rfp = *(unsigned int**)_ebp;
+  for (rfp = *(_Jv_uintptr_t **)_ebp;
        rfp && i < state->length;
-       rfp = *(unsigned int **)rfp)
+       rfp = *(_Jv_uintptr_t **)rfp)
     {
-      int diff = *rfp - (unsigned int)rfp;
-      if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0)
+      /* Sanity checks to eliminate dubious-looking frame pointer chains.
+         The frame pointer should be a 32-bit word-aligned stack address.
+         Since the stack grows downwards on x86, the frame pointer must have
+         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
+          || 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)
+        {
+          state->frames[i-1].start_ip
+            = (void *)((_Jv_uintptr_t)ip + 4 + *(_Jv_uintptr_t *)ip);
+        }
+
       state->frames[i].type = frame_native;
-      state->frames[i].ip = (void*)(rfp[1]-4);
+      state->frames[i].ip = ip;
+
       i++;
     }
   state->pos = i;
Index: stacktrace.cc
===================================================================
--- stacktrace.cc	(revision 114838)
+++ stacktrace.cc	(working copy)
@@ -9,16 +9,13 @@ Libgcj License.  Please consult the file
 details.  */
 
 #include <config.h>
+#include <platform.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>
@@ -184,41 +181,36 @@ _Jv_StackTrace::getLineNumberForFrame(_J
       return;
     }
 #endif
-  // Use dladdr() to determine in which binary the address IP resides.
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
-  Dl_info info;
+
+  // Use _Jv_platform_dladdr() to determine in which binary the address IP
+  // resides.
+  _Jv_AddrInfo info;
   jstring binaryName = NULL;
   const char *argv0 = _Jv_GetSafeArg(0);
 
   void *ip = frame->ip;
   _Unwind_Ptr offset = 0;
 
-  if (dladdr (ip, &info))
+  if (_Jv_platform_dladdr (ip, &info))
     {
-      if (info.dli_fname)
-	binaryName = JvNewStringUTF (info.dli_fname);
+      if (info.file_name)
+	binaryName = JvNewStringUTF (info.file_name);
       else
         return;
 
-      if (*methodName == NULL && info.dli_sname)
-	*methodName = JvNewStringUTF (info.dli_sname);
+      if (*methodName == NULL && info.sym_name)
+	*methodName = JvNewStringUTF (info.sym_name);
 
       // addr2line expects relative addresses for shared libraries.
-      if (strcmp (info.dli_fname, argv0) == 0)
+      if (strcmp (info.file_name, argv0) == 0)
         offset = (_Unwind_Ptr) ip;
       else
-        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.dli_fbase;
+        offset = (_Unwind_Ptr) ip - (_Unwind_Ptr) info.base;
 
-      //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();
@@ -234,7 +226,6 @@ _Jv_StackTrace::getLineNumberForFrame(_J
           *sourceFileName = t->toString();
         }
     }
-#endif
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +274,7 @@ _Jv_StackTrace::GetStackTraceElements (_
 {
   ArrayList *list = new ArrayList ();
 
-#ifdef SJLJ_EXCEPTIONS
+#if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
   // 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");
@@ -302,7 +293,7 @@ _Jv_StackTrace::GetStackTraceElements (_
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +361,7 @@ _Jv_StackTrace::GetStackTraceElements (_
     }
   
   finder->close();
-#endif /* SJLJ_EXCEPTIONS */
+#endif /* SJLJ_EXCEPTIONS && !WIN32 */
 
   JArray<Object *> *array = JvNewObjectArray (list->size (), 
     &StackTraceElement::class$, NULL);
@@ -472,7 +463,13 @@ _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;
@@ -543,7 +540,13 @@ _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;

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-29  4:06       ` Ranjit Mathew
@ 2006-06-29 16:27         ` Ranjit Mathew
  2006-06-29 18:27           ` Tom Tromey
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-06-29 16:27 UTC (permalink / raw)
  To: java-patches

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

Ranjit Mathew wrote:
> 
> I've tested this revision with an i686-pc-linux-gnu to
> i686-pc-mingw32 cross-compiler. I hope to commit it
> after testing with an i686-pc-linux-gnu native compiler
> finishes successfully.

The i686-pc-linux-gnu native compiler built successfully
and there were no regressions in the testsuire. Visual
inspection of stacktraces with native and interpreted
programmes also looked OK.

I have therefore checked in the patch.

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

iD8DBQFEo/92Yb1hx2wRS48RAp/NAJ9CiHDCKcSK2CSLMIiBsPFMGmcv4wCfeG1n
zJcDoDrDKvDnio5HVxpiO0o=
=T8LJ
-----END PGP SIGNATURE-----

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-29 16:27         ` Ranjit Mathew
@ 2006-06-29 18:27           ` Tom Tromey
  0 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2006-06-29 18:27 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

>>>>> "Ranjit" == Ranjit Mathew <rmathew@gmail.com> writes:

Ranjit> I have therefore checked in the patch.

Excellent, thanks.  And, thanks for persevering through the rewrites.

Tom

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-06-27  1:29   ` Ranjit Mathew
  2006-06-27  8:33     ` Andrew Haley
@ 2006-07-05  9:22     ` Ranjit Mathew
  2006-07-05 15:08       ` Bryce McKinlay
  1 sibling, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-07-05  9:22 UTC (permalink / raw)
  To: java-patches

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

Ranjit Mathew wrote:
> Andrew Haley wrote:
>>> What happens with -findirect-dispatch?
> 
> The stack-trace changes to:
> --------------------------- 8< ---------------------------
> Exception in thread "main" java.lang.Exception: I don't like you!
>    at java.lang.VMThrowable.fillInStackTrace(a.exe)
>    at java.lang.Throwable.<init>(a.exe)
> --------------------------- 8< ---------------------------

Since methods are called via the atable, the calling
instruction is no longer a simple "CALL <XYZ>". The
hack in fallback_backtrace() therefore doesn't work
for methods called via indirect dispatch.

Ranjit.

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

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


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEq4R9Yb1hx2wRS48RAjLeAJ9rVvX1eza8wdbwhtBvuikJ7S/LSgCfQoVj
5+1En2FwUuqXnsTBwLutF+c=
=dSwC
-----END PGP SIGNATURE-----

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05  9:22     ` Ranjit Mathew
@ 2006-07-05 15:08       ` Bryce McKinlay
  2006-07-05 15:51         ` Ranjit Mathew
  0 siblings, 1 reply; 36+ messages in thread
From: Bryce McKinlay @ 2006-07-05 15:08 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
>> The stack-trace changes to:
>> --------------------------- 8< ---------------------------
>> Exception in thread "main" java.lang.Exception: I don't like you!
>>    at java.lang.VMThrowable.fillInStackTrace(a.exe)
>>    at java.lang.Throwable.<init>(a.exe)
>> --------------------------- 8< ---------------------------
>>     
>
> Since methods are called via the atable, the calling
> instruction is no longer a simple "CALL <XYZ>". The
> hack in fallback_backtrace() therefore doesn't work
> for methods called via indirect dispatch.
>   

I don't think it'll work for ordinary virtual calls either, or even 
non-local calls in a non-static-linked binary.

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 15:08       ` Bryce McKinlay
@ 2006-07-05 15:51         ` Ranjit Mathew
  2006-07-05 16:07           ` Bryce McKinlay
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-07-05 15:51 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

On 7/5/06, Bryce McKinlay <mckinlay@redhat.com> wrote:
> > Since methods are called via the atable, the calling
> > instruction is no longer a simple "CALL <XYZ>". The
> > hack in fallback_backtrace() therefore doesn't work
> > for methods called via indirect dispatch.
> >
>
> I don't think it'll work for ordinary virtual calls either, or even
> non-local calls in a non-static-linked binary.

Yes. I realise that my testing was always with static
methods. :-(

Perhaps we should try to resurrect the c++filt bit in
NameFinder for such severely crippled targets...

Thanks,
Ranjit.

-- 
Ranjit Mathew      Email: rmathew AT gmail DOT com

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

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 15:51         ` Ranjit Mathew
@ 2006-07-05 16:07           ` Bryce McKinlay
  2006-07-05 17:13             ` Ranjit Mathew
  0 siblings, 1 reply; 36+ messages in thread
From: Bryce McKinlay @ 2006-07-05 16:07 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew wrote:
> Yes. I realise that my testing was always with static
> methods. :-(
>
> Perhaps we should try to resurrect the c++filt bit in
> NameFinder for such severely crippled targets...

Using dlsym/c++filt is a poor solution because it is slow and relies on 
a binary which (windows) users are not likely to have installed. Even if 
we were to parse the method symbols directly, this approach is not 
usable for security and calling-class checks.

A better solution, I think, would be to add a "method length" field to 
class metadata. This would mean that we could build a data structure of 
IP ranges and use that to find the method based just on the IP. A little 
tricky for CNI methods, though.

Bryce

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 16:07           ` Bryce McKinlay
@ 2006-07-05 17:13             ` Ranjit Mathew
  2006-07-05 17:20               ` Andrew Haley
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-07-05 17:13 UTC (permalink / raw)
  To: Bryce McKinlay; +Cc: java-patches

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

Bryce McKinlay wrote:
> 
> A better solution, I think, would be to add a "method length" field to 
> class metadata. This would mean that we could build a data structure of 
> IP ranges and use that to find the method based just on the IP. A little 
> tricky for CNI methods, though.

Without affecting the class metadata, there is perhaps
another approach we can take: from the faulting instruction,
scan backwards on an even address boundary for the function
prologue "pushl %ebp; movl %esp, %ebp" (in any case we assume
- -fno-omit-frame-pointer for fallback_backtrace()) for
some arbitrary amount of code, say, 64K.

Do you think this is viable?

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

iD8DBQFEq/NxYb1hx2wRS48RAj7uAJ96aNFuRCI5WFbT8nX+5U0HaO60XgCdE8Ab
N9LoXEbpUO5zyzcc7IhDLLc=
=/jPl
-----END PGP SIGNATURE-----

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 17:13             ` Ranjit Mathew
@ 2006-07-05 17:20               ` Andrew Haley
  2006-07-05 17:35                 ` Ranjit Mathew
  0 siblings, 1 reply; 36+ messages in thread
From: Andrew Haley @ 2006-07-05 17:20 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: Bryce McKinlay, java-patches

Ranjit Mathew writes:
 > -----BEGIN PGP SIGNED MESSAGE-----
 > Hash: SHA1
 > 
 > Bryce McKinlay wrote:
 > > 
 > > A better solution, I think, would be to add a "method length" field to 
 > > class metadata. This would mean that we could build a data structure of 
 > > IP ranges and use that to find the method based just on the IP. A little 
 > > tricky for CNI methods, though.
 > 
 > Without affecting the class metadata, there is perhaps another
 > approach we can take: from the faulting instruction, scan backwards
 > on an even address boundary for the function prologue "pushl %ebp;
 > movl %esp, %ebp" (in any case we assume - -fno-omit-frame-pointer
 > for fallback_backtrace()) for some arbitrary amount of code, say,
 > 64K.
 > 
 > Do you think this is viable?

Probably, but is it worth it?  Wouldn't it be better to apply all those
brain cycles to fixing exception handling to use DWARF rather than all
these kludges?

Andrew.

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 17:20               ` Andrew Haley
@ 2006-07-05 17:35                 ` Ranjit Mathew
  2006-07-05 17:39                   ` Andrew Haley
  0 siblings, 1 reply; 36+ messages in thread
From: Ranjit Mathew @ 2006-07-05 17:35 UTC (permalink / raw)
  To: Andrew Haley; +Cc: java-patches

On 7/5/06, Andrew Haley <aph@redhat.com> wrote:
>
> Probably, but is it worth it?  Wouldn't it be better to apply all those
> brain cycles to fixing exception handling to use DWARF rather than all
> these kludges?

I couldn't agree with you more. However, switching to DW2 EH
will not happen:

  1. for GCC 4.2.0
  2. unless someone figures out the unwinding-from-a-GUI-callback
  thing.

Given these constraints, I think it is not that much of a waste of time
to make stack traces work with SJLJ EH for MinGW.

Thanks,
Ranjit.

-- 
Ranjit Mathew      Email: rmathew AT gmail DOT com

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

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

* Re: [MinGW] RFC/RFA: Get Partial Stack Traces on Windows
  2006-07-05 17:35                 ` Ranjit Mathew
@ 2006-07-05 17:39                   ` Andrew Haley
  0 siblings, 0 replies; 36+ messages in thread
From: Andrew Haley @ 2006-07-05 17:39 UTC (permalink / raw)
  To: Ranjit Mathew; +Cc: java-patches

Ranjit Mathew writes:
 > On 7/5/06, Andrew Haley <aph@redhat.com> wrote:
 > >
 > > Probably, but is it worth it?  Wouldn't it be better to apply all those
 > > brain cycles to fixing exception handling to use DWARF rather than all
 > > these kludges?
 > 
 > I couldn't agree with you more. However, switching to DW2 EH
 > will not happen:
 > 
 >   1. for GCC 4.2.0
 >   2. unless someone figures out the unwinding-from-a-GUI-callback
 >   thing.
 > 
 > Given these constraints, I think it is not that much of a waste of time
 > to make stack traces work with SJLJ EH for MinGW.

OK.  Well, scanning backwards for the prologue should work.

Andrew.

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

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

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-26 18:16 [MinGW] RFC/RFA: Get Partial Stack Traces on Windows Ranjit Mathew
2006-06-26 18:38 ` Bryce McKinlay
2006-06-27  2:23   ` Ranjit Mathew
2006-06-27 11:27     ` Marco Trudel
2006-06-27 11:38       ` Ranjit Mathew
2006-06-27 12:37         ` Marco Trudel
2006-06-27 13:14           ` Ranjit Mathew
2006-06-27 21:20     ` Bryce McKinlay
2006-06-26 19:06 ` Andrew Haley
2006-06-26 19:15   ` Tom Tromey
2006-06-26 19:20     ` Andrew Haley
2006-06-27  1:29   ` Ranjit Mathew
2006-06-27  8:33     ` Andrew Haley
2006-06-27  9:11       ` Ranjit Mathew
2006-06-27  9:29         ` Andrew Haley
2006-06-27 21:57         ` Bryce McKinlay
2006-07-05  9:22     ` Ranjit Mathew
2006-07-05 15:08       ` Bryce McKinlay
2006-07-05 15:51         ` Ranjit Mathew
2006-07-05 16:07           ` Bryce McKinlay
2006-07-05 17:13             ` Ranjit Mathew
2006-07-05 17:20               ` Andrew Haley
2006-07-05 17:35                 ` Ranjit Mathew
2006-07-05 17:39                   ` Andrew Haley
2006-06-27 15:28 ` Ranjit Mathew
2006-06-27 19:57   ` Tom Tromey
2006-06-28  2:51 ` Ranjit Mathew
2006-06-28 13:56   ` Ranjit Mathew
2006-06-28 15:02     ` Bryce McKinlay
2006-06-28 15:15       ` Andrew Haley
2006-06-28 15:45         ` Bryce McKinlay
2006-06-28 15:49         ` Bryce McKinlay
2006-06-28 16:11           ` Andrew Haley
2006-06-29  4:06       ` Ranjit Mathew
2006-06-29 16:27         ` Ranjit Mathew
2006-06-29 18:27           ` Tom Tromey

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