/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include "stdio.h" #include "string.h" #include "mach-o/loader.h" #include "objc/objc-runtime.h" #include "stuff/allocate.h" #include "stuff/bytesex.h" #include "stuff/symbol.h" #include "ofile_print.h" /* * Here we need structures that have the same memory layout and size as the * 32-bit Objective-C 1 meta data structures. * * The real structure definitions come from the header file objc/objc-runtime.h * and those it includes like objc/objc-class.h, etc. But since this program * must also run on 64-bit hosts that can't be used. */ struct objc_module_t { uint32_t version; uint32_t size; uint32_t name; /* char * (32-bit pointer) */ uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */ }; struct objc_symtab_t { uint32_t sel_ref_cnt; uint32_t refs; /* SEL * (32-bit pointer) */ uint16_t cls_def_cnt; uint16_t cat_def_cnt; uint32_t defs[1]; /* void * (32-bit pointer) variable size */ }; struct objc_class_t { uint32_t isa; /* struct objc_class * (32-bit pointer) */ uint32_t super_class; /* struct objc_class * (32-bit pointer) */ uint32_t name; /* const char * (32-bit pointer) */ int32_t version; int32_t info; int32_t instance_size; uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */ uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */ uint32_t cache; /* struct objc_cache * (32-bit pointer) */ uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */ }; struct objc_category_t { uint32_t category_name; /* char * (32-bit pointer) */ uint32_t class_name; /* char * (32-bit pointer) */ uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */ uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */ uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */ }; struct objc_ivar_t { uint32_t ivar_name; /* char * (32-bit pointer) */ uint32_t ivar_type; /* char * (32-bit pointer) */ int32_t ivar_offset; }; struct objc_ivar_list_t { int32_t ivar_count; struct objc_ivar_t ivar_list[1]; /* variable length structure */ }; struct objc_method_t { uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */ uint32_t method_types; /* char * (32-bit pointer) */ uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...) (32-bit pointer) */ }; struct objc_method_list_t { uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */ int32_t method_count; struct objc_method_t method_list[1]; /* variable length structure */ }; struct objc_protocol_t { uint32_t isa; /* struct objc_class * (32-bit pointer) */ uint32_t protocol_name; /* char * (32-bit pointer) */ uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */ uint32_t instance_methods; /* struct objc_method_description_list * (32-bit pointer) */ uint32_t class_methods; /* struct objc_method_description_list * (32-bit pointer) */ }; struct objc_protocol_list_t { uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */ int32_t count; uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t * ( (32-bit pointer) */ }; struct objc_method_description_t { uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */ uint32_t types; /* char * (32-bit pointer) */ }; struct objc_method_description_list_t { int32_t count; struct objc_method_description_t list[1]; }; /* * The header file "objc/NXString.h" has gone away and there is no real public * header file to get this definition from anymore. */ struct objc_string_object_t { uint32_t isa; /* struct objc_class * (32-bit pointer) */ uint32_t characters; /* char * (32-bit pointer) */ uint32_t _length; }; typedef struct objc_string_object_t NXConstantString; #define SIZEHASHTABLE 821 struct _hashEntry_t { uint32_t next; /* struct _hashEntry * (32-bit pointer) */ uint32_t sel; /* char * (32-bit pointer) */ }; struct imageInfo_t { uint32_t version; uint32_t flags; }; static void swap_imageInfo_t( struct imageInfo_t *o, enum byte_sex target_byte_sex) { o->version = SWAP_INT(o->version); o->flags = SWAP_INT(o->flags); } void swap_objc_module_t( struct objc_module_t *module, enum byte_sex target_byte_sex) { module->version = SWAP_INT(module->version); module->size = SWAP_INT(module->size); module->name = SWAP_INT(module->name); module->symtab = SWAP_INT(module->symtab); } void swap_objc_symtab_t( struct objc_symtab_t *symtab, enum byte_sex target_byte_sex) { symtab->sel_ref_cnt = SWAP_INT(symtab->sel_ref_cnt); symtab->refs = SWAP_INT(symtab->refs); symtab->cls_def_cnt = SWAP_SHORT(symtab->cls_def_cnt); symtab->cat_def_cnt = SWAP_SHORT(symtab->cat_def_cnt); } void swap_objc_class_t( struct objc_class_t *objc_class, enum byte_sex target_byte_sex) { objc_class->isa = SWAP_INT(objc_class->isa); objc_class->super_class = SWAP_INT(objc_class->super_class); objc_class->name = SWAP_INT(objc_class->name); objc_class->version = SWAP_INT(objc_class->version); objc_class->info = SWAP_INT(objc_class->info); objc_class->instance_size = SWAP_INT(objc_class->instance_size); objc_class->ivars = SWAP_INT(objc_class->ivars); objc_class->methodLists = SWAP_INT(objc_class->methodLists); objc_class->cache = SWAP_INT(objc_class->cache); objc_class->protocols = SWAP_INT(objc_class->protocols); } void swap_objc_category_t( struct objc_category_t *objc_category, enum byte_sex target_byte_sex) { objc_category->category_name = SWAP_INT(objc_category->category_name); objc_category->class_name = SWAP_INT(objc_category->class_name); objc_category->instance_methods = SWAP_INT(objc_category->instance_methods); objc_category->class_methods = SWAP_INT(objc_category->class_methods); objc_category->protocols = SWAP_INT(objc_category->protocols); } void swap_objc_ivar_list_t( struct objc_ivar_list_t *objc_ivar_list, enum byte_sex target_byte_sex) { objc_ivar_list->ivar_count = SWAP_INT(objc_ivar_list->ivar_count); } void swap_objc_ivar_t( struct objc_ivar_t *objc_ivar, enum byte_sex target_byte_sex) { objc_ivar->ivar_name = SWAP_INT(objc_ivar->ivar_name); objc_ivar->ivar_type = SWAP_INT(objc_ivar->ivar_type); objc_ivar->ivar_offset = SWAP_INT(objc_ivar->ivar_offset); } void swap_objc_method_list_t( struct objc_method_list_t *method_list, enum byte_sex target_byte_sex) { method_list->obsolete = SWAP_INT(method_list->obsolete); method_list->method_count = SWAP_INT(method_list->method_count); } void swap_objc_method_t( struct objc_method_t *method, enum byte_sex target_byte_sex) { method->method_name = SWAP_INT(method->method_name); method->method_types = SWAP_INT(method->method_types); method->method_imp = SWAP_INT(method->method_imp); } void swap_objc_protocol_list_t( struct objc_protocol_list_t *protocol_list, enum byte_sex target_byte_sex) { protocol_list->next = SWAP_INT(protocol_list->next); protocol_list->count = SWAP_INT(protocol_list->count); } void swap_objc_protocol_t( struct objc_protocol_t *protocol, enum byte_sex target_byte_sex) { protocol->isa = SWAP_INT(protocol->isa); protocol->protocol_name = SWAP_INT(protocol->protocol_name); protocol->protocol_list = SWAP_INT(protocol->protocol_list); protocol->instance_methods = SWAP_INT(protocol->instance_methods); protocol->class_methods = SWAP_INT(protocol->class_methods); } void swap_objc_method_description_list_t( struct objc_method_description_list_t *mdl, enum byte_sex target_byte_sex) { mdl->count = SWAP_INT(mdl->count); } void swap_objc_method_description_t( struct objc_method_description_t *md, enum byte_sex target_byte_sex) { md->name = SWAP_INT(md->name); md->types = SWAP_INT(md->types); } void swap_string_object_t( struct objc_string_object_t *string_object, enum byte_sex target_byte_sex) { string_object->isa = SWAP_INT(string_object->isa); string_object->characters = SWAP_INT(string_object->characters); string_object->_length = SWAP_INT(string_object->_length); } void swap_hashEntry_t( struct _hashEntry_t *_hashEntry, enum byte_sex target_byte_sex) { _hashEntry->next = SWAP_INT(_hashEntry->next); _hashEntry->sel = SWAP_INT(_hashEntry->sel); } struct section_info { char *contents; uint32_t addr; uint32_t size; }; static void get_objc_sections( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, struct section_info **objc_sections, uint32_t *nobjc_sections, char *sectname, char **sect, uint32_t *sect_addr, uint32_t *sect_size); static void get_cstring_section( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, struct section_info *cstring_section_ptr); static enum bool print_method_list( uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, struct symbol *sorted_symbols, uint32_t nsorted_symbols, enum bool verbose); static enum bool print_protocol_list( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose); static void print_protocol( uint32_t indent, struct objc_protocol_t *protocol, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose); static enum bool print_method_description_list( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose); static enum bool print_PHASH( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose); static void print_indent( uint32_t indent); static void *get_pointer( uint32_t addr, uint32_t *left, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr); static enum bool get_symtab( uint32_t addr, struct objc_symtab_t *symtab, uint32_t **defs, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_objc_class( uint32_t addr, struct objc_class_t *objc_class, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_objc_category( uint32_t addr, struct objc_category_t *objc_category, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_ivar_list( uint32_t addr, struct objc_ivar_list_t *objc_ivar_list, struct objc_ivar_t **ivar_list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_method_list( uint32_t addr, struct objc_method_list_t *method_list, struct objc_method_t **methods, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_protocol_list( uint32_t addr, struct objc_protocol_list_t *protocol_list, uint32_t **list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_protocol( uint32_t addr, struct objc_protocol_t *protocol, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_method_description_list( uint32_t addr, struct objc_method_description_list_t *mdl, struct objc_method_description_t **list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); static enum bool get_hashEntry( uint32_t addr, struct _hashEntry_t *_hashEntry, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped); /* * Print the objc segment. */ void print_objc_segment( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, struct symbol *sorted_symbols, uint32_t nsorted_symbols, enum bool verbose) { enum byte_sex host_byte_sex; enum bool swapped, trunc; uint32_t i, j, left, size, defs_left, def, ivar_list_left; char *p; struct section_info *objc_sections; uint32_t nobjc_sections; struct section_info cstring_section; struct objc_module_t *modules, *m, module; uint32_t modules_addr, modules_size; struct objc_symtab_t symtab; uint32_t *defs; struct objc_class_t objc_class; struct objc_ivar_list_t objc_ivar_list; struct objc_ivar_t *ivar_list, ivar; struct objc_category_t objc_category; struct imageInfo_t *imageInfo, info; uint32_t imageInfo_addr, imageInfo_size; printf("Objective-C segment\n"); get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &objc_sections, &nobjc_sections, SECT_OBJC_MODULES, (char **)&modules, &modules_addr, &modules_size); if(modules == NULL){ printf("can't print objective-C information no (" SEG_OBJC "," SECT_OBJC_MODULES ") section\n"); return; } if (verbose) get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &cstring_section); host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; memset(&module, '\0', sizeof(struct objc_module_t)); for(m = modules; (char *)m < (char *)modules + modules_size; m = (struct objc_module_t *)((char *)m + module.size) ){ memset(&module, '\0', sizeof(struct objc_module_t)); left = modules_size - (m - modules); size = left < sizeof(struct objc_module_t) ? left : sizeof(struct objc_module_t); memcpy(&module, m, size); if(swapped) swap_objc_module_t(&module, host_byte_sex); if((char *)m + module.size > (char *)m + modules_size) printf("module extends past end of " SECT_OBJC_MODULES " section\n"); printf("Module 0x%x\n", (unsigned int) (modules_addr + (char *)m - (char *)modules)); printf(" version %u\n", module.version); printf(" size %u\n", module.size); if(verbose){ p = get_pointer(module.name, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" name %.*s\n", (int)left, p); else printf(" name 0x%08x (not in an " SEG_OBJC " section)\n", (unsigned int)module.name); } else printf(" name 0x%08x\n", (unsigned int)(module.name)); if(get_symtab(module.symtab, &symtab, &defs, &defs_left, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE){ printf(" symtab 0x%08x (not in an " SEG_OBJC " section)\n", (unsigned int)module.symtab); continue; } printf(" symtab 0x%08x\n", (unsigned int)module.symtab); if(trunc == TRUE) printf("\tsymtab extends past end of an " SEG_OBJC " section\n"); printf("\tsel_ref_cnt %u\n", symtab.sel_ref_cnt); p = get_pointer(symtab.refs, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf("\trefs 0x%08x", symtab.refs); else printf("\trefs 0x%08x (not in an " SEG_OBJC " section)\n", symtab.refs); printf("\tcls_def_cnt %d\n", symtab.cls_def_cnt); printf("\tcat_def_cnt %d\n", symtab.cat_def_cnt); if(symtab.cls_def_cnt > 0) printf("\tClass Definitions\n"); for(i = 0; i < symtab.cls_def_cnt; i++){ if((i + 1) * sizeof(uint32_t) > defs_left){ printf("\t(remaining class defs entries entends past " "the end of the section)\n"); break; } memcpy(&def, defs + i, sizeof(uint32_t)); if(swapped) def = SWAP_INT(def); if(get_objc_class(def, &objc_class, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == TRUE){ printf("\tdefs[%u] 0x%08x", i, def); print_objc_class: if(trunc == TRUE) printf(" (entends past the end of the section)\n"); else printf("\n"); printf("\t\t isa 0x%08x", objc_class.isa); if(verbose && CLS_GETINFO(&objc_class, CLS_META)){ p = get_pointer(objc_class.isa, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t super_class 0x%08x",objc_class.super_class); if(verbose){ p = get_pointer(objc_class.super_class, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t name 0x%08x", objc_class.name); if(verbose){ p = get_pointer(objc_class.name, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t version 0x%08x\n", (unsigned int)objc_class.version); printf("\t\t info 0x%08x", (unsigned int)objc_class.info); if(verbose){ if(CLS_GETINFO(&objc_class, CLS_CLASS)) printf(" CLS_CLASS\n"); else if(CLS_GETINFO(&objc_class, CLS_META)) printf(" CLS_META\n"); else printf("\n"); } else printf("\n"); printf("\t instance_size 0x%08x\n", (unsigned int)objc_class.instance_size); if(get_ivar_list(objc_class.ivars, &objc_ivar_list, &ivar_list, &ivar_list_left, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == TRUE){ printf("\t\t ivars 0x%08x\n", (unsigned int)objc_class.ivars); if(trunc == TRUE) printf("\t\t objc_ivar_list extends past end " "of " SECT_OBJC_SYMBOLS " section\n"); printf("\t\t ivar_count %d\n", objc_ivar_list.ivar_count); for(j = 0; j < (uint32_t)objc_ivar_list.ivar_count; j++){ if((j + 1) * sizeof(struct objc_ivar_t) > ivar_list_left){ printf("\t\t remaining ivar's extend past " "the of the section\n"); break; } memcpy(&ivar, ivar_list + j, sizeof(struct objc_ivar_t)); if(swapped) swap_objc_ivar_t(&ivar, host_byte_sex); printf("\t\t\tivar_name 0x%08x", (unsigned int)ivar.ivar_name); if(verbose){ p = get_pointer(ivar.ivar_name, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t\tivar_type 0x%08x", (unsigned int)ivar.ivar_type); if(verbose){ p = get_pointer(ivar.ivar_type, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t ivar_offset 0x%08x\n", (unsigned int)ivar.ivar_offset); } } else{ printf("\t\t ivars 0x%08x (not in an " SEG_OBJC " section)\n", (unsigned int)objc_class.ivars); } printf("\t\t methods 0x%08x", (unsigned int)objc_class.methodLists); if(print_method_list(objc_class.methodLists, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, sorted_symbols, nsorted_symbols, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); printf("\t\t cache 0x%08x\n", (unsigned int)objc_class.cache); printf("\t\tprotocols 0x%08x", (unsigned int)objc_class.protocols); if(print_protocol_list(16, objc_class.protocols, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); if(CLS_GETINFO((&objc_class), CLS_CLASS)){ printf("\tMeta Class"); if(get_objc_class((uint32_t)objc_class.isa, &objc_class, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == TRUE){ goto print_objc_class; } else printf(" (not in " SECT_OBJC_SYMBOLS " section)\n"); } } else printf("\tdefs[%u] 0x%08x (not in an " SEG_OBJC " section)\n", i, (unsigned int)def); } if(symtab.cat_def_cnt > 0) printf("\tCategory Definitions\n"); for(i = 0; i < symtab.cat_def_cnt; i++){ if((i + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left){ printf("\t(remaining category defs entries entends " "past the end of the section)\n"); break; } memcpy(&def, defs + i + symtab.cls_def_cnt, sizeof(uint32_t)); if(swapped) def = SWAP_INT(def); if(get_objc_category(def, &objc_category, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == TRUE){ printf("\tdefs[%u] 0x%08x", i + symtab.cls_def_cnt, (unsigned int)def); if(trunc == TRUE) printf(" (entends past the end of the section)\n"); else printf("\n"); printf("\t category name 0x%08x", objc_category.category_name); if(verbose){ p = get_pointer(objc_category.category_name, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t class name 0x%08x", objc_category.class_name); if(verbose){ p = get_pointer(objc_category.class_name, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t instance methods 0x%08x", objc_category.instance_methods); if(print_method_list(objc_category.instance_methods, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, sorted_symbols, nsorted_symbols, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); printf("\t class methods 0x%08x", objc_category.class_methods); if(print_method_list(objc_category.class_methods, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, sorted_symbols, nsorted_symbols, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\tdefs[%u] 0x%08x (not in an " SEG_OBJC " section)\n", i + symtab.cls_def_cnt, (unsigned int)def); } } printf("Contents of (%s,%s) section\n", SEG_OBJC, "__image_info"); get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &objc_sections, &nobjc_sections, "__image_info", (char **)&imageInfo, &imageInfo_addr, &imageInfo_size); memset(&info, '\0', sizeof(struct imageInfo_t)); if(imageInfo_size < sizeof(struct imageInfo_t)){ memcpy(&info, imageInfo, imageInfo_size); printf(" (imageInfo entends past the end of the section)\n"); } else memcpy(&info, imageInfo, sizeof(struct imageInfo_t)); if(swapped) swap_imageInfo_t(&info, host_byte_sex); printf(" version %u\n", info.version); printf(" flags 0x%x", info.flags); if(info.flags & 0x1) printf(" F&C"); if(info.flags & 0x2) printf(" GC"); if(info.flags & 0x4) printf(" GC-only"); else printf(" RR"); printf("\n"); } void print_objc_protocol_section( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, enum bool verbose) { enum byte_sex host_byte_sex; enum bool swapped; struct section_info *objc_sections, cstring_section; uint32_t nobjc_sections; struct objc_protocol_t *protocols, *p, protocol; uint32_t protocols_addr, protocols_size; uint32_t size, left; printf("Contents of (" SEG_OBJC ",__protocol) section\n"); get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &objc_sections, &nobjc_sections, "__protocol", (char **)&protocols, &protocols_addr, &protocols_size); if (verbose) get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &cstring_section); host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; for(p = protocols; (char *)p < (char *)protocols + protocols_size; p++){ memset(&protocol, '\0', sizeof(struct objc_protocol_t)); left = protocols_size - (p - protocols); size = left < sizeof(struct objc_protocol_t) ? left : sizeof(struct objc_protocol_t); memcpy(&protocol, p, size); if((char *)p + sizeof(struct objc_protocol_t) > (char *)p + protocols_size) printf("Protocol extends past end of __protocol section\n"); printf("Protocol 0x%x\n", (unsigned int) (protocols_addr + (char *)p - (char *)protocols)); print_protocol(0, &protocol, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, verbose); } } void print_objc_string_object_section( char *sectname, struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, enum bool verbose) { enum byte_sex host_byte_sex; enum bool swapped; struct section_info *objc_sections; uint32_t nobjc_sections; struct section_info cstring_section; struct objc_string_object_t *string_objects, *s, string_object; uint32_t string_objects_addr, string_objects_size; uint32_t size, left; char *p; printf("Contents of (" SEG_OBJC ",%s) section\n", sectname); get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &objc_sections, &nobjc_sections, sectname, (char **)&string_objects, &string_objects_addr, &string_objects_size); get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &cstring_section); host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; for(s = string_objects; (char *)s < (char *)string_objects + string_objects_size; s++){ memset(&string_object, '\0', sizeof(struct objc_string_object_t)); left = string_objects_size - (s - string_objects); size = left < sizeof(struct objc_string_object_t) ? left : sizeof(struct objc_string_object_t); memcpy(&string_object, s, size); if((char *)s + sizeof(struct objc_string_object_t) > (char *)s + string_objects_size) printf("String Object extends past end of %s section\n", sectname); printf("String Object 0x%x\n", (unsigned int) (string_objects_addr + (char *)s - (char *)string_objects)); if(swapped) swap_string_object_t(&string_object, host_byte_sex); printf(" isa 0x%x\n", string_object.isa); printf(" characters 0x%x", (unsigned int)string_object.characters); if(verbose){ p = get_pointer(string_object.characters, &left, &cstring_section, 1, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in the (" SEG_TEXT ",__cstring) section)\n"); } else printf("\n"); printf(" _length %u\n", string_object._length); } } /* * PHASH[SIZEHASHTABLE]; * HASH[?]; variable sized (computed from size of section). */ void print_objc_runtime_setup_section( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, enum bool verbose) { enum byte_sex host_byte_sex; enum bool swapped; struct section_info *objc_sections, cstring_section; uint32_t i, nobjc_sections, left; struct _hashEntry_t **PHASH, *HASH, _hashEntry; char *sect, *p; uint32_t sect_addr, sect_size, phash; printf("Contents of (" SEG_OBJC ",__runtime_setup) section\n"); get_objc_sections(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &objc_sections, &nobjc_sections, "__runtime_setup", §, §_addr, §_size); if (verbose) get_cstring_section(load_commands, ncmds, sizeofcmds, object_byte_sex, object_addr, object_size, &cstring_section); host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; PHASH = (struct _hashEntry_t **)sect; for(i = 0; i < SIZEHASHTABLE && (i + 1) * sizeof(uint32_t) < sect_size; i++){ memcpy(&phash, PHASH + i, sizeof(uint32_t)); if(swapped) phash = SWAP_INT(phash); if(phash == 0) continue; printf("PHASH[%3u] 0x%x", i, (unsigned int)phash); if(print_PHASH(4, phash, objc_sections, nobjc_sections, &cstring_section, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); } HASH = (struct _hashEntry_t *)(PHASH + SIZEHASHTABLE); for(i = 0; (char *)(HASH + i) < sect + sect_size; i++){ memcpy((char *)&_hashEntry, HASH + i, sizeof(struct _hashEntry_t)); if(swapped) swap_hashEntry_t(&_hashEntry, host_byte_sex); printf("HASH at 0x%08x\n", (unsigned int)(sect_addr + (char *)(HASH + i) - sect)); printf(" sel 0x%08x", (unsigned int)_hashEntry.sel); if(verbose){ p = get_pointer(_hashEntry.sel, &left, objc_sections, nobjc_sections, &cstring_section); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf(" next 0x%08x", (unsigned int)_hashEntry.next); if(_hashEntry.next == 0){ printf("\n"); } else{ if((uint32_t)_hashEntry.next < sect_addr || (uint32_t)_hashEntry.next >= sect_addr + sect_size) printf(" (not in the ("SEG_OBJC ",__runtime_setup " "section)\n"); else printf("\n"); } } } static void get_objc_sections( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, struct section_info **objc_sections, uint32_t *nobjc_sections, char *sectname, char **sect, uint32_t *sect_addr, uint32_t *sect_size) { enum byte_sex host_byte_sex; enum bool swapped; uint32_t i, j, left, size; struct load_command lcmd, *lc; char *p; struct segment_command sg; struct section s; host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; *objc_sections = NULL; *nobjc_sections = 0; *sect = NULL; *sect_addr = 0; *sect_size = 0; lc = load_commands; for(i = 0 ; i < ncmds; i++){ memcpy((char *)&lcmd, (char *)lc, sizeof(struct load_command)); if(swapped) swap_load_command(&lcmd, host_byte_sex); if(lcmd.cmdsize % sizeof(int32_t) != 0) printf("load command %u size not a multiple of " "sizeof(int32_t)\n", i); if((char *)lc + lcmd.cmdsize > (char *)load_commands + sizeofcmds) printf("load command %u extends past end of load " "commands\n", i); left = sizeofcmds - ((char *)lc - (char *)load_commands); switch(lcmd.cmd){ case LC_SEGMENT: memset((char *)&sg, '\0', sizeof(struct segment_command)); size = left < sizeof(struct segment_command) ? left : sizeof(struct segment_command); memcpy((char *)&sg, (char *)lc, size); if(swapped) swap_segment_command(&sg, host_byte_sex); p = (char *)lc + sizeof(struct segment_command); for(j = 0 ; j < sg.nsects ; j++){ if(p + sizeof(struct section) > (char *)load_commands + sizeofcmds){ printf("section structure command extends past " "end of load commands\n"); } left = sizeofcmds - (p - (char *)load_commands); memset((char *)&s, '\0', sizeof(struct section)); size = left < sizeof(struct section) ? left : sizeof(struct section); memcpy((char *)&s, p, size); if(swapped) swap_section(&s, 1, host_byte_sex); if(strcmp(s.segname, SEG_OBJC) == 0){ *objc_sections = reallocate(*objc_sections, sizeof(struct section_info) * (*nobjc_sections + 1)); (*objc_sections)[*nobjc_sections].addr = s.addr; (*objc_sections)[*nobjc_sections].contents = object_addr + s.offset; if(s.offset > object_size){ printf("section contents of: (%.16s,%.16s) is past " "end of file\n", s.segname, s.sectname); (*objc_sections)[*nobjc_sections].size = 0; } else if(s.offset + s.size > object_size){ printf("part of section contents of: (%.16s,%.16s) " "is past end of file\n", s.segname, s.sectname); (*objc_sections)[*nobjc_sections].size = object_size - s.offset; } else (*objc_sections)[*nobjc_sections].size = s.size; if(strncmp(s.sectname, sectname, 16) == 0){ if(*sect != NULL) printf("more than one (" SEG_OBJC ",%s) " "section\n", sectname); else{ *sect = (object_addr + s.offset); *sect_size = s.size; *sect_addr = s.addr; } } (*nobjc_sections)++; } if(p + sizeof(struct section) > (char *)load_commands + sizeofcmds) break; p += size; } break; } if(lcmd.cmdsize == 0){ printf("load command %u size zero (can't advance to other " "load commands)\n", i); break; } lc = (struct load_command *)((char *)lc + lcmd.cmdsize); if((char *)lc > (char *)load_commands + sizeofcmds) break; } } static void get_cstring_section( struct load_command *load_commands, uint32_t ncmds, uint32_t sizeofcmds, enum byte_sex object_byte_sex, char *object_addr, uint32_t object_size, struct section_info *cstring_section) { enum byte_sex host_byte_sex; enum bool swapped; uint32_t i, j, left, size; struct load_command lcmd, *lc; char *p; struct segment_command sg; struct section s; host_byte_sex = get_host_byte_sex(); swapped = host_byte_sex != object_byte_sex; memset(cstring_section, '\0', sizeof(struct section_info)); lc = load_commands; for(i = 0 ; i < ncmds; i++){ memcpy((char *)&lcmd, (char *)lc, sizeof(struct load_command)); if(swapped) swap_load_command(&lcmd, host_byte_sex); if(lcmd.cmdsize % sizeof(int32_t) != 0) printf("load command %u size not a multiple of " "sizeof(int32_t)\n", i); if((char *)lc + lcmd.cmdsize > (char *)load_commands + sizeofcmds) printf("load command %u extends past end of load " "commands\n", i); left = sizeofcmds - ((char *)lc - (char *)load_commands); switch(lcmd.cmd){ case LC_SEGMENT: memset((char *)&sg, '\0', sizeof(struct segment_command)); size = left < sizeof(struct segment_command) ? left : sizeof(struct segment_command); memcpy((char *)&sg, (char *)lc, size); if(swapped) swap_segment_command(&sg, host_byte_sex); p = (char *)lc + sizeof(struct segment_command); for(j = 0 ; j < sg.nsects ; j++){ if(p + sizeof(struct section) > (char *)load_commands + sizeofcmds){ printf("section structure command extends past " "end of load commands\n"); } left = sizeofcmds - (p - (char *)load_commands); memset((char *)&s, '\0', sizeof(struct section)); size = left < sizeof(struct section) ? left : sizeof(struct section); memcpy((char *)&s, p, size); if(swapped) swap_section(&s, 1, host_byte_sex); if(strcmp(s.segname, SEG_TEXT) == 0 && strcmp(s.sectname, "__cstring") == 0){ cstring_section->addr = s.addr; cstring_section->contents = object_addr + s.offset; if(s.offset > object_size){ printf("section contents of: (%.16s,%.16s) is past " "end of file\n", s.segname, s.sectname); cstring_section->size = 0; } else if(s.offset + s.size > object_size){ printf("part of section contents of: (%.16s,%.16s) " "is past end of file\n", s.segname, s.sectname); cstring_section->size = object_size - s.offset; } else cstring_section->size = s.size; return; } if(p + sizeof(struct section) > (char *)load_commands + sizeofcmds) break; p += size; } break; } if(lcmd.cmdsize == 0){ printf("load command %u size zero (can't advance to other " "load commands)\n", i); break; } lc = (struct load_command *)((char *)lc + lcmd.cmdsize); if((char *)lc > (char *)load_commands + sizeofcmds) break; } } static enum bool print_method_list( uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, struct symbol *sorted_symbols, uint32_t nsorted_symbols, enum bool verbose) { struct objc_method_t *methods, method; struct objc_method_list_t method_list; enum bool trunc; uint32_t i, methods_left, left; char *p; if(get_method_list(addr, &method_list, &methods, &methods_left, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE) return(FALSE); printf("\n"); if(trunc == TRUE) printf("\t\t objc_method_list extends past end of the section\n"); printf("\t\t obsolete 0x%08x\n", (unsigned int)method_list.obsolete); printf("\t\t method_count %d\n", method_list.method_count); for(i = 0; i < (uint32_t)method_list.method_count; i++){ if((i + 1) * sizeof(struct objc_method_t) > methods_left){ printf("\t\t remaining method's extend past the of the " "section\n"); break; } memcpy(&method, methods + i, sizeof(struct objc_method_t)); if(swapped) swap_objc_method_t(&method, host_byte_sex); printf("\t\t method_name 0x%08x", method.method_name); if(verbose){ p = get_pointer(method.method_name, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t method_types 0x%08x", method.method_types); if(verbose){ p = get_pointer(method.method_types, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); printf("\t\t method_imp 0x%08x ", method.method_imp); if(verbose) print_label(method.method_imp, FALSE, sorted_symbols, nsorted_symbols); printf("\n"); } return(TRUE); } static enum bool print_protocol_list( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose) { uint32_t *list; struct objc_protocol_t protocol; struct objc_protocol_list_t protocol_list; enum bool trunc; uint32_t l, i, list_left; if(get_protocol_list(addr, &protocol_list, &list, &list_left, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE) return(FALSE); printf("\n"); if(trunc == TRUE){ print_indent(indent); printf(" objc_protocol_list extends past end of the section\n"); } print_indent(indent); printf(" next 0x%08x\n", (unsigned int)protocol_list.next); print_indent(indent); printf(" count %u\n", protocol_list.count); for(i = 0; i < protocol_list.count; i++){ if((i + 1) * sizeof(uint32_t) > list_left){ print_indent(indent); printf(" remaining list entries extend past the of the " "section\n"); break; } memcpy(&l, list + i, sizeof(uint32_t)); if(swapped) l = SWAP_INT(l); print_indent(indent); printf(" list[%u] 0x%08x", i, l); if(get_protocol(l, &protocol, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE){ printf(" (not in an " SEG_OBJC " section)\n"); continue; } printf("\n"); if(trunc == TRUE){ print_indent(indent); printf(" Protocol extends past end of the " "section\n"); } print_protocol(indent, &protocol, objc_sections, nobjc_sections, cstring_section_ptr, host_byte_sex, swapped, verbose); } return(TRUE); } static void print_protocol( uint32_t indent, struct objc_protocol_t *protocol, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose) { uint32_t left; char *p; print_indent(indent); printf(" isa 0x%08x\n", (unsigned int)protocol->isa); print_indent(indent); printf(" protocol_name 0x%08x", (unsigned int)protocol->protocol_name); if(verbose){ p = get_pointer(protocol->protocol_name, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); print_indent(indent); printf(" protocol_list 0x%08x", (unsigned int)protocol->protocol_list); if(print_protocol_list(indent + 4, protocol->protocol_list, objc_sections, nobjc_sections, cstring_section_ptr, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); print_indent(indent); printf(" instance_methods 0x%08x", (unsigned int)protocol->instance_methods); if(print_method_description_list(indent, protocol->instance_methods, objc_sections, nobjc_sections, cstring_section_ptr, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); print_indent(indent); printf(" class_methods 0x%08x", (unsigned int)protocol->class_methods); if(print_method_description_list(indent, protocol->class_methods, objc_sections, nobjc_sections, cstring_section_ptr, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); } static enum bool print_method_description_list( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose) { struct objc_method_description_list_t mdl; struct objc_method_description_t *list, md; enum bool trunc; uint32_t i, list_left, left; char *p; if(get_method_description_list(addr, &mdl, &list, &list_left, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE) return(FALSE); printf("\n"); if(trunc == TRUE){ print_indent(indent); printf(" objc_method_description_list extends past end of the " "section\n"); } print_indent(indent); printf(" count %d\n", mdl.count); for(i = 0; i < (uint32_t)mdl.count; i++){ if((i + 1) * sizeof(struct objc_method_description_t) > list_left){ print_indent(indent); printf(" remaining list entries extend past the of the " "section\n"); break; } print_indent(indent); printf(" list[%u]\n", i); memcpy(&md, list + i, sizeof(struct objc_method_description_t)); if(swapped) swap_objc_method_description_t(&md, host_byte_sex); print_indent(indent); printf(" name 0x%08x", (unsigned int)md.name); if(verbose){ p = get_pointer(md.name, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); print_indent(indent); printf(" types 0x%08x", (unsigned int)md.types); if(verbose){ p = get_pointer(md.types, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); } return(TRUE); } static enum bool print_PHASH( uint32_t indent, uint32_t addr, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr, enum byte_sex host_byte_sex, enum bool swapped, enum bool verbose) { struct _hashEntry_t _hashEntry; enum bool trunc; uint32_t left; char *p; if(get_hashEntry(addr, &_hashEntry, &trunc, objc_sections, nobjc_sections, host_byte_sex, swapped) == FALSE) return(FALSE); printf("\n"); if(trunc == TRUE){ print_indent(indent); printf("_hashEntry extends past end of the section\n"); } print_indent(indent); printf(" sel 0x%08x", (unsigned int)_hashEntry.sel); if(verbose){ p = get_pointer(_hashEntry.sel, &left, objc_sections, nobjc_sections, cstring_section_ptr); if(p != NULL) printf(" %.*s\n", (int)left, p); else printf(" (not in an " SEG_OBJC " section)\n"); } else printf("\n"); print_indent(indent); printf("next 0x%08x", (unsigned int)_hashEntry.next); if(_hashEntry.next == 0){ printf("\n"); return(TRUE); } if(print_PHASH(indent+4, _hashEntry.next, objc_sections, nobjc_sections, cstring_section_ptr, host_byte_sex, swapped, verbose) == FALSE) printf(" (not in an " SEG_OBJC " section)\n"); return(TRUE); } static void print_indent( uint32_t indent) { uint32_t i; for(i = 0; i < indent; ){ if(indent - i >= 8){ printf("\t"); i += 8; } else{ printf("%.*s", (int)(indent - i), " "); return; } } } static void * get_pointer( uint32_t addr, uint32_t *left, struct section_info *objc_sections, uint32_t nobjc_sections, struct section_info *cstring_section_ptr) { void* returnValue = NULL; uint32_t i; if(addr >= cstring_section_ptr->addr && addr < cstring_section_ptr->addr + cstring_section_ptr->size){ *left = cstring_section_ptr->size - (addr - cstring_section_ptr->addr); returnValue = (cstring_section_ptr->contents + (addr - cstring_section_ptr->addr)); } for(i = 0; returnValue != NULL && i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); returnValue = (objc_sections[i].contents + (addr - objc_sections[i].addr)); } } return(returnValue); } static enum bool get_symtab( uint32_t addr, struct objc_symtab_t *symtab, uint32_t **defs, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t i; memset(symtab, '\0', sizeof(struct objc_symtab_t)); if(addr == 0) return(0); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); if(*left >= sizeof(struct objc_symtab_t) - sizeof(uint32_t)){ memcpy(symtab, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_symtab_t) - sizeof(uint32_t)); *left -= sizeof(struct objc_symtab_t) - sizeof(uint32_t); *defs = (uint32_t *)(objc_sections[i].contents + (addr - objc_sections[i].addr) + sizeof(struct objc_symtab_t) - sizeof(uint32_t)); *trunc = FALSE; } else{ memcpy(symtab, objc_sections[i].contents + (addr - objc_sections[i].addr), *left); *left = 0; *defs = NULL; *trunc = TRUE; } if(swapped) swap_objc_symtab_t(symtab, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_objc_class( uint32_t addr, struct objc_class_t *objc_class, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t left, i; memset(objc_class, '\0', sizeof(struct objc_class_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ left = objc_sections[i].size - (addr - objc_sections[i].addr); if(left >= sizeof(struct objc_class_t)){ memcpy(objc_class, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_class_t)); *trunc = FALSE; } else{ memcpy(objc_class, objc_sections[i].contents + (addr - objc_sections[i].addr), left); *trunc = TRUE; } if(swapped) swap_objc_class_t(objc_class, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_objc_category( uint32_t addr, struct objc_category_t *objc_category, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t left, i; memset(objc_category, '\0', sizeof(struct objc_category_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ left = objc_sections[i].size - (addr - objc_sections[i].addr); if(left >= sizeof(struct objc_category_t)){ memcpy(objc_category, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_category_t)); *trunc = FALSE; } else{ memcpy(objc_category, objc_sections[i].contents + (addr - objc_sections[i].addr), left); *trunc = TRUE; } if(swapped) swap_objc_category_t(objc_category, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_ivar_list( uint32_t addr, struct objc_ivar_list_t *objc_ivar_list, struct objc_ivar_t **ivar_list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t i; memset(objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); if(*left >= sizeof(struct objc_ivar_list_t) - sizeof(struct objc_ivar_t)){ memcpy(objc_ivar_list, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_ivar_list_t) - sizeof(struct objc_ivar_t)); *left -= sizeof(struct objc_ivar_list_t) - sizeof(struct objc_ivar_t); *ivar_list = (struct objc_ivar_t *) (objc_sections[i].contents + (addr - objc_sections[i].addr) + sizeof(struct objc_ivar_list_t) - sizeof(struct objc_ivar_t)); *trunc = FALSE; } else{ memcpy(objc_ivar_list, objc_sections[i].contents + (addr - objc_sections[i].addr), *left); *left = 0; *ivar_list = NULL; *trunc = TRUE; } if(swapped) swap_objc_ivar_list_t(objc_ivar_list, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_method_list( uint32_t addr, struct objc_method_list_t *method_list, struct objc_method_t **methods, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t i; memset(method_list, '\0', sizeof(struct objc_method_list_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); if(*left >= sizeof(struct objc_method_list_t) - sizeof(struct objc_method_t)){ memcpy(method_list, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_method_list_t) - sizeof(struct objc_method_t)); *left -= sizeof(struct objc_method_list_t) - sizeof(struct objc_method_t); *methods = (struct objc_method_t *) (objc_sections[i].contents + (addr - objc_sections[i].addr) + sizeof(struct objc_method_list_t) - sizeof(struct objc_method_t)); *trunc = FALSE; } else{ memcpy(method_list, objc_sections[i].contents + (addr - objc_sections[i].addr), *left); *left = 0; *methods = NULL; *trunc = TRUE; } if(swapped) swap_objc_method_list_t(method_list, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_protocol_list( uint32_t addr, struct objc_protocol_list_t *protocol_list, uint32_t **list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t i; memset(protocol_list, '\0', sizeof(struct objc_protocol_list_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); if(*left >= sizeof(struct objc_protocol_list_t) - sizeof(uint32_t)){ memcpy(protocol_list, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_protocol_list_t) - sizeof(uint32_t)); *left -= sizeof(struct objc_protocol_list_t) - sizeof(uint32_t); *list = (uint32_t *) (objc_sections[i].contents + (addr - objc_sections[i].addr) + sizeof(struct objc_protocol_list_t) - sizeof(uint32_t)); *trunc = FALSE; } else{ memcpy(protocol_list, objc_sections[i].contents + (addr - objc_sections[i].addr), *left); *left = 0; *list = NULL; *trunc = TRUE; } if(swapped) swap_objc_protocol_list_t(protocol_list, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_protocol( uint32_t addr, struct objc_protocol_t *protocol, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t left, i; memset(protocol, '\0', sizeof(struct objc_protocol_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ left = objc_sections[i].size - (addr - objc_sections[i].addr); if(left >= sizeof(struct objc_protocol_t)){ memcpy(protocol, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_protocol_t)); *trunc = FALSE; } else{ memcpy(protocol, objc_sections[i].contents + (addr - objc_sections[i].addr), left); *trunc = TRUE; } if(swapped) swap_objc_protocol_t(protocol, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_method_description_list( uint32_t addr, struct objc_method_description_list_t *mdl, struct objc_method_description_t **list, uint32_t *left, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t i; memset(mdl, '\0', sizeof(struct objc_method_description_list_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ *left = objc_sections[i].size - (addr - objc_sections[i].addr); if(*left >= sizeof(struct objc_method_description_list_t) - sizeof(struct objc_method_description_t)){ memcpy(mdl, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct objc_method_description_list_t) - sizeof(struct objc_method_description_t)); *left -= sizeof(struct objc_method_description_list_t) - sizeof(struct objc_method_description_t); *list = (struct objc_method_description_t *) (objc_sections[i].contents + (addr - objc_sections[i].addr) + sizeof(struct objc_method_description_list_t) - sizeof(struct objc_method_description_t)); *trunc = FALSE; } else{ memcpy(mdl, objc_sections[i].contents + (addr - objc_sections[i].addr), *left); *left = 0; *list = NULL; *trunc = TRUE; } if(swapped) swap_objc_method_description_list_t(mdl, host_byte_sex); return(TRUE); } } return(FALSE); } static enum bool get_hashEntry( uint32_t addr, struct _hashEntry_t *_hashEntry, enum bool *trunc, struct section_info *objc_sections, uint32_t nobjc_sections, enum byte_sex host_byte_sex, enum bool swapped) { uint32_t left, i; memset(_hashEntry, '\0', sizeof(struct _hashEntry_t)); if(addr == 0) return(FALSE); for(i = 0; i < nobjc_sections; i++){ if(addr >= objc_sections[i].addr && addr < objc_sections[i].addr + objc_sections[i].size){ left = objc_sections[i].size - (addr - objc_sections[i].addr); if(left >= sizeof(struct _hashEntry_t)){ memcpy(_hashEntry, objc_sections[i].contents + (addr - objc_sections[i].addr), sizeof(struct _hashEntry_t)); *trunc = FALSE; } else{ memcpy(_hashEntry, objc_sections[i].contents + (addr - objc_sections[i].addr), left); *trunc = TRUE; } if(swapped) swap_hashEntry_t(_hashEntry, host_byte_sex); return(TRUE); } } return(FALSE); }