00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
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
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
00078
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
00113
00114 if (tmp == 0)
00115 return false;
00116
00117
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
00125
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
00159 if (version != 1)
00160 return _URC_FATAL_PHASE1_ERROR;
00161
00162
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
00176 if (! language_specific_data)
00177 return _URC_CONTINUE_UNWIND;
00178
00179
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
00189
00190
00191
00192 if ((int) ip < 0)
00193 return _URC_CONTINUE_UNWIND;
00194 else if (ip == 0)
00195 {
00196
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
00209
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
00217 while (p < info.action_table)
00218 {
00219 _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
00220
00221
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
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
00242
00243
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
00251
00252 found_type = found_nothing;
00253 }
00254 else if (action_record == 0)
00255 {
00256
00257
00258
00259 found_type = found_cleanup;
00260 }
00261 else
00262 {
00263
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
00271
00272
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
00291 saw_cleanup = true;
00292 }
00293 else if (ar_filter > 0)
00294 {
00295
00296 catch_type = get_ttype_entry (&info, ar_filter);
00297 adjusted_ptr = xh + 1;
00298
00299
00300
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
00312
00313
00314
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
00328
00329
00330
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
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
00371
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
00385
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
00407
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
00420
00421
00422 __cxa_eh_globals *globals = __cxa_get_globals_fast ();
00423 __cxa_exception *new_xh = globals->caughtExceptions;
00424
00425
00426 lsda_header_info info;
00427 parse_lsda_header (0, xh->languageSpecificData, &info);
00428 info.ttype_base = (_Unwind_Ptr) xh->catchTemp;
00429
00430
00431 if (check_exception_spec (&info, new_xh->exceptionType,
00432 xh->handlerSwitchValue))
00433 throw;
00434
00435
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
00441 __terminate(xh->terminateHandler);
00442 }
00443 }