1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * Copyright (c) 2008 Likewise Software, Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * Portions of this software have been released under the following terms: 32 * 33 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 34 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 35 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 36 * 37 * To anyone who acknowledges that this file is provided "AS IS" 38 * without any express or implied warranty: 39 * permission to use, copy, modify, and distribute this file for any 40 * purpose is hereby granted without fee, provided that the above 41 * copyright notices and this notice appears in all source code copies, 42 * and that none of the names of Open Software Foundation, Inc., Hewlett- 43 * Packard Company or Digital Equipment Corporation be used 44 * in advertising or publicity pertaining to distribution of the software 45 * without specific, written prior permission. Neither Open Software 46 * Foundation, Inc., Hewlett-Packard Company nor Digital 47 * Equipment Corporation makes any representations about the suitability 48 * of this software for any purpose. 49 * 50 * Copyright (c) 2007, Novell, Inc. All rights reserved. 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 55 * 1. Redistributions of source code must retain the above copyright 56 * notice, this list of conditions and the following disclaimer. 57 * 2. Redistributions in binary form must reproduce the above copyright 58 * notice, this list of conditions and the following disclaimer in the 59 * documentation and/or other materials provided with the distribution. 60 * 3. Neither the name of Novell Inc. nor the names of its contributors 61 * may be used to endorse or promote products derived from this 62 * this software without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 65 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 66 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 67 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 68 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 69 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 70 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 71 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 73 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 74 * 75 * @APPLE_LICENSE_HEADER_END@ 76 */ 77 78#include <config.h> 79#include <string.h> 80#include <setjmp.h> 81#include <errno.h> 82#include <stdio.h> 83#ifdef HAVE_EXECINFO_H 84# include <execinfo.h> 85#endif 86#include <assert.h> 87 88#include "dcethread-exception.h" 89#include "dcethread-debug.h" 90#include "dcethread-private.h" 91 92static pthread_key_t frame_key; 93static void (*uncaught_handler) (dcethread_exc* exc, const char* file, unsigned int line, void* data); 94static void* uncaught_handler_data; 95 96dcethread_exc dcethread_uninitexc_e; 97dcethread_exc dcethread_exquota_e; 98dcethread_exc dcethread_insfmem_e; 99dcethread_exc dcethread_nopriv_e; 100dcethread_exc dcethread_illaddr_e; 101dcethread_exc dcethread_illinstr_e; 102dcethread_exc dcethread_resaddr_e; 103dcethread_exc dcethread_privinst_e; 104dcethread_exc dcethread_resoper_e; 105dcethread_exc dcethread_aritherr_e; 106dcethread_exc dcethread_intovf_e; 107dcethread_exc dcethread_intdiv_e; 108dcethread_exc dcethread_fltovf_e; 109dcethread_exc dcethread_fltdiv_e; 110dcethread_exc dcethread_fltund_e; 111dcethread_exc dcethread_decovf_e; 112dcethread_exc dcethread_subrng_e; 113dcethread_exc dcethread_excpu_e; 114dcethread_exc dcethread_exfilsiz_e; 115dcethread_exc dcethread_SIGTRAP_e; 116dcethread_exc dcethread_SIGIOT_e; 117dcethread_exc dcethread_SIGEMT_e; 118dcethread_exc dcethread_SIGSYS_e; 119dcethread_exc dcethread_SIGPIPE_e; 120dcethread_exc dcethread_unksyncsig_e; 121dcethread_exc dcethread_interrupt_e; 122dcethread_exc dcethread_badparam_e; /* Bad parameter */ 123dcethread_exc dcethread_existence_e; /* Object does not exist */ 124dcethread_exc dcethread_in_use_e; /* Object is in use */ 125dcethread_exc dcethread_use_error_e; /* Object inappropriate for operation */ 126dcethread_exc dcethread_nostackmem_e; /* No memory to allocate stack */ 127dcethread_exc dcethread_exit_thread_e; /* Used to terminate a thread */ 128 129static void 130default_uncaught_handler(dcethread_exc* exc, const char* file, 131 unsigned int line, void* data ATTRIBUTE_UNUSED) 132{ 133 if (!dcethread__exc_matches(exc, &dcethread_interrupt_e) && 134 !dcethread__exc_matches(exc, &dcethread_exit_thread_e)) 135 { 136 const char* name = dcethread__exc_getname(exc); 137 if (name) 138 { 139 fprintf(stderr, "%s:%i: uncaught exception %s in thread %p\n", file, line, name, dcethread__self()); 140 } 141 else 142 { 143 fprintf(stderr, "%s:%i: uncaught exception %p (%i) in thread %p\n", 144 file, line, exc, dcethread__exc_getstatus(exc), dcethread__self()); 145 } 146 147#ifdef HAVE_BACKTRACE_SYMBOLS_FD 148 void* buffer[256]; 149 int size; 150 151 size = backtrace(buffer, 256); 152 153 fprintf(stderr, "Backtrace:\n"); 154 backtrace_symbols_fd(buffer, size, fileno(stderr)); 155#endif 156 abort(); 157 } 158 159 pthread_exit(0); 160} 161 162void 163dcethread__init_exceptions(void) 164{ 165 pthread_key_create(&frame_key, NULL); 166 uncaught_handler = default_uncaught_handler; 167 168 DCETHREAD_EXC_INIT(dcethread_uninitexc_e); 169 DCETHREAD_EXC_INIT(dcethread_exquota_e); 170 DCETHREAD_EXC_INIT(dcethread_insfmem_e); 171 DCETHREAD_EXC_INIT(dcethread_nopriv_e); 172 DCETHREAD_EXC_INIT(dcethread_illaddr_e); 173 DCETHREAD_EXC_INIT(dcethread_illinstr_e); 174 DCETHREAD_EXC_INIT(dcethread_resaddr_e); 175 DCETHREAD_EXC_INIT(dcethread_privinst_e); 176 DCETHREAD_EXC_INIT(dcethread_resoper_e); 177 DCETHREAD_EXC_INIT(dcethread_aritherr_e); 178 DCETHREAD_EXC_INIT(dcethread_intovf_e); 179 DCETHREAD_EXC_INIT(dcethread_intdiv_e); 180 DCETHREAD_EXC_INIT(dcethread_fltovf_e); 181 DCETHREAD_EXC_INIT(dcethread_fltdiv_e); 182 DCETHREAD_EXC_INIT(dcethread_fltund_e); 183 DCETHREAD_EXC_INIT(dcethread_decovf_e); 184 DCETHREAD_EXC_INIT(dcethread_subrng_e); 185 DCETHREAD_EXC_INIT(dcethread_excpu_e); 186 DCETHREAD_EXC_INIT(dcethread_exfilsiz_e); 187 DCETHREAD_EXC_INIT(dcethread_SIGTRAP_e); 188 DCETHREAD_EXC_INIT(dcethread_SIGIOT_e); 189 DCETHREAD_EXC_INIT(dcethread_SIGEMT_e); 190 DCETHREAD_EXC_INIT(dcethread_SIGSYS_e); 191 DCETHREAD_EXC_INIT(dcethread_SIGPIPE_e); 192 DCETHREAD_EXC_INIT(dcethread_unksyncsig_e); 193 DCETHREAD_EXC_INIT(dcethread_interrupt_e); 194 DCETHREAD_EXC_INIT(dcethread_badparam_e); 195 DCETHREAD_EXC_INIT(dcethread_existence_e); 196 DCETHREAD_EXC_INIT(dcethread_in_use_e); 197 DCETHREAD_EXC_INIT(dcethread_use_error_e); 198 DCETHREAD_EXC_INIT(dcethread_nostackmem_e); 199 DCETHREAD_EXC_INIT(dcethread_exit_thread_e); 200} 201 202void 203dcethread__frame_push(dcethread_frame* frame) 204{ 205 dcethread_frame* cur = pthread_getspecific(frame_key); 206 void *pframe = (void*)(struct _dcethread_frame*) frame; 207 208 memset(pframe, 0, sizeof(*frame)); 209 210 frame->parent = cur; 211 212 pthread_setspecific(frame_key, (void*) frame); 213} 214 215void 216dcethread__frame_pop(dcethread_frame* frame) 217{ 218 dcethread_frame* cur = pthread_getspecific(frame_key); 219 220 if (cur == frame) 221 { 222 pthread_setspecific(frame_key, (void*) frame->parent); 223 } 224 else 225 { 226 DCETHREAD_ERROR("Attempted to pop exception frame in incorrect order"); 227 } 228} 229 230void 231dcethread__exc_init(dcethread_exc* exc, const char* name) 232{ 233 exc->kind = DCETHREAD_EXC_KIND_ADDRESS; 234 exc->match.address = exc; 235 exc->name = name; 236} 237 238void 239dcethread__exc_setstatus(dcethread_exc* exc, int value) 240{ 241 exc->kind = DCETHREAD_EXC_KIND_STATUS; 242 exc->match.value = value; 243} 244 245int 246dcethread__exc_getstatus(dcethread_exc* exc) 247{ 248 if (exc->kind == DCETHREAD_EXC_KIND_STATUS) 249 return exc->match.value; 250 else 251 return -1; 252} 253 254const char* 255dcethread__exc_getname(dcethread_exc* exc) 256{ 257 if (exc->kind == DCETHREAD_EXC_KIND_STATUS) 258 { 259 return exc->name; 260 } 261 else 262 { 263 return ((dcethread_exc*) exc->match.address)->name; 264 } 265} 266 267int 268dcethread__exc_matches(dcethread_exc* exc, dcethread_exc* pattern) 269{ 270 assert (exc != NULL); 271 assert (pattern != NULL); 272 273 return (exc->kind == pattern->kind && 274 (exc->kind == DCETHREAD_EXC_KIND_STATUS ? 275 exc->match.value == pattern->match.value : 276 exc->match.address == pattern->match.address)); 277} 278 279void 280dcethread__exc_raise(dcethread_exc* exc, const char* file, unsigned int line) 281{ 282 dcethread_frame* cur; 283 284 /* Ensure thread system is initialized */ 285 dcethread__init(); 286 287 cur = pthread_getspecific(frame_key); 288 289 if (cur) 290 { 291 cur->exc = *exc; 292 cur->file = file; 293 cur->line = line; 294 siglongjmp(((struct _dcethread_frame*) cur)->jmpbuf, 1); 295 } 296 else 297 { 298 uncaught_handler(exc, file, line, uncaught_handler_data); 299 abort(); 300 } 301} 302 303void 304dcethread__exc_handle_interrupt(dcethread* thread ATTRIBUTE_UNUSED, void* data) 305{ 306 dcethread__exc_raise((dcethread_exc*) data, NULL, 0); 307} 308 309dcethread_exc* 310dcethread__exc_from_errno(int err) 311{ 312 switch (err) 313 { 314 case EINVAL: return &dcethread_badparam_e; 315 case ERANGE: return &dcethread_badparam_e; 316 case EDEADLK: return &dcethread_in_use_e; 317 case EBUSY: return &dcethread_in_use_e; 318 case EAGAIN: return &dcethread_in_use_e; 319 case ENOMEM: return &dcethread_insfmem_e; 320 case EPERM: return &dcethread_nopriv_e; 321 case -1: return &dcethread_interrupt_e; /* XXX */ 322 default: return &dcethread_use_error_e; 323 } 324} 325 326void 327dcethread__exc_set_uncaught_handler(void (*handler) (dcethread_exc*, const char*, unsigned int, void*), void* data) 328{ 329 uncaught_handler = handler; 330 uncaught_handler_data = data; 331} 332