diff --git a/.gitignore b/.gitignore index ade24f3..dadc816 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,10 @@ *.la *.a +# Assembly files +*.s + libcxxabi +app +*log.txt +.vscode \ No newline at end of file diff --git a/abi_v08/mycppabi.cpp b/abi_v08/mycppabi.cpp index cd2344d..e4c0314 100644 --- a/abi_v08/mycppabi.cpp +++ b/abi_v08/mycppabi.cpp @@ -85,53 +85,117 @@ void __cxa_end_catch() * &LSDA_ptr will be a non-const pointer to a const place in memory */ typedef const uint8_t* LSDA_ptr; +typedef _uleb128_t LSDA_line; + + +//This function receives a pointer the first byte to be decoded and the address of where to put the decoded value. +const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + result = 0; + do + { + byte = *p++; + // Shifting the byte to the left and propagating the new byte to it (if there's any) + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + // if the 8th bit is 1, this means that there still another byte to be concatinated to the current byte (if zero, then decoding is done) + while (byte & 0x80); + *val = result; + return p; +} + +// This function recieves a pointer to a ttype entry and return the corrisponding type_info +// It's an implementation of three different functions from unwind-pe.h specific to our case and cannot be generalized for different encoding and size +const std::type_info * +get_ttype_entry (uint8_t* entry) +{ + // Get a pointer to the value of the address inside entry + const int32_t *u = (const int32_t *) entry; + unsigned long result; + + // The final address will be the value stored plus the address of the value (pc relative addressing) + result = *u + (unsigned long)u; + result = *(unsigned long *)result; + + // Type cast it into a valid type_info + const std::type_info *tinfo = reinterpret_cast(result); + return tinfo; +} struct LSDA_Header { /** * Read the LSDA table into a struct; advances the lsda pointer - * as many bytes as read + * as many bytes as read. The commented code is the old one and will be deletedin later version */ LSDA_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + // LSDA_ptr read_ptr = *lsda; + + // // Copy the LSDA fields + // start_encoding = read_ptr[0]; + // type_encoding = read_ptr[1]; + // type_table_offset = read_ptr[2]; - // Copy the LSDA fields + // // Advance the lsda pointer + // *lsda = read_ptr + sizeof(LSDA_Header); + + // Modified version of read for compatability with decodoing function + const unsigned char *read_ptr = (const unsigned char *)*lsda; start_encoding = read_ptr[0]; type_encoding = read_ptr[1]; - type_table_offset = read_ptr[2]; - - // Advance the lsda pointer - *lsda = read_ptr + sizeof(LSDA_Header); + read_ptr += 2; + read_ptr = read_uleb128(read_ptr, &type_table_offset); + *lsda = (LSDA_ptr)read_ptr; } uint8_t start_encoding; uint8_t type_encoding; // This is the offset, from the end of the header, to the types table - uint8_t type_table_offset; + LSDA_line type_table_offset; }; struct LSDA_CS_Header { // Same as other LSDA constructors LSDA_CS_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + // LSDA_ptr read_ptr = *lsda; + // encoding = read_ptr[0]; + // length = read_ptr[1]; + // *lsda = read_ptr + sizeof(LSDA_CS_Header); + + // Modified version of read for compatability with decodoing function + const unsigned char *read_ptr = (const unsigned char *)*lsda; encoding = read_ptr[0]; - length = read_ptr[1]; - *lsda = read_ptr + sizeof(LSDA_CS_Header); + read_ptr += 1; + read_ptr = read_uleb128(read_ptr, &length); + *lsda = (LSDA_ptr)read_ptr; } uint8_t encoding; - uint8_t length; + LSDA_line length; }; struct LSDA_CS { // Same as other LSDA constructors LSDA_CS(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - start = read_ptr[0]; - len = read_ptr[1]; - lp = read_ptr[2]; - action = read_ptr[3]; - *lsda = read_ptr + sizeof(LSDA_CS); + // LSDA_ptr read_ptr = *lsda; + // start = read_ptr[0]; + // len = read_ptr[1]; + // lp = read_ptr[2]; + // action = read_ptr[3]; + // *lsda = read_ptr + sizeof(LSDA_CS); + + // Modified version of read for compatability with decodoing function + const unsigned char *read_ptr = (const unsigned char *)*lsda; + read_ptr = read_uleb128(read_ptr, &start); + read_ptr = read_uleb128(read_ptr, &len); + read_ptr = read_uleb128(read_ptr, &lp); + read_ptr = read_uleb128(read_ptr, &action); + *lsda = (LSDA_ptr)read_ptr; } LSDA_CS() { } @@ -141,14 +205,14 @@ struct LSDA_CS { // is relative to start // Offset into function from which we could handle a throw - uint8_t start; + LSDA_line start; // Length of the block that might throw - uint8_t len; + LSDA_line len; // Landing pad - uint8_t lp; + LSDA_line lp; // Offset into action table + 1 (0 means no action) // Used to run destructors - uint8_t action; + LSDA_line action; }; /** @@ -184,7 +248,8 @@ struct LSDA // Get the start of the types table (it's actually the end of the // table, but since the action index will hold a negative index // for this table we can say it's the beginning - types_table_start( (const void**)(raw_lsda + header.type_table_offset) ), + // modified the pointer size for pointer arthemitics + types_table_start( (const void**)((uint8_t*)raw_lsda + header.type_table_offset) ), // Read the LSDA CS header cs_header(&raw_lsda), @@ -193,7 +258,8 @@ struct LSDA cs_table_start(raw_lsda), // Calculate where the end of the LSDA CS table is - cs_table_end(raw_lsda + cs_header.length), + // Pointer Arth. has been changed to accomodate the lareger pointer type + cs_table_end((const LSDA_ptr)((uint8_t*)(raw_lsda) + cs_header.length)), // Get the start of action tables action_tbl_start( cs_table_end ) @@ -251,6 +317,10 @@ _Unwind_Reason_Code __gxx_personality_v0 ( // Go through each call site in this stack frame to check whether // the current exception can be handled here + /* + * This loop produces a segmentation fault error due to accesing a wrong memory location + * This happens probably because the LSDA entries are read without proper decoding so until we fix it, it will remain preceded by these nice // + */ for(const LSDA_CS *cs = lsda.next_call_site_entry(true); cs != NULL; cs = lsda.next_call_site_entry()) @@ -280,10 +350,14 @@ _Unwind_Reason_Code __gxx_personality_v0 ( // For a landing pad with a catch the action table will // hold an index to a list of types - int type_index = action[0]; - - const void* catch_type_info = lsda.types_table_start[ -1 * type_index ]; - const std::type_info *catch_ti = (const std::type_info *) catch_type_info; + // the 4 is the size of the .long data that stores types in ttable + int type_index = 4 * action[0]; + + uint8_t* catch_type_info = (uint8_t*)lsda.types_table_start; + catch_type_info -= type_index; + // void** catch_type_info_void = (void**)catch_type_info_byte; + // const void* catch_type_info = (const void*)(catch_type_info_void[0]); + const std::type_info *catch_ti = get_ttype_entry(catch_type_info); printf("%s\n", catch_ti->name()); } @@ -301,6 +375,30 @@ _Unwind_Reason_Code __gxx_personality_v0 ( break; } + // // This is used to print the values inside the headers + // printf("LSDA Header:\n"); + // printf("\tstart_encoding: %i\n", lsda.header.start_encoding); + // printf("\ttype_encoding: %i\n", lsda.header.type_encoding); + // printf("\ttype_table_offset: %i\n", lsda.header.type_table_offset); + + // printf("LSDA Call Site Header:\n"); + // printf("\tencoding: %i\n", lsda.cs_header.encoding); + // printf("\tlength: %i\n", lsda.cs_header.length); + + // //Now this one is a cute little for loop for accessing the Call Site table entries for debugging + // int i = 0; + // for (const LSDA_CS *cs = lsda.next_call_site_entry(true); + // cs != NULL; + // cs = lsda.next_call_site_entry()) + // { + // printf("Found a CS #%i:\n", i); + // printf("\tcs_start: %i\n", cs->start); + // printf("\tcs_len: %i\n", cs->len); + // printf("\tcs_lp: %i\n", cs->lp); + // printf("\tcs_action: %i\n", cs->action); + // i++; + // } + return _URC_INSTALL_CONTEXT; } else { printf("Personality function, error\n"); diff --git a/abi_v09/mycppabi.cpp b/abi_v09/mycppabi.cpp index a57cc03..db1d1a8 100644 --- a/abi_v09/mycppabi.cpp +++ b/abi_v09/mycppabi.cpp @@ -54,7 +54,9 @@ void __cxa_throw(void* thrown_exception, { printf("__cxa_throw called\n"); - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); + __cxa_exception *header = ((__cxa_exception *) thrown_exception); + const char* nm = tinfo->name(); + printf("%s\n", nm); // We need to save the type info in the exception header _Unwind_ will // receive, otherwise we won't be able to know it when unwinding @@ -89,6 +91,46 @@ void __cxa_end_catch() * &LSDA_ptr will be a non-const pointer to a const place in memory */ typedef const uint8_t* LSDA_ptr; +typedef _uleb128_t LSDA_line; + +//This function receives a pointer the first byte to be decoded and the address of where to put the decoded value. +const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + result = 0; + do + { + byte = *p++; + // Shifting the byte to the left and propagating the new byte to it (if there's any) + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + // if the 8th bit is 1, this means that there still another byte to be concatinated to the current byte (if zero, then decoding is done) + while (byte & 0x80); + *val = result; + return p; +} + +// This function recieves a pointer to a ttype entry and return the corrisponding type_info +// It's an implementation of three different functions from unwind-pe.h specific to our case and cannot be generalized for different encoding and size +const std::type_info * +get_ttype_entry (uint8_t* entry) +{ + // Get a pointer to the value of the address inside entry + const int32_t *u = (const int32_t *) entry; + unsigned long result; + + // The final address will be the value stored plus the address of the value (pc relative addressing) + result = *u + (unsigned long)u; + result = *(unsigned long *)result; + + // Type cast it into a valid type_info + const std::type_info *tinfo = reinterpret_cast(result); + return tinfo; +} struct LSDA_Header { /** @@ -96,46 +138,44 @@ struct LSDA_Header { * as many bytes as read */ LSDA_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - - // Copy the LSDA fields + const unsigned char *read_ptr = (const unsigned char *)*lsda; start_encoding = read_ptr[0]; type_encoding = read_ptr[1]; - type_table_offset = read_ptr[2]; - - // Advance the lsda pointer - *lsda = read_ptr + sizeof(LSDA_Header); + read_ptr += 2; + read_ptr = read_uleb128(read_ptr, &type_table_offset); + *lsda = (LSDA_ptr)read_ptr; } uint8_t start_encoding; uint8_t type_encoding; // This is the offset, from the end of the header, to the types table - uint8_t type_table_offset; + LSDA_line type_table_offset; }; struct LSDA_CS_Header { // Same as other LSDA constructors LSDA_CS_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + const unsigned char *read_ptr = (const unsigned char *)*lsda; encoding = read_ptr[0]; - length = read_ptr[1]; - *lsda = read_ptr + sizeof(LSDA_CS_Header); + read_ptr += 1; + read_ptr = read_uleb128(read_ptr, &length); + *lsda = (LSDA_ptr)read_ptr; } uint8_t encoding; - uint8_t length; + LSDA_line length; }; struct LSDA_CS { // Same as other LSDA constructors LSDA_CS(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - start = read_ptr[0]; - len = read_ptr[1]; - lp = read_ptr[2]; - action = read_ptr[3]; - *lsda = read_ptr + sizeof(LSDA_CS); + const unsigned char *read_ptr = (const unsigned char *)*lsda; + read_ptr = read_uleb128(read_ptr, &start); + read_ptr = read_uleb128(read_ptr, &len); + read_ptr = read_uleb128(read_ptr, &lp); + read_ptr = read_uleb128(read_ptr, &action); + *lsda = (LSDA_ptr)read_ptr; } LSDA_CS() { } @@ -145,14 +185,14 @@ struct LSDA_CS { // is relative to start // Offset into function from which we could handle a throw - uint8_t start; + LSDA_line start; // Length of the block that might throw - uint8_t len; + LSDA_line len; // Landing pad - uint8_t lp; + LSDA_line lp; // Offset into action table + 1 (0 means no action) // Used to run destructors - uint8_t action; + LSDA_line action; }; /** @@ -188,7 +228,7 @@ struct LSDA // Get the start of the types table (it's actually the end of the // table, but since the action index will hold a negative index // for this table we can say it's the beginning - types_table_start( (const void**)(raw_lsda + header.type_table_offset) ), + types_table_start( (const void**)((uint8_t*)raw_lsda + header.type_table_offset) ), // Read the LSDA CS header cs_header(&raw_lsda), @@ -197,7 +237,7 @@ struct LSDA cs_table_start(raw_lsda), // Calculate where the end of the LSDA CS table is - cs_table_end(raw_lsda + cs_header.length), + cs_table_end((const LSDA_ptr)((uint8_t*)(raw_lsda) + cs_header.length)), // Get the start of action tables action_tbl_start( cs_table_end ) @@ -284,11 +324,12 @@ _Unwind_Reason_Code __gxx_personality_v0 ( // For a landing pad with a catch the action table will // hold an index to a list of types - int type_index = action[0]; + int type_index = 4 * action[0]; // Get the type of the exception we can handle - const void* catch_type_info = lsda.types_table_start[ -1 * type_index ]; - const std::type_info *catch_ti = (const std::type_info *) catch_type_info; + uint8_t* catch_type_info = (uint8_t*)lsda.types_table_start; + catch_type_info -= type_index; + const std::type_info *catch_ti = get_ttype_entry(catch_type_info); // Get the type of the original exception being thrown __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; diff --git a/abi_v10/mycppabi.cpp b/abi_v10/mycppabi.cpp index f3e2392..aa8d6b0 100644 --- a/abi_v10/mycppabi.cpp +++ b/abi_v10/mycppabi.cpp @@ -54,7 +54,7 @@ void __cxa_throw(void* thrown_exception, { printf("__cxa_throw called\n"); - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); + __cxa_exception *header = ((__cxa_exception *) thrown_exception); // We need to save the type info in the exception header _Unwind_ will // receive, otherwise we won't be able to know it when unwinding @@ -89,6 +89,46 @@ void __cxa_end_catch() * &LSDA_ptr will be a non-const pointer to a const place in memory */ typedef const uint8_t* LSDA_ptr; +typedef _uleb128_t LSDA_line; + +//This function receives a pointer the first byte to be decoded and the address of where to put the decoded value. +const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + result = 0; + do + { + byte = *p++; + // Shifting the byte to the left and propagating the new byte to it (if there's any) + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + // if the 8th bit is 1, this means that there still another byte to be concatinated to the current byte (if zero, then decoding is done) + while (byte & 0x80); + *val = result; + return p; +} + +// This function recieves a pointer to a ttype entry and return the corrisponding type_info +// It's an implementation of three different functions from unwind-pe.h specific to our case and cannot be generalized for different encoding and size +const std::type_info * +get_ttype_entry (uint8_t* entry) +{ + // Get a pointer to the value of the address inside entry + const int32_t *u = (const int32_t *) entry; + unsigned long result; + + // The final address will be the value stored plus the address of the value (pc relative addressing) + result = *u + (unsigned long)u; + result = *(unsigned long *)result; + + // Type cast it into a valid type_info + const std::type_info *tinfo = reinterpret_cast(result); + return tinfo; +} struct LSDA_Header { /** @@ -96,46 +136,44 @@ struct LSDA_Header { * as many bytes as read */ LSDA_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - - // Copy the LSDA fields + const unsigned char *read_ptr = (const unsigned char *)*lsda; start_encoding = read_ptr[0]; type_encoding = read_ptr[1]; - type_table_offset = read_ptr[2]; - - // Advance the lsda pointer - *lsda = read_ptr + sizeof(LSDA_Header); + read_ptr += 2; + read_ptr = read_uleb128(read_ptr, &type_table_offset); + *lsda = (LSDA_ptr)read_ptr; } uint8_t start_encoding; uint8_t type_encoding; // This is the offset, from the end of the header, to the types table - uint8_t type_table_offset; + LSDA_line type_table_offset; }; struct LSDA_CS_Header { // Same as other LSDA constructors LSDA_CS_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + const unsigned char *read_ptr = (const unsigned char *)*lsda; encoding = read_ptr[0]; - length = read_ptr[1]; - *lsda = read_ptr + sizeof(LSDA_CS_Header); + read_ptr += 1; + read_ptr = read_uleb128(read_ptr, &length); + *lsda = (LSDA_ptr)read_ptr; } uint8_t encoding; - uint8_t length; + LSDA_line length; }; struct LSDA_CS { // Same as other LSDA constructors LSDA_CS(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - start = read_ptr[0]; - len = read_ptr[1]; - lp = read_ptr[2]; - action = read_ptr[3]; - *lsda = read_ptr + sizeof(LSDA_CS); + const unsigned char *read_ptr = (const unsigned char *)*lsda; + read_ptr = read_uleb128(read_ptr, &start); + read_ptr = read_uleb128(read_ptr, &len); + read_ptr = read_uleb128(read_ptr, &lp); + read_ptr = read_uleb128(read_ptr, &action); + *lsda = (LSDA_ptr)read_ptr; } LSDA_CS() { } @@ -145,14 +183,14 @@ struct LSDA_CS { // is relative to start // Offset into function from which we could handle a throw - uint8_t start; + LSDA_line start; // Length of the block that might throw - uint8_t len; + LSDA_line len; // Landing pad - uint8_t lp; + LSDA_line lp; // Offset into action table + 1 (0 means no action) // Used to run destructors - uint8_t action; + LSDA_line action; }; /** @@ -188,7 +226,7 @@ struct LSDA // Get the start of the types table (it's actually the end of the // table, but since the action index will hold a negative index // for this table we can say it's the beginning - types_table_start( (const void**)(raw_lsda + header.type_table_offset) ), + types_table_start( (const void**)((uint8_t*)raw_lsda + header.type_table_offset) ), // Read the LSDA CS header cs_header(&raw_lsda), @@ -197,7 +235,7 @@ struct LSDA cs_table_start(raw_lsda), // Calculate where the end of the LSDA CS table is - cs_table_end(raw_lsda + cs_header.length), + cs_table_end((const LSDA_ptr)((uint8_t*)(raw_lsda) + cs_header.length)), // Get the start of action tables action_tbl_start( cs_table_end ) @@ -279,11 +317,12 @@ _Unwind_Reason_Code __gxx_personality_v0 ( // For a landing pad with a catch the action table will // hold an index to a list of types - int type_index = action[0]; + int type_index = 4 * action[0]; // Get the type of the exception we can handle - const void* catch_type_info = lsda.types_table_start[ -1 * type_index ]; - const std::type_info *catch_ti = (const std::type_info *) catch_type_info; + uint8_t* catch_type_info = (uint8_t*)lsda.types_table_start; + catch_type_info -= type_index; + const std::type_info *catch_ti = get_ttype_entry(catch_type_info); // Get the type of the original exception being thrown __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; diff --git a/abi_v11/mycppabi.cpp b/abi_v11/mycppabi.cpp index 60acf1e..39f2e12 100644 --- a/abi_v11/mycppabi.cpp +++ b/abi_v11/mycppabi.cpp @@ -51,7 +51,7 @@ void __cxa_throw(void* thrown_exception, std::type_info *tinfo, void (*dest)(void*)) { - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); + __cxa_exception *header = ((__cxa_exception *) thrown_exception); // We need to save the type info in the exception header _Unwind_ will // receive, otherwise we won't be able to know it when unwinding @@ -108,6 +108,46 @@ int readSLEB128(const uint8_t* data) * &LSDA_ptr will be a non-const pointer to a const place in memory */ typedef const uint8_t* LSDA_ptr; +typedef _uleb128_t LSDA_line; + +//This function receives a pointer the first byte to be decoded and the address of where to put the decoded value. +const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + result = 0; + do + { + byte = *p++; + // Shifting the byte to the left and propagating the new byte to it (if there's any) + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + // if the 8th bit is 1, this means that there still another byte to be concatinated to the current byte (if zero, then decoding is done) + while (byte & 0x80); + *val = result; + return p; +} + +// This function recieves a pointer to a ttype entry and return the corrisponding type_info +// It's an implementation of three different functions from unwind-pe.h specific to our case and cannot be generalized for different encoding and size +const std::type_info * +get_ttype_entry (const uint8_t* entry) +{ + // Get a pointer to the value of the address inside entry + const int32_t *u = (const int32_t *) entry; + unsigned long result; + + // The final address will be the value stored plus the address of the value (pc relative addressing) + result = *u + (unsigned long)u; + result = *(unsigned long *)result; + + // Type cast it into a valid type_info + const std::type_info *tinfo = reinterpret_cast(result); + return tinfo; +} struct LSDA_Header { /** @@ -115,46 +155,44 @@ struct LSDA_Header { * as many bytes as read */ LSDA_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - - // Copy the LSDA fields + const unsigned char *read_ptr = (const unsigned char *)*lsda; start_encoding = read_ptr[0]; type_encoding = read_ptr[1]; - type_table_offset = read_ptr[2]; - - // Advance the lsda pointer - *lsda = read_ptr + sizeof(LSDA_Header); + read_ptr += 2; + read_ptr = read_uleb128(read_ptr, &type_table_offset); + *lsda = (LSDA_ptr)read_ptr; } uint8_t start_encoding; uint8_t type_encoding; // This is the offset, from the end of the header, to the types table - uint8_t type_table_offset; + LSDA_line type_table_offset; }; struct Call_Site_Header { // Same as other LSDA constructors Call_Site_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + const unsigned char *read_ptr = (const unsigned char *)*lsda; encoding = read_ptr[0]; - length = read_ptr[1]; - *lsda = read_ptr + sizeof(Call_Site_Header); + read_ptr += 1; + read_ptr = read_uleb128(read_ptr, &length); + *lsda = (LSDA_ptr)read_ptr; } uint8_t encoding; - uint8_t length; + LSDA_line length; }; struct Call_Site { // Same as other LSDA constructors Call_Site(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - start = read_ptr[0]; - len = read_ptr[1]; - lp = read_ptr[2]; - action = read_ptr[3]; - *lsda = read_ptr + sizeof(Call_Site); + const unsigned char *read_ptr = (const unsigned char *)*lsda; + read_ptr = read_uleb128(read_ptr, &start); + read_ptr = read_uleb128(read_ptr, &len); + read_ptr = read_uleb128(read_ptr, &lp); + read_ptr = read_uleb128(read_ptr, &action); + *lsda = (LSDA_ptr)read_ptr; } Call_Site() { } @@ -164,14 +202,14 @@ struct Call_Site { // is relative to start // Offset into function from which we could handle a throw - uint8_t start; + LSDA_line start; // Length of the block that might throw - uint8_t len; + LSDA_line len; // Landing pad - uint8_t lp; + LSDA_line lp; // Offset into action table + 1 (0 means no action) // Used to run destructors - uint8_t action; + LSDA_line action; bool has_landing_pad() const { return lp; } @@ -231,7 +269,7 @@ struct LSDA // Get the start of the types table (it's actually the end of the // table, but since the action index will hold a negative index // for this table we can say it's the beginning - types_table_start( (const void**)(raw_lsda + header.type_table_offset) ), + types_table_start( (const void**)((uint8_t*)raw_lsda + header.type_table_offset) ), // Read the LSDA CS header cs_header(&raw_lsda), @@ -240,7 +278,7 @@ struct LSDA cs_table_start(raw_lsda), // Calculate where the end of the LSDA CS table is - cs_table_end(raw_lsda + cs_header.length), + cs_table_end((const LSDA_ptr)((uint8_t*)(raw_lsda) + cs_header.length)), // Get the start of action tables action_tbl_start( cs_table_end ) @@ -352,8 +390,9 @@ struct LSDA { // The index starts at the end of the types table int idx = -1 * action->type_index; - const void* catch_type_info = this->types_table_start[idx]; - return (const std::type_info *) catch_type_info; + const uint8_t* catch_type_info = ((const uint8_t*)this->types_table_start) + (idx * 4); + //return 0; + return get_ttype_entry(catch_type_info);; } }; diff --git a/abi_v12/mycppabi.cpp b/abi_v12/mycppabi.cpp index 8b4d643..c580d3a 100644 --- a/abi_v12/mycppabi.cpp +++ b/abi_v12/mycppabi.cpp @@ -51,7 +51,7 @@ void __cxa_throw(void* thrown_exception, std::type_info *tinfo, void (*dest)(void*)) { - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); + __cxa_exception *header = ((__cxa_exception *) thrown_exception); // We need to save the type info in the exception header _Unwind_ will // receive, otherwise we won't be able to know it when unwinding @@ -108,6 +108,46 @@ int readSLEB128(const uint8_t* data) * &LSDA_ptr will be a non-const pointer to a const place in memory */ typedef const uint8_t* LSDA_ptr; +typedef _uleb128_t LSDA_line; + +//This function receives a pointer the first byte to be decoded and the address of where to put the decoded value. +const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + result = 0; + do + { + byte = *p++; + // Shifting the byte to the left and propagating the new byte to it (if there's any) + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + // if the 8th bit is 1, this means that there still another byte to be concatinated to the current byte (if zero, then decoding is done) + while (byte & 0x80); + *val = result; + return p; +} + +// This function recieves a pointer to a ttype entry and return the corrisponding type_info +// It's an implementation of three different functions from unwind-pe.h specific to our case and cannot be generalized for different encoding and size +const std::type_info * +get_ttype_entry (const uint8_t* entry) +{ + // Get a pointer to the value of the address inside entry + const int32_t *u = (const int32_t *) entry; + unsigned long result; + + // The final address will be the value stored plus the address of the value (pc relative addressing) + result = *u + (unsigned long)u; + result = *(unsigned long *)result; + + // Type cast it into a valid type_info + const std::type_info *tinfo = reinterpret_cast(result); + return tinfo; +} struct LSDA_Header { /** @@ -115,46 +155,44 @@ struct LSDA_Header { * as many bytes as read */ LSDA_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - - // Copy the LSDA fields + const unsigned char *read_ptr = (const unsigned char *)*lsda; start_encoding = read_ptr[0]; type_encoding = read_ptr[1]; - type_table_offset = read_ptr[2]; - - // Advance the lsda pointer - *lsda = read_ptr + sizeof(LSDA_Header); + read_ptr += 2; + read_ptr = read_uleb128(read_ptr, &type_table_offset); + *lsda = (LSDA_ptr)read_ptr; } uint8_t start_encoding; uint8_t type_encoding; // This is the offset, from the end of the header, to the types table - uint8_t type_table_offset; + LSDA_line type_table_offset; }; struct Call_Site_Header { // Same as other LSDA constructors Call_Site_Header(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; + const unsigned char *read_ptr = (const unsigned char *)*lsda; encoding = read_ptr[0]; - length = read_ptr[1]; - *lsda = read_ptr + sizeof(Call_Site_Header); + read_ptr += 1; + read_ptr = read_uleb128(read_ptr, &length); + *lsda = (LSDA_ptr)read_ptr; } uint8_t encoding; - uint8_t length; + LSDA_line length; }; struct Call_Site { // Same as other LSDA constructors Call_Site(LSDA_ptr *lsda) { - LSDA_ptr read_ptr = *lsda; - start = read_ptr[0]; - len = read_ptr[1]; - lp = read_ptr[2]; - action = read_ptr[3]; - *lsda = read_ptr + sizeof(Call_Site); + const unsigned char *read_ptr = (const unsigned char *)*lsda; + read_ptr = read_uleb128(read_ptr, &start); + read_ptr = read_uleb128(read_ptr, &len); + read_ptr = read_uleb128(read_ptr, &lp); + read_ptr = read_uleb128(read_ptr, &action); + *lsda = (LSDA_ptr)read_ptr; } Call_Site() { } @@ -164,14 +202,14 @@ struct Call_Site { // is relative to start // Offset into function from which we could handle a throw - uint8_t start; + LSDA_line start; // Length of the block that might throw - uint8_t len; + LSDA_line len; // Landing pad - uint8_t lp; + LSDA_line lp; // Offset into action table + 1 (0 means no action) // Used to run destructors - uint8_t action; + LSDA_line action; bool has_landing_pad() const { return lp; } @@ -231,7 +269,7 @@ struct LSDA // Get the start of the types table (it's actually the end of the // table, but since the action index will hold a negative index // for this table we can say it's the beginning - types_table_start( (const void**)(raw_lsda + header.type_table_offset) ), + types_table_start( (const void**)((uint8_t*)raw_lsda + header.type_table_offset) ), // Read the LSDA CS header cs_header(&raw_lsda), @@ -240,7 +278,7 @@ struct LSDA cs_table_start(raw_lsda), // Calculate where the end of the LSDA CS table is - cs_table_end(raw_lsda + cs_header.length), + cs_table_end((const LSDA_ptr)((uint8_t*)(raw_lsda) + cs_header.length)), // Get the start of action tables action_tbl_start( cs_table_end ) @@ -352,8 +390,9 @@ struct LSDA { // The index starts at the end of the types table int idx = -1 * action->type_index; - const void* catch_type_info = this->types_table_start[idx]; - return (const std::type_info *) catch_type_info; + const uint8_t* catch_type_info = ((const uint8_t*)this->types_table_start) + (idx * 4); + //return 0; + return get_ttype_entry(catch_type_info);; } }; @@ -457,7 +496,7 @@ _Unwind_Reason_Code __gxx_personality_v0 ( // Get the types this action can handle const std::type_info *catch_type = lsda.get_type_for(action); - if (can_handle(catch_type, thrown_exception_type)) + if (can_handle(thrown_exception_type, catch_type)) // order reversed in original { // If we are on search phase, tell _Unwind_ we can handle this one if (actions & _UA_SEARCH_PHASE) return _URC_HANDLER_FOUND; diff --git a/debugging.md b/debugging.md new file mode 100644 index 0000000..a42e0d3 --- /dev/null +++ b/debugging.md @@ -0,0 +1,46 @@ +### ULEB128 encoding +As mentioned in the blog (prior knowledge of the source code from the blog until v08 is required), the personality function iterates through the LSDA call site table (LSDACS) entries in search for a proper handler. the entries are encoded in ULEB128 formate (for god knows why) and one of the assumptions that sadly wasn't true is that the values will be small enough so that their encoded value will be the same as the original (check [ULEB128 encoding](https://en.wikipedia.org/wiki/LEB128) for more info about the encoding process). The values stored represent relative addresses for possible handlers and while the assumption holds true for this case on a 32 bit machine, the longer machine code in a 64 bit resulted in a higher value for the relative addresses ultimately exceeding 127 (which is the maximum value that has the same encoding as its original) and as result the value read directly from the call site table wasn't the ones we needed and we had to proberly decode them. To solve this issue, a simple decoding function 'read_uleb128' was implemented and called each time a uleb128 entry was accessed. The result is, we can now access all the entries (with the correct values) in the lsda table, but it's never too easy. We still had the segmentation fault error, and the reason this time was another architicture dependant issue. +### Void* size +After finding the correct handler from the call site table, the next step is accessing its related entry in the action table (and we can do this without a problem). The problem happens when we try jumping to the needed entry in the type table (basic understanding of the exception handling flow is required). Entries in type table are of type long and hold addresses to the needed data types (of type 'type_info') to check the thrown exception type. '.long' data type in x86 assembly (mostly anywhere actually) have a size of 4 bytes. The original source code iterated the table with the help of a simple void pointer and some pointer arthematics. ++1-ing a void pointer simply adds its size ('sizeof(void*)' which is 4 byte for 32 bit architicture) to the address contained in the pointer and this is how we access subsequent entries in the table, so far so good. Now when we go to a 64 bit machine, the size of the void* increases to 8 bytes but the entries are still spaced at 4 byte (because the .long size doesn't change with the architicture) and what happens is a troublsome out of bounds case. by modifying the mechanism of iteration (modifying the pointer size) we were able to access the correct address value. Now you would think that by jumping to this address we can have our required 'type_info', little did we know it wasn't that simple. +### Table type entries encoding +In one of the earlier version when we first started reading the lsda, we came across a '.byte' entry that we ignored assuming that it holds unnecessary information about the encoding of the type table. Well, this seamingly innocent single byte value should be masked with 3 different values to get the appropriate size, encoding, and relative address base. Now the size and encoding were not a problem (well we already solved the size issue and the size directives made it clear that this is a 4 byte value). The relative address base on the other hand was wrongfully ignored. It was assumed in the blog that the adress was an absolute address to a location in the assembly code (it was actually if you try it in the same environment). It turns out it's a pc-relative address (relative to the location of the current entry to be exact) after tracing the eh-personality of the libsupc++ library on an 64 bit machine. In order to get the correct address, just add the value found in the type table to the address of the value in the table (this was implemented in 'get_ttype_entry'). And there you have it, v08 now finally works on an x86_64 machine. We were hoping that propagating the changes to v12 would solve everything, but '__cxa_throw' function had another say in the matter. +### __cxa_throw 'thrown_exception' parameter +If you jump all the way up to cxa_throw you will notice that there is a weird -1 (in the old version at least). This -1 moves the '\*header' up by the size of '__cxa_exception'. The only logical reason you would need to do this is if the pointer '\*thrown_exception' that is passed to the function was pointing to the end of the struct and not the begining, but who decides where the pointer is? Well, it's '__cxa_allocate' but in our version it's normally pointing to the begining of the buffer that would be casted later on to a '__cxa_exception' type. So, all that we need is to remove the -1 and all will be good, right? Well actually this indeed solved the problem this time, but (there is always a but) the allocate method in gcc/libsupc++ responsible for exception handling sends the pointer at the end for some reason, so it's a good idea to follow it just in case some unwind function expects the '\*thrown_exception' to point at the end. Get the -1 back and make allocate point to the end of the buffer. And there you have it, your minimal working exception handling ABI. +____ +### TTBase_encoding break down +The info stored in @TTBase_encoding can be obtained by applying different masks + +To get the size of the encoded value mask it with 0x07 +|Mask Result |Size | +|-------------|---------------| +|0x00 |sizeof(void*) | +|0x02 |2 bytes | +|0x03 |4 bytes | +|0x04 |8 bytes | + +To get the encoding and data type mask it with 0x0f +|Mask Result |Type | +|-------------|-------------------| +|0x00 |void* | +|0x01 |uleb128 | +|0x09 |sleb128 | +|0x02 |unsigned 2 bytes | +|0x03 |unsigned 4 bytes | +|0x04 |unsigned 8 bytes | +|0x0a |signed 2 bytes | +|0x0b |signed 4 bytes | +|0x0c |signed 8 bytes | + +There is a special treatment if the value of @TTBase_encoding is 0x50 (if it's of reference aligned) + +To get the base of the relative address mask it with 0x70 +|Mask Result |Reference | +|-------------|-------------------| +|0x00 |absolute ptr | +|0x10 |pc relative | +|0x50 |aligned* | +|0x20 |text relative | +|0x30 |data relative | +|0x40 |function relative | + +*aligned is still unknown and for know is deemed unnecessary