1/* SJLJ exception handling and frame unwind runtime interface routines. 2 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 3 Free Software Foundation, Inc. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 In addition to the permissions in the GNU General Public License, the 13 Free Software Foundation gives you unlimited permission to link the 14 compiled version of this file into combinations with other programs, 15 and to distribute those combinations without any restriction coming 16 from the use of this file. (The General Public License restrictions 17 do apply in other respects; for example, they cover modification of 18 the file, and distribution when not linked into a combined 19 executable.) 20 21 GCC is distributed in the hope that it will be useful, but WITHOUT 22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 23 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 24 License for more details. 25 26 You should have received a copy of the GNU General Public License 27 along with GCC; see the file COPYING. If not, write to the Free 28 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 29 02110-1301, USA. */ 30 31#include "tconfig.h" 32#include "tsystem.h" 33#include "coretypes.h" 34#include "tm.h" 35#include "unwind.h" 36#include "gthr.h" 37 38#ifdef __USING_SJLJ_EXCEPTIONS__ 39 40#ifdef DONT_USE_BUILTIN_SETJMP 41#ifndef inhibit_libc 42#include <setjmp.h> 43#else 44typedef void *jmp_buf[JMP_BUF_SIZE]; 45extern void longjmp(jmp_buf, int) __attribute__((noreturn)); 46#endif 47#else 48#define longjmp __builtin_longjmp 49#endif 50 51/* The setjmp side is dealt with in the except.c file. */ 52#undef setjmp 53#define setjmp setjmp_should_not_be_used_in_this_file 54 55 56/* This structure is allocated on the stack of the target function. 57 This must match the definition created in except.c:init_eh. */ 58struct SjLj_Function_Context 59{ 60 /* This is the chain through all registered contexts. It is 61 filled in by _Unwind_SjLj_Register. */ 62 struct SjLj_Function_Context *prev; 63 64 /* This is assigned in by the target function before every call 65 to the index of the call site in the lsda. It is assigned by 66 the personality routine to the landing pad index. */ 67 int call_site; 68 69 /* This is how data is returned from the personality routine to 70 the target function's handler. */ 71 _Unwind_Word data[4]; 72 73 /* These are filled in once by the target function before any 74 exceptions are expected to be handled. */ 75 _Unwind_Personality_Fn personality; 76 void *lsda; 77 78#ifdef DONT_USE_BUILTIN_SETJMP 79 /* We don't know what sort of alignment requirements the system 80 jmp_buf has. We over estimated in except.c, and now we have 81 to match that here just in case the system *didn't* have more 82 restrictive requirements. */ 83 jmp_buf jbuf __attribute__((aligned)); 84#else 85 void *jbuf[]; 86#endif 87}; 88 89struct _Unwind_Context 90{ 91 struct SjLj_Function_Context *fc; 92}; 93 94typedef struct 95{ 96 _Unwind_Personality_Fn personality; 97} _Unwind_FrameState; 98 99 100/* Manage the chain of registered function contexts. */ 101 102/* Single threaded fallback chain. */ 103static struct SjLj_Function_Context *fc_static; 104 105#if __GTHREADS 106static __gthread_key_t fc_key; 107static int use_fc_key = -1; 108 109static void 110fc_key_init (void) 111{ 112 use_fc_key = __gthread_key_create (&fc_key, 0) == 0; 113} 114 115static void 116fc_key_init_once (void) 117{ 118 static __gthread_once_t once = __GTHREAD_ONCE_INIT; 119 if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0) 120 use_fc_key = 0; 121} 122#endif 123 124void 125_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) 126{ 127#if __GTHREADS 128 if (use_fc_key < 0) 129 fc_key_init_once (); 130 131 if (use_fc_key) 132 { 133 fc->prev = __gthread_getspecific (fc_key); 134 __gthread_setspecific (fc_key, fc); 135 } 136 else 137#endif 138 { 139 fc->prev = fc_static; 140 fc_static = fc; 141 } 142} 143 144static inline struct SjLj_Function_Context * 145_Unwind_SjLj_GetContext (void) 146{ 147#if __GTHREADS 148 if (use_fc_key < 0) 149 fc_key_init_once (); 150 151 if (use_fc_key) 152 return __gthread_getspecific (fc_key); 153#endif 154 return fc_static; 155} 156 157static inline void 158_Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc) 159{ 160#if __GTHREADS 161 if (use_fc_key < 0) 162 fc_key_init_once (); 163 164 if (use_fc_key) 165 __gthread_setspecific (fc_key, fc); 166 else 167#endif 168 fc_static = fc; 169} 170 171void 172_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) 173{ 174 _Unwind_SjLj_SetContext (fc->prev); 175} 176 177 178/* Get/set the return data value at INDEX in CONTEXT. */ 179 180_Unwind_Word 181_Unwind_GetGR (struct _Unwind_Context *context, int index) 182{ 183 return context->fc->data[index]; 184} 185 186/* Get the value of the CFA as saved in CONTEXT. */ 187 188_Unwind_Word 189_Unwind_GetCFA (struct _Unwind_Context *context __attribute__((unused))) 190{ 191 /* ??? Ideally __builtin_setjmp places the CFA in the jmpbuf. */ 192 193#ifndef DONT_USE_BUILTIN_SETJMP 194 /* This is a crude imitation of the CFA: the saved stack pointer. 195 This is roughly the CFA of the frame before CONTEXT. When using the 196 DWARF-2 unwinder _Unwind_GetCFA returns the CFA of the frame described 197 by CONTEXT instead; but for DWARF-2 the cleanups associated with 198 CONTEXT have already been run, and for SJLJ they have not yet been. */ 199 if (context->fc != NULL) 200 return (_Unwind_Word) context->fc->jbuf[2]; 201#endif 202 203 /* Otherwise we're out of luck for now. */ 204 return (_Unwind_Word) 0; 205} 206 207void 208_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) 209{ 210 context->fc->data[index] = val; 211} 212 213/* Get the call-site index as saved in CONTEXT. */ 214 215_Unwind_Ptr 216_Unwind_GetIP (struct _Unwind_Context *context) 217{ 218 return context->fc->call_site + 1; 219} 220 221_Unwind_Ptr 222_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) 223{ 224 *ip_before_insn = 0; 225 return context->fc->call_site + 1; 226} 227 228/* Set the return landing pad index in CONTEXT. */ 229 230void 231_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) 232{ 233 context->fc->call_site = val - 1; 234} 235 236void * 237_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) 238{ 239 return context->fc->lsda; 240} 241 242_Unwind_Ptr 243_Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) ) 244{ 245 return 0; 246} 247 248void * 249_Unwind_FindEnclosingFunction (void *pc __attribute__((unused))) 250{ 251 return NULL; 252} 253 254#ifndef __ia64__ 255_Unwind_Ptr 256_Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) ) 257{ 258 return 0; 259} 260 261_Unwind_Ptr 262_Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) ) 263{ 264 return 0; 265} 266#endif 267 268static inline _Unwind_Reason_Code 269uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) 270{ 271 if (context->fc == NULL) 272 { 273 fs->personality = NULL; 274 return _URC_END_OF_STACK; 275 } 276 else 277 { 278 fs->personality = context->fc->personality; 279 return _URC_NO_REASON; 280 } 281} 282 283static inline void 284uw_update_context (struct _Unwind_Context *context, 285 _Unwind_FrameState *fs __attribute__((unused)) ) 286{ 287 context->fc = context->fc->prev; 288} 289 290static void 291uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) 292{ 293 _Unwind_SjLj_Unregister (context->fc); 294 uw_update_context (context, fs); 295} 296 297static inline void 298uw_init_context (struct _Unwind_Context *context) 299{ 300 context->fc = _Unwind_SjLj_GetContext (); 301} 302 303static void __attribute__((noreturn)) 304uw_install_context (struct _Unwind_Context *current __attribute__((unused)), 305 struct _Unwind_Context *target) 306{ 307 _Unwind_SjLj_SetContext (target->fc); 308 longjmp (target->fc->jbuf, 1); 309} 310 311static inline _Unwind_Ptr 312uw_identify_context (struct _Unwind_Context *context) 313{ 314 return (_Unwind_Ptr) context->fc; 315} 316 317 318/* Play games with unwind symbols so that we can have call frame 319 and sjlj symbols in the same shared library. Not that you can 320 use them simultaneously... */ 321#define _Unwind_RaiseException _Unwind_SjLj_RaiseException 322#define _Unwind_ForcedUnwind _Unwind_SjLj_ForcedUnwind 323#define _Unwind_Resume _Unwind_SjLj_Resume 324#define _Unwind_Resume_or_Rethrow _Unwind_SjLj_Resume_or_Rethrow 325 326#include "unwind.inc" 327 328#endif /* USING_SJLJ_EXCEPTIONS */ 329