This machine mirrors various open-source projects.
20 Gbit/s uplink.
If there are any issues or you want another project mirrored, please contact
mirror-service -=AT=- netcologne DOT de !
00001 /*===-- runtime/crt_exceptions.c --------------------------------------------=== 00002 * 00003 * This file is distributed under the MIT license. See LICENSE.txt for details. 00004 * 00005 * Copyright (C) 2009, Stephen Wilson 00006 * 00007 *===----------------------------------------------------------------------===*/ 00008 00009 /* 00010 * This file defines Comma's exception handling primitives. 00011 */ 00012 #include "comma/runtime/commart.h" 00013 00014 #include <assert.h> 00015 #include <stddef.h> 00016 #include <stdio.h> 00017 #include <stdlib.h> 00018 #include <string.h> 00019 00020 #define __STDC_FORMAT_MACROS 00021 #include <inttypes.h> 00022 00023 00024 /* 00025 * Forward declarations. 00026 */ 00027 struct _Unwind_Exception; 00028 struct _Unwind_Context; 00029 00030 /* 00031 * Reason codes used to communicate the outcomes of several operations. 00032 */ 00033 typedef enum { 00034 _URC_NO_REASON = 0, 00035 _URC_FOREIGN_EXCEPTION_CAUGHT = 1, 00036 _URC_FATAL_PHASE2_ERROR = 2, 00037 _URC_FATAL_PHASE1_ERROR = 3, 00038 _URC_NORMAL_STOP = 4, 00039 _URC_END_OF_STACK = 5, 00040 _URC_HANDLER_FOUND = 6, 00041 _URC_INSTALL_CONTEXT = 7, 00042 _URC_CONTINUE_UNWIND = 8 00043 } _Unwind_Reason_Code; 00044 00045 /* 00046 * The type of an exception cleanup function. This is used, for example, when 00047 * an exception handler needs to free a forgien exception object. 00048 */ 00049 typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code reason, 00050 struct _Unwind_Exception *exc); 00051 00052 /* 00053 * The system routine which raises an exception. 00054 */ 00055 extern _Unwind_Reason_Code 00056 _Unwind_RaiseException(struct _Unwind_Exception *exception_object); 00057 00058 /* 00059 * Propagates an existing exception object. Causes unwinding to proceed 00060 * further. 00061 */ 00062 extern void _Unwind_Resume(struct _Unwind_Exception *exception_object); 00063 00064 /* 00065 * Accessor the the LSDA. 00066 */ 00067 extern uintptr_t 00068 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); 00069 00070 /* 00071 * Accessor to the start of the handler/cleanup code. 00072 */ 00073 extern uintptr_t 00074 _Unwind_GetRegionStart(struct _Unwind_Context *context); 00075 00076 /* 00077 * Accessor to the instruction pointer. This pointer is one past the 00078 * instruction which actually resulted in the raising of an exception. 00079 */ 00080 extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); 00081 00082 /* 00083 * Sets the value of the given general purpose registe. 00084 */ 00085 extern void _Unwind_SetGR(struct _Unwind_Context *context, 00086 int reg, uintptr_t value); 00087 00088 /* 00089 * Sets the instruction pointer to the given value. 00090 */ 00091 extern void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t IP); 00092 00093 /* 00094 * The exception header structure which all exception objects must contain. 00095 */ 00096 struct _Unwind_Exception { 00097 uint64_t exception_class; 00098 _Unwind_Exception_Cleanup_Fn exception_cleanup; 00099 uint64_t private_1; 00100 uint64_t private_2; 00101 }; 00102 00103 /* 00104 * The action argument to the personality routine, and the various action codes. 00105 */ 00106 typedef int _Unwind_Action; 00107 static const _Unwind_Action _UA_SEARCH_PHASE = 1; 00108 static const _Unwind_Action _UA_CLEANUP_PHASE = 2; 00109 static const _Unwind_Action _UA_HANDLER_FRAME = 4; 00110 static const _Unwind_Action _UA_FORCE_UNWIND = 8; 00111 00112 /*===----------------------------------------------------------------------=== 00113 * DWARF value parsing. 00114 *===----------------------------------------------------------------------===*/ 00115 00116 /* 00117 * The following constants are used in the encoding of the DWARF exception 00118 * headers. Such an encoding is represented as a single byte. The lower four 00119 * bits describes the data format of a DWARF value. These lower bits are 00120 * itemized in the Dwaf_Encoding enumeration. The upper four bits describes how 00121 * the value is to be interpreted, and are itemized in Dwarf_Application. These 00122 * values are defined in the LSB-3.0.0 (see http://refspecs.freestandards.org). 00123 * 00124 * Apparently GCC defines other encodings not mentioned in the LSB (for example, 00125 * DW_EH_PE_signed) but they are not needed for our purposes. 00126 */ 00127 typedef enum { 00128 DW_EH_PE_omit = 0xFF, /* No value is present. */ 00129 DW_EH_PE_uleb128 = 0x01, /* Unsigned LEB128 encoded value. */ 00130 DW_EH_PE_udata2 = 0x02, /* 2 byte unsigned data. */ 00131 DW_EH_PE_udata4 = 0x03, /* 4 byte unsigned data. */ 00132 DW_EH_PE_udata8 = 0x04, /* 8 byte unsigned data. */ 00133 DW_EH_PE_sleb128 = 0x09, /* Signed LEB128 encoded value. */ 00134 DW_EH_PE_sdata2 = 0x0A, /* 2 byte signed data. */ 00135 DW_EH_PE_sdata4 = 0x0B, /* 4 byte signed data. */ 00136 DW_EH_PE_sdata8 = 0x0C, /* 8 byte signed data. */ 00137 } Dwarf_Encoding; 00138 00139 typedef enum { 00140 DW_EH_PE_absptr = 0x00, /* Value is used without modification. */ 00141 DW_EH_PE_pcrel = 0x10, /* Value relative to program counter. */ 00142 DW_EH_PE_datarel = 0x30, /* Value relative to .eh_frame_hdr. */ 00143 } Dwarf_Application; 00144 00145 /* 00146 * The following two subroutines parse signed and unsigned Little-Endian Base 00147 * 128 (LEB128) encoded values. This is a compression technique used in DWARF 00148 * for encoding integers. 00149 * 00150 * LEB128 is variable length data. The following subroutines take two 00151 * parameters: 00152 * 00153 * - start : a pointer to the start of the data. 00154 * 00155 * - value : an out parameter filled set to the decoded value. 00156 * 00157 * A pointer to the byte following the decoded value is returned. 00158 */ 00159 static unsigned char *parse_uleb128(unsigned char *start, uint64_t *value) 00160 { 00161 uint64_t res = 0; 00162 unsigned bits = 0; 00163 00164 /* 00165 * Read a sequence of bytes so long as the high bit is set. Form a value 00166 * using the lower 7 bits in little-endian order. 00167 */ 00168 while (*start & 0x80) { 00169 res |= (((uint64_t)*start) & 0x7F) << bits; 00170 bits += 7; 00171 ++start; 00172 } 00173 00174 /* 00175 * Bring in the most significant byte. 00176 */ 00177 res |= (((uint64_t)*start) & 0x7F) << bits; 00178 00179 *value = res; 00180 return ++start; 00181 } 00182 00183 static unsigned char *parse_sleb128(unsigned char *start, int64_t *value) 00184 { 00185 uint64_t res = 0; 00186 unsigned bits = 0; 00187 00188 /* 00189 * Read a sequence of bytes so long as the high bit is set. Form a value 00190 * using the lower 7 bits in little-endian order. 00191 */ 00192 while (*start & 0x80) { 00193 res |= (((uint64_t)*start) & 0x7F) << bits; 00194 bits += 7; 00195 ++start; 00196 } 00197 00198 /* 00199 * Bring in the most significant byte. If it is signed, extend the result. 00200 */ 00201 res |= (((uint64_t)*start) & 0x7F) << bits; 00202 00203 if (*start & 0x40) { 00204 bits += 7; 00205 res |= ~((uint64_t)0) << bits; 00206 } 00207 00208 *value = (int64_t)res; 00209 return ++start; 00210 } 00211 00212 /* 00213 * The following subroutine parses a DWARF encoded value. 00214 * 00215 * - ID : The type of DWARF value to parse. 00216 * 00217 * - start : A pointer to the first byte of the encoded value. 00218 * 00219 * - value : The parsed result. 00220 * 00221 * A pointer to the byte following the decoded value is returned. 00222 * 00223 * Note that this implementation uses memcpy to ensure that we do not do 00224 * unaligned memory accesses. 00225 */ 00226 static unsigned char * 00227 parse_dwarf_value(Dwarf_Encoding ID, unsigned char *start, uint64_t *value) 00228 { 00229 switch (ID) { 00230 00231 default: 00232 assert(0 && "Invalid DWARF encoding!"); 00233 return start; 00234 00235 case DW_EH_PE_omit: 00236 return start; 00237 00238 case DW_EH_PE_uleb128: 00239 return parse_uleb128(start, value); 00240 00241 case DW_EH_PE_udata2: { 00242 uint8_t dst; 00243 memcpy(&dst, start, 2); 00244 *value = (uint64_t)dst; 00245 return start + 2; 00246 } 00247 00248 case DW_EH_PE_udata4: { 00249 uint16_t dst; 00250 memcpy(&dst, start, 4); 00251 *value = (uint64_t)dst; 00252 return start + 4; 00253 } 00254 00255 case DW_EH_PE_udata8: 00256 memcpy(value, start, 8); 00257 return start + 8; 00258 00259 case DW_EH_PE_sleb128: 00260 return parse_sleb128(start, (int64_t*)value); 00261 00262 case DW_EH_PE_sdata2: { 00263 int8_t dst; 00264 memcpy(&dst, start, 2); 00265 *value = (int64_t)dst; 00266 return start + 2; 00267 } 00268 00269 case DW_EH_PE_sdata4: { 00270 int16_t dst; 00271 memcpy(&dst, start, 4); 00272 *value = (int64_t)dst; 00273 return start + 4; 00274 } 00275 00276 case DW_EH_PE_sdata8: 00277 memcpy(value, start, 8); 00278 return start + 8; 00279 } 00280 } 00281 00282 /*===----------------------------------------------------------------------=== 00283 * LSDA 00284 *===----------------------------------------------------------------------===*/ 00285 00286 /* 00287 * The Language Specific Data Area is an opaque structure. The contents provide 00288 * the data needed by our exception personality to identify the nature of a 00289 * particular call frame. The information is organized as a set of DWARF 00290 * encoded tables. A sketch of the layout is given below. Items in the sketch 00291 * delimited by "===" markers introduce a sub-table of the LSDA and do not 00292 * represent actual entries. 00293 * 00294 * +==================+ +=============+ 00295 * | LSDA | | TYPES TABLE | 00296 * +==================+ +=============+ 00297 * | @LPStart | | Type info N | 00298 * +------------------+ +-------------+ 00299 * | @TTBase format | ... 00300 * +------------------+ +-------------+ 00301 * | @TTBase | -----+ | Type info 2 | 00302 * +==================+ | +-------------+ 00303 * | CALL-SITE TABLE | | | Type info 1 | 00304 * +==================+ | +-------------+ 00305 * | format | +-> | 0 | 00306 * +------------------+ +-------------+ 00307 * | size | --+ | Filter 1 | 00308 * +------------------+ | +-------------+ 00309 * | Call-site record | | ... 00310 * +------------------+ | +-------------+ 00311 * ... | | Filter N | 00312 * +==================+ | +-------------+ 00313 * | ACTION TABLE | | 00314 * +==================+ | 00315 * | Action record | <-+ 00316 * +------------------+ | 00317 * | Action record | <-+ 00318 * +------------------+ 00319 * ... 00320 * 00321 * The header of the LSDA consists of the following values. 00322 * 00323 * @LPStart : A DWARF encoded value yielding an offset relative to the LSDA 00324 * to the start of the landing pad code. If the encoding is DW_EH_PE_omit, 00325 * then there is no value and the offset to use to calculate the location 00326 * of the landing pad code is given by a call to _Unwind_GetRegionStart. 00327 * 00328 * @TTBase format : A DWARF encoding byte telling us how to interpret 00329 * the entries in the type table. 00330 * 00331 * @TTBase : An unsigned LEB128 value yielding a self relative offset. This 00332 * gives the start of the type table (well, the `middle' of the type table 00333 * as seen in the diagram above). 00334 * 00335 * The call-site table is organized as follows: 00336 * 00337 * format : This is one of the Dwarf_Encoding values and is used to interpret 00338 * the data in the call site records when the precise format of a value is 00339 * otherwise undefined. 00340 * 00341 * size : An unsigned LED128 value giving total size (in bytes) of all the 00342 * call-site records to follow. 00343 * 00344 * Call site records have the following format: 00345 * 00346 * +==================+ 00347 * | CALL-SITE RECORD | 00348 * +==================+ 00349 * | region start | 00350 * +------------------+ 00351 * | region length | 00352 * +------------------+ 00353 * | landing pad | 00354 * +------------------+ 00355 * | action | 00356 * +------------------+ 00357 * 00358 * region start : Offset of the call site relative to the value returned by a 00359 * call to _Unwind_GetRegionStart. This value should be interpreted using 00360 * the table encoding. 00361 * 00362 * region length : Length of the call site region. This value should be 00363 * interpreted using the table encoding. 00364 * 00365 * landing pad : Offset of the landing pad for this region relative to 00366 * @LPBase. A landing pad offset value of 0 means there is no landing pad, 00367 * and therefore no action, for this particular call site. This value 00368 * should be interpreted using the table encoding. 00369 * 00370 * action : Index into the actions table (which immediately follows the 00371 * call-site table). A action index of 0 means that the landing pad points 00372 * to a cleanup rather than a handler. This value is encoded as an unsigned 00373 * LEB128. 00374 * 00375 * Immediately following the call-site table is the action table, consisting of 00376 * a number of action records. These records have the following form: 00377 * 00378 * +==================+ 00379 * | ACTION RECORD | 00380 * +==================+ 00381 * | type index | 00382 * +------------------+ 00383 * | next action | 00384 * +------------------+ 00385 * 00386 * type index : An index into the Types Table, relative to @TTBase. These are 00387 * encoded as a signed LEB128 value. There are two cases to consider: 00388 * 00389 * For an index I > 0, compute @TTBase - I, yielding a type info object 00390 * corresponding to a particular handler. 00391 * 00392 * For an index I < 0, compute @TTBase + I, yielding a null terminated 00393 * filter. These are not used in Comma. Type filters are the mechanism 00394 * used to enforce C++ throw() specifications. 00395 * 00396 * next action : The offset in bytes from the address of this entry to the 00397 * start of the next (these entries are variable length). This is 00398 * represented as a signed LEB128. A value of 0 terminates the chain of 00399 * action records. 00400 */ 00401 00402 /* 00403 * Forward declarations for the structures used to represent the LSDA tables. 00404 */ 00405 struct LSDA_Header; 00406 struct Call_Site; 00407 struct Action_Record; 00408 00409 /* 00410 * The following structure is used to represent the LSDA Header. 00411 */ 00412 struct LSDA_Header { 00413 /* 00414 * Start address of the LSDA. 00415 */ 00416 unsigned char *lsda_start; 00417 00418 /* 00419 * Start of the landing pad code, corresoinding the @LPStart. 00420 */ 00421 intptr_t lpstart; 00422 00423 /* 00424 * DWARF format attribute used for interpreting @TTBase. 00425 */ 00426 unsigned char type_table_format; 00427 00428 /* 00429 * @TTBase table pointer. 00430 */ 00431 unsigned char *type_table; 00432 00433 /* 00434 * Dwarf encoding format to use while interpreting call site records. 00435 */ 00436 Dwarf_Encoding call_site_format; 00437 00438 /* 00439 * Call site table size. 00440 */ 00441 uint64_t call_table_size; 00442 00443 /* 00444 * Pointer to the first call site record in the table. 00445 */ 00446 unsigned char *call_sites; 00447 00448 /* 00449 * Pointer to the actions table. 00450 */ 00451 unsigned char *actions; 00452 }; 00453 00454 /* 00455 * We parse the variable length call-site entries into the following structure. 00456 */ 00457 struct Call_Site { 00458 /* 00459 * Start of the call site (relative to _Unwind_GetRegionStart). 00460 */ 00461 int64_t region_start; 00462 00463 /* 00464 * Length of the call site in bytes. 00465 */ 00466 uint64_t region_length; 00467 00468 /* 00469 * Landing pad offset (relative to @LPStart). 00470 */ 00471 int64_t landing_pad; 00472 00473 /* 00474 * Action index. 00475 */ 00476 uint64_t action_index; 00477 }; 00478 00479 /* 00480 * We parse the variable length action records into the following structure. 00481 */ 00482 struct Action_Record { 00483 /* 00484 * Index into the type table. 00485 */ 00486 uint64_t info_index; 00487 00488 /* 00489 * Offset in bytes to the next action. 00490 */ 00491 uint64_t next_action; 00492 }; 00493 00494 /*===----------------------------------------------------------------------=== 00495 * LSDA Parsers and Comma's Exception Personality. 00496 *===----------------------------------------------------------------------===*/ 00497 00498 /* 00499 * The following routine aborts the process when a hard error is encountered. 00500 */ 00501 static void fatal_error(const char *message) 00502 { 00503 fprintf(stderr, "EXCEPTION ERROR : %s\n", message); 00504 abort(); 00505 } 00506 00507 /* 00508 * The following enumeration encodes a set of flags which are embedded into a 00509 * Comma exception. There is only one flag at the moment which indicates if the 00510 * message is dynamically allocated or not. 00511 */ 00512 typedef enum { 00513 COMMA_DYN_MESSAGE = 1 << 0 00514 } comma_exception_flag; 00515 00516 /* 00517 * This is the exception object thrown by the runtime. It contains the 00518 * exceptions exinfo object, the file name and line number of the exception 00519 * occurrence, a pointer to a null terminated string yielding a message, and a 00520 * set of flags. It is likely that more flags will be needed in the future 00521 * (this representation is not trying to be intentionally wasteful). 00522 */ 00523 struct comma_exception { 00524 comma_exinfo_t id; 00525 const char *file_name; 00526 uint32_t line_number; 00527 char *message; 00528 uint32_t flags; 00529 struct _Unwind_Exception header; 00530 }; 00531 00532 /* 00533 * Conversions to and from comma_exception's and _Unwind_Exceptions. 00534 */ 00535 struct comma_exception * 00536 to_comma_exception(struct _Unwind_Exception *header) 00537 { 00538 char *ptr = (char *)header; 00539 ptr -= offsetof(struct comma_exception, header); 00540 return (struct comma_exception *)ptr; 00541 } 00542 00543 struct _Unwind_Exception * 00544 to_Unwind_Exception(struct comma_exception *exception) 00545 { 00546 return &exception->header; 00547 } 00548 00549 /* 00550 * The following function parses the LSDA header. Returns 0 in sucess and 1 on 00551 * error. 00552 */ 00553 static int parse_LSDA(struct _Unwind_Context *context, struct LSDA_Header *lsda) 00554 { 00555 unsigned char *ptr; 00556 uint64_t tmp; 00557 00558 lsda->lsda_start = 00559 (unsigned char *)_Unwind_GetLanguageSpecificData(context); 00560 00561 if (!lsda->lsda_start) 00562 return 1; 00563 else 00564 ptr = lsda->lsda_start; 00565 00566 /* 00567 * Parse @LPStart. This is given by _Unwind_GetRegionStart, possibly 00568 * augmented by a DWARF value. 00569 * 00570 * FIXME: We do not parse the DWARF value currently. LLVM never emits such 00571 * code at this time. 00572 */ 00573 if (*ptr == DW_EH_PE_omit) { 00574 lsda->lpstart = _Unwind_GetRegionStart(context); 00575 ++ptr; 00576 } 00577 else 00578 fatal_error("Unexpected DWARF value for @LPStart!"); 00579 00580 /* 00581 * FIXME: Currently, we do not make use of the @TTBase format. We assume it 00582 * is DW_EH_PE_absptr and interpet the type table entries as such. See 00583 * match_exception() for a few more notes on the issue. 00584 */ 00585 lsda->type_table_format = *ptr; 00586 ++ptr; 00587 if (lsda->type_table_format != DW_EH_PE_absptr) 00588 fatal_error("Unexpected type table format!"); 00589 00590 /* 00591 * Take @TTBase as a self relative offset. 00592 */ 00593 ptr = parse_uleb128(ptr, &tmp); 00594 lsda->type_table = ptr + tmp; 00595 00596 /* 00597 * Read in the call site encoding. Unlike @TTBase format, we can respect 00598 * this. 00599 */ 00600 lsda->call_site_format = *ptr; 00601 ++ptr; 00602 00603 /* 00604 * Read the call table size as an unsigned LEB128. 00605 */ 00606 ptr = parse_uleb128(ptr, &lsda->call_table_size); 00607 00608 /* 00609 * The current pointer indicates the start of the call site table. 00610 */ 00611 lsda->call_sites = ptr; 00612 00613 /* 00614 * The action table immediately follows the call site table. 00615 */ 00616 lsda->actions = lsda->call_sites + lsda->call_table_size; 00617 00618 return 0; 00619 } 00620 00621 /* 00622 * Debug routine to spill the contents of an LSDA_Header, conditional on the 00623 * setting of COMMA_EH_DEBUG. 00624 */ 00625 static void dump_LSDA(struct LSDA_Header *lsda) 00626 { 00627 #ifdef COMMA_EH_DEBUG 00628 fputs("LSDA_Header :\n", stderr); 00629 fprintf(stderr, " lsda_start : %" PRIXPTR "\n", 00630 (uintptr_t)lsda->lsda_start); 00631 fprintf(stderr, " lpstart : %" PRIXPTR "\n", 00632 lsda->lpstart); 00633 fprintf(stderr, " tt format : %u\n", 00634 (unsigned)lsda->type_table_format); 00635 fprintf(stderr, " type_table : %" PRIXPTR "\n", 00636 (uintptr_t)lsda->type_table); 00637 fprintf(stderr, " call format : %u\n", 00638 (unsigned)lsda->call_site_format); 00639 fprintf(stderr, " call size : %" PRIu64 "\n", 00640 lsda->call_table_size); 00641 fprintf(stderr, " call sites : %" PRIXPTR "\n", 00642 (uintptr_t)lsda->call_sites); 00643 fprintf(stderr, " actions : %" PRIXPTR "\n", 00644 (uintptr_t)lsda->actions); 00645 #endif 00646 } 00647 00648 /* 00649 * The following function parses a call-site filling dst with the result. 00650 * Returns a pointer to the next site on success or null if there are no more 00651 * call sites to parse. 00652 */ 00653 static unsigned char * 00654 parse_Call_Site(struct LSDA_Header *lsda, 00655 unsigned char *ptr, struct Call_Site *dst) 00656 { 00657 /* 00658 * First, check that the given pointer is within the bounds of the 00659 * call-site table. 00660 */ 00661 if (ptr >= (lsda->call_sites + lsda->call_table_size)) 00662 return 0; 00663 00664 /* 00665 * Using the DWARF format control for the call size table, parse the call 00666 * size region, length, and landing pad info. 00667 */ 00668 ptr = parse_dwarf_value(lsda->call_site_format, 00669 ptr, (uint64_t*)&dst->region_start); 00670 ptr = parse_dwarf_value(lsda->call_site_format, 00671 ptr, &dst->region_length); 00672 ptr = parse_dwarf_value(lsda->call_site_format, 00673 ptr, (uint64_t*)&dst->landing_pad); 00674 00675 /* 00676 * The action is always an unsigned LEB128 value. 00677 */ 00678 ptr = parse_uleb128(ptr, &dst->action_index); 00679 return ptr; 00680 } 00681 00682 /* 00683 * Debug routine to spill the contents of a Call_Site, conditional on the 00684 * setting of COMMA_EH_DEBUG. 00685 */ 00686 static void dump_Call_Site(struct Call_Site *site) 00687 { 00688 #ifdef COMMA_EH_DEBUG 00689 fputs("Call_Site :\n", stderr); 00690 fprintf(stderr, " region_start : %" PRIx64 "\n", site->region_start); 00691 fprintf(stderr, " region_length : %" PRIu64 "\n", site->region_length); 00692 fprintf(stderr, " landing_pad : %" PRIx64 "\n", site->landing_pad); 00693 fprintf(stderr, " action_index : %" PRIu64 "\n", site->action_index); 00694 #endif 00695 } 00696 00697 /* 00698 * Parses an action record starting at the given address. Returns a pointer to 00699 * the next action record if one follows, else null. 00700 */ 00701 static unsigned char * 00702 parse_Action_Record(unsigned char *ptr, struct Action_Record *dst) 00703 { 00704 unsigned char *start; 00705 00706 /* 00707 * Both fields of an action record are signed LEB128 encoded values. Obtain 00708 * the index into the types table. 00709 */ 00710 ptr = parse_sleb128(ptr, (int64_t*)&dst->info_index); 00711 00712 /* 00713 * Adjust the current address by the next value yielding the next action 00714 * record. 00715 */ 00716 start = ptr; 00717 parse_sleb128(ptr, (int64_t*)&dst->next_action); 00718 00719 /* 00720 * A next value of zero terminates the action list. Build a pointer to the 00721 * next entry or signal completion. 00722 */ 00723 if (dst->next_action) 00724 return start + dst->next_action; 00725 else 00726 return 0; 00727 } 00728 00729 /* 00730 * The following routine walks the list of call site records provided by the 00731 * LSDA and determines which one is applicable using the given _Unwind_Context. 00732 * Fills the Call_Site structure dst with the relevant info and returns 0 on 00733 * success. Otherwise, returns 1 with the contents of dst undefined. 00734 */ 00735 static int 00736 find_applicable_call_site(struct LSDA_Header *lsda, 00737 struct _Unwind_Context *context, 00738 struct Call_Site *dst) 00739 { 00740 /* 00741 * Get the current instruction pointer. This value is one past the location 00742 * of the actual instruction that raised, hense the -1. 00743 */ 00744 unsigned char *IP = (unsigned char *)_Unwind_GetIP(context) - 1; 00745 00746 /* 00747 * Get a pointer to the initial call site record. 00748 */ 00749 unsigned char *ptr = lsda->call_sites; 00750 00751 /* 00752 * Get a pointer to the region of code this exception header covers. The 00753 * call site regions start relative to this position. 00754 */ 00755 unsigned char *region = 00756 (unsigned char *)_Unwind_GetRegionStart(context); 00757 00758 /* 00759 * Walk the list of call sites. 00760 */ 00761 while ((ptr = parse_Call_Site(lsda, ptr, dst))) { 00762 00763 /* 00764 * Since the call sites are sorted, we stop when the IP is less than the 00765 * start of the current site records region. 00766 */ 00767 unsigned char *region_start = region + dst->region_start; 00768 if (IP < region_start) 00769 return 1; 00770 00771 /* 00772 * We know the IP is greater than or equal to the start of the call site 00773 * region. Check if it is in bounds. If so, we have a match. 00774 */ 00775 if (IP < region_start + dst->region_length) 00776 return 0; 00777 } 00778 00779 /* 00780 * We have scanned all of the call sites. Not only did we not find a match 00781 * but the IP was out of bounds for all of them. This should never happen. 00782 */ 00783 fatal_error("IP out of bounds for call site table!"); 00784 return 1; 00785 } 00786 00787 /* 00788 * The following routine takes an LSDA, an action index, and a generic exception 00789 * object as arguments. Returns 0 if the exception object matches the set of 00790 * exception ID's starting at the given action index and 1 otherwise. When a 00791 * match was found, the matching action index is placed in dst. 00792 */ 00793 static int 00794 match_exception(struct LSDA_Header *lsda, 00795 struct _Unwind_Exception *exceptionObject, 00796 uint64_t action_index, uint64_t *dst) 00797 { 00798 struct Action_Record action; 00799 unsigned char *ptr; 00800 00801 /* 00802 * Convert the generic exception into a Comma exception. 00803 */ 00804 struct comma_exception *exception = to_comma_exception(exceptionObject); 00805 00806 /* 00807 * We should never have a zero action index, as that indicates no action at 00808 * all. Assert this fact and remove the bias. 00809 */ 00810 if (action_index == 0) { 00811 fatal_error("Invalid action index!"); 00812 return 1; 00813 } 00814 else { 00815 action_index -= 1; 00816 ptr = lsda->actions + action_index; 00817 } 00818 00819 /* 00820 * Parse each action record in search of a match. 00821 */ 00822 do { 00823 ptr = parse_Action_Record(ptr, &action); 00824 00825 if (action.info_index > 0) { 00826 /* 00827 * FIXME: We should be using the type table format here to interpret 00828 * both the size of the entries themselves and how to interpret the 00829 * values. Here we assume a format of DW_EH_PE_absptr. This works 00830 * for static code, but there are other cases (for PIC code the 00831 * references will be indirect). In short, we should: 00832 * 00833 * - Use the ttable format to get a scale factor for the action 00834 * index. 00835 * 00836 * - Use the ttable format to fetch the required base. For 00837 * example, a format of DW_EH_PE_funcrel would indicate that we 00838 * interpret the entries as offsets relative to the value of 00839 * _Unwind_GetRegionStart(). 00840 */ 00841 comma_exinfo_t *info; 00842 info = (comma_exinfo_t *)lsda->type_table; 00843 info -= action.info_index; 00844 00845 /* 00846 * If the info pointer is 0, then this is a catch-all. Otherwise, 00847 * the exeption objects id must match the handlers associated 00848 * exinfo. 00849 */ 00850 if ((*info == 0) || (exception->id == *info)) { 00851 *dst = action.info_index; 00852 return 0; 00853 } 00854 } 00855 else { 00856 /* 00857 * Negative indices in an action record correspond to filters. Such 00858 * things are only used in C++ and should never appear in Comma. 00859 */ 00860 if (action.info_index < 0) { 00861 fatal_error("Filter action detected!"); 00862 return 1; 00863 } 00864 } 00865 } while (ptr); 00866 00867 /* 00868 * No match was found. 00869 */ 00870 return 1; 00871 } 00872 00873 static void 00874 install_handler(struct _Unwind_Context *context, 00875 struct _Unwind_Exception *exceptionObject, 00876 int64_t landing_pad, uintptr_t id) 00877 { 00878 /* 00879 * Handler code expects the exception object to be in the native Comma 00880 * format, rather than the generic format used by the system unwinder. 00881 */ 00882 struct comma_exception *exception = to_comma_exception(exceptionObject); 00883 00884 /* 00885 * Load the register to contain the exception pointer. 00886 */ 00887 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 00888 (uintptr_t)exception); 00889 00890 /* 00891 * Return the matching exception identity to that the landing pad knows 00892 * which action to take. 00893 */ 00894 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), id); 00895 00896 /* 00897 * Set the IP to the location of the landing pad. 00898 */ 00899 _Unwind_SetIP(context, (uintptr_t)landing_pad); 00900 } 00901 00902 /* 00903 * The following magic number identifies Comma exceptions. It reads as the 00904 * string "SMW\0CMA\0", where the first four bytes denotes the "vendor" (my 00905 * initials, in this case), and the last four bytes identifies the language. 00906 */ 00907 static const uint64_t Comma_Exception_Class_ID = 0x534D570434D410Ull; 00908 00909 /* 00910 * Cleanup routine for Comma exceptions. 00911 */ 00912 static void _comma_cleanup_exception(_Unwind_Reason_Code reason, 00913 struct _Unwind_Exception *exc) 00914 { 00915 struct comma_exception *exception = to_comma_exception(exc); 00916 if (exception->flags & COMMA_DYN_MESSAGE) 00917 free(exception->message); 00918 free(exception); 00919 } 00920 00921 /* 00922 * The following function is called to allocate and raise a Comma exception 00923 * which has a null-terminated statically allocated string as a message. 00924 */ 00925 void _comma_raise_exception(comma_exinfo_t info, 00926 const char *file_name, uint32_t line_number, 00927 const char *message) 00928 { 00929 struct comma_exception *exception; 00930 struct _Unwind_Exception *exception_object; 00931 00932 /* 00933 * Allocate the exception and fill in the Comma specific bits. 00934 */ 00935 exception = malloc(sizeof(struct comma_exception)); 00936 exception->id = info; 00937 exception->file_name = file_name; 00938 exception->line_number = line_number; 00939 exception->message = (char*)message; 00940 exception->flags = 0; 00941 00942 /* 00943 * Fill in the ABI bits. 00944 * 00945 * The magic number reads as "SMW\0CMA\0" 00946 */ 00947 exception->header.exception_class = Comma_Exception_Class_ID; 00948 exception->header.exception_cleanup = _comma_cleanup_exception; 00949 00950 /* 00951 * Fire it off. 00952 */ 00953 exception_object = to_Unwind_Exception(exception); 00954 _Unwind_RaiseException(exception_object); 00955 } 00956 00957 /* 00958 * The following function is called to allocate and raise a Comma exception 00959 * which allocates its own copy of the given message. 00960 */ 00961 void _comma_raise_nexception(comma_exinfo_t info, 00962 const char *file_name, uint32_t line_number, 00963 const char *message, uint32_t length) 00964 { 00965 struct comma_exception *exception; 00966 struct _Unwind_Exception *exception_object; 00967 00968 /* 00969 * Allocate the exception and fill in the Comma specific bits. 00970 */ 00971 exception = malloc(sizeof(struct comma_exception)); 00972 exception->id = info; 00973 exception->file_name = file_name; 00974 exception->line_number = line_number; 00975 00976 if (message) { 00977 exception->message = malloc(length + 1); 00978 exception->message = memcpy(exception->message, message, length); 00979 exception->message[length] = 0; 00980 exception->flags = COMMA_DYN_MESSAGE; 00981 } 00982 else { 00983 exception->message = 0; 00984 exception->flags = 0; 00985 } 00986 00987 /* 00988 * Fill in the ABI bits. 00989 * 00990 * The magic number reads as "SMW\0CMA\0" 00991 */ 00992 exception->header.exception_class = Comma_Exception_Class_ID; 00993 exception->header.exception_cleanup = _comma_cleanup_exception; 00994 00995 /* 00996 * Fire it off. 00997 */ 00998 exception_object = to_Unwind_Exception(exception); 00999 _Unwind_RaiseException(exception_object); 01000 } 01001 01002 /* 01003 * Re-raises a comma exception. 01004 */ 01005 void _comma_reraise_exception(struct comma_exception *exception) 01006 { 01007 struct _Unwind_Exception *exception_object = to_Unwind_Exception(exception); 01008 _Unwind_RaiseException(exception_object); 01009 } 01010 01011 /* 01012 * Raises a specific system exception. 01013 */ 01014 void _comma_raise_system(uint32_t id, 01015 const char *file_name, uint32_t line_number, 01016 const char *message) 01017 { 01018 comma_exinfo_t info = _comma_get_exception(id); 01019 _comma_raise_exception(info, file_name, line_number, message); 01020 } 01021 01022 /* 01023 * Comma's exception personality. 01024 */ 01025 _Unwind_Reason_Code 01026 _comma_eh_personality(int version, 01027 _Unwind_Action actions, 01028 uint64_t exceptionClass, 01029 struct _Unwind_Exception *exceptionObject, 01030 struct _Unwind_Context *context) 01031 { 01032 struct LSDA_Header lsda; 01033 struct Call_Site site; 01034 uint64_t id; 01035 intptr_t handler; 01036 01037 /* 01038 * The C++ Itanium ABI specifies a version number of 1. This is the only 01039 * ABI we cope with. 01040 */ 01041 if (version != 1) { 01042 return _URC_FATAL_PHASE1_ERROR; 01043 } 01044 01045 /* 01046 * Check that the exception class is a Comma exception. Currently, this is 01047 * a fatal error. In the future, we may support the catching of foreign 01048 * exceptions in a catch-all context. 01049 */ 01050 if (exceptionClass != Comma_Exception_Class_ID) { 01051 return _URC_FATAL_PHASE1_ERROR; 01052 } 01053 01054 /* 01055 * If we could not parse the lsda, continue to unwind. 01056 */ 01057 if (parse_LSDA(context, &lsda)) 01058 return _URC_CONTINUE_UNWIND; 01059 dump_LSDA(&lsda); 01060 01061 /* 01062 * Find the applicable call site. If none was found, continue unwinding. 01063 */ 01064 if (find_applicable_call_site(&lsda, context, &site)) 01065 return _URC_CONTINUE_UNWIND; 01066 dump_Call_Site(&site); 01067 01068 /* 01069 * If this site does not define a landing pad there is nothing to do. 01070 * Continue to unwind. 01071 */ 01072 if (!site.landing_pad) 01073 return _URC_CONTINUE_UNWIND; 01074 01075 /* 01076 * If there is no action defined for this site, then this is a cleanup. 01077 * Comma does not support cleanups ATM, so this is a hard error for now. 01078 */ 01079 if (!site.action_index) { 01080 fatal_error("Cleanups are not supported!"); 01081 return _URC_FATAL_PHASE1_ERROR; 01082 } 01083 01084 /* 01085 * Similarly, if we are just unwinding the stack to get at a handler there 01086 * is nothing for the personality routine to. 01087 */ 01088 if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) 01089 return _URC_CONTINUE_UNWIND; 01090 01091 /* 01092 * We have an action index. If the thrown exception matches any of the 01093 * excption ids acceptable to the landing pad we have found a handler. If 01094 * not, continue to unwind. 01095 */ 01096 if (match_exception(&lsda, exceptionObject, site.action_index, &id)) 01097 return _URC_CONTINUE_UNWIND; 01098 01099 /* 01100 * A handler was found. Report the fact when in phase 1. 01101 */ 01102 if (actions & _UA_SEARCH_PHASE) 01103 return _URC_HANDLER_FOUND; 01104 01105 /* 01106 * If the _UA_HANDLER_FRAME bit is not set then continue to unwind. 01107 */ 01108 if (!(actions & _UA_HANDLER_FRAME)) 01109 return _URC_CONTINUE_UNWIND; 01110 01111 /* 01112 * We are in phase 2. Compute the landing pad address relative to @LPStart 01113 * and install into the context. 01114 */ 01115 handler = lsda.lpstart + site.landing_pad; 01116 install_handler(context, exceptionObject, handler, id); 01117 return _URC_INSTALL_CONTEXT; 01118 } 01119 01120 /* 01121 * When the main Comma procedure catches an uncaught exception, the following 01122 * function is invoked to report the incident. 01123 */ 01124 void _comma_unhandled_exception(struct comma_exception *exception) 01125 { 01126 const char *message = exception->message; 01127 01128 if (message) 01129 fprintf(stderr, "Unhandled exception: %s:%d: %s: %s\n", 01130 exception->file_name, exception->line_number, 01131 *exception->id, message); 01132 else 01133 fprintf(stderr, "Unhandled exception: %s:%d: %s\n", 01134 exception->file_name, exception->line_number, 01135 *exception->id); 01136 01137 abort(); 01138 } 01139 01140 /* 01141 * The following items are the built in comma_exinfo's. These are exported 01142 * symbols as the compiler generates direct references to them. 01143 */ 01144 char *_comma_exinfo_program_error = "PROGRAM_ERROR"; 01145 char *_comma_exinfo_constraint_error = "CONSTRAINT_ERROR"; 01146 char *_comma_exinfo_assertion_error = "ASSERTION_ERROR"; 01147 01148 /* 01149 * API to access the system-level exinfo's. 01150 */ 01151 comma_exinfo_t _comma_get_exception(comma_exception_id id) 01152 { 01153 comma_exinfo_t info = 0; 01154 switch (id) { 01155 default: 01156 fatal_error("Invalid exception ID!"); 01157 break; 01158 01159 case COMMA_CONSTRAINT_ERROR_E: 01160 info = &_comma_exinfo_constraint_error; 01161 break; 01162 01163 case COMMA_PROGRAM_ERROR_E: 01164 info = &_comma_exinfo_program_error; 01165 break; 01166 01167 case COMMA_ASSERTION_ERROR_E: 01168 info = &_comma_exinfo_assertion_error; 01169 break; 01170 } 01171 return info; 01172 }