Changeset View
Changeset View
Standalone View
Standalone View
head/contrib/libcxxrt/dwarf_eh.h
Show First 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* Returns the encoding for a DWARF EH table entry. The encoding is stored in | * Returns the encoding for a DWARF EH table entry. The encoding is stored in | ||||
* the low four of an octet. The high four bits store the addressing mode. | * the low four of an octet. The high four bits store the addressing mode. | ||||
*/ | */ | ||||
static inline enum dwarf_data_encoding get_encoding(unsigned char x) | static inline enum dwarf_data_encoding get_encoding(unsigned char x) | ||||
{ | { | ||||
return (enum dwarf_data_encoding)(x & 0xf); | return static_cast<enum dwarf_data_encoding>(x & 0xf); | ||||
} | } | ||||
/** | /** | ||||
* DWARF addressing mode constants. When reading a pointer value from a DWARF | * DWARF addressing mode constants. When reading a pointer value from a DWARF | ||||
* exception table, you must know how it is stored and what the addressing mode | * exception table, you must know how it is stored and what the addressing mode | ||||
* is. The low four bits tell you the encoding, allowing you to decode a | * is. The low four bits tell you the encoding, allowing you to decode a | ||||
* number. The high four bits tell you the addressing mode, allowing you to | * number. The high four bits tell you the addressing mode, allowing you to | ||||
* turn that number into an address in memory. | * turn that number into an address in memory. | ||||
Show All 15 Lines | enum dwarf_data_relative | ||||
/// Pointer points to address of real value | /// Pointer points to address of real value | ||||
DW_EH_PE_indirect = 0x80 | DW_EH_PE_indirect = 0x80 | ||||
}; | }; | ||||
/** | /** | ||||
* Returns the addressing mode component of this encoding. | * Returns the addressing mode component of this encoding. | ||||
*/ | */ | ||||
static inline enum dwarf_data_relative get_base(unsigned char x) | static inline enum dwarf_data_relative get_base(unsigned char x) | ||||
{ | { | ||||
return (enum dwarf_data_relative)(x & 0x70); | return static_cast<enum dwarf_data_relative>(x & 0x70); | ||||
} | } | ||||
/** | /** | ||||
* Returns whether an encoding represents an indirect address. | * Returns whether an encoding represents an indirect address. | ||||
*/ | */ | ||||
static int is_indirect(unsigned char x) | static int is_indirect(unsigned char x) | ||||
{ | { | ||||
return ((x & DW_EH_PE_indirect) == DW_EH_PE_indirect); | return ((x & DW_EH_PE_indirect) == DW_EH_PE_indirect); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int bits; | int bits; | ||||
// Read as if it's signed | // Read as if it's signed | ||||
uint64_t uleb = read_leb128(data, &bits); | uint64_t uleb = read_leb128(data, &bits); | ||||
// If the most significant bit read is 1, then we need to sign extend it | // If the most significant bit read is 1, then we need to sign extend it | ||||
if ((uleb >> (bits-1)) == 1) | if ((uleb >> (bits-1)) == 1) | ||||
{ | { | ||||
// Sign extend by setting all bits in front of it to 1 | // Sign extend by setting all bits in front of it to 1 | ||||
uleb |= ((int64_t)-1) << bits; | uleb |= static_cast<int64_t>(-1) << bits; | ||||
} | } | ||||
return (int64_t)uleb; | return static_cast<int64_t>(uleb); | ||||
} | } | ||||
/** | /** | ||||
* Reads a value using the specified encoding from the address pointed to by | * Reads a value using the specified encoding from the address pointed to by | ||||
* *data. Updates the value of *data to point to the next byte after the end | * *data. Updates the value of *data to point to the next byte after the end | ||||
* of the data. | * of the data. | ||||
*/ | */ | ||||
static uint64_t read_value(char encoding, dw_eh_ptr_t *data) | static uint64_t read_value(char encoding, dw_eh_ptr_t *data) | ||||
{ | { | ||||
enum dwarf_data_encoding type = get_encoding(encoding); | enum dwarf_data_encoding type = get_encoding(encoding); | ||||
uint64_t v; | uint64_t v; | ||||
switch (type) | switch (type) | ||||
{ | { | ||||
// Read fixed-length types | // Read fixed-length types | ||||
#define READ(dwarf, type) \ | #define READ(dwarf, type) \ | ||||
case dwarf:\ | case dwarf:\ | ||||
v = (uint64_t)(*(type*)(*data));\ | v = static_cast<uint64_t>(*reinterpret_cast<type*>(*data));\ | ||||
*data += sizeof(type);\ | *data += sizeof(type);\ | ||||
break; | break; | ||||
READ(DW_EH_PE_udata2, uint16_t) | READ(DW_EH_PE_udata2, uint16_t) | ||||
READ(DW_EH_PE_udata4, uint32_t) | READ(DW_EH_PE_udata4, uint32_t) | ||||
READ(DW_EH_PE_udata8, uint64_t) | READ(DW_EH_PE_udata8, uint64_t) | ||||
READ(DW_EH_PE_sdata2, int16_t) | READ(DW_EH_PE_sdata2, int16_t) | ||||
READ(DW_EH_PE_sdata4, int32_t) | READ(DW_EH_PE_sdata4, int32_t) | ||||
READ(DW_EH_PE_sdata8, int64_t) | READ(DW_EH_PE_sdata8, int64_t) | ||||
Show All 22 Lines | |||||
static uint64_t resolve_indirect_value(_Unwind_Context *c, | static uint64_t resolve_indirect_value(_Unwind_Context *c, | ||||
unsigned char encoding, | unsigned char encoding, | ||||
int64_t v, | int64_t v, | ||||
dw_eh_ptr_t start) | dw_eh_ptr_t start) | ||||
{ | { | ||||
switch (get_base(encoding)) | switch (get_base(encoding)) | ||||
{ | { | ||||
case DW_EH_PE_pcrel: | case DW_EH_PE_pcrel: | ||||
v += (uint64_t)start; | v += reinterpret_cast<uint64_t>(start); | ||||
break; | break; | ||||
case DW_EH_PE_textrel: | case DW_EH_PE_textrel: | ||||
v += (uint64_t)_Unwind_GetTextRelBase(c); | v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetTextRelBase(c))); | ||||
break; | break; | ||||
case DW_EH_PE_datarel: | case DW_EH_PE_datarel: | ||||
v += (uint64_t)_Unwind_GetDataRelBase(c); | v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetDataRelBase(c))); | ||||
break; | break; | ||||
case DW_EH_PE_funcrel: | case DW_EH_PE_funcrel: | ||||
v += (uint64_t)_Unwind_GetRegionStart(c); | v += static_cast<uint64_t>(static_cast<uintptr_t>(_Unwind_GetRegionStart(c))); | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
// If this is an indirect value, then it is really the address of the real | // If this is an indirect value, then it is really the address of the real | ||||
// value | // value | ||||
// TODO: Check whether this should really always be a pointer - it seems to | // TODO: Check whether this should really always be a pointer - it seems to | ||||
// be a GCC extensions, so not properly documented... | // be a GCC extensions, so not properly documented... | ||||
if (is_indirect(encoding)) | if (is_indirect(encoding)) | ||||
{ | { | ||||
v = (uint64_t)(uintptr_t)*(void**)v; | v = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(*reinterpret_cast<void**>(v))); | ||||
} | } | ||||
return v; | return v; | ||||
} | } | ||||
/** | /** | ||||
* Reads an encoding and a value, updating *data to point to the next byte. | * Reads an encoding and a value, updating *data to point to the next byte. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
* Parse the header on the language-specific data area and return a structure | * Parse the header on the language-specific data area and return a structure | ||||
* containing the addresses and encodings of the various tables. | * containing the addresses and encodings of the various tables. | ||||
*/ | */ | ||||
static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context, | static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context, | ||||
unsigned char *data) | unsigned char *data) | ||||
{ | { | ||||
struct dwarf_eh_lsda lsda; | struct dwarf_eh_lsda lsda; | ||||
lsda.region_start = (dw_eh_ptr_t)(uintptr_t)_Unwind_GetRegionStart(context); | lsda.region_start = reinterpret_cast<dw_eh_ptr_t>(_Unwind_GetRegionStart(context)); | ||||
// If the landing pads are relative to anything other than the start of | // If the landing pads are relative to anything other than the start of | ||||
// this region, find out where. This is @LPStart in the spec, although the | // this region, find out where. This is @LPStart in the spec, although the | ||||
// encoding that GCC uses does not quite match the spec. | // encoding that GCC uses does not quite match the spec. | ||||
uint64_t v = (uint64_t)(uintptr_t)lsda.region_start; | uint64_t v = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(lsda.region_start)); | ||||
read_value_with_encoding(context, &data, &v); | read_value_with_encoding(context, &data, &v); | ||||
lsda.landing_pads = (dw_eh_ptr_t)(uintptr_t)v; | lsda.landing_pads = reinterpret_cast<dw_eh_ptr_t>(static_cast<uintptr_t>(v)); | ||||
// If there is a type table, find out where it is. This is @TTBase in the | // If there is a type table, find out where it is. This is @TTBase in the | ||||
// spec. Note: we find whether there is a type table pointer by checking | // spec. Note: we find whether there is a type table pointer by checking | ||||
// whether the leading byte is DW_EH_PE_omit (0xff), which is not what the | // whether the leading byte is DW_EH_PE_omit (0xff), which is not what the | ||||
// spec says, but does seem to be how G++ indicates this. | // spec says, but does seem to be how G++ indicates this. | ||||
lsda.type_table = 0; | lsda.type_table = 0; | ||||
lsda.type_table_encoding = *data++; | lsda.type_table_encoding = *data++; | ||||
if (lsda.type_table_encoding != DW_EH_PE_omit) | if (lsda.type_table_encoding != DW_EH_PE_omit) | ||||
{ | { | ||||
v = read_uleb128(&data); | v = read_uleb128(&data); | ||||
dw_eh_ptr_t type_table = data; | dw_eh_ptr_t type_table = data; | ||||
type_table += v; | type_table += v; | ||||
lsda.type_table = type_table; | lsda.type_table = type_table; | ||||
//lsda.type_table = (uintptr_t*)(data + v); | //lsda.type_table = (uintptr_t*)(data + v); | ||||
} | } | ||||
#if __arm__ | #if defined(__arm__) && !defined(__ARM_DWARF_EH__) | ||||
lsda.type_table_encoding = (DW_EH_PE_pcrel | DW_EH_PE_indirect); | lsda.type_table_encoding = (DW_EH_PE_pcrel | DW_EH_PE_indirect); | ||||
#endif | #endif | ||||
lsda.callsite_encoding = (enum dwarf_data_encoding)(*(data++)); | lsda.callsite_encoding = static_cast<enum dwarf_data_encoding>(*(data++)); | ||||
// Action table is immediately after the call site table | // Action table is immediately after the call site table | ||||
lsda.action_table = data; | lsda.action_table = data; | ||||
uintptr_t callsite_size = (uintptr_t)read_uleb128(&data); | uintptr_t callsite_size = static_cast<uintptr_t>(read_uleb128(&data)); | ||||
lsda.action_table = data + callsite_size; | lsda.action_table = data + callsite_size; | ||||
// Call site table is immediately after the header | // Call site table is immediately after the header | ||||
lsda.call_site_table = (dw_eh_ptr_t)data; | lsda.call_site_table = static_cast<dw_eh_ptr_t>(data); | ||||
return lsda; | return lsda; | ||||
} | } | ||||
/** | /** | ||||
* Structure representing an action to be performed while unwinding. This | * Structure representing an action to be performed while unwinding. This | ||||
* contains the address that should be unwound to and the action record that | * contains the address that should be unwound to and the action record that | ||||
Show All 20 Lines | |||||
static bool dwarf_eh_find_callsite(struct _Unwind_Context *context, | static bool dwarf_eh_find_callsite(struct _Unwind_Context *context, | ||||
struct dwarf_eh_lsda *lsda, | struct dwarf_eh_lsda *lsda, | ||||
struct dwarf_eh_action *result) | struct dwarf_eh_action *result) | ||||
{ | { | ||||
result->action_record = 0; | result->action_record = 0; | ||||
result->landing_pad = 0; | result->landing_pad = 0; | ||||
// The current instruction pointer offset within the region | // The current instruction pointer offset within the region | ||||
uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context); | uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context); | ||||
unsigned char *callsite_table = (unsigned char*)lsda->call_site_table; | unsigned char *callsite_table = static_cast<unsigned char*>(lsda->call_site_table); | ||||
while (callsite_table <= lsda->action_table) | while (callsite_table <= lsda->action_table) | ||||
{ | { | ||||
// Once again, the layout deviates from the spec. | // Once again, the layout deviates from the spec. | ||||
uint64_t call_site_start, call_site_size, landing_pad, action; | uint64_t call_site_start, call_site_size, landing_pad, action; | ||||
call_site_start = read_value(lsda->callsite_encoding, &callsite_table); | call_site_start = read_value(lsda->callsite_encoding, &callsite_table); | ||||
call_site_size = read_value(lsda->callsite_encoding, &callsite_table); | call_site_size = read_value(lsda->callsite_encoding, &callsite_table); | ||||
Show All 33 Lines | if (call_site_start < ip && ip <= call_site_start + call_site_size) | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
/// Defines an exception class from 8 bytes (endian independent) | /// Defines an exception class from 8 bytes (endian independent) | ||||
#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \ | #define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \ | ||||
(((uint64_t)a << 56) +\ | ((static_cast<uint64_t>(a) << 56) +\ | ||||
((uint64_t)b << 48) +\ | (static_cast<uint64_t>(b) << 48) +\ | ||||
((uint64_t)c << 40) +\ | (static_cast<uint64_t>(c) << 40) +\ | ||||
((uint64_t)d << 32) +\ | (static_cast<uint64_t>(d) << 32) +\ | ||||
((uint64_t)e << 24) +\ | (static_cast<uint64_t>(e) << 24) +\ | ||||
((uint64_t)f << 16) +\ | (static_cast<uint64_t>(f) << 16) +\ | ||||
((uint64_t)g << 8) +\ | (static_cast<uint64_t>(g) << 8) +\ | ||||
((uint64_t)h)) | (static_cast<uint64_t>(h))) | ||||
#define GENERIC_EXCEPTION_CLASS(e,f,g,h) \ | #define GENERIC_EXCEPTION_CLASS(e,f,g,h) \ | ||||
((uint32_t)e << 24) +\ | (static_cast<uint32_t>(e) << 24) +\ | ||||
((uint32_t)f << 16) +\ | (static_cast<uint32_t>(f) << 16) +\ | ||||
((uint32_t)g << 8) +\ | (static_cast<uint32_t>(g) << 8) +\ | ||||
((uint32_t)h) | (static_cast<uint32_t>(h)) |