javaprims.h (_Jv_uintptr_t): New typedef similar to uintptr_t in C99.

* 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
This commit is contained in:
Ranjit Mathew 2006-06-29 14:57:39 +00:00
parent 6150b60261
commit 3379268423
9 changed files with 209 additions and 58 deletions

View 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> 2006-06-27 Tom Tromey <tromey@redhat.com>
* java/io/OutputStreamWriter.java (writeChars): Use a 'do' loop. * java/io/OutputStreamWriter.java (writeChars): Use a 'do' loop.

View 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_uint __attribute__((__mode__(__SI__)));
typedef unsigned int _Jv_ulong __attribute__((__mode__(__DI__))); 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 class _Jv_Utf8Const
{ {
_Jv_ushort hash; _Jv_ushort hash;

View File

@ -1,6 +1,6 @@
// java-stack.h - Definitions for unwinding & inspecting the call stack. // 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. This file is part of libgcj.
@ -11,6 +11,7 @@ details. */
#ifndef __JV_STACKTRACE_H__ #ifndef __JV_STACKTRACE_H__
#define __JV_STACKTRACE_H__ #define __JV_STACKTRACE_H__
#include <stdlib.h>
#include <unwind.h> #include <unwind.h>
#include <gcj/cni.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__ */ #endif /* __JV_STACKTRACE_H__ */

View File

@ -194,4 +194,11 @@ _Jv_pipe (int filedes[2])
return ::pipe (filedes); 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__ */ #endif /* __JV_POSIX_H__ */

View File

@ -11,7 +11,7 @@ details. */
#ifndef __JV_WIN32_H__ #ifndef __JV_WIN32_H__
#define __JV_WIN32_H__ #define __JV_WIN32_H__
// Enable UNICODE Support.? // Enable UNICODE support?
#ifdef MINGW_LIBGCJ_UNICODE #ifdef MINGW_LIBGCJ_UNICODE
#define UNICODE #define UNICODE
@ -175,8 +175,11 @@ _Jv_platform_usleep (unsigned long usecs)
} }
#endif /* JV_HASH_SYNCHRONIZATION */ #endif /* JV_HASH_SYNCHRONIZATION */
/* Store up to SIZE return address of the current program state in // Forward declaration. See java-stack.h for definition.
ARRAY and return the exact number of values stored. */ struct _Jv_AddrInfo;
extern int backtrace (void **__array, int __size);
// 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__ */ #endif /* __JV_WIN32_H__ */

View File

@ -17,7 +17,12 @@ details. */
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <jvm.h> #include <jvm.h>
#include <java-stack.h>
#include <java/lang/Thread.h> #include <java/lang/Thread.h>
#include <java/io/InterruptedIOException.h> #include <java/io/InterruptedIOException.h>
#include <java/util/Properties.h> #include <java/util/Properties.h>
@ -203,3 +208,31 @@ _Jv_select (int n, fd_set *readfds, fd_set *writefds,
return 0; return 0;
#endif #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;
}

View File

@ -9,16 +9,13 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */ details. */
#include <config.h> #include <config.h>
#include <platform.h>
#include <jvm.h> #include <jvm.h>
#include <gcj/cni.h> #include <gcj/cni.h>
#include <java-interp.h> #include <java-interp.h>
#include <java-stack.h> #include <java-stack.h>
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <java/lang/Class.h> #include <java/lang/Class.h>
@ -184,41 +181,36 @@ _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
return; return;
} }
#endif #endif
// Use dladdr() to determine in which binary the address IP resides.
#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) // Use _Jv_platform_dladdr() to determine in which binary the address IP
Dl_info info; // resides.
_Jv_AddrInfo info;
jstring binaryName = NULL; jstring binaryName = NULL;
const char *argv0 = _Jv_GetSafeArg(0); const char *argv0 = _Jv_GetSafeArg(0);
void *ip = frame->ip; void *ip = frame->ip;
_Unwind_Ptr offset = 0; _Unwind_Ptr offset = 0;
if (dladdr (ip, &info)) if (_Jv_platform_dladdr (ip, &info))
{ {
if (info.dli_fname) if (info.file_name)
binaryName = JvNewStringUTF (info.dli_fname); binaryName = JvNewStringUTF (info.file_name);
else else
return; return;
if (*methodName == NULL && info.dli_sname) if (*methodName == NULL && info.sym_name)
*methodName = JvNewStringUTF (info.dli_sname); *methodName = JvNewStringUTF (info.sym_name);
// addr2line expects relative addresses for shared libraries. // 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; offset = (_Unwind_Ptr) ip;
else 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 // The unwinder gives us the return address. In order to get the right
// line number for the stack trace, roll it back a little. // line number for the stack trace, roll it back a little.
offset -= 1; offset -= 1;
// printf ("%s: 0x%x\n", info.dli_fname, offset);
finder->lookup (binaryName, (jlong) offset); finder->lookup (binaryName, (jlong) offset);
*sourceFileName = finder->getSourceFile(); *sourceFileName = finder->getSourceFile();
*lineNum = finder->getLineNum(); *lineNum = finder->getLineNum();
@ -234,7 +226,6 @@ _Jv_StackTrace::getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder,
*sourceFileName = t->toString(); *sourceFileName = t->toString();
} }
} }
#endif
} }
// Look up class and method info for the given stack frame, setting // 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 (); ArrayList *list = new ArrayList ();
#ifdef SJLJ_EXCEPTIONS #if defined (SJLJ_EXCEPTIONS) && ! defined (WIN32)
// We can't use the nCodeMap without unwinder support. Instead, // We can't use the nCodeMap without unwinder support. Instead,
// fake the method name by giving the IP in hex - better than nothing. // fake the method name by giving the IP in hex - better than nothing.
jstring hex = JvNewStringUTF ("0x"); jstring hex = JvNewStringUTF ("0x");
@ -302,7 +293,7 @@ _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
list->add (element); list->add (element);
} }
#else /* SJLJ_EXCEPTIONS */ #else /* SJLJ_EXCEPTIONS && !WIN32 */
//JvSynchronized (ncodeMap); //JvSynchronized (ncodeMap);
UpdateNCodeMap (); UpdateNCodeMap ();
@ -370,7 +361,7 @@ _Jv_StackTrace::GetStackTraceElements (_Jv_StackTrace *trace,
} }
finder->close(); finder->close();
#endif /* SJLJ_EXCEPTIONS */ #endif /* SJLJ_EXCEPTIONS && !WIN32 */
JArray<Object *> *array = JvNewObjectArray (list->size (), JArray<Object *> *array = JvNewObjectArray (list->size (),
&StackTraceElement::class$, NULL); &StackTraceElement::class$, NULL);
@ -472,7 +463,13 @@ _Jv_StackTrace::GetClassContext (jclass checkClass)
//JvSynchronized (ncodeMap); //JvSynchronized (ncodeMap);
UpdateNCodeMap (); 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); _Unwind_Backtrace (UnwindTraceFn, &state);
#endif /* SJLJ_EXCEPTIONS */
// Count the number of Java frames on the stack. // Count the number of Java frames on the stack.
int jframe_count = 0; int jframe_count = 0;
@ -543,7 +540,13 @@ _Jv_StackTrace::GetFirstNonSystemClassLoader ()
//JvSynchronized (ncodeMap); //JvSynchronized (ncodeMap);
UpdateNCodeMap (); 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); _Unwind_Backtrace (UnwindTraceFn, &state);
#endif /* SJLJ_EXCEPTIONS */
if (state.trace_data) if (state.trace_data)
return (ClassLoader *) state.trace_data; return (ClassLoader *) state.trace_data;

View File

@ -1,6 +1,6 @@
// backtrace.h - Fallback backtrace implementation. i386 implementation. // 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. This file is part of libgcj.
@ -22,19 +22,44 @@ fallback_backtrace (_Jv_UnwindState *state)
{ {
register void *_ebp __asm__ ("ebp"); register void *_ebp __asm__ ("ebp");
register void *_esp __asm__ ("esp"); register void *_esp __asm__ ("esp");
unsigned int *rfp; _Jv_uintptr_t *rfp;
int i = state->pos; int i = state->pos;
for (rfp = *(unsigned int**)_ebp; for (rfp = *(_Jv_uintptr_t **)_ebp;
rfp && i < state->length; rfp && i < state->length;
rfp = *(unsigned int **)rfp) rfp = *(_Jv_uintptr_t **)rfp)
{ {
int diff = *rfp - (unsigned int)rfp; /* Sanity checks to eliminate dubious-looking frame pointer chains.
if ((void*)rfp < _esp || diff > 4 * 1024 || diff < 0) 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; 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].type = frame_native;
state->frames[i].ip = (void*)(rfp[1]-4); state->frames[i].ip = ip;
i++; i++;
} }
state->pos = i; state->pos = i;

View File

@ -12,8 +12,11 @@ details. */
#include <platform.h> #include <platform.h>
#include <sys/timeb.h> #include <sys/timeb.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <java-stack.h>
#include <java/lang/ArithmeticException.h> #include <java/lang/ArithmeticException.h>
#include <java/lang/UnsupportedOperationException.h> #include <java/lang/UnsupportedOperationException.h>
#include <java/io/IOException.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 int
_Jv_pipe (int filedes[2]) _Jv_pipe (int filedes[2])
{ {
@ -477,3 +458,42 @@ _Jv_platform_close_on_exec (HANDLE h)
// no effect under Win9X. // no effect under Win9X.
SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0); 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;
}