Stub out parsing and binary search of the first level page mapping.

This commit is contained in:
Landon Fuller 2013-03-06 17:06:18 -05:00
Родитель e1bd7489c2
Коммит ce4bd8ff6d
7 изменённых файлов: 92 добавлений и 26 удалений

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

@ -1,16 +1,19 @@
#if defined(__x86_64__)
.globl _main
_main:
.cfi_startproc
// TODO
movl $5, %eax
ret
.cfi_endproc
#elif defined(__i386__)
.globl _main
_main:
.cfi_startproc
// TODO
movl $5, %eax
ret
.cfi_endproc
#elif defined(__arm__)
.align 4
.arm

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

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

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

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

@ -89,25 +89,84 @@ plcrash_error_t plcrash_async_cfe_reader_init (plcrash_async_cfe_reader_t *reade
* TODO
*
* @param reader The initialized CFE reader.
* @param ip The instruction pointer to search for within the CFE data.
* @param pc The PC value to search for within the CFE data.
*/
plcrash_error_t plcrash_async_cfe_reader_find_ip (plcrash_async_cfe_reader_t *reader, pl_vm_address_t ip) {
plcrash_error_t plcrash_async_cfe_reader_find_pc (plcrash_async_cfe_reader_t *reader, pl_vm_address_t pc) {
const plcrash_async_byteorder_t *byteorder = reader->byteorder;
/* Map the PC to its file offset */
/* Find the index */
struct unwind_info_section_header_index_entry *index_entry;
/* Find and map the index */
uint32_t index_off = byteorder->swap32(reader->header.indexSectionOffset);
uint32_t index_count = byteorder->swap32(reader->header.indexCount);
// TODO - binary search for the index entry
// TODO - unbounded index_count could trigger overflow
pl_vm_address_t base_addr = plcrash_async_mobject_base_address(reader->mobj);
index_entry = plcrash_async_mobject_remap_address(reader->mobj, base_addr, index_off, index_count * sizeof(*index_entry));
if (index_entry == NULL) {
PLCF_DEBUG("Could not map the full unwind info section index");
if (SIZE_MAX / sizeof(struct unwind_info_section_header_index_entry) < index_count) {
PLCF_DEBUG("CFE index count extends beyond the range of size_t");
return PLCRASH_EINVAL;
}
size_t index_len = index_count * sizeof(struct unwind_info_section_header_index_entry);
struct unwind_info_section_header_index_entry *entries = plcrash_async_mobject_remap_address(reader->mobj,
plcrash_async_mobject_base_address(reader->mobj),
index_off,
index_len);
if (entries == NULL) {
PLCF_DEBUG("The declared entries table lies outside the mapped CFE range");
return PLCRASH_EINVAL;
}
/* Binary search for the first-level entry */
struct unwind_info_section_header_index_entry *first_level_entry = NULL;
uint32_t min = 0;
uint32_t mid = 0;
uint32_t max = index_count - 1;
/* Search while entries[min:max] is not empty */
while (max >= min) {
/* Calculate midpoint */
mid = (min + max) / 2;
/* Determine which half of the array to search */
uint32_t mid_fun_offset = byteorder->swap32(entries[mid].functionOffset);
if (mid_fun_offset < pc) {
/* Check for inclusive equality */
if (mid == max || byteorder->swap32(entries[mid+1].functionOffset) > pc) {
first_level_entry = &entries[mid];
break;
}
/* Base our search on the upper array */
min = mid + 1;
} else if (mid_fun_offset > pc) {
/* Base our search on the lower array */
max = mid - 1;
} else if (mid_fun_offset == pc) {
/* Direct match found */
first_level_entry = &entries[mid];
}
}
/* The final entry will always match remaining PC values */
PLCF_ASSERT(first_level_entry != NULL);
uint32_t *second_level_kind = plcrash_async_mobject_remap_address(reader->mobj,
plcrash_async_mobject_base_address(reader->mobj),
byteorder->swap32(first_level_entry->secondLevelPagesSectionOffset),
sizeof(uint32_t));
switch (byteorder->swap32(*second_level_kind)) {
case UNWIND_SECOND_LEVEL_REGULAR:
PLCF_DEBUG("Regular!");
break;
case UNWIND_SECOND_LEVEL_COMPRESSED:
PLCF_DEBUG("Compressed!");
break;
default:
PLCF_DEBUG("Unsupported second-level CFE table kind: %" PRIx32, byteorder->swap32(*second_level_kind));
return PLCRASH_EINVAL;
}
return PLCRASH_ESUCCESS;
}

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

@ -57,7 +57,7 @@ typedef struct plcrash_async_cfe_reader {
plcrash_error_t plcrash_async_cfe_reader_init (plcrash_async_cfe_reader_t *reader, plcrash_async_mobject_t *mobj, cpu_type_t cputype);
plcrash_error_t plcrash_async_cfe_reader_find_ip (plcrash_async_cfe_reader_t *reader, pl_vm_address_t ip);
plcrash_error_t plcrash_async_cfe_reader_find_pc (plcrash_async_cfe_reader_t *reader, pl_vm_address_t pc);
void plcrash_async_cfe_reader_free (plcrash_async_cfe_reader_t *reader);

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

@ -34,6 +34,7 @@
#import <mach-o/fat.h>
#import <mach-o/arch.h>
#import <mach-o/dyld.h>
#if TARGET_OS_MAC && (!TARGET_OS_IPHONE)
#define TEST_BINARY @"test.macosx"
@ -97,20 +98,23 @@
* and then return the architecture's image @a size and @a offset from the head of @a mobj;
*/
- (void) findBinary: (plcrash_async_mobject_t *) mobj offset: (uint32_t *) offset size: (uint32_t *) size {
struct fat_header *fh = plcrash_async_mobject_remap_address(mobj, mobj->task_address, 0, sizeof(struct fat_header));
pl_vm_address_t header = plcrash_async_mobject_base_address(mobj);
struct fat_header *fh = plcrash_async_mobject_remap_address(mobj, header, 0, sizeof(struct fat_header));
STAssertNotNULL(fh, @"Could not load fat header");
if (fh->magic != FAT_MAGIC && fh->magic != FAT_CIGAM)
STFail(@"Not a fat binary!");
/* Load all the fat architectures */
pl_vm_address_t header = plcrash_async_mobject_base_address(mobj);
struct fat_arch *base = plcrash_async_mobject_remap_address(mobj, header, sizeof(*fh), sizeof(*fh));
struct fat_arch *base = plcrash_async_mobject_remap_address(mobj,
header,
sizeof(struct fat_header),
sizeof(struct fat_arch));
uint32_t count = OSSwapBigToHostInt32(fh->nfat_arch);
struct fat_arch *archs = calloc(count, sizeof(*archs));
struct fat_arch *archs = calloc(count, sizeof(struct fat_arch));
for (uint32_t i = 0; i < count; i++) {
struct fat_arch *fa = &base[i];
if (!plcrash_async_mobject_verify_local_pointer(mobj, fa, 0, sizeof(*fa))) {
if (!plcrash_async_mobject_verify_local_pointer(mobj, fa, 0, sizeof(struct fat_arch))) {
STFail(@"Pointer outside of mapped range");
}
@ -121,11 +125,11 @@
archs[i].align = OSSwapBigToHostInt32(fa->align);
}
/* Find the right architecture */
const NXArchInfo *local_arch = NXGetLocalArchInfo();
const struct fat_arch *best_arch = NXFindBestFatArch(local_arch->cputype, local_arch->cpusubtype, archs, count);
STAssertNotNULL(best_arch, @"Could not find a matching entry for the host architecture");
/* Find the right architecture; we based this on the first loaded Mach-O image, as NXGetLocalArchInfo returns
* the incorrect i386 cpu type on x86-64. */
const struct mach_header *hdr = _dyld_get_image_header(0);
const struct fat_arch *best_arch = NXFindBestFatArch(hdr->cputype, hdr->cpusubtype, archs, count);
/* Clean up */
free(archs);
@ -175,10 +179,10 @@
pl_vm_address_t mainPC;
err = plcrash_async_macho_find_symbol_by_name(&_image, "_main", &mainPC);
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to locate main symbol");
err = plcrash_async_cfe_reader_find_ip(&reader, mainPC);
#if 0
err = plcrash_async_cfe_reader_find_pc(&reader, mainPC);
STAssertEquals(PLCRASH_ESUCCESS, err, @"Failed to locate CFE entry for main");
#endif
plcrash_async_cfe_reader_free(&reader);
}