From f4c680ef57944270e5b934e54146c0c5592cb545 Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Mon, 1 Jul 2013 14:53:18 -0400 Subject: [PATCH] Fix GNU EH pointer reads; these should use the native platform pointer size, rather than the DWARF entry's 32/64 word size. --- .../dwarf_encoding_test.h | 38 ++++--- .../PLCrashAsyncDwarfEncodingTests/test.c | 96 +++++++++++++++--- .../PLCrashAsyncDwarfEncodingTests/test.ios | Bin 33232 -> 33232 bytes .../test.macosx | Bin 24996 -> 24996 bytes .../PLCrashAsyncDwarfEncodingTests/test.sim | Bin 8608 -> 8608 bytes Source/PLCrashAsyncDwarfCIE.c | 2 +- Source/PLCrashAsyncDwarfEncoding.c | 2 +- Source/PLCrashAsyncDwarfEncodingTests.m | 23 +++-- 8 files changed, 127 insertions(+), 34 deletions(-) diff --git a/Resources/Tests/PLCrashAsyncDwarfEncodingTests/dwarf_encoding_test.h b/Resources/Tests/PLCrashAsyncDwarfEncodingTests/dwarf_encoding_test.h index 851d929..7080b3a 100644 --- a/Resources/Tests/PLCrashAsyncDwarfEncodingTests/dwarf_encoding_test.h +++ b/Resources/Tests/PLCrashAsyncDwarfEncodingTests/dwarf_encoding_test.h @@ -2,7 +2,7 @@ /* Constants and structures used to generate the CFI test binaries. See also: Resources/Tests/PLCrashAsyncDwarfEncodingTests */ -struct __attribute__((packed)) pl_cie_data_64 { +struct __attribute__((packed)) pl_cie_data { uint8_t version; /* Must be set to 1 or 3 -- 1=eh_frame, 3=DWARF3, 4=DWARF4 */ uint8_t augmentation[7]; @@ -22,6 +22,13 @@ struct __attribute__((packed)) pl_fde_data_64 { uint8_t instructions[]; }; +struct __attribute__((packed)) pl_fde_data_32 { + uint32_t initial_location; + uint32_t address_range; + uint8_t instructions[]; +}; + + /* 32-bit and 64-bit length headers */ struct pl_cfi_header_32 { uint32_t length; @@ -35,16 +42,21 @@ struct pl_cfi_header_64 { } __attribute__((packed)); /* Mock entry */ -typedef struct pl_cfi_entry { - union { - struct pl_cfi_header_32 hdr_32; - struct pl_cfi_header_64 hdr_64; - }; - - union { - struct pl_cie_data_64 cie_64; - struct pl_fde_data_64 fde_64; - }; +typedef union pl_cfi_entry { + struct { + struct pl_cfi_header_64 hdr; + union { + struct pl_cie_data cie; + struct pl_fde_data_64 fde; + }; + } e64; + struct { + struct pl_cfi_header_32 hdr; + union { + struct pl_cie_data cie; + struct pl_fde_data_32 fde; + }; + } e32; } pl_cfi_entry; /* Initial length field size */ @@ -52,8 +64,8 @@ typedef struct pl_cfi_entry { #define PL_CFI_LEN_SIZE_32 (sizeof(uint32_t)) /* CFE lengths, minus the initial length field. */ -#define PL_CFI_SIZE_64 (sizeof(pl_cfi_entry) - sizeof(uint32_t) - sizeof(uint64_t)) -#define PL_CFI_SIZE_32 (sizeof(pl_cfi_entry) - sizeof(uint32_t)) +#define PL_CFI_SIZE_64 (sizeof(pl_cfi_entry) - PL_CFI_LEN_SIZE_64) +#define PL_CFI_SIZE_32 (sizeof(pl_cfi_entry) - PL_CFI_LEN_SIZE_32) /* PC values to be used when searching for FDE entries. */ #define PL_CFI_EH_FRAME_PC 0x60 diff --git a/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.c b/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.c index ed513e4..e3d69dc 100644 --- a/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.c +++ b/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.c @@ -4,15 +4,16 @@ // TODO pl_cfi_entry ef[] __attribute__((section("__PL_DWARF,__eh_frame"))) = { +#ifdef __LP64__ /* Common CIE entry */ { - .hdr_64 = { + .e64.hdr = { .flag64 = UINT32_MAX, .length = PL_CFI_SIZE_64, .cie_id = 0, }, - .cie_64 = { + .e64.cie = { .version = 1, // eh_frame .augmentation[0] = 'z', // Enable GNU EH augmentation handling .augmentation[1] = 'R', // Pointer encoding is included in the augmentation data. @@ -22,26 +23,61 @@ pl_cfi_entry ef[] __attribute__((section("__PL_DWARF,__eh_frame"))) = { .data_alignment_factor = 0, .return_address_register = 0, - .augmentation_data[0] = sizeof(ef[0].cie_64.augmentation_data), // augmentation data length; uleb128, must fit in 7 bits. + .augmentation_data[0] = sizeof(ef[0].e64.cie.augmentation_data), // augmentation data length; uleb128, must fit in 7 bits. .augmentation_data[1] = 0x04, // DW_EH_PE_udata8 FDE pointer size } }, /* A FDE entry */ { - .hdr_64 = { + .e64.hdr = { .flag64 = UINT32_MAX, .length = PL_CFI_SIZE_64, .cie_id = sizeof(ef[0]) + PL_CFI_LEN_SIZE_64, // Offset to the first CIE entry }, - .fde_64 = { + .e64.fde = { .initial_location = PL_CFI_EH_FRAME_PC, .address_range = PL_CFI_EH_FRAME_PC_RANGE } }, +#else + /* Common CIE entry */ + { + .e32.hdr = { + .length = PL_CFI_SIZE_32, + .cie_id = 0, + }, + + .e32.cie = { + .version = 1, // eh_frame + .augmentation[0] = 'z', // Enable GNU EH augmentation handling + .augmentation[1] = 'R', // Pointer encoding is included in the augmentation data. + .augmentation[2] = '\0', + + .code_alignment_factor = 0, + .data_alignment_factor = 0, + .return_address_register = 0, + + .augmentation_data[0] = sizeof(ef[0].e32.cie.augmentation_data), // augmentation data length; uleb128, must fit in 7 bits. + .augmentation_data[1] = 0x04, // DW_EH_PE_udata8 FDE pointer size + } + }, + + /* A FDE entry */ + { + .e32.hdr = { + .length = PL_CFI_SIZE_32, + .cie_id = sizeof(ef[0]) + PL_CFI_LEN_SIZE_32, // Offset to the first CIE entry + }, + .e32.fde = { + .initial_location = PL_CFI_EH_FRAME_PC, + .address_range = PL_CFI_EH_FRAME_PC_RANGE + } + }, +#endif /* Terminator */ - {.hdr_32 = { + {.e32.hdr = { .length = 0x0 }} @@ -51,15 +87,16 @@ pl_cfi_entry ef[] __attribute__((section("__PL_DWARF,__eh_frame"))) = { pl_cfi_entry df[] __attribute__((section("__PL_DWARF,__debug_frame"))) = { +#ifdef __LP64__ /* Common CIE entry */ { - .hdr_64 = { + .e64.hdr = { .flag64 = UINT32_MAX, .length = PL_CFI_SIZE_64, .cie_id = UINT64_MAX, }, - .cie_64 = { + .e64.cie = { .version = 1, // eh_frame .augmentation[0] = 'z', .augmentation[1] = 'R', @@ -69,26 +106,61 @@ pl_cfi_entry df[] __attribute__((section("__PL_DWARF,__debug_frame"))) = { .data_alignment_factor = 0, .return_address_register = 0, - .augmentation_data[0] = sizeof(ef[0].cie_64.augmentation_data), // uleb128, must fit in 7 bits. + .augmentation_data[0] = sizeof(ef[0].e64.cie.augmentation_data), // uleb128, must fit in 7 bits. .augmentation_data[1] = 0x04, // DW_EH_PE_udata8 FDE pointer size } }, /* A FDE entry */ { - .hdr_64 = { + .e64.hdr = { .flag64 = UINT32_MAX, .length = PL_CFI_SIZE_64, .cie_id = 0, // Offset to the first CIE entry }, - .fde_64 = { + .e64.fde = { .initial_location = PL_CFI_DEBUG_FRAME_PC, .address_range = PL_CFI_DEBUG_FRAME_PC_RANGE } }, +#else + /* Common CIE entry */ + { + .e32.hdr = { + .length = PL_CFI_SIZE_32, + .cie_id = UINT32_MAX, + }, + + .e32.cie = { + .version = 1, // eh_frame + .augmentation[0] = 'z', + .augmentation[1] = 'R', + .augmentation[2] = '\0', + + .code_alignment_factor = 0, + .data_alignment_factor = 0, + .return_address_register = 0, + + .augmentation_data[0] = sizeof(ef[0].e32.cie.augmentation_data), // uleb128, must fit in 7 bits. + .augmentation_data[1] = 0x04, // DW_EH_PE_udata8 FDE pointer size + } + }, + + /* A FDE entry */ + { + .e32.hdr = { + .length = PL_CFI_SIZE_32, + .cie_id = 0, // Offset to the first CIE entry + }, + .e32.fde = { + .initial_location = PL_CFI_DEBUG_FRAME_PC, + .address_range = PL_CFI_DEBUG_FRAME_PC_RANGE + } + }, +#endif /* Terminator */ - {.hdr_32 = { + {.e32.hdr = { .length = 0x0 }} }; diff --git a/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.ios b/Resources/Tests/PLCrashAsyncDwarfEncodingTests/test.ios index 64e89d5e09ef10f1098643af711bca48431e360e..c1bc20d983ab703afc5fa64d4f071e532c5ff9b4 100755 GIT binary patch delta 225 zcmcc6%ygldX~PpCfnAH7HNNdP**KXY{GrO!m47#X5#o_$RGiFfAR)?t1Qda6O(0H~ zY-eCN(LsO(Brv(&Komn2NRt6b)kX&+{z(ox%S?52Qd_YKKbA?j}FQejQ zUIhtJ1|*;eWNQL(!sK-djw~SFFiIjgb@a{jnIfZEsFYkXKkYs>@$&3OLlE@;4P>BQ( zJy}n{&<cie_version != 1 && info->cie_version != 3 && info->cie_version != 4) { - PLCF_DEBUG("CIE id is not one of 1 (eh_frame) or 3 (DWARF3) or 4 (DWARF4): %" PRIu8, info->cie_version); + PLCF_DEBUG("CIE version is not one of 1 (eh_frame) or 3 (DWARF3) or 4 (DWARF4): %" PRIu8, info->cie_version); return PLCRASH_EINVAL; } diff --git a/Source/PLCrashAsyncDwarfEncoding.c b/Source/PLCrashAsyncDwarfEncoding.c index c799ec5..820d834 100644 --- a/Source/PLCrashAsyncDwarfEncoding.c +++ b/Source/PLCrashAsyncDwarfEncoding.c @@ -182,7 +182,7 @@ plcrash_error_t plcrash_async_dwarf_frame_reader_find_fde (plcrash_async_dwarf_f } /* Decode the FDE */ - err = plcrash_async_dwarf_fde_info_init(fde_info, reader->mobj, byteorder, dwarf_word_size, cfi_entry, reader->debug_frame); + err = plcrash_async_dwarf_fde_info_init(fde_info, reader->mobj, byteorder, reader->address_size, cfi_entry, reader->debug_frame); if (err != PLCRASH_ESUCCESS) return err; diff --git a/Source/PLCrashAsyncDwarfEncodingTests.m b/Source/PLCrashAsyncDwarfEncodingTests.m index 5f0d19a..e0e2c82 100644 --- a/Source/PLCrashAsyncDwarfEncodingTests.m +++ b/Source/PLCrashAsyncDwarfEncodingTests.m @@ -125,10 +125,14 @@ err = plcrash_async_dwarf_frame_reader_find_fde(&_eh_reader, 0x0, PL_CFI_EH_FRAME_PC+PL_CFI_EH_FRAME_PC_RANGE-1, &fde_info); STAssertEquals(PLCRASH_ESUCCESS, err, @"FDE search failed"); - /* Should be the second entry in the table, plus the 12 byte length initial length field. */ - STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + 12, @"Incorrect offset"); - - STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length"); + /* Should be the second entry in the table, plus the initial length field. */ + if (_eh_reader.address_size == 8) { + STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_64, @"Incorrect offset"); + STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length"); + } else { + STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_32, @"Incorrect offset"); + STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_32, @"Incorrect length"); + } //STAssertEquals(fde_info.fde_instruction_offset, (pl_vm_address_t)0x0, @"Incorrect instruction offset (should be the first entry)"); plcrash_async_dwarf_fde_info_free(&fde_info); @@ -145,10 +149,15 @@ err = plcrash_async_dwarf_frame_reader_find_fde(&_debug_reader, 0x0, PL_CFI_DEBUG_FRAME_PC+PL_CFI_DEBUG_FRAME_PC_RANGE-1, &fde_info); STAssertEquals(PLCRASH_ESUCCESS, err, @"FDE search failed"); - /* Should be the second entry in the table, plus the 12 byte length initial length field. */ - STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + 12, @"Incorrect offset"); + /* Should be the second entry in the table, plus the initial length field. */ + if (_eh_reader.address_size == 8) { + STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_64, @"Incorrect offset"); + STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length"); + } else { + STAssertEquals(fde_info.fde_offset, (pl_vm_address_t) (sizeof(pl_cfi_entry)) + PL_CFI_LEN_SIZE_32, @"Incorrect offset"); + STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_32, @"Incorrect length"); + } - STAssertEquals(fde_info.fde_length, (uint64_t)PL_CFI_SIZE_64, @"Incorrect length"); //STAssertEquals(fde_info.fde_instruction_offset, (pl_vm_address_t)0x0, @"Incorrect instruction offset (should be the first entry)"); plcrash_async_dwarf_fde_info_free(&fde_info);