Implement basic CFI iteration (with 32-bit and 64-bit length support).

This commit is contained in:
Landon Fuller 2013-05-23 14:38:15 -04:00
Родитель 03f3d68965
Коммит f7a81d11ac
8 изменённых файлов: 110 добавлений и 21 удалений

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

@ -1,10 +1,34 @@
#include <stdint.h>
/* Mock entry */
typedef union cfi_entry {
/* 32-bit and 64-bit size headers */
struct {
uint32_t size;
} hdr_32;
struct {
uint32_t flag64; /* Must be set to 0xffffffff */
uint64_t size;
} hdr_64;
} cfi_entry;
// TODO
uint32_t ef __attribute__((section("__PL_DWARF,__eh_frame"))) = {
0
cfi_entry ef[] __attribute__((section("__PL_DWARF,__eh_frame"))) = {
{.hdr_64 = {
.flag64 = 0xffffffff,
.size = 24,
}},
/* Terminator */
{.hdr_32 = {
.size = 0x0
}}
/* Additional entries after terminator -- used to test offset handling */
// TODO
};
uint32_t df __attribute__((section("__PL_DWARF,__debug_frame"))) = {
uint32_t df[] __attribute__((section("__PL_DWARF,__debug_frame"))) = {
0
};

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

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

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

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

@ -25,6 +25,7 @@
*/
#include "PLCrashAsyncDwarfEncoding.h"
#include <inttypes.h>
/**
* @internal
@ -43,27 +44,80 @@
* @param reader The reader instance to initialize.
* @param mobj The memory object containing frame data (eh_frame or debug_frame) at the start address. This instance must
* survive for the lifetime of the reader.
* @param cpu_type The target architecture of the CFE data, encoded as a Mach-O CPU type. Interpreting CFE data is
* architecture-specific, and Apple has not defined encodings for all supported architectures.
* @param byteoder The byte order of the data referenced by @a mobj.
*/
plcrash_error_t plcrash_async_dwarf_frame_reader_init (plcrash_async_dwarf_frame_reader_t *reader, plcrash_async_mobject_t *mobj, cpu_type_t cputype) {
// TODO
return PLCRASH_EUNKNOWN;
plcrash_error_t plcrash_async_dwarf_frame_reader_init (plcrash_async_dwarf_frame_reader_t *reader, plcrash_async_mobject_t *mobj, const plcrash_async_byteorder_t *byteorder) {
reader->mobj = mobj;
reader->byteorder = byteorder;
return PLCRASH_ESUCCESS;
}
/**
* Locate the frame descriptor entry for @a pc, if available.
*
* @param reader The initialized frame reader which will be searched for the entry.
* @param offset A section-relative offset at which the FDE search will be initiated. This is primarily useful in combination with the compact unwind
* encoding, in cases where the unwind instructions can not be expressed, and instead a FDE offset is provided by the encoding. Pass an offset of 0
* to begin searching at the beginning of the unwind data.
* @param pc The PC value to search for within the frame data. Note that this value must be relative to
* the target Mach-O image's __TEXT vmaddr.
*
* @return Returns PLFRAME_ESUCCCESS on success, or one of the remaining error codes if a DWARF parsing error occurs. If
* the entry can not be found, PLFRAME_ENOTFOUND will be returned.
*/
plcrash_error_t plcrash_async_dwarf_frame_reader_find_fde (plcrash_async_dwarf_frame_reader_t *reader, pl_vm_address_t pc) {
plcrash_error_t plcrash_async_dwarf_frame_reader_find_fde (plcrash_async_dwarf_frame_reader_t *reader, pl_vm_size_t offset, pl_vm_address_t pc) {
//const plcrash_async_byteorder_t *byteorder = reader->byteorder;
const pl_vm_address_t base_addr = plcrash_async_mobject_base_address(reader->mobj);
const pl_vm_address_t end_addr = base_addr + plcrash_async_mobject_length(reader->mobj);
/* Apply the FDE offset */
pl_vm_address_t cfi_entry = base_addr;
if (!plcrash_async_address_apply_offset(base_addr, offset, &cfi_entry)) {
PLCF_DEBUG("FDE offset hint overflows the mobject's base address");
return PLCRASH_EINVAL;
}
if (cfi_entry >= end_addr) {
PLCF_DEBUG("FDE base address + offset falls outside the mapped range");
return PLCRASH_EINVAL;
}
/* Iterate over table entries */
while (cfi_entry < end_addr) {
/* Fetch the entry length */
uint64_t length;
uint32_t *length32 = plcrash_async_mobject_remap_address(reader->mobj, cfi_entry, 0x0, sizeof(uint32_t));
if (length32 == NULL) {
PLCF_DEBUG("The current CFI entry 0x%" PRIx64 " header lies outside the mapped range", (uint64_t) cfi_entry);
return PLCRASH_EINVAL;
}
if (*length32 == 0xffffffff) {
uint64_t *length64 = plcrash_async_mobject_remap_address(reader->mobj, cfi_entry, 4, sizeof(uint64_t));
if (length64 == NULL) {
PLCF_DEBUG("The current CFI entry 0x%" PRIx64 " header lies outside the mapped range", (uint64_t) cfi_entry);
return PLCRASH_EINVAL;
}
length = *length64;
} else {
length = *length32;
}
/* Check for end marker */
if (length == 0x0)
return PLCRASH_ENOTFOUND;
/* Skip over entry */
if (!plcrash_async_address_apply_offset(cfi_entry, length, &cfi_entry)) {
PLCF_DEBUG("Entry length overflows the CFI address");
return PLCRASH_EINVAL;
}
}
// TODO
return PLCRASH_EUNKNOWN;
return PLCRASH_ESUCCESS;
}
/**

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

@ -43,10 +43,7 @@
typedef struct plcrash_async_dwarf_frame_reader {
/** A memory object containing the DWARF data at the starting address. */
plcrash_async_mobject_t *mobj;
/** The target CPU type. */
cpu_type_t cpu_type;
/** The byte order of the encoded data. */
const plcrash_async_byteorder_t *byteorder;
} plcrash_async_dwarf_frame_reader_t;
@ -59,9 +56,9 @@ typedef struct plcrash_async_dwarf_fde {
} plcrash_async_dwarf_fde_t;
plcrash_error_t plcrash_async_dwarf_frame_reader_init (plcrash_async_dwarf_frame_reader_t *reader, plcrash_async_mobject_t *mobj, cpu_type_t cputype);
plcrash_error_t plcrash_async_dwarf_frame_reader_init (plcrash_async_dwarf_frame_reader_t *reader, plcrash_async_mobject_t *mobj, const plcrash_async_byteorder_t *byteorder);
plcrash_error_t plcrash_async_dwarf_frame_reader_find_fde (plcrash_async_dwarf_frame_reader_t *reader, pl_vm_address_t pc);
plcrash_error_t plcrash_async_dwarf_frame_reader_find_fde (plcrash_async_dwarf_frame_reader_t *reader, pl_vm_size_t offset, pl_vm_address_t pc);
void plcrash_async_dwarf_frame_reader_free (plcrash_async_dwarf_frame_reader_t *reader);

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

@ -92,10 +92,10 @@
STAssertEquals(err, PLCRASH_ESUCCESS, @"Failed to map __debug_frame section");
/* Initialize eh/debug readers */
err = plcrash_async_dwarf_frame_reader_init(&_eh_reader, &_eh_frame, plcrash_async_macho_cpu_type(&_image));
err = plcrash_async_dwarf_frame_reader_init(&_eh_reader, &_eh_frame, plcrash_async_macho_byteorder(&_image));
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to initialize reader");
err = plcrash_async_dwarf_frame_reader_init(&_debug_reader, &_debug_frame, plcrash_async_macho_cpu_type(&_image));
err = plcrash_async_dwarf_frame_reader_init(&_debug_reader, &_debug_frame, plcrash_async_macho_byteorder(&_image));
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to initialize reader");
}
@ -112,7 +112,7 @@
- (void) testFindEHFrameDescriptorEntry {
plcrash_error_t err;
err = plcrash_async_dwarf_frame_reader_find_fde(&_eh_reader, 0x0 /* TODO */);
err = plcrash_async_dwarf_frame_reader_find_fde(&_eh_reader, 0x0, 0x0 /* TODO */);
STAssertEquals(PLCRASH_ESUCCESS, err, @"FDE search failed");
}
@ -161,11 +161,10 @@
}
/* Smoke test the FDE parser */
cpu_type_t cpu_type = plcrash_async_macho_cpu_type(&image);
// TODO
if (has_eh_frame) {
plcrash_async_dwarf_frame_reader_t reader;
plcrash_async_dwarf_frame_reader_init(&reader, &eh_frame, cpu_type);
plcrash_async_dwarf_frame_reader_init(&reader, &eh_frame, plcrash_async_macho_byteorder(&_image));
}
if (has_debug_frame) {

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

@ -76,7 +76,22 @@
/* Clean up */
plcrash_async_mobject_free(&mobj);
}
- (void) testLength {
size_t size = vm_page_size+1;
uint8_t template[size];
/* Map the memory */
plcrash_async_mobject_t mobj;
STAssertEquals(PLCRASH_ESUCCESS, plcrash_async_mobject_init(&mobj, mach_task_self(), (pl_vm_address_t)template, size, true), @"Failed to initialize mapping");
STAssertEquals((pl_vm_address_t)template, (pl_vm_address_t) (mobj.address + mobj.vm_slide), @"Incorrect slide value!");
/* Test length accessor; this must be the user-requested length, not the page length. */
STAssertEquals((pl_vm_size_t)size, plcrash_async_mobject_length(&mobj), @"Incorrect mapping length");
/* Clean up */
plcrash_async_mobject_free(&mobj);
}