Whole document tree eh_personality.ccGo to the documentation of this file.00001 // -*- C++ -*- The GNU C++ exception personality routine. 00002 // Copyright (C) 2001 Free Software Foundation, Inc. 00003 // 00004 // This file is part of GNU CC. 00005 // 00006 // GNU CC is free software; you can redistribute it and/or modify 00007 // it under the terms of the GNU General Public License as published by 00008 // the Free Software Foundation; either version 2, or (at your option) 00009 // any later version. 00010 // 00011 // GNU CC is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU General Public License 00017 // along with GNU CC; see the file COPYING. If not, write to 00018 // the Free Software Foundation, 59 Temple Place - Suite 330, 00019 // Boston, MA 02111-1307, USA. 00020 00021 // As a special exception, you may use this file as part of a free software 00022 // library without restriction. Specifically, if other files instantiate 00023 // templates or use macros or inline functions from this file, or you compile 00024 // this file and link it with other files to produce an executable, this 00025 // file does not by itself cause the resulting executable to be covered by 00026 // the GNU General Public License. This exception does not however 00027 // invalidate any other reasons why the executable file might be covered by 00028 // the GNU General Public License. 00029 00030 00031 #include <bits/c++config.h> 00032 #include <cstdlib> 00033 #include "unwind-cxx.h" 00034 00035 using namespace __cxxabiv1; 00036 00037 #include "unwind-pe.h" 00038 00039 00040 struct lsda_header_info 00041 { 00042 _Unwind_Ptr Start; 00043 _Unwind_Ptr LPStart; 00044 _Unwind_Ptr ttype_base; 00045 const unsigned char *TType; 00046 const unsigned char *action_table; 00047 unsigned char ttype_encoding; 00048 unsigned char call_site_encoding; 00049 }; 00050 00051 static const unsigned char * 00052 parse_lsda_header (_Unwind_Context *context, const unsigned char *p, 00053 lsda_header_info *info) 00054 { 00055 _Unwind_Ptr tmp; 00056 unsigned char lpstart_encoding; 00057 00058 info->Start = (context ? _Unwind_GetRegionStart (context) : 0); 00059 00060 // Find @LPStart, the base to which landing pad offsets are relative. 00061 lpstart_encoding = *p++; 00062 if (lpstart_encoding != DW_EH_PE_omit) 00063 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); 00064 else 00065 info->LPStart = info->Start; 00066 00067 // Find @TType, the base of the handler and exception spec type data. 00068 info->ttype_encoding = *p++; 00069 if (info->ttype_encoding != DW_EH_PE_omit) 00070 { 00071 p = read_uleb128 (p, &tmp); 00072 info->TType = p + tmp; 00073 } 00074 else 00075 info->TType = 0; 00076 00077 // The encoding and length of the call-site table; the action table 00078 // immediately follows. 00079 info->call_site_encoding = *p++; 00080 p = read_uleb128 (p, &tmp); 00081 info->action_table = p + tmp; 00082 00083 return p; 00084 } 00085 00086 static const std::type_info * 00087 get_ttype_entry (lsda_header_info *info, long i) 00088 { 00089 _Unwind_Ptr ptr; 00090 00091 i *= size_of_encoded_value (info->ttype_encoding); 00092 read_encoded_value_with_base (info->ttype_encoding, info->ttype_base, 00093 info->TType - i, &ptr); 00094 00095 return reinterpret_cast<const std::type_info *>(ptr); 00096 } 00097 00098 static bool 00099 check_exception_spec (lsda_header_info *info, const std::type_info *throw_type, 00100 long filter_value) 00101 { 00102 const unsigned char *e = info->TType - filter_value - 1; 00103 00104 while (1) 00105 { 00106 const std::type_info *catch_type; 00107 _Unwind_Ptr tmp; 00108 void *dummy; 00109 00110 e = read_uleb128 (e, &tmp); 00111 00112 // Zero signals the end of the list. If we've not found 00113 // a match by now, then we've failed the specification. 00114 if (tmp == 0) 00115 return false; 00116 00117 // Match a ttype entry. 00118 catch_type = get_ttype_entry (info, tmp); 00119 if (catch_type->__do_catch (throw_type, &dummy, 1)) 00120 return true; 00121 } 00122 } 00123 00124 // Using a different personality function name causes link failures 00125 // when trying to mix code using different exception handling models. 00126 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS 00127 #define PERSONALITY_FUNCTION __gxx_personality_sj0 00128 #define __builtin_eh_return_data_regno(x) x 00129 #else 00130 #define PERSONALITY_FUNCTION __gxx_personality_v0 00131 #endif 00132 00133 extern "C" _Unwind_Reason_Code 00134 PERSONALITY_FUNCTION (int version, 00135 _Unwind_Action actions, 00136 _Unwind_Exception_Class exception_class, 00137 struct _Unwind_Exception *ue_header, 00138 struct _Unwind_Context *context) 00139 { 00140 __cxa_exception *xh = __get_exception_header_from_ue (ue_header); 00141 00142 enum found_handler_type 00143 { 00144 found_nothing, 00145 found_terminate, 00146 found_cleanup, 00147 found_handler 00148 } found_type; 00149 00150 lsda_header_info info; 00151 const unsigned char *language_specific_data; 00152 const unsigned char *action_record; 00153 const unsigned char *p; 00154 _Unwind_Ptr landing_pad, ip; 00155 int handler_switch_value; 00156 void *adjusted_ptr = xh + 1; 00157 00158 // Interface version check. 00159 if (version != 1) 00160 return _URC_FATAL_PHASE1_ERROR; 00161 00162 // Shortcut for phase 2 found handler for domestic exception. 00163 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) 00164 && exception_class == __gxx_exception_class) 00165 { 00166 handler_switch_value = xh->handlerSwitchValue; 00167 landing_pad = (_Unwind_Ptr) xh->catchTemp; 00168 found_type = (landing_pad == 0 ? found_terminate : found_handler); 00169 goto install_context; 00170 } 00171 00172 language_specific_data = (const unsigned char *) 00173 _Unwind_GetLanguageSpecificData (context); 00174 00175 // If no LSDA, then there are no handlers or cleanups. 00176 if (! language_specific_data) 00177 return _URC_CONTINUE_UNWIND; 00178 00179 // Parse the LSDA header. 00180 p = parse_lsda_header (context, language_specific_data, &info); 00181 info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); 00182 ip = _Unwind_GetIP (context) - 1; 00183 landing_pad = 0; 00184 action_record = 0; 00185 handler_switch_value = 0; 00186 00187 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS 00188 // The given "IP" is an index into the call-site table, with two 00189 // exceptions -- -1 means no-action, and 0 means terminate. But 00190 // since we're using uleb128 values, we've not got random access 00191 // to the array. 00192 if ((int) ip < 0) 00193 return _URC_CONTINUE_UNWIND; 00194 else if (ip == 0) 00195 { 00196 // Fall through to set found_terminate. 00197 } 00198 else 00199 { 00200 _Unwind_Ptr cs_lp, cs_action; 00201 do 00202 { 00203 p = read_uleb128 (p, &cs_lp); 00204 p = read_uleb128 (p, &cs_action); 00205 } 00206 while (--ip); 00207 00208 // Can never have null landing pad for sjlj -- that would have 00209 // been indicated by a -1 call site index. 00210 landing_pad = cs_lp + 1; 00211 if (cs_action) 00212 action_record = info.action_table + cs_action - 1; 00213 goto found_something; 00214 } 00215 #else 00216 // Search the call-site table for the action associated with this IP. 00217 while (p < info.action_table) 00218 { 00219 _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action; 00220 00221 // Note that all call-site encodings are "absolute" displacements. 00222 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); 00223 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); 00224 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); 00225 p = read_uleb128 (p, &cs_action); 00226 00227 // The table is sorted, so if we've passed the ip, stop. 00228 if (ip < info.Start + cs_start) 00229 p = info.action_table; 00230 else if (ip < info.Start + cs_start + cs_len) 00231 { 00232 if (cs_lp) 00233 landing_pad = info.LPStart + cs_lp; 00234 if (cs_action) 00235 action_record = info.action_table + cs_action - 1; 00236 goto found_something; 00237 } 00238 } 00239 #endif // _GLIBCPP_SJLJ_EXCEPTIONS 00240 00241 // If ip is not present in the table, call terminate. This is for 00242 // a destructor inside a cleanup, or a library routine the compiler 00243 // was not expecting to throw. 00244 found_type = (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate); 00245 goto do_something; 00246 00247 found_something: 00248 if (landing_pad == 0) 00249 { 00250 // If ip is present, and has a null landing pad, there are 00251 // no cleanups or handlers to be run. 00252 found_type = found_nothing; 00253 } 00254 else if (action_record == 0) 00255 { 00256 // If ip is present, has a non-null landing pad, and a null 00257 // action table offset, then there are only cleanups present. 00258 // Cleanups use a zero switch value, as set above. 00259 found_type = found_cleanup; 00260 } 00261 else 00262 { 00263 // Otherwise we have a catch handler or exception specification. 00264 00265 signed long ar_filter, ar_disp; 00266 const std::type_info *throw_type, *catch_type; 00267 bool saw_cleanup = false; 00268 bool saw_handler = false; 00269 00270 // During forced unwinding, we only run cleanups. With a foreign 00271 // exception class, there's no exception type. 00272 // ??? What to do about GNU Java and GNU Ada exceptions. 00273 00274 if ((actions & _UA_FORCE_UNWIND) 00275 || exception_class != __gxx_exception_class) 00276 throw_type = 0; 00277 else 00278 throw_type = xh->exceptionType; 00279 00280 while (1) 00281 { 00282 _Unwind_Ptr tmp; 00283 00284 p = action_record; 00285 p = read_sleb128 (p, &tmp); ar_filter = tmp; 00286 read_sleb128 (p, &tmp); ar_disp = tmp; 00287 00288 if (ar_filter == 0) 00289 { 00290 // Zero filter values are cleanups. 00291 saw_cleanup = true; 00292 } 00293 else if (ar_filter > 0) 00294 { 00295 // Positive filter values are handlers. 00296 catch_type = get_ttype_entry (&info, ar_filter); 00297 adjusted_ptr = xh + 1; 00298 00299 // Null catch type is a catch-all handler. We can catch 00300 // foreign exceptions with this. 00301 if (! catch_type) 00302 { 00303 if (!(actions & _UA_FORCE_UNWIND)) 00304 { 00305 saw_handler = true; 00306 break; 00307 } 00308 } 00309 else if (throw_type) 00310 { 00311 // Pointer types need to adjust the actual pointer, not 00312 // the pointer to pointer that is the exception object. 00313 // This also has the effect of passing pointer types 00314 // "by value" through the __cxa_begin_catch return value. 00315 if (throw_type->__is_pointer_p ()) 00316 adjusted_ptr = *(void **) adjusted_ptr; 00317 00318 if (catch_type->__do_catch (throw_type, &adjusted_ptr, 1)) 00319 { 00320 saw_handler = true; 00321 break; 00322 } 00323 } 00324 } 00325 else 00326 { 00327 // Negative filter values are exception specifications. 00328 // ??? How do foreign exceptions fit in? As far as I can 00329 // see we can't match because there's no __cxa_exception 00330 // object to stuff bits in for __cxa_call_unexpected to use. 00331 if (throw_type 00332 && ! check_exception_spec (&info, throw_type, ar_filter)) 00333 { 00334 saw_handler = true; 00335 break; 00336 } 00337 } 00338 00339 if (ar_disp == 0) 00340 break; 00341 action_record = p + ar_disp; 00342 } 00343 00344 if (saw_handler) 00345 { 00346 handler_switch_value = ar_filter; 00347 found_type = found_handler; 00348 } 00349 else 00350 found_type = (saw_cleanup ? found_cleanup : found_nothing); 00351 } 00352 00353 do_something: 00354 if (found_type == found_nothing) 00355 return _URC_CONTINUE_UNWIND; 00356 00357 if (actions & _UA_SEARCH_PHASE) 00358 { 00359 if (found_type == found_cleanup) 00360 return _URC_CONTINUE_UNWIND; 00361 00362 // For domestic exceptions, we cache data from phase 1 for phase 2. 00363 if (exception_class == __gxx_exception_class) 00364 { 00365 xh->handlerSwitchValue = handler_switch_value; 00366 xh->actionRecord = action_record; 00367 xh->languageSpecificData = language_specific_data; 00368 xh->adjustedPtr = adjusted_ptr; 00369 00370 // ??? Completely unknown what this field is supposed to be for. 00371 // ??? Need to cache TType encoding base for call_unexpected. 00372 xh->catchTemp = (void *) (_Unwind_Ptr) landing_pad; 00373 } 00374 return _URC_HANDLER_FOUND; 00375 } 00376 00377 install_context: 00378 if (found_type == found_terminate) 00379 { 00380 __cxa_begin_catch (&xh->unwindHeader); 00381 __terminate (xh->terminateHandler); 00382 } 00383 00384 // Cache the TType base value for __cxa_call_unexpected, as we won't 00385 // have an _Unwind_Context then. 00386 if (handler_switch_value < 0) 00387 { 00388 parse_lsda_header (context, xh->languageSpecificData, &info); 00389 xh->catchTemp = (void *) base_of_encoded_value (info.ttype_encoding, 00390 context); 00391 } 00392 00393 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), 00394 (_Unwind_Ptr) &xh->unwindHeader); 00395 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 00396 handler_switch_value); 00397 _Unwind_SetIP (context, landing_pad); 00398 return _URC_INSTALL_CONTEXT; 00399 } 00400 00401 extern "C" void 00402 __cxa_call_unexpected (_Unwind_Exception *exc_obj) 00403 { 00404 __cxa_begin_catch (exc_obj); 00405 00406 // This function is a handler for our exception argument. If we exit 00407 // by throwing a different exception, we'll need the original cleaned up. 00408 struct end_catch_protect 00409 { 00410 end_catch_protect() { } 00411 ~end_catch_protect() { __cxa_end_catch(); } 00412 } end_catch_protect_obj; 00413 00414 __cxa_exception *xh = __get_exception_header_from_ue (exc_obj); 00415 00416 try { 00417 __unexpected (xh->unexpectedHandler); 00418 } catch (...) { 00419 // Get the exception thrown from unexpected. 00420 // ??? Foreign exceptions can't be stacked this way. 00421 00422 __cxa_eh_globals *globals = __cxa_get_globals_fast (); 00423 __cxa_exception *new_xh = globals->caughtExceptions; 00424 00425 // We don't quite have enough stuff cached; re-parse the LSDA. 00426 lsda_header_info info; 00427 parse_lsda_header (0, xh->languageSpecificData, &info); 00428 info.ttype_base = (_Unwind_Ptr) xh->catchTemp; 00429 00430 // If this new exception meets the exception spec, allow it. 00431 if (check_exception_spec (&info, new_xh->exceptionType, 00432 xh->handlerSwitchValue)) 00433 throw; 00434 00435 // If the exception spec allows std::bad_exception, throw that. 00436 const std::type_info &bad_exc = typeid (std::bad_exception); 00437 if (check_exception_spec (&info, &bad_exc, xh->handlerSwitchValue)) 00438 throw std::bad_exception (); 00439 00440 // Otherwise, die. 00441 __terminate(xh->terminateHandler); 00442 } 00443 } Generated on Mon Apr 8 03:11:24 2002 for libstdc++-v3 Source by ![]() |