1/* Mudflap: narrow-pointer bounds-checking by tree rewriting. 2 Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. 3 Contributed by Frank Ch. Eigler <fche@redhat.com> 4 and Graydon Hoare <graydon@redhat.com> 5 6This file is part of GCC. 7 8GCC is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13In addition to the permissions in the GNU General Public License, the 14Free Software Foundation gives you unlimited permission to link the 15compiled version of this file into combinations with other programs, 16and to distribute those combinations without any restriction coming 17from the use of this file. (The General Public License restrictions 18do apply in other respects; for example, they cover modification of 19the file, and distribution when not linked into a combine 20executable.) 21 22GCC is distributed in the hope that it will be useful, but WITHOUT ANY 23WARRANTY; without even the implied warranty of MERCHANTABILITY or 24FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25for more details. 26 27You should have received a copy of the GNU General Public License 28along with GCC; see the file COPYING. If not, write to the Free 29Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 3002110-1301, USA. */ 31 32 33#include "config.h" 34 35#ifndef HAVE_SOCKLEN_T 36#define socklen_t int 37#endif 38 39/* These attempt to coax various unix flavours to declare all our 40 needed tidbits in the system headers. */ 41#if !defined(__FreeBSD__) && !defined(__APPLE__) 42#define _POSIX_SOURCE 43#endif /* Some BSDs break <sys/socket.h> if this is defined. */ 44#define _GNU_SOURCE 45#define _XOPEN_SOURCE 46#define _BSD_TYPES 47#define __EXTENSIONS__ 48#define _ALL_SOURCE 49#define _LARGE_FILE_API 50#define _XOPEN_SOURCE_EXTENDED 1 51 52#include <string.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <unistd.h> 56#include <assert.h> 57#include <errno.h> 58#include <stdbool.h> 59 60#include "mf-runtime.h" 61#include "mf-impl.h" 62 63#ifdef _MUDFLAP 64#error "Do not compile this file with -fmudflap!" 65#endif 66 67#ifndef LIBMUDFLAPTH 68#error "pthreadstuff is to be included only in libmudflapth" 69#endif 70 71/* ??? Why isn't this done once in the header files. */ 72DECLARE(void *, malloc, size_t sz); 73DECLARE(void, free, void *ptr); 74DECLARE(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, 75 void * (*start) (void *), void *arg); 76 77 78/* Multithreading support hooks. */ 79 80 81#ifndef HAVE_TLS 82/* We don't have TLS. Ordinarily we could use pthread keys, but since we're 83 commandeering malloc/free that presents a few problems. The first is that 84 we'll recurse from __mf_get_state to pthread_setspecific to malloc back to 85 __mf_get_state during thread startup. This can be solved with clever uses 86 of a mutex. The second problem is that thread shutdown is indistinguishable 87 from thread startup, since libpthread is deallocating our state variable. 88 I've no good solution for this. 89 90 Which leaves us to handle this mess by totally by hand. */ 91 92/* Yes, we want this prime. If pthread_t is a pointer, it's almost always 93 page aligned, and if we use a smaller power of 2, this results in "%N" 94 being the worst possible hash -- all threads hash to zero. */ 95#define LIBMUDFLAPTH_THREADS_MAX 1021 96 97struct mf_thread_data 98{ 99 pthread_t self; 100 unsigned char used_p; 101 unsigned char state; 102}; 103 104static struct mf_thread_data mf_thread_data[LIBMUDFLAPTH_THREADS_MAX]; 105static pthread_mutex_t mf_thread_data_lock = PTHREAD_MUTEX_INITIALIZER; 106 107#define PTHREAD_HASH(p) ((unsigned long) (p) % LIBMUDFLAPTH_THREADS_MAX) 108 109static struct mf_thread_data * 110__mf_find_threadinfo (int alloc) 111{ 112 pthread_t self = pthread_self (); 113 unsigned long hash = PTHREAD_HASH (self); 114 unsigned long rehash; 115 116#ifdef __alpha__ 117 /* Alpha has the loosest memory ordering rules of all. We need a memory 118 barrier to flush the reorder buffer before considering a *read* of a 119 shared variable. Since we're not always taking a lock, we have to do 120 this by hand. */ 121 __sync_synchronize (); 122#endif 123 124 rehash = hash; 125 while (1) 126 { 127 if (mf_thread_data[rehash].used_p && mf_thread_data[rehash].self == self) 128 return &mf_thread_data[rehash]; 129 130 rehash += 7; 131 if (rehash >= LIBMUDFLAPTH_THREADS_MAX) 132 rehash -= LIBMUDFLAPTH_THREADS_MAX; 133 if (rehash == hash) 134 break; 135 } 136 137 if (alloc) 138 { 139 pthread_mutex_lock (&mf_thread_data_lock); 140 141 rehash = hash; 142 while (1) 143 { 144 if (!mf_thread_data[rehash].used_p) 145 { 146 mf_thread_data[rehash].self = self; 147 __sync_synchronize (); 148 mf_thread_data[rehash].used_p = 1; 149 150 pthread_mutex_unlock (&mf_thread_data_lock); 151 return &mf_thread_data[rehash]; 152 } 153 154 rehash += 7; 155 if (rehash >= LIBMUDFLAPTH_THREADS_MAX) 156 rehash -= LIBMUDFLAPTH_THREADS_MAX; 157 if (rehash == hash) 158 break; 159 } 160 161 pthread_mutex_unlock (&mf_thread_data_lock); 162 } 163 164 return NULL; 165} 166 167enum __mf_state_enum 168__mf_get_state (void) 169{ 170 struct mf_thread_data *data = __mf_find_threadinfo (0); 171 if (data) 172 return data->state; 173 174 /* If we've never seen this thread before, consider it to be in the 175 reentrant state. The state gets reset to active for the main thread 176 in __mf_init, and for child threads in __mf_pthread_spawner. 177 178 The trickiest bit here is that the LinuxThreads pthread_manager thread 179 should *always* be considered to be reentrant, so that none of our 180 hooks actually do anything. Why? Because that thread isn't a real 181 thread from the point of view of the thread library, and so lots of 182 stuff isn't initialized, leading to SEGV very quickly. Even calling 183 pthread_self is a bit suspect, but it happens to work. */ 184 185 return reentrant; 186} 187 188void 189__mf_set_state (enum __mf_state_enum new_state) 190{ 191 struct mf_thread_data *data = __mf_find_threadinfo (1); 192 data->state = new_state; 193} 194#endif 195 196/* The following two functions are used only with __mf_opts.heur_std_data. 197 We're interested in recording the location of the thread-local errno 198 variable. 199 200 Note that this doesn't handle TLS references in general; we have no 201 visibility into __tls_get_data for when that memory is allocated at 202 runtime. Hopefully we get to see the malloc or mmap operation that 203 eventually allocates the backing store. */ 204 205/* Describe the startup information for a new user thread. */ 206struct mf_thread_start_info 207{ 208 /* The user's thread entry point and argument. */ 209 void * (*user_fn)(void *); 210 void *user_arg; 211}; 212 213 214static void 215__mf_pthread_cleanup (void *arg) 216{ 217 if (__mf_opts.heur_std_data) 218 __mf_unregister (&errno, sizeof (errno), __MF_TYPE_GUESS); 219 220#ifndef HAVE_TLS 221 struct mf_thread_data *data = __mf_find_threadinfo (0); 222 if (data) 223 data->used_p = 0; 224#endif 225} 226 227 228static void * 229__mf_pthread_spawner (void *arg) 230{ 231 void *result = NULL; 232 233 __mf_set_state (active); 234 235 /* NB: We could use __MF_TYPE_STATIC here, but we guess that the thread 236 errno is coming out of some dynamically allocated pool that we already 237 know of as __MF_TYPE_HEAP. */ 238 if (__mf_opts.heur_std_data) 239 __mf_register (&errno, sizeof (errno), __MF_TYPE_GUESS, 240 "errno area (thread)"); 241 242 /* We considered using pthread_key_t objects instead of these 243 cleanup stacks, but they were less cooperative with the 244 interposed malloc hooks in libmudflap. */ 245 /* ??? The pthread_key_t problem is solved above... */ 246 pthread_cleanup_push (__mf_pthread_cleanup, NULL); 247 248 /* Extract given entry point and argument. */ 249 struct mf_thread_start_info *psi = arg; 250 void * (*user_fn)(void *) = psi->user_fn; 251 void *user_arg = psi->user_arg; 252 CALL_REAL (free, arg); 253 254 result = (*user_fn)(user_arg); 255 256 pthread_cleanup_pop (1 /* execute */); 257 258 return result; 259} 260 261 262#if PIC 263/* A special bootstrap variant. */ 264int 265__mf_0fn_pthread_create (pthread_t *thr, const pthread_attr_t *attr, 266 void * (*start) (void *), void *arg) 267{ 268 return -1; 269} 270#endif 271 272 273#undef pthread_create 274WRAPPER(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, 275 void * (*start) (void *), void *arg) 276{ 277 struct mf_thread_start_info *si; 278 279 TRACE ("pthread_create\n"); 280 281 /* Fill in startup-control fields. */ 282 si = CALL_REAL (malloc, sizeof (*si)); 283 si->user_fn = start; 284 si->user_arg = arg; 285 286 /* Actually create the thread. */ 287 return CALL_REAL (pthread_create, thr, attr, __mf_pthread_spawner, si); 288} 289