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