aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2006-04-30 17:45:10 +0000
committerMark Mitchell <mark@codesourcery.com>2006-04-30 17:45:10 +0000
commitaf87caaf5ab9c29aacd068937d73d43ae55b2643 (patch)
tree3cf5eff8d81dc32f9682be72efc2801da6cf0287
parent2d12d46d2312fb2677ad030f456d36628c3496eb (diff)
Backport:
2004-10-28 Pascal Obry <obry@act-europe.fr> * w32-shared-ptr.c: New file. * w32-shared-ptr.h: Likewise. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl-gxxpro-3_4-branch@113393 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--ChangeLog.csl7
-rw-r--r--gcc/config/i386/w32-shared-ptr.c248
-rw-r--r--gcc/config/i386/w32-shared-ptr.h65
-rw-r--r--gcc/config/i386/win32-ehfb.c196
4 files changed, 516 insertions, 0 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index fb185dcbd32..a7d4858a60c 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,10 @@
+2006-04-30 Mark Mitchell <mark@codesourcery.com>
+
+ Backport:
+ 2004-10-28 Pascal Obry <obry@act-europe.fr>
+ * w32-shared-ptr.c: New file.
+ * w32-shared-ptr.h: Likewise.
+
2006-04-26 Joseph Myers <joseph@codesourcery.com>
From Bugzilla:
diff --git a/gcc/config/i386/w32-shared-ptr.c b/gcc/config/i386/w32-shared-ptr.c
new file mode 100644
index 00000000000..c0ef09d410c
--- /dev/null
+++ b/gcc/config/i386/w32-shared-ptr.c
@@ -0,0 +1,248 @@
+/*
+ * w32-shared-ptr.c
+ *
+ * Share informations between EXE/DLLs without using an
+ * additional DLL.
+ *
+ * Contributors:
+ * Created by Adriano dos Santos Fernandes <adrianosf@uol.com.br>
+ * Enhanced by Thomas Pfaff <tpfaff@gmx.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAMED. This includes but is not limited to warrenties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifdef __MINGW32__
+#undef _CRTIMP
+#define _CRTIMP
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef __CYGWIN__
+#include <unistd.h>
+#endif
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "gthr.h"
+
+#include "w32-shared-ptr.h"
+
+#if defined (__CYGWIN__) /* FIXME: This shouldn't be necessary. */
+typedef unsigned short ATOM;
+ATOM __attribute__ ((stdcall)) AddAtomA(const char*);
+ATOM __attribute__ ((stdcall)) FindAtomA(const char*);
+unsigned int __attribute__ ((stdcall)) GetAtomNameA(ATOM,char*,int);
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include <assert.h>
+
+W32_EH_SHARED * __w32_sharedptr;
+
+void ** __w32_sharedptr_terminate;
+void ** __w32_sharedptr_unexpected;
+
+
+#define W32_ATOM_SUFFIX "-LIBGCCW32-EH"
+
+#define VERSION_SUFFIX "-2"
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#define SJLJ_SUFFIX "-SJLJ"
+#else
+#define SJLJ_SUFFIX
+#endif
+
+#if __GTHREADS
+#define GTHR_SUFFIX "-GTHR"
+#else
+#define GTHR_SUFFIX
+#endif
+
+#ifdef __CYGWIN__
+#define SYS_SUFFIX "-CYGWIN"
+#else
+#define SYS_SUFFIX "-MINGW32"
+#endif
+
+static const char w32_atom_suffix[]
+ = W32_ATOM_SUFFIX VERSION_SUFFIX SJLJ_SUFFIX GTHR_SUFFIX SYS_SUFFIX;
+
+#define SHAREDPTR_BIT1 'A'
+#define SHAREDPTR_BIT0 'a'
+
+#define SHAREDPTR_BITS (sizeof(W32_EH_SHARED*)*8)
+#define SHARED_ATOM_NAME_LEN (SHAREDPTR_BITS + sizeof(w32_atom_suffix))
+
+static ATOM __w32_sharedptr_set (W32_EH_SHARED *w32_sharedptr);
+static W32_EH_SHARED * __w32_sharedptr_get (ATOM atom);
+static void __w32_sharedptr_default_unexpected(void);
+
+#ifdef __CYGWIN__
+static void __w32_sharedptr_fixup_after_fork (void);
+#endif
+
+static void __w32_sharedptr_default_unexpected(void)
+{
+ ((void(*)(void))__w32_sharedptr->terminate)();
+}
+
+static void __w32_eh_shared_initialize (W32_EH_SHARED *w32_sharedptr)
+{
+#ifdef __GTHREAD_MUTEX_INIT
+ static __gthread_mutex_t dw2_object_mutex = __GTHREAD_MUTEX_INIT;
+#else
+ static __gthread_mutex_t dw2_object_mutex;
+#endif
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+ static __gthread_once_t dw2_once = __GTHREAD_ONCE_INIT;
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+#if __GTHREADS
+ static __gthread_key_t sjl_fc_key;
+ static __gthread_once_t sjl_once = __GTHREAD_ONCE_INIT;
+#endif
+#endif
+
+ memset (w32_sharedptr, 0, sizeof(W32_EH_SHARED));
+
+ w32_sharedptr->size = sizeof(W32_EH_SHARED);
+
+ w32_sharedptr->terminate = (void*)abort;
+ w32_sharedptr->unexpected = (void*)__w32_sharedptr_default_unexpected;
+
+ w32_sharedptr->dw2_object_mutex = dw2_object_mutex;
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+ w32_sharedptr->dw2_once = dw2_once;
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+ w32_sharedptr->sjlj_fc_static = NULL;
+#if __GTHREADS
+ w32_sharedptr->sjlj_fc_key = sjl_fc_key;
+ w32_sharedptr->sjlj_use_fc_key = -1;
+ w32_sharedptr->sjlj_once = sjl_once;
+#endif
+#endif
+}
+
+void __w32_sharedptr_initialize (void)
+{
+ W32_EH_SHARED *w32_sharedptr;
+ char s[SHARED_ATOM_NAME_LEN];
+ ATOM atom;
+
+ if (__w32_sharedptr)
+ return;
+
+ memset (s, SHAREDPTR_BIT1, SHAREDPTR_BITS);
+ memcpy (&(s[SHAREDPTR_BITS]), w32_atom_suffix, sizeof(w32_atom_suffix));
+
+ atom = FindAtomA (s);
+ if (atom)
+ w32_sharedptr = __w32_sharedptr_get (atom);
+ else
+ {
+ w32_sharedptr = (W32_EH_SHARED *) malloc (sizeof(W32_EH_SHARED));
+ if (!w32_sharedptr)
+ abort ();
+
+ __w32_eh_shared_initialize (w32_sharedptr);
+
+ if (__w32_sharedptr_set (w32_sharedptr))
+ {
+#ifdef __CYGWIN__
+ /* recreate atom after fork */
+ pthread_atfork (NULL,NULL,__w32_sharedptr_fixup_after_fork);
+#endif
+ }
+ else
+ {
+ free (w32_sharedptr);
+ w32_sharedptr = __w32_sharedptr_get (FindAtomA (s));
+ }
+ }
+
+ __w32_sharedptr_terminate = &w32_sharedptr->terminate;
+ __w32_sharedptr_unexpected = &w32_sharedptr->unexpected;
+
+ /* THIS MUST BE THE LAST STEP */
+ __w32_sharedptr = w32_sharedptr;
+}
+
+static ATOM __w32_sharedptr_set (W32_EH_SHARED *w32_sharedptr)
+{
+ int i;
+ int bit;
+ char s[SHARED_ATOM_NAME_LEN];
+ ATOM atom;
+
+ /* This should optimize out entirely by O2 */
+ if (sizeof(bit) != sizeof(w32_sharedptr))
+ abort ();
+
+ for (i = SHAREDPTR_BITS - 1, bit = 1; i >= 0; --i, bit <<= 1)
+ s[i] = ((int)w32_sharedptr) & bit ? SHAREDPTR_BIT1 :
+ SHAREDPTR_BIT0;
+
+ memcpy (&(s[SHAREDPTR_BITS]), w32_atom_suffix, sizeof(w32_atom_suffix));
+
+ atom = AddAtomA (s);
+ /* Sanity check to avoid race by concurrent initialization */
+ if (!atom || __w32_sharedptr_get (atom) != w32_sharedptr)
+ return 0;
+
+#ifdef DEBUG
+ printf ("%s: set sharedptr: (%p):%s\n",
+ __FUNCTION__,w32_sharedptr, s);
+#endif
+
+ return atom;
+}
+
+static W32_EH_SHARED *__w32_sharedptr_get (ATOM atom)
+{
+ W32_EH_SHARED *w32_sharedptr;
+ int i;
+ int bit;
+ int address = 0;
+ char s[SHARED_ATOM_NAME_LEN];
+
+ /* If this fails something went wrong */
+ assert (GetAtomNameA (atom, s, sizeof(s)) != 0);
+
+ for (i = SHAREDPTR_BITS - 1, bit = 1; i >= 0; --i, bit <<= 1)
+ address |= s[i] == SHAREDPTR_BIT1 ? bit : 0;
+ w32_sharedptr = (W32_EH_SHARED*) address;
+
+ assert (w32_sharedptr->size == sizeof(W32_EH_SHARED));
+
+#ifdef DEBUG
+ printf ("%s: got sharedptr (%p): %s\n",
+ __FUNCTION__, w32_sharedptr, s);
+#endif
+ return w32_sharedptr;
+}
+
+#ifdef __CYGWIN__
+static void __w32_sharedptr_fixup_after_fork (void)
+{
+ assert (__w32_sharedptr_set (__w32_sharedptr) != 0);
+}
+#endif
diff --git a/gcc/config/i386/w32-shared-ptr.h b/gcc/config/i386/w32-shared-ptr.h
new file mode 100644
index 00000000000..d056a31e499
--- /dev/null
+++ b/gcc/config/i386/w32-shared-ptr.h
@@ -0,0 +1,65 @@
+/*
+ * w32-shared-ptr.h
+ *
+ * Contributors:
+ * Created by Thomas Pfaff <tpfaff@gmx.net>
+ *
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAMED. This includes but is not limited to warrenties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef GCC_W32_SHARED_PTR_H
+#define GCC_W32_SHARED_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+ int size;
+
+ void *terminate;
+ void *unexpected;
+
+ void *dw2_unseen_objects;
+ void *dw2_seen_objects;
+ __gthread_mutex_t dw2_object_mutex;
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+ __gthread_once_t dw2_once;
+#endif
+ void *dw2_marker;
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+ void* sjlj_fc_static;
+#if __GTHREADS
+ __gthread_key_t sjlj_fc_key;
+ int sjlj_use_fc_key;
+ __gthread_once_t sjlj_once;
+#endif
+#endif
+
+} W32_EH_SHARED;
+
+extern W32_EH_SHARED *__w32_sharedptr;
+
+extern void ** __w32_sharedptr_terminate;
+extern void ** __w32_sharedptr_unexpected;
+
+extern void __w32_sharedptr_initialize (void);
+
+#define W32_SHAREDPTR_INITIALIZE() if (!__w32_sharedptr) __w32_sharedptr_initialize ()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gcc/config/i386/win32-ehfb.c b/gcc/config/i386/win32-ehfb.c
new file mode 100644
index 00000000000..20debf7cb9b
--- /dev/null
+++ b/gcc/config/i386/win32-ehfb.c
@@ -0,0 +1,196 @@
+
+/* This file implements the md_fallback_frame_state_for routine for Windows,
+ triggered when the GCC table based unwinding process hits a frame for which
+ no unwind info has been registered. This typically occurs when raising an
+ exception from a signal handler, because the handler is actually called
+ from the OS kernel.
+
+ The basic idea is to detect that we are indeed trying to unwind past a
+ signal handler and to fill out the GCC internal unwinding structures for
+ the OS kernel frame as if it had been directly called from the interrupted
+ context.
+
+ This is all assuming that the code to set the handler asked the kernel to
+ pass a pointer to such context information.
+
+ There is three main parts.
+
+ 1) The first thing to do is to check if we are in a signal context. If not
+ we can just return as there is nothing to do. We are probably on some
+ foreign code for which no unwind frame can be found. If this is a call
+ from the Windows signal handler, then:
+
+ 2) We must get the signal context information.
+
+ * With the standard exception filter:
+
+ This is on Windows pointed to by an EXCEPTION_POINTERS. We know that the
+ signal handle will call an UnhandledExceptionFilter with this
+ parameter. The spec for this routine is:
+
+ LONG WINAPI UnhandledExceptionFilter(struct _EXCEPTION_POINTERS*);
+
+ So the pointer to struct _EXCEPTION_POINTERS must be somewhere on the
+ stack.
+
+ This was found experimentally to always be at offset 0 of the context
+ frame in all cases handled by this implementation.
+
+ * With the SEH exception handler:
+
+ In this case the signal context is directly on the stack as the SEH
+ exception handler has the following prototype:
+
+ DWORD
+ SEH_error_handler (PEXCEPTION_RECORD ExceptionRecord,
+ PVOID EstablisherFrame,
+ PCONTEXT ContextRecord,
+ PVOID DispatcherContext)
+
+ This was found experimentally to always be at offset 56 of the context
+ frame in all cases handled by this implementation.
+
+ 3) When we have the signal context we just have to save some registers and
+ set the return address based on the program counter (Eip).
+
+ Note that this implementation follows closely the same principles as the
+ GNU/Linux and OSF ones. */
+
+
+/* Patterns found experimentally to be on a Windows signal handler */
+
+/* In a standard exception filter */
+
+#define SIG_PAT1 \
+ (pc_[-2] == 0xff && pc_[-1] == 0xd0 /* call %eax */ \
+ && pc_[0] == 0x83 && pc_[1] == 0xf8) /* cmp 0xdepl,%eax */
+
+#define SIG_PAT2 \
+ (pc_[-5] == 0xe8 && pc_[-4] == 0x68 /* call (depl16) */ \
+ && pc_[0] == 0xc3) /* ret */
+
+/* In a Win32 SEH handler */
+
+#define SIG_SEH1 \
+ (pc_[-5] == 0xe8 /* call addr */ \
+ && pc_[0] == 0x83 && pc_[1] == 0xc4 /* add 0xval,%esp */ \
+ && pc_[3] == 0xb8) /* mov 0xval,%eax */
+
+#define SIG_SEH2 \
+ (pc_[-5] == 0x8b && pc_[-4] == 0x4d /* mov depl(%ebp),%ecx */ \
+ && pc_[0] == 0x64 && pc_[1] == 0x8b) /* mov %fs:(0),<reg> */ \
+
+/* In the GCC alloca (stack probing) */
+
+#define SIG_ALLOCA \
+ (pc_[-1] == 0x83 /* orl $0x0,(%ecx) */ \
+ && pc_[0] == 0x9 && pc_[1] == 0 \
+ && pc_[2] == 0x2d && pc_[3] == 0 /* subl $0x1000,%eax */ \
+ && pc_[4] == 0x10 && pc_[5] == 0)
+
+int
+md_fallback_frame_state_for (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs);
+
+int
+md_fallback_frame_state_for (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+
+{
+ char * eh_debug_env = getenv ("EH_DEBUG");
+ int eh_debug = eh_debug_env ? atoi (eh_debug_env) : 0;
+
+ void * ctx_ra_ = (void *)(context->ra); /* return address */
+ void * ctx_cfa_ = (void *)(context->cfa); /* context frame address */
+ unsigned char * pc_ = (unsigned char *) ctx_ra_;
+
+ if (eh_debug)
+ printf ("FALLBACK called for CFA = 0x%p, RA = 0x%p\n", ctx_cfa_, ctx_ra_);
+
+ /* In the test below we look for two specific patterns found
+ experimentally to be in the Windows signal handler. */
+
+ if (SIG_PAT1 || SIG_PAT2 || SIG_SEH1 || SIG_SEH2)
+ {
+ PEXCEPTION_POINTERS weinfo_;
+ PCONTEXT proc_ctx_;
+ long new_cfa_;
+
+ if (SIG_SEH1)
+ {
+ proc_ctx_ = (PCONTEXT) (*(int*)(ctx_cfa_ + 56));
+ }
+ else if (SIG_SEH2)
+ {
+ proc_ctx_ = (PCONTEXT) (*(int*)(ctx_cfa_ + 8));
+ }
+ else
+ {
+ weinfo_ = (PEXCEPTION_POINTERS) (*(int*)ctx_cfa_);
+ proc_ctx_ = weinfo_->ContextRecord;
+ }
+
+ /* The new context frame address is the stack pointer. */
+
+ new_cfa_ = proc_ctx_->Esp;
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = __builtin_dwarf_sp_column();
+ fs->cfa_offset = new_cfa_ - (long) ctx_cfa_;
+
+ /* Save some registers. */
+
+ fs->regs.reg[0].how = REG_SAVED_OFFSET;
+ fs->regs.reg[0].loc.offset = (long)&proc_ctx_->Eax - new_cfa_;
+ fs->regs.reg[3].how = REG_SAVED_OFFSET;
+ fs->regs.reg[3].loc.offset = (long)&proc_ctx_->Ebx - new_cfa_;
+ fs->regs.reg[1].how = REG_SAVED_OFFSET;
+ fs->regs.reg[1].loc.offset = (long)&proc_ctx_->Ecx - new_cfa_;
+ fs->regs.reg[2].how = REG_SAVED_OFFSET;
+ fs->regs.reg[2].loc.offset = (long)&proc_ctx_->Edx - new_cfa_;
+ fs->regs.reg[6].how = REG_SAVED_OFFSET;
+ fs->regs.reg[6].loc.offset = (long)&proc_ctx_->Esi - new_cfa_;
+ fs->regs.reg[7].how = REG_SAVED_OFFSET;
+ fs->regs.reg[7].loc.offset = (long)&proc_ctx_->Edi - new_cfa_;
+ fs->regs.reg[9].how = REG_SAVED_OFFSET;
+ fs->regs.reg[9].loc.offset = (long)&proc_ctx_->Eip - new_cfa_;
+ fs->regs.reg[4].how = REG_SAVED_OFFSET;
+ fs->regs.reg[4].loc.offset = (long)&proc_ctx_->Ebp - new_cfa_;
+
+ /* Set the return address to Eip + 1. As we can be called multiple
+ times we use another register for this. */
+
+ proc_ctx_->Dr0 = proc_ctx_->Eip + 1;
+ fs->regs.reg[8].how = REG_SAVED_OFFSET;
+ fs->regs.reg[8].loc.offset = (long)&proc_ctx_->Dr0 - new_cfa_;
+ fs->retaddr_column = 8;
+ return 1;
+ }
+
+ /* Unwinding through _alloca, propagating from a trap triggered by
+ one of it's probes prior to the real SP aadjustment. The only
+ operations of interest performed is "pushl %ecx", followed by
+ ecx clobbering. */
+
+ else if (SIG_ALLOCA)
+ {
+ /* Only one push between entry in _alloca and the probe trap. */
+ long new_cfa_ = (long) ctx_cfa_ + 4;
+
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = __builtin_dwarf_sp_column();
+ fs->cfa_offset = new_cfa_ - (long) ctx_cfa_;
+
+ /* The saved value of %ecx is at CFA - 4 */
+ fs->regs.reg[1].how = REG_SAVED_OFFSET;
+ fs->regs.reg[1].loc.offset = -4;
+
+ /* and what is stored at the CFA is the return address. */
+ fs->retaddr_column = 8;
+ fs->regs.reg[8].how = REG_SAVED_OFFSET;
+ fs->regs.reg[8].loc.offset = 0;
+
+ return 1;
+ }
+ else
+ return 0;
+}