Add implementation and tests for PC-based filtering of FDE search results.

This commit is contained in:
Landon Fuller 2013-06-21 15:28:04 -04:00
Родитель 92319f58b0
Коммит 0ac7d4eee5
8 изменённых файлов: 50 добавлений и 15 удалений

Просмотреть файл

@ -16,6 +16,12 @@ struct __attribute__((packed)) pl_cie_data_64 {
uint8_t initial_instructions[0];
};
struct __attribute__((packed)) pl_fde_data_64 {
uint64_t initial_location;
uint64_t address_range;
uint8_t instructions[];
};
/* 32-bit and 64-bit length headers */
struct pl_cfi_header_32 {
uint32_t length;
@ -37,9 +43,17 @@ typedef struct pl_cfi_entry {
union {
struct pl_cie_data_64 cie_64;
struct pl_fde_data_64 fde_64;
};
} pl_cfi_entry;
/* CFE lengths, minus the initial length field. */
#define PL_CFI_LEN_64 (sizeof(pl_cfi_entry) - sizeof(uint32_t) - sizeof(uint64_t))
#define PL_CFI_LEN_32 (sizeof(pl_cfi_entry) - sizeof(uint32_t))
/* PC values to be used when searching for FDE entries. */
#define PL_CFI_EH_FRAME_PC 0x60
#define PL_CFI_EH_FRAME_PC_RANGE 0x10
#define PL_CFI_DEBUG_FRAME_PC 0x30
#define PL_CFI_DEBUG_FRAME_PC_RANGE 0x10

Просмотреть файл

@ -14,25 +14,31 @@ pl_cfi_entry ef[] __attribute__((section("__PL_DWARF,__eh_frame"))) = {
.cie_64 = {
.version = 1, // eh_frame
.augmentation[0] = 'z',
.augmentation[1] = 'R',
.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].cie_64.augmentation_data), // uleb128, must fit in 7 bits.
.augmentation_data[0] = sizeof(ef[0].cie_64.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 = {
{
.hdr_64 = {
.flag64 = UINT32_MAX,
.length = PL_CFI_LEN_64,
.cie_id = sizeof(ef[0]), // Offset to the first CIE entry
}},
},
.fde_64 = {
.initial_location = PL_CFI_EH_FRAME_PC,
.address_range = PL_CFI_EH_FRAME_PC_RANGE
}
},
/* Terminator */
{.hdr_32 = {
@ -69,11 +75,17 @@ pl_cfi_entry df[] __attribute__((section("__PL_DWARF,__debug_frame"))) = {
},
/* A FDE entry */
{.hdr_64 = {
{
.hdr_64 = {
.flag64 = UINT32_MAX,
.length = PL_CFI_LEN_64,
.cie_id = 0, // Offset to the first CIE entry
}},
},
.fde_64 = {
.initial_location = PL_CFI_DEBUG_FRAME_PC,
.address_range = PL_CFI_DEBUG_FRAME_PC_RANGE
}
},
/* Terminator */
{.hdr_32 = {

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -182,19 +182,20 @@ 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, reader->address_size, cfi_entry, reader->debug_frame);
err = plcrash_async_dwarf_fde_info_init(fde_info, reader->mobj, byteorder, dwarf_word_size, cfi_entry, reader->debug_frame);
if (err != PLCRASH_ESUCCESS)
return err;
// TODO
return PLCRASH_ESUCCESS;
/* Check if our PC is within range */
PLCF_DEBUG("Evaluating entry with start %"PRIx64 " end=%" PRIx64 " pc=%" PRIx64, fde_info->pc_start, fde_info->pc_end, pc);
if (pc >= fde_info->pc_start && pc < fde_info->pc_end)
return PLCRASH_ESUCCESS;
/* Skip to the next entry */
cfi_entry = next_cfi_entry;
}
// TODO
return PLCRASH_ESUCCESS;
return PLCRASH_ENOTFOUND;
}

Просмотреть файл

@ -122,7 +122,7 @@
plcrash_error_t err;
plcrash_async_dwarf_fde_info_t fde_info;
err = plcrash_async_dwarf_frame_reader_find_fde(&_eh_reader, 0x0, 0x0 /* TODO */, &fde_info);
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. */
@ -132,13 +132,17 @@
//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);
/* Verify that an unknown PC returns ENOTFOUND. */
err = plcrash_async_dwarf_frame_reader_find_fde(&_debug_reader, 0x0, PL_CFI_EH_FRAME_PC+PL_CFI_EH_FRAME_PC_RANGE, &fde_info);
STAssertEquals(PLCRASH_ENOTFOUND, err, @"FDE should not have been found");
}
- (void) testFindDebugFrameDescriptorEntry {
plcrash_error_t err;
plcrash_async_dwarf_fde_info_t fde_info;
err = plcrash_async_dwarf_frame_reader_find_fde(&_debug_reader, 0x0, 0x0 /* TODO */, &fde_info);
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. */
@ -148,6 +152,10 @@
//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);
/* Verify that an unknown PC freturns ENOTFOUND */
err = plcrash_async_dwarf_frame_reader_find_fde(&_debug_reader, 0x0, PL_CFI_DEBUG_FRAME_PC+PL_CFI_DEBUG_FRAME_PC_RANGE, &fde_info);
STAssertEquals(PLCRASH_ENOTFOUND, err, @"FDE should not have been found");
}
/**

Просмотреть файл

@ -55,7 +55,7 @@ typedef struct plcrash_async_dwarf_fde_info {
* the in-memory PC address of a loaded images. */
uint64_t pc_start;
/** The end of the IP range covered by this FDE (inclusive). The address is relative to the image's base address, <em>not</em>
/** The end of the IP range covered by this FDE (exclusive). The address is relative to the image's base address, <em>not</em>
* the in-memory PC address of a loaded images. */
uint64_t pc_end;