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
00038
00039
00040
00041
00042 #define DW_EH_PE_absptr 0x00
00043 #define DW_EH_PE_omit 0xff
00044
00045 #define DW_EH_PE_uleb128 0x01
00046 #define DW_EH_PE_udata2 0x02
00047 #define DW_EH_PE_udata4 0x03
00048 #define DW_EH_PE_udata8 0x04
00049 #define DW_EH_PE_sleb128 0x09
00050 #define DW_EH_PE_sdata2 0x0A
00051 #define DW_EH_PE_sdata4 0x0B
00052 #define DW_EH_PE_sdata8 0x0C
00053 #define DW_EH_PE_signed 0x08
00054
00055 #define DW_EH_PE_pcrel 0x10
00056 #define DW_EH_PE_textrel 0x20
00057 #define DW_EH_PE_datarel 0x30
00058 #define DW_EH_PE_funcrel 0x40
00059
00060 static unsigned int
00061 size_of_encoded_value (unsigned char encoding)
00062 {
00063 switch (encoding & 0x07)
00064 {
00065 case DW_EH_PE_absptr:
00066 return sizeof (void *);
00067 case DW_EH_PE_udata2:
00068 return 2;
00069 case DW_EH_PE_udata4:
00070 return 4;
00071 case DW_EH_PE_udata8:
00072 return 8;
00073 }
00074 abort ();
00075 }
00076
00077 static const unsigned char *
00078 read_encoded_value (_Unwind_Context *context, unsigned char encoding,
00079 const unsigned char *p, _Unwind_Ptr *val)
00080 {
00081 union unaligned
00082 {
00083 void *ptr;
00084 unsigned u2 __attribute__ ((mode (HI)));
00085 unsigned u4 __attribute__ ((mode (SI)));
00086 unsigned u8 __attribute__ ((mode (DI)));
00087 signed s2 __attribute__ ((mode (HI)));
00088 signed s4 __attribute__ ((mode (SI)));
00089 signed s8 __attribute__ ((mode (DI)));
00090 } __attribute__((__packed__));
00091
00092 union unaligned *u = (union unaligned *) p;
00093 _Unwind_Ptr result;
00094
00095 switch (encoding & 0x0f)
00096 {
00097 case DW_EH_PE_absptr:
00098 result = (_Unwind_Ptr) u->ptr;
00099 p += sizeof (void *);
00100 break;
00101
00102 case DW_EH_PE_uleb128:
00103 {
00104 unsigned int shift = 0;
00105 unsigned char byte;
00106
00107 result = 0;
00108 do
00109 {
00110 byte = *p++;
00111 result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
00112 shift += 7;
00113 }
00114 while (byte & 0x80);
00115 }
00116 break;
00117
00118 case DW_EH_PE_sleb128:
00119 {
00120 unsigned int shift = 0;
00121 unsigned char byte;
00122
00123 result = 0;
00124 do
00125 {
00126 byte = *p++;
00127 result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
00128 shift += 7;
00129 }
00130 while (byte & 0x80);
00131
00132 if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
00133 result |= -(1L << shift);
00134 }
00135 break;
00136
00137 case DW_EH_PE_udata2:
00138 result = u->u2;
00139 p += 2;
00140 break;
00141 case DW_EH_PE_udata4:
00142 result = u->u4;
00143 p += 4;
00144 break;
00145 case DW_EH_PE_udata8:
00146 result = u->u8;
00147 p += 8;
00148 break;
00149
00150 case DW_EH_PE_sdata2:
00151 result = u->s2;
00152 p += 2;
00153 break;
00154 case DW_EH_PE_sdata4:
00155 result = u->s4;
00156 p += 4;
00157 break;
00158 case DW_EH_PE_sdata8:
00159 result = u->s8;
00160 p += 8;
00161 break;
00162
00163 default:
00164 abort ();
00165 }
00166
00167 if (result != 0)
00168 switch (encoding & 0xf0)
00169 {
00170 case DW_EH_PE_absptr:
00171 break;
00172
00173 case DW_EH_PE_pcrel:
00174
00175 result += (_Unwind_Ptr) u;
00176 break;
00177
00178 case DW_EH_PE_textrel:
00179 case DW_EH_PE_datarel:
00180
00181 abort ();
00182
00183 case DW_EH_PE_funcrel:
00184 result += _Unwind_GetRegionStart (context);
00185 break;
00186
00187 default:
00188 abort ();
00189 }
00190
00191 *val = result;
00192 return p;
00193 }
00194
00195 static inline const unsigned char *
00196 read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
00197 {
00198 return read_encoded_value (0, DW_EH_PE_uleb128, p, val);
00199 }
00200
00201 static inline const unsigned char *
00202 read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
00203 {
00204 return read_encoded_value (0, DW_EH_PE_sleb128, p, val);
00205 }
00206
00207
00208 struct lsda_header_info
00209 {
00210 _Unwind_Ptr Start;
00211 _Unwind_Ptr LPStart;
00212 const unsigned char *TType;
00213 const unsigned char *action_table;
00214 unsigned char ttype_encoding;
00215 unsigned char call_site_encoding;
00216 };
00217
00218 static const unsigned char *
00219 parse_lsda_header (_Unwind_Context *context, const unsigned char *p,
00220 lsda_header_info *info)
00221 {
00222 _Unwind_Ptr tmp;
00223 unsigned char lpstart_encoding;
00224
00225 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
00226
00227
00228 lpstart_encoding = *p++;
00229 if (lpstart_encoding != DW_EH_PE_omit)
00230 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
00231 else
00232 info->LPStart = info->Start;
00233
00234
00235 info->ttype_encoding = *p++;
00236 if (info->ttype_encoding != DW_EH_PE_omit)
00237 {
00238 p = read_uleb128 (p, &tmp);
00239 info->TType = p + tmp;
00240 }
00241 else
00242 info->TType = 0;
00243
00244
00245
00246 info->call_site_encoding = *p++;
00247 p = read_uleb128 (p, &tmp);
00248 info->action_table = p + tmp;
00249
00250 return p;
00251 }
00252
00253 static const std::type_info *
00254 get_ttype_entry (_Unwind_Context *context, lsda_header_info *info, long i)
00255 {
00256 _Unwind_Ptr ptr;
00257
00258 i *= size_of_encoded_value (info->ttype_encoding);
00259 read_encoded_value (context, info->ttype_encoding, info->TType - i, &ptr);
00260
00261 return reinterpret_cast<const std::type_info *>(ptr);
00262 }
00263
00264 static bool
00265 check_exception_spec (_Unwind_Context *context, lsda_header_info *info,
00266 const std::type_info *throw_type, long filter_value)
00267 {
00268 const unsigned char *e = info->TType - filter_value - 1;
00269
00270 while (1)
00271 {
00272 const std::type_info *catch_type;
00273 _Unwind_Ptr tmp;
00274 void *dummy;
00275
00276 e = read_uleb128 (e, &tmp);
00277
00278
00279
00280 if (tmp == 0)
00281 return false;
00282
00283
00284 catch_type = get_ttype_entry (context, info, tmp);
00285 if (catch_type->__do_catch (throw_type, &dummy, 1))
00286 return true;
00287 }
00288 }
00289
00290
00291
00292 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS
00293 #define PERSONALITY_FUNCTION __gxx_personality_sj0
00294 #define __builtin_eh_return_data_regno(x) x
00295 #else
00296 #define PERSONALITY_FUNCTION __gxx_personality_v0
00297 #endif
00298
00299 extern "C" _Unwind_Reason_Code
00300 PERSONALITY_FUNCTION (int version,
00301 _Unwind_Action actions,
00302 _Unwind_Exception_Class exception_class,
00303 struct _Unwind_Exception *ue_header,
00304 struct _Unwind_Context *context)
00305 {
00306 __cxa_exception *xh = __get_exception_header_from_ue (ue_header);
00307
00308 enum found_handler_type
00309 {
00310 found_nothing,
00311 found_terminate,
00312 found_cleanup,
00313 found_handler
00314 } found_type;
00315
00316 lsda_header_info info;
00317 const unsigned char *language_specific_data;
00318 const unsigned char *action_record;
00319 const unsigned char *p;
00320 _Unwind_Ptr landing_pad, ip;
00321 int handler_switch_value;
00322 void *adjusted_ptr = xh + 1;
00323
00324
00325 if (version != 1)
00326 return _URC_FATAL_PHASE1_ERROR;
00327
00328
00329 if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME)
00330 && exception_class == __gxx_exception_class)
00331 {
00332 handler_switch_value = xh->handlerSwitchValue;
00333 landing_pad = (_Unwind_Ptr) xh->catchTemp;
00334 found_type = (landing_pad == 0 ? found_terminate : found_handler);
00335 goto install_context;
00336 }
00337
00338 language_specific_data = (const unsigned char *)
00339 _Unwind_GetLanguageSpecificData (context);
00340
00341
00342 if (! language_specific_data)
00343 return _URC_CONTINUE_UNWIND;
00344
00345
00346 p = parse_lsda_header (context, language_specific_data, &info);
00347 ip = _Unwind_GetIP (context) - 1;
00348 landing_pad = 0;
00349 action_record = 0;
00350 handler_switch_value = 0;
00351
00352 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS
00353
00354
00355
00356
00357 if ((int) ip < 0)
00358 return _URC_CONTINUE_UNWIND;
00359 else if (ip == 0)
00360 {
00361
00362 }
00363 else
00364 {
00365 _Unwind_Ptr cs_lp, cs_action;
00366 do
00367 {
00368 p = read_uleb128 (p, &cs_lp);
00369 p = read_uleb128 (p, &cs_action);
00370 }
00371 while (--ip);
00372
00373
00374
00375 landing_pad = cs_lp + 1;
00376 if (cs_action)
00377 action_record = info.action_table + cs_action - 1;
00378 goto found_something;
00379 }
00380 #else
00381
00382 while (p < info.action_table)
00383 {
00384 _Unwind_Ptr cs_start, cs_len, cs_lp, cs_action;
00385
00386
00387 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
00388 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
00389 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
00390 p = read_uleb128 (p, &cs_action);
00391
00392
00393 if (ip < info.Start + cs_start)
00394 p = info.action_table;
00395 else if (ip < info.Start + cs_start + cs_len)
00396 {
00397 if (cs_lp)
00398 landing_pad = info.LPStart + cs_lp;
00399 if (cs_action)
00400 action_record = info.action_table + cs_action - 1;
00401 goto found_something;
00402 }
00403 }
00404 #endif // _GLIBCPP_SJLJ_EXCEPTIONS
00405
00406
00407
00408
00409 found_type = (actions & _UA_FORCE_UNWIND ? found_nothing : found_terminate);
00410 goto do_something;
00411
00412 found_something:
00413 if (landing_pad == 0)
00414 {
00415
00416
00417 found_type = found_nothing;
00418 }
00419 else if (action_record == 0)
00420 {
00421
00422
00423
00424 found_type = found_cleanup;
00425 }
00426 else
00427 {
00428
00429
00430 signed long ar_filter, ar_disp;
00431 const std::type_info *throw_type, *catch_type;
00432 bool saw_cleanup = false;
00433 bool saw_handler = false;
00434
00435
00436
00437
00438
00439 if ((actions & _UA_FORCE_UNWIND)
00440 || exception_class != __gxx_exception_class)
00441 throw_type = 0;
00442 else
00443 throw_type = xh->exceptionType;
00444
00445 while (1)
00446 {
00447 _Unwind_Ptr tmp;
00448
00449 p = action_record;
00450 p = read_sleb128 (p, &tmp); ar_filter = tmp;
00451 read_sleb128 (p, &tmp); ar_disp = tmp;
00452
00453 if (ar_filter == 0)
00454 {
00455
00456 saw_cleanup = true;
00457 }
00458 else if (ar_filter > 0)
00459 {
00460
00461 catch_type = get_ttype_entry (context, &info, ar_filter);
00462 adjusted_ptr = xh + 1;
00463
00464
00465
00466 if (! catch_type)
00467 {
00468 if (!(actions & _UA_FORCE_UNWIND))
00469 {
00470 saw_handler = true;
00471 break;
00472 }
00473 }
00474 else if (throw_type)
00475 {
00476
00477
00478
00479
00480 if (throw_type->__is_pointer_p ())
00481 adjusted_ptr = *(void **) adjusted_ptr;
00482
00483 if (catch_type->__do_catch (throw_type, &adjusted_ptr, 1))
00484 {
00485 saw_handler = true;
00486 break;
00487 }
00488 }
00489 }
00490 else
00491 {
00492
00493
00494
00495
00496 if (throw_type
00497 && ! check_exception_spec (context, &info, throw_type,
00498 ar_filter))
00499 {
00500 saw_handler = true;
00501 break;
00502 }
00503 }
00504
00505 if (ar_disp == 0)
00506 break;
00507 action_record = p + ar_disp;
00508 }
00509
00510 if (saw_handler)
00511 {
00512 handler_switch_value = ar_filter;
00513 found_type = found_handler;
00514 }
00515 else
00516 found_type = (saw_cleanup ? found_cleanup : found_nothing);
00517 }
00518
00519 do_something:
00520 if (found_type == found_nothing)
00521 return _URC_CONTINUE_UNWIND;
00522
00523 if (actions & _UA_SEARCH_PHASE)
00524 {
00525 if (found_type == found_cleanup)
00526 return _URC_CONTINUE_UNWIND;
00527
00528
00529 if (exception_class == __gxx_exception_class)
00530 {
00531 xh->handlerSwitchValue = handler_switch_value;
00532 xh->actionRecord = action_record;
00533 xh->languageSpecificData = language_specific_data;
00534 xh->adjustedPtr = adjusted_ptr;
00535
00536
00537
00538 xh->catchTemp = (void *) (_Unwind_Ptr) landing_pad;
00539 }
00540 return _URC_HANDLER_FOUND;
00541 }
00542
00543 install_context:
00544 if (found_type == found_terminate)
00545 {
00546 __cxa_begin_catch (&xh->unwindHeader);
00547 __terminate (xh->terminateHandler);
00548 }
00549
00550 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
00551 (_Unwind_Ptr) &xh->unwindHeader);
00552 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1),
00553 handler_switch_value);
00554 _Unwind_SetIP (context, landing_pad);
00555 return _URC_INSTALL_CONTEXT;
00556 }
00557
00558 extern "C" void
00559 __cxa_call_unexpected (_Unwind_Exception *exc_obj)
00560 {
00561 __cxa_begin_catch (exc_obj);
00562
00563
00564
00565 struct end_catch_protect
00566 {
00567 end_catch_protect() { }
00568 ~end_catch_protect() { __cxa_end_catch(); }
00569 } end_catch_protect_obj;
00570
00571 __cxa_exception *xh = __get_exception_header_from_ue (exc_obj);
00572
00573 try {
00574 __unexpected (xh->unexpectedHandler);
00575 } catch (...) {
00576
00577
00578
00579 __cxa_eh_globals *globals = __cxa_get_globals_fast ();
00580 __cxa_exception *new_xh = globals->caughtExceptions;
00581
00582
00583 lsda_header_info info;
00584 parse_lsda_header (0, xh->languageSpecificData, &info);
00585
00586
00587 if (check_exception_spec (0, &info, new_xh->exceptionType,
00588 xh->handlerSwitchValue))
00589 throw;
00590
00591
00592 const std::type_info &bad_exc = typeid (std::bad_exception);
00593 if (check_exception_spec (0, &info, &bad_exc, xh->handlerSwitchValue))
00594 throw std::bad_exception ();
00595
00596
00597 __terminate(xh->terminateHandler);
00598 }
00599 }