diff options
author | Mark Mitchell <mark@codesourcery.com> | 2006-04-30 17:45:10 +0000 |
---|---|---|
committer | Mark Mitchell <mark@codesourcery.com> | 2006-04-30 17:45:10 +0000 |
commit | af87caaf5ab9c29aacd068937d73d43ae55b2643 (patch) | |
tree | 3cf5eff8d81dc32f9682be72efc2801da6cf0287 | |
parent | 2d12d46d2312fb2677ad030f456d36628c3496eb (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.csl | 7 | ||||
-rw-r--r-- | gcc/config/i386/w32-shared-ptr.c | 248 | ||||
-rw-r--r-- | gcc/config/i386/w32-shared-ptr.h | 65 | ||||
-rw-r--r-- | gcc/config/i386/win32-ehfb.c | 196 |
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; +} |