javaprims.h (_Jv_uintptr_t): New typedef similar to uintptr_t in C99.
authorRanjit Mathew <rmathew@gcc.gnu.org>
Thu, 29 Jun 2006 14:57:39 +0000 (14:57 +0000)
committerRanjit Mathew <rmathew@gcc.gnu.org>
Thu, 29 Jun 2006 14:57:39 +0000 (14:57 +0000)
* 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.

From-SVN: r115069

libjava/ChangeLog
libjava/gcj/javaprims.h
libjava/include/java-stack.h
libjava/include/posix.h
libjava/include/win32.h
libjava/posix.cc
libjava/stacktrace.cc
libjava/sysdep/i386/backtrace.h
libjava/win32.cc

index 55c07620a9b1de6f27dc4e9d05e26f3b408b3af3..9076505c5cf92afb0b0a6dc0652534997e411804 100644 (file)
@@ -1,3 +1,28 @@
+2006-06-29  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.
+
 2006-06-27  Tom Tromey  <tromey@redhat.com>
 
        * java/io/OutputStreamWriter.java (writeChars): Use a 'do' loop.
index 04f99edd68ccacc420f892eaa2cc427d379d73a2..61f5276c0229f473b1023263cea0125155e39aa9 100644 (file)
@@ -624,6 +624,10 @@ typedef unsigned short _Jv_ushort __attribute__((__mode__(__HI__)));
 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 7bf4d7b39d01df4f98075a51d1577c0aaf7923d5..eb1ddcce4c770598eda1cbae0b13a8ffb4c64893 100644 (file)
@@ -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 5b74eb7da77ec88f07751140f6723284678f2b58..15795ddfdafe36d1fb940b8577e0e387718b578a 100644 (file)
@@ -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 3e2beabe5d350403f5de508fb165326e783db661..26c307c1d47b401e223b7990a51049a7312d2f9c 100644 (file)
@@ -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 608fd5dad901e0793b464bac7a23d7cf9fa2da2d..41702dfffb90e4cc062435d467179d52f994aa39 100644 (file)
@@ -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_set  *writefds,
   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 5d429e67d145c6e2ab79b08c46ab8041dd6420fe..06a4dfadb98a4e2a275dcfede329667114b226b7 100644 (file)
@@ -9,16 +9,13 @@ Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 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(_Jv_StackFrame *frame, NameFinder *finder,
       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(_Jv_StackFrame *frame, NameFinder *finder,
           *sourceFileName = t->toString();
         }
     }
-#endif
 }
 
 // Look up class and method info for the given stack frame, setting 
@@ -283,7 +274,7 @@ _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
 {
   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 (_Jv_StackTrace *trace,
       list->add (element);
     }
 
-#else /* SJLJ_EXCEPTIONS */
+#else /* SJLJ_EXCEPTIONS && !WIN32 */
 
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
@@ -370,7 +361,7 @@ _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
     }
   
   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 checkClass)
   //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::GetFirstNonSystemClassLoader ()
   //JvSynchronized (ncodeMap);
   UpdateNCodeMap ();
   
+#ifdef SJLJ_EXCEPTIONS
+  // The Unwind interface doesn't work with the SJLJ exception model.
+  // Fall back to a platform-specific unwinder.
+  fallback_backtrace (&state);
+#else /* SJLJ_EXCEPTIONS */  
   _Unwind_Backtrace (UnwindTraceFn, &state);
+#endif /* SJLJ_EXCEPTIONS */  
 
   if (state.trace_data)
     return (ClassLoader *) state.trace_data;
index b10840213a4448d2bdb12a7418c9197ef832fc4a..8d46cbf1702ed1119c16798e5f91bdfa5ac75a17 100644 (file)
@@ -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 *state)
 {
   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 a0ae0f0f9cb52c1c7097f5d863fe26c5e36a22ac..a78f814c6873a087d3e96832b4037767767df281 100644 (file)
@@ -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::Properties* newprops)
     }
 }
 
-/* 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;
+}