summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libjava/ChangeLog25
-rw-r--r--libjava/gcj/javaprims.h4
-rw-r--r--libjava/include/java-stack.h33
-rw-r--r--libjava/include/posix.h7
-rw-r--r--libjava/include/win32.h11
-rw-r--r--libjava/posix.cc33
-rw-r--r--libjava/stacktrace.cc51
-rw-r--r--libjava/sysdep/i386/backtrace.h39
-rw-r--r--libjava/win32.cc64
9 files changed, 209 insertions, 58 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 55c07620a9b..9076505c5cf 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -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.
diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h
index 04f99edd68c..61f5276c022 100644
--- a/libjava/gcj/javaprims.h
+++ b/libjava/gcj/javaprims.h
@@ -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;
diff --git a/libjava/include/java-stack.h b/libjava/include/java-stack.h
index 7bf4d7b39d0..eb1ddcce4c7 100644
--- a/libjava/include/java-stack.h
+++ b/libjava/include/java-stack.h
@@ -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__ */
diff --git a/libjava/include/posix.h b/libjava/include/posix.h
index 5b74eb7da77..15795ddfdaf 100644
--- a/libjava/include/posix.h
+++ b/libjava/include/posix.h
@@ -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__ */
diff --git a/libjava/include/win32.h b/libjava/include/win32.h
index 3e2beabe5d3..26c307c1d47 100644
--- a/libjava/include/win32.h
+++ b/libjava/include/win32.h
@@ -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__ */
diff --git a/libjava/posix.cc b/libjava/posix.cc
index 608fd5dad90..41702dfffb9 100644
--- a/libjava/posix.cc
+++ b/libjava/posix.cc
@@ -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;
+}
diff --git a/libjava/stacktrace.cc b/libjava/stacktrace.cc
index 5d429e67d14..06a4dfadb98 100644
--- a/libjava/stacktrace.cc
+++ b/libjava/stacktrace.cc
@@ -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;
diff --git a/libjava/sysdep/i386/backtrace.h b/libjava/sysdep/i386/backtrace.h
index b10840213a4..8d46cbf1702 100644
--- a/libjava/sysdep/i386/backtrace.h
+++ b/libjava/sysdep/i386/backtrace.h
@@ -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;
diff --git a/libjava/win32.cc b/libjava/win32.cc
index a0ae0f0f9cb..a78f814c687 100644
--- a/libjava/win32.cc
+++ b/libjava/win32.cc
@@ -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;
+}