/*
 * setup_code_signature() does the work to add or update the needed
 * LC_CODE_SIGNATURE load command for the specified broken out ofile if it
 * is of one of the architecures specifed with a -a command line options.
 */
static
void
setup_code_signature(
    struct arch *arch,
    struct member *member,
    struct object *object)
{
    uint32_t i;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t flags, linkedit_end;
    uint32_t dyld_info_start;
    uint32_t dyld_info_end;
    uint32_t align_delta;

    linkedit_end = 0;
    /*
     * First set up all the pointers and sizes of the symbolic info.
     */
    if(object->st != NULL && object->st->nsyms != 0) {
        if(object->mh != NULL) {
            object->output_symbols = (struct nlist *)
                                     (object->object_addr + object->st->symoff);
            if(object->object_byte_sex != get_host_byte_sex())
                swap_nlist(object->output_symbols,
                           object->st->nsyms,
                           get_host_byte_sex());
            object->output_symbols64 = NULL;
        }
        else {
            object->output_symbols64 = (struct nlist_64 *)
                                       (object->object_addr + object->st->symoff);
            if(object->object_byte_sex != get_host_byte_sex())
                swap_nlist_64(object->output_symbols64,
                              object->st->nsyms,
                              get_host_byte_sex());
            object->output_symbols = NULL;
        }
        object->output_nsymbols = object->st->nsyms;
        object->output_strings =
            object->object_addr + object->st->stroff;
        object->output_strings_size = object->st->strsize;
        if(object->mh != NULL) {
            object->input_sym_info_size =
                object->st->nsyms * sizeof(struct nlist) +
                object->st->strsize;
        }
        else {
            object->input_sym_info_size =
                object->st->nsyms * sizeof(struct nlist_64) +
                object->st->strsize;
        }
    }
    if(object->dyld_info != NULL) {
        /* there are five parts to the dyld info, but
         codesign_allocate does not alter them, so copy as a block */
        dyld_info_start = 0;
        if (object->dyld_info->rebase_off != 0)
            dyld_info_start = object->dyld_info->rebase_off;
        else if (object->dyld_info->bind_off != 0)
            dyld_info_start = object->dyld_info->bind_off;
        else if (object->dyld_info->weak_bind_off != 0)
            dyld_info_start = object->dyld_info->weak_bind_off;
        else if (object->dyld_info->lazy_bind_off != 0)
            dyld_info_start = object->dyld_info->lazy_bind_off;
        else if (object->dyld_info->export_off != 0)
            dyld_info_start = object->dyld_info->export_off;
        dyld_info_end = 0;
        if (object->dyld_info->export_size != 0)
            dyld_info_end = object->dyld_info->export_off
                            + object->dyld_info->export_size;
        else if (object->dyld_info->lazy_bind_size != 0)
            dyld_info_end = object->dyld_info->lazy_bind_off
                            + object->dyld_info->lazy_bind_size;
        else if (object->dyld_info->weak_bind_size != 0)
            dyld_info_end = object->dyld_info->weak_bind_off
                            + object->dyld_info->weak_bind_size;
        else if (object->dyld_info->bind_size != 0)
            dyld_info_end = object->dyld_info->bind_off
                            + object->dyld_info->bind_size;
        else if (object->dyld_info->rebase_size != 0)
            dyld_info_end = object->dyld_info->rebase_off
                            + object->dyld_info->rebase_size;
        object->output_dyld_info = object->object_addr + dyld_info_start;
        object->output_dyld_info_size = dyld_info_end - dyld_info_start;
        object->output_sym_info_size += object->output_dyld_info_size;
    }
    if(object->dyst != NULL) {
        object->output_ilocalsym = object->dyst->ilocalsym;
        object->output_nlocalsym = object->dyst->nlocalsym;
        object->output_iextdefsym = object->dyst->iextdefsym;
        object->output_nextdefsym = object->dyst->nextdefsym;
        object->output_iundefsym = object->dyst->iundefsym;
        object->output_nundefsym = object->dyst->nundefsym;
        object->output_indirect_symtab = (uint32_t *)
                                         (object->object_addr + object->dyst->indirectsymoff);
        object->output_loc_relocs = (struct relocation_info *)
                                    (object->object_addr + object->dyst->locreloff);
        if(object->split_info_cmd != NULL) {
            object->output_split_info_data =
                (object->object_addr + object->split_info_cmd->dataoff);
            object->output_split_info_data_size =
                object->split_info_cmd->datasize;
        }
        if(object->func_starts_info_cmd != NULL) {
            object->output_func_start_info_data =
                (object->object_addr + object->func_starts_info_cmd->dataoff);
            object->output_func_start_info_data_size =
                object->func_starts_info_cmd->datasize;
        }
        if(object->data_in_code_cmd != NULL) {
            object->output_data_in_code_info_data =
                (object->object_addr + object->data_in_code_cmd->dataoff);
            object->output_data_in_code_info_data_size =
                object->data_in_code_cmd->datasize;
        }
        if(object->code_sign_drs_cmd != NULL) {
            object->output_code_sign_drs_info_data =
                (object->object_addr + object->code_sign_drs_cmd->dataoff);
            object->output_code_sign_drs_info_data_size =
                object->code_sign_drs_cmd->datasize;
        }
        if(object->link_opt_hint_cmd != NULL) {
            object->output_link_opt_hint_info_data =
                (object->object_addr + object->link_opt_hint_cmd->dataoff);
            object->output_link_opt_hint_info_data_size =
                object->link_opt_hint_cmd->datasize;
        }
        object->output_ext_relocs = (struct relocation_info *)
                                    (object->object_addr + object->dyst->extreloff);
        object->output_tocs =
            (struct dylib_table_of_contents *)
            (object->object_addr + object->dyst->tocoff);
        object->output_ntoc = object->dyst->ntoc;
        if(object->mh != NULL) {
            object->output_mods = (struct dylib_module *)
                                  (object->object_addr + object->dyst->modtaboff);
            object->output_mods64 = NULL;
        }
        else {
            object->output_mods64 = (struct dylib_module_64 *)
                                    (object->object_addr + object->dyst->modtaboff);
            object->output_mods = NULL;
        }
        object->output_nmodtab = object->dyst->nmodtab;
        object->output_refs = (struct dylib_reference *)
                              (object->object_addr + object->dyst->extrefsymoff);
        object->output_nextrefsyms = object->dyst->nextrefsyms;
        if(object->hints_cmd != NULL) {
            object->output_hints = (struct twolevel_hint *)
                                   (object->object_addr +
                                    object->hints_cmd->offset);
        }
        if(object->dyld_info != NULL) {
            object->input_sym_info_size += object->dyld_info->rebase_size
                                           + object->dyld_info->bind_size
                                           + object->dyld_info->weak_bind_size
                                           + object->dyld_info->lazy_bind_size
                                           + object->dyld_info->export_size;
        }
        object->input_sym_info_size +=
            object->dyst->nlocrel *
            sizeof(struct relocation_info) +
            object->dyst->nextrel *
            sizeof(struct relocation_info) +
            object->dyst->ntoc *
            sizeof(struct dylib_table_of_contents)+
            object->dyst->nextrefsyms *
            sizeof(struct dylib_reference);
        if(object->split_info_cmd != NULL)
            object->input_sym_info_size += object->split_info_cmd->datasize;
        if(object->func_starts_info_cmd != NULL)
            object->input_sym_info_size +=
                object->func_starts_info_cmd->datasize;
        if(object->data_in_code_cmd != NULL)
            object->input_sym_info_size +=
                object->data_in_code_cmd->datasize;
        if(object->code_sign_drs_cmd != NULL)
            object->input_sym_info_size +=
                object->code_sign_drs_cmd->datasize;
        if(object->link_opt_hint_cmd != NULL)
            object->input_sym_info_size +=
                object->link_opt_hint_cmd->datasize;
        if(object->mh != NULL) {
            object->input_sym_info_size +=
                object->dyst->nmodtab *
                sizeof(struct dylib_module) +
                object->dyst->nindirectsyms *
                sizeof(uint32_t);
        }
        else {
            object->input_sym_info_size +=
                object->dyst->nmodtab *
                sizeof(struct dylib_module_64) +
                object->dyst->nindirectsyms *
                sizeof(uint32_t) +
                object->input_indirectsym_pad;
        }
        if(object->hints_cmd != NULL) {
            object->input_sym_info_size +=
                object->hints_cmd->nhints *
                sizeof(struct twolevel_hint);
        }
    }
    object->output_sym_info_size = object->input_sym_info_size;
    if(object->code_sig_cmd != NULL) {
        object->input_sym_info_size = rnd(object->input_sym_info_size,
                                          16);
        object->input_sym_info_size += object->code_sig_cmd->datasize;
    }

    /*
     * Now see if one of the -a flags matches this object.
     */
    if(object->mh != NULL) {
        cputype = object->mh->cputype;
        cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK;
        flags = object->mh->flags;
    }
    else {
        cputype = object->mh64->cputype;
        cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK;
        flags = object->mh64->flags;
    }
    for(i = 0; i < narch_signs; i++) {
        if(arch_signs[i].arch_flag.cputype == cputype &&
                arch_signs[i].arch_flag.cpusubtype == cpusubtype)
            break;
    }
    /*
     * If we didn't find a matching -a flag then just use the existing
     * code signature if any.
     */
    if(i >= narch_signs) {
        if(object->code_sig_cmd != NULL) {
            object->output_code_sig_data_size =
                object->code_sig_cmd->datasize;
        }
        object->output_sym_info_size = object->input_sym_info_size;
        return;
    }

    /*
     * We did find a matching -a flag for this object
     */
    arch_signs[i].found = TRUE;

    /*
     * We now allow statically linked objects as well as objects that are
     * input for the dynamic linker or an MH_OBJECT filetypes to have
     * code signatures.  So no checks are done here anymore based on the
     * flags or filetype in the mach_header.
     */

    /*
     * If this has a code signature load command reuse it and just change
     * the size of that data.  But do not use the old data.
     */
    if(object->code_sig_cmd != NULL) {
        if(object->seg_linkedit != NULL) {
            object->seg_linkedit->filesize +=
                arch_signs[i].datasize - object->code_sig_cmd->datasize;
            if(object->seg_linkedit->filesize >
                    object->seg_linkedit->vmsize)
                object->seg_linkedit->vmsize =
                    rnd(object->seg_linkedit->filesize,
                        get_segalign_from_flag(&arch_signs[i].arch_flag));
        }
        else if(object->seg_linkedit64 != NULL) {
            object->seg_linkedit64->filesize +=
                arch_signs[i].datasize;
            object->seg_linkedit64->filesize -=
                object->code_sig_cmd->datasize;
            if(object->seg_linkedit64->filesize >
                    object->seg_linkedit64->vmsize)
                object->seg_linkedit64->vmsize =
                    rnd(object->seg_linkedit64->filesize,
                        get_segalign_from_flag(&arch_signs[i].arch_flag));
        }

        object->code_sig_cmd->datasize = arch_signs[i].datasize;
        object->output_code_sig_data_size = arch_signs[i].datasize;
        object->output_code_sig_data = NULL;

        object->output_sym_info_size = rnd(object->output_sym_info_size,
                                           16);
        object->output_sym_info_size += object->code_sig_cmd->datasize;
    }
    /*
     * The object does not have a code signature load command we add one.
     * And if that does not fail we then set the new load command's size and
     * offset of the code signature data to allocate in the object.  We also
     * adjust the linkedit's segment size.
     */
    else {
        object->code_sig_cmd = add_code_sig_load_command(arch,
                               arch_signs[i].arch_flag.name);
        object->code_sig_cmd->datasize = arch_signs[i].datasize;
        if(object->seg_linkedit != NULL)
            linkedit_end = object->seg_linkedit->fileoff +
                           object->seg_linkedit->filesize;
        else if(object->seg_linkedit64 != NULL)
            linkedit_end = object->seg_linkedit64->fileoff +
                           object->seg_linkedit64->filesize;
        else if(object->mh_filetype == MH_OBJECT)
            linkedit_end = object->object_size;
        else
            fatal("can't allocate code signature data for: %s (for "
                  "architecture %s) because file does not have a "
                  SEG_LINKEDIT " segment", arch->file_name,
                  arch_signs[i].arch_flag.name);

        object->code_sig_cmd->dataoff = rnd(linkedit_end, 16);
        object->output_code_sig_data_size = arch_signs[i].datasize;
        object->output_code_sig_data = NULL;
        align_delta = object->code_sig_cmd->dataoff - linkedit_end;

        if(object->output_sym_info_size != 0)
            object->output_sym_info_size = rnd(object->output_sym_info_size,
                                               16);
        else
            object->output_sym_info_size = align_delta;
        object->output_sym_info_size += object->code_sig_cmd->datasize;

        if(object->seg_linkedit != NULL) {
            object->seg_linkedit->filesize =
                rnd(object->seg_linkedit->filesize, 16) +
                object->code_sig_cmd->datasize;
            if(object->seg_linkedit->filesize >
                    object->seg_linkedit->vmsize)
                object->seg_linkedit->vmsize =
                    rnd(object->seg_linkedit->filesize,
                        get_segalign_from_flag(&arch_signs[i].arch_flag));
        }
        else if(object->seg_linkedit64 != NULL) {
            object->seg_linkedit64->filesize =
                rnd(object->seg_linkedit64->filesize, 16) +
                object->code_sig_cmd->datasize;
            if(object->seg_linkedit64->filesize >
                    object->seg_linkedit64->vmsize)
                object->seg_linkedit64->vmsize =
                    rnd(object->seg_linkedit64->filesize,
                        get_segalign_from_flag(&arch_signs[i].arch_flag));
        }
    }
}
Beispiel #2
0
static
void
setup_object_symbolic_info(
struct object *object)
{
    uint32_t output_indirectsym_pad_diff;

	if(object->st != NULL && object->st->nsyms != 0){
	    if(object->mh != NULL){
		object->output_symbols = (struct nlist *)
		    (object->object_addr + object->st->symoff);
		if(object->object_byte_sex != get_host_byte_sex())
		    swap_nlist(object->output_symbols,
			       object->st->nsyms,
			       get_host_byte_sex());
		object->output_symbols64 = NULL;
	    }
	    else{
		object->output_symbols64 = (struct nlist_64 *)
		    (object->object_addr + object->st->symoff);
		if(object->object_byte_sex != get_host_byte_sex())
		    swap_nlist_64(object->output_symbols64,
				  object->st->nsyms,
				  get_host_byte_sex());
		object->output_symbols = NULL;
	    }
	    object->output_nsymbols = object->st->nsyms;
	    object->output_strings =
		object->object_addr + object->st->stroff;
	    object->output_strings_size = object->st->strsize;
	    if(object->mh != NULL){
		object->input_sym_info_size =
		    object->st->nsyms * sizeof(struct nlist) +
		    object->st->strsize;
	    }
	    else{
		object->input_sym_info_size =
		    object->st->nsyms * sizeof(struct nlist_64) +
		    object->st->strsize;
	    }
	}
	output_indirectsym_pad_diff = 0;
	if(object->dyst != NULL){
	    object->output_ilocalsym = object->dyst->ilocalsym;
	    object->output_nlocalsym = object->dyst->nlocalsym;
	    object->output_iextdefsym = object->dyst->iextdefsym;
	    object->output_nextdefsym = object->dyst->nextdefsym;
	    object->output_iundefsym = object->dyst->iundefsym;
	    object->output_nundefsym = object->dyst->nundefsym;
	    object->output_indirect_symtab = (uint32_t *)
		(object->object_addr + object->dyst->indirectsymoff);
	    object->output_loc_relocs = (struct relocation_info *)
		(object->object_addr + object->dyst->locreloff);
	    if(object->split_info_cmd != NULL){
		object->output_split_info_data = 
		(object->object_addr + object->split_info_cmd->dataoff);
		object->output_split_info_data_size = 
		    object->split_info_cmd->datasize;
	    }
	    if(object->func_starts_info_cmd != NULL){
		object->output_func_start_info_data = 
		(object->object_addr + object->func_starts_info_cmd->dataoff);
		object->output_func_start_info_data_size = 
		    object->func_starts_info_cmd->datasize;
	    }
	    if(object->data_in_code_cmd != NULL){
		object->output_data_in_code_info_data = 
		(object->object_addr + object->data_in_code_cmd->dataoff);
		object->output_data_in_code_info_data_size = 
		    object->data_in_code_cmd->datasize;
	    }
	    if(object->code_sign_drs_cmd != NULL){
		object->output_code_sign_drs_info_data = 
		(object->object_addr + object->code_sign_drs_cmd->dataoff);
		object->output_code_sign_drs_info_data_size = 
		    object->code_sign_drs_cmd->datasize;
	    }
	    if(object->link_opt_hint_cmd != NULL){
		object->output_link_opt_hint_info_data = 
		(object->object_addr + object->link_opt_hint_cmd->dataoff);
		object->output_link_opt_hint_info_data_size = 
		    object->link_opt_hint_cmd->datasize;
	    }
	    object->output_ext_relocs = (struct relocation_info *)
		(object->object_addr + object->dyst->extreloff);
	    object->output_tocs =
		(struct dylib_table_of_contents *)
		(object->object_addr + object->dyst->tocoff);
	    object->output_ntoc = object->dyst->ntoc;
	    if(object->mh != NULL){
		object->output_mods = (struct dylib_module *)
		    (object->object_addr + object->dyst->modtaboff);
		object->output_mods64 = NULL;
	    }
	    else{
		object->output_mods64 = (struct dylib_module_64 *)
		    (object->object_addr + object->dyst->modtaboff);
		object->output_mods = NULL;
	    }
	    object->output_nmodtab = object->dyst->nmodtab;
	    object->output_refs = (struct dylib_reference *)
		(object->object_addr + object->dyst->extrefsymoff);
	    object->output_nextrefsyms = object->dyst->nextrefsyms;
	    if(object->hints_cmd != NULL){
		object->output_hints = (struct twolevel_hint *)
		    (object->object_addr +
		     object->hints_cmd->offset);
	    }
	    if(object->code_sig_cmd != NULL){
		object->output_code_sig_data = object->object_addr +
		    object->code_sig_cmd->dataoff;
		object->output_code_sig_data_size = 
		    object->code_sig_cmd->datasize;
	    }
	    object->input_sym_info_size +=
		object->dyst->nlocrel *
		    sizeof(struct relocation_info) +
		object->dyst->nextrel *
		    sizeof(struct relocation_info) +
		object->dyst->ntoc *
		    sizeof(struct dylib_table_of_contents)+
		object->dyst->nextrefsyms *
		    sizeof(struct dylib_reference);
	    if(object->split_info_cmd != NULL)
		object->input_sym_info_size += object->split_info_cmd->datasize;
	    if(object->func_starts_info_cmd != NULL)
		object->input_sym_info_size +=
		    object->func_starts_info_cmd->datasize;
	    if(object->data_in_code_cmd != NULL)
		object->input_sym_info_size +=
		    object->data_in_code_cmd->datasize;
	    if(object->code_sign_drs_cmd != NULL)
		object->input_sym_info_size +=
		    object->code_sign_drs_cmd->datasize;
	    if(object->link_opt_hint_cmd != NULL)
		object->input_sym_info_size +=
		    object->link_opt_hint_cmd->datasize;
	    if(object->mh != NULL){
		object->input_sym_info_size +=
		    object->dyst->nmodtab *
			sizeof(struct dylib_module) +
		    object->dyst->nindirectsyms *
			sizeof(uint32_t);
	    }
	    else{
		object->input_sym_info_size +=
		    object->dyst->nmodtab *
			sizeof(struct dylib_module_64)+
		    object->dyst->nindirectsyms *
			  sizeof(uint32_t) +
		    object->input_indirectsym_pad;
		    if(object->input_indirectsym_pad == 0 &&
		       (object->dyst->nindirectsyms % 2) != 0)
			output_indirectsym_pad_diff = 4;
	    }
	    if(object->hints_cmd != NULL){
		object->input_sym_info_size +=
		    object->hints_cmd->nhints *
		    sizeof(struct twolevel_hint);
	    }
	    if(object->code_sig_cmd != NULL){
		object->input_sym_info_size = rnd(object->input_sym_info_size,
						    16);
		object->input_sym_info_size += object->code_sig_cmd->datasize;
	    }
	    if(output_indirectsym_pad_diff != 0){
		if(object->output_ntoc != 0)
		    object->dyst->tocoff += output_indirectsym_pad_diff;
		if(object->output_nmodtab != 0)
		    object->dyst->modtaboff += output_indirectsym_pad_diff;
		if(object->output_nextrefsyms != 0)
		    object->dyst->extrefsymoff += output_indirectsym_pad_diff;
		if(object->output_strings_size != 0)
		    object->st->stroff += output_indirectsym_pad_diff;
		object->seg_linkedit64->filesize += output_indirectsym_pad_diff;
		if(object->seg_linkedit64->filesize >
		   object->seg_linkedit64->vmsize)
		    object->seg_linkedit64->vmsize +=
			output_indirectsym_pad_diff;
	    }
	}
	object->output_sym_info_size =
	    object->input_sym_info_size + output_indirectsym_pad_diff;
}
int main(int argc, char * argv[])
{
    ToolError	err;
    int			i, fd;
    const char *	output_name = NULL;
    uint32_t		zero = 0, num_files = 0;
    uint32_t		filenum;
    uint32_t		strx, strtabsize, strtabpad;
    struct symbol *	import_symbols;
    struct symbol *	export_symbols;
    uint32_t		num_import_syms, num_export_syms;
    uint32_t		result_count, num_removed_syms;
    uint32_t		import_idx, export_idx;
    const NXArchInfo *	host_arch;
    const NXArchInfo *	target_arch;
    boolean_t		require_imports = true;
    boolean_t		diff = false;


    struct file {
        vm_offset_t  mapped;
        vm_size_t    mapped_size;
	uint32_t     nsyms;
	boolean_t    import;
	const char * path;
    };
    struct file files[64];
    
    host_arch = NXGetLocalArchInfo();
    target_arch = host_arch;

    for( i = 1; i < argc; i += 2)
    {
	boolean_t import;

        if (!strcmp("-sect", argv[i]))
        {
	    require_imports = false;
	    i--;
	    continue;
        }
        if (!strcmp("-diff", argv[i]))
        {
	    require_imports = false;
	    diff = true;
	    i--;
	    continue;
        }

	if (i == (argc - 1))
	{
	    fprintf(stderr, "bad arguments: %s\n", argv[i]);
	    exit(1);
	}

        if (!strcmp("-arch", argv[i]))
        {
            target_arch = DL_NXGetArchInfoFromName(argv[i + 1]);
	    if (!target_arch)
	    {
		fprintf(stderr, "unknown architecture name: %s\n", argv[i+1]);
		exit(1);
	    }
            continue;
        }
        if (!strcmp("-output", argv[i]))
        {
	    output_name = argv[i+1];
            continue;
        }

        if (!strcmp("-import", argv[i]))
	    import = true;
	else if (!strcmp("-export", argv[i]))
	    import = false;
	else
	{
	    fprintf(stderr, "unknown option: %s\n", argv[i]);
	    exit(1);
	}

        err = readFile(argv[i+1], &files[num_files].mapped, &files[num_files].mapped_size);
        if (kErrorNone != err)
            exit(1);

        if (files[num_files].mapped && files[num_files].mapped_size)
	{
	    files[num_files].import = import;
	    files[num_files].path   = argv[i+1];
            num_files++;
	}
    }

    if (!output_name)
    {
	fprintf(stderr, "no output file\n");
	exit(1);
    }

    num_import_syms = 0;
    num_export_syms = 0;
    for (filenum = 0; filenum < num_files; filenum++)
    {
        files[filenum].nsyms = count_symbols((char *) files[filenum].mapped, files[filenum].mapped_size);
	if (files[filenum].import)
	    num_import_syms += files[filenum].nsyms;
	else
	    num_export_syms += files[filenum].nsyms;
    }
    if (!num_export_syms)
    {
	fprintf(stderr, "no export names\n");
	exit(1);
    }

    import_symbols = calloc(num_import_syms, sizeof(struct symbol));
    export_symbols = calloc(num_export_syms, sizeof(struct symbol));

    import_idx = 0;
    export_idx = 0;

    for (filenum = 0; filenum < num_files; filenum++)
    {
	if (files[filenum].import)
	{
	    store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
					import_symbols, import_idx, num_import_syms);
	    import_idx += files[filenum].nsyms;
	}
	else
	{
	    store_symbols((char *) files[filenum].mapped, files[filenum].mapped_size,
					export_symbols, export_idx, num_export_syms);
	    export_idx += files[filenum].nsyms;
	}
	if (false && !files[filenum].nsyms)
	{
	    fprintf(stderr, "warning: file %s contains no names\n", files[filenum].path);
	}
    }


    qsort(import_symbols, num_import_syms, sizeof(struct symbol), &qsort_cmp);
    qsort(export_symbols, num_export_syms, sizeof(struct symbol), &qsort_cmp);

    result_count = 0;
    num_removed_syms = 0;
    strtabsize = 4;
    if (num_import_syms)
    {
	for (export_idx = 0; export_idx < num_export_syms; export_idx++)
	{
	    struct symbol * result;
	    char * name;
	    size_t len;
	    boolean_t wild;

	    name = export_symbols[export_idx].indirect;
	    len  = export_symbols[export_idx].indirect_len;
	    if (!name)
	    {
		name = export_symbols[export_idx].name;
		len  = export_symbols[export_idx].name_len;
	    }
	    wild = ((len > 2) && ('*' == name[len-=2]));
	    if (wild)
	    {
		struct bsearch_key key;
		key.name = name;
		key.name_len = len;
		result = bsearch(&key, import_symbols, 
				    num_import_syms, sizeof(struct symbol), &bsearch_cmp_prefix);

		if (result)
		{
		    struct symbol * first;
		    struct symbol * last;

		    strtabsize += (result->name_len + result->indirect_len);

		    first = result;
		    while (--first >= &import_symbols[0])
		    {
			if (bsearch_cmp_prefix(&key, first))
			    break;
			strtabsize += (first->name_len + first->indirect_len);
		    }
		    first++;

		    last = result;
		    while (++last < (&import_symbols[0] + num_import_syms))
		    {
			if (bsearch_cmp_prefix(&key, last))
			    break;
			strtabsize += (last->name_len + last->indirect_len);
		    }
		    result_count += last - first;
		    result = first;
		    export_symbols[export_idx].list = first;
		    export_symbols[export_idx].list_count = last - first;
		    export_symbols[export_idx].flags |= kExported;
		}
	    }
	    else
		result = bsearch(name, import_symbols, 
				    num_import_syms, sizeof(struct symbol), &bsearch_cmp);

	    if (!result && require_imports)
	    {
		int status;
		char * demangled_result = 
			__cxa_demangle(export_symbols[export_idx].name + 1, NULL, NULL, &status);
		fprintf(stderr, "exported name not in import list: %s\n",
					demangled_result ? demangled_result : export_symbols[export_idx].name);
//		fprintf(stderr, "                                : %s\n", export_symbols[export_idx].name);
		if (demangled_result) {
			free(demangled_result);
		}
		num_removed_syms++;
	    }
	    if (diff)
	    {
		if (!result)
		    result = &export_symbols[export_idx];
		else
		    result = NULL;
	    }
	    if (result && !wild)
	    {
		export_symbols[export_idx].flags |= kExported;
		strtabsize += (export_symbols[export_idx].name_len + export_symbols[export_idx].indirect_len);
		result_count++;
		export_symbols[export_idx].list = &export_symbols[export_idx];
		export_symbols[export_idx].list_count = 1;
	    }
	}
    }
    strtabpad = (strtabsize + 3) & ~3;

    if (require_imports && num_removed_syms)
    {
	err = kError;
	goto finish;
    }

    fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
    if (-1 == fd)
    {
	perror("couldn't write output");
	err = kErrorFileAccess;
	goto finish;
    }

    struct symtab_command symcmd;
    struct uuid_command uuidcmd;

    symcmd.cmd		= LC_SYMTAB;
    symcmd.cmdsize	= sizeof(symcmd);
    symcmd.symoff	= sizeof(symcmd) + sizeof(uuidcmd);
    symcmd.nsyms	= result_count;
    symcmd.strsize	= strtabpad;

    uuidcmd.cmd         = LC_UUID;
    uuidcmd.cmdsize     = sizeof(uuidcmd);
    uuid_generate(uuidcmd.uuid);

    if (CPU_ARCH_ABI64 & target_arch->cputype)
    {
	struct mach_header_64 hdr;
	hdr.magic	= MH_MAGIC_64;
	hdr.cputype	= target_arch->cputype;
	hdr.cpusubtype	= target_arch->cpusubtype;
	hdr.filetype	= MH_KEXT_BUNDLE;
	hdr.ncmds	= 2;
	hdr.sizeofcmds	= sizeof(symcmd) + sizeof(uuidcmd);
	hdr.flags	= MH_INCRLINK;

	symcmd.symoff	+= sizeof(hdr);
	symcmd.stroff	= result_count * sizeof(struct nlist_64) 
				+ symcmd.symoff;

	if (target_arch->byteorder != host_arch->byteorder)
	    swap_mach_header_64(&hdr, target_arch->byteorder);
	err = writeFile(fd, &hdr, sizeof(hdr));
    }
    else
    {
	struct mach_header    hdr;
	hdr.magic	= MH_MAGIC;
	hdr.cputype	= target_arch->cputype;
	hdr.cpusubtype	= target_arch->cpusubtype;
	hdr.filetype	= (target_arch->cputype == CPU_TYPE_I386) ? MH_OBJECT : MH_KEXT_BUNDLE;
	hdr.ncmds	= 2;
	hdr.sizeofcmds	= sizeof(symcmd) + sizeof(uuidcmd);
	hdr.flags	= MH_INCRLINK;

	symcmd.symoff	+= sizeof(hdr);
	symcmd.stroff	= result_count * sizeof(struct nlist) 
				+ symcmd.symoff;

	if (target_arch->byteorder != host_arch->byteorder)
	    swap_mach_header(&hdr, target_arch->byteorder);
	err = writeFile(fd, &hdr, sizeof(hdr));
    }

    if (kErrorNone != err)
	goto finish;

    if (target_arch->byteorder != host_arch->byteorder) {
        swap_symtab_command(&symcmd, target_arch->byteorder);
        swap_uuid_command(&uuidcmd, target_arch->byteorder);
    }
    err = writeFile(fd, &symcmd, sizeof(symcmd));
    if (kErrorNone != err)
	goto finish;
    err = writeFile(fd, &uuidcmd, sizeof(uuidcmd));
    if (kErrorNone != err)
        goto finish;

    strx = 4;
    for (export_idx = 0; export_idx < num_export_syms; export_idx++)
    {
	if (!export_symbols[export_idx].name)
	    continue;
	if (!(kExported & export_symbols[export_idx].flags))
	    continue;

	if (export_idx
	  && export_symbols[export_idx - 1].name
	  && !strcmp(export_symbols[export_idx - 1].name, export_symbols[export_idx].name))
	{
	    fprintf(stderr, "duplicate export: %s\n", export_symbols[export_idx - 1].name);
	    err = kErrorDuplicate;
	    goto finish;
	}

	for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
	{

	    if (export_symbols[export_idx].list != &export_symbols[export_idx])
	    {
		printf("wild: %s, %s\n", export_symbols[export_idx].name, 
			export_symbols[export_idx].list[import_idx].name);
	    }
	    if (CPU_ARCH_ABI64 & target_arch->cputype)
	    {
		struct nlist_64 nl;

		nl.n_sect  = 0;
                nl.n_desc  = 0;
		nl.n_un.n_strx = strx;
		strx += export_symbols[export_idx].list[import_idx].name_len;
                
                if (export_symbols[export_idx].flags & kObsolete) {
                    nl.n_desc |= N_DESC_DISCARDED;
                }

		if (export_symbols[export_idx].list[import_idx].indirect)
		{
		    nl.n_type  = N_INDR | N_EXT;
		    nl.n_value = strx;
		    strx += export_symbols[export_idx].list[import_idx].indirect_len;
		}
		else
		{
		    nl.n_type  = N_UNDF | N_EXT;
		    nl.n_value = 0;
		}

		if (target_arch->byteorder != host_arch->byteorder)
		    swap_nlist_64(&nl, 1, target_arch->byteorder);

		err = writeFile(fd, &nl, sizeof(nl));
	    }
	    else
	    {
		struct nlist nl;

		nl.n_sect  = 0;
		nl.n_desc  = 0;
		nl.n_un.n_strx = strx;
		strx += export_symbols[export_idx].list[import_idx].name_len;
 
                if (export_symbols[export_idx].flags & kObsolete) {
                    nl.n_desc |= N_DESC_DISCARDED;
                }

		if (export_symbols[export_idx].list[import_idx].indirect)
		{
		    nl.n_type  = N_INDR | N_EXT;
		    nl.n_value = strx;
		    strx += export_symbols[export_idx].list[import_idx].indirect_len;
		}
		else
		{
		    nl.n_type  = N_UNDF | N_EXT;
		    nl.n_value = 0;
		}

		if (target_arch->byteorder != host_arch->byteorder)
		    swap_nlist(&nl, 1, target_arch->byteorder);

		err = writeFile(fd, &nl, sizeof(nl));
	    }
	}

	if (kErrorNone != err)
	    goto finish;
    }

    strx = sizeof(uint32_t);
    err = writeFile(fd, &zero, strx);
    if (kErrorNone != err)
	goto finish;

    for (export_idx = 0; export_idx < num_export_syms; export_idx++)
    {
	if (!export_symbols[export_idx].name)
	    continue;

	for (import_idx = 0; import_idx < export_symbols[export_idx].list_count; import_idx++)
	{
	    err = writeFile(fd, export_symbols[export_idx].list[import_idx].name, 
			export_symbols[export_idx].list[import_idx].name_len);
	    if (kErrorNone != err)
		goto finish;
	    if (export_symbols[export_idx].list[import_idx].indirect)
	    {
		err = writeFile(fd, export_symbols[export_idx].list[import_idx].indirect, 
			    export_symbols[export_idx].list[import_idx].indirect_len);
		if (kErrorNone != err)
		    goto finish;
	    }
	}
    }

    err = writeFile(fd, &zero, strtabpad - strtabsize);
    if (kErrorNone != err)
	goto finish;
	
    close(fd);


finish:
    for (filenum = 0; filenum < num_files; filenum++) {
        // unmap file
        if (files[filenum].mapped_size)
        {
            munmap((caddr_t)files[filenum].mapped, files[filenum].mapped_size);
            files[filenum].mapped     = 0;
            files[filenum].mapped_size = 0;
        }

    }

    if (kErrorNone != err)
    {
	if (output_name)
	    unlink(output_name);
        exit(1);
    }
    else
        exit(0);
    return(0);
}
Beispiel #4
0
/*
 * ctf_insert() does the work to add the ctf section in the specified broken
 * out ofile for the architecure specifed with a -arch command line option.
 */
static
void
ctf_insert(
struct arch *arch,
struct member *member,
struct object *object)
{
    uint32_t i, move_size;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t flags, offset;
    uint64_t addr;

	if(object->mh != NULL){
	    cputype = object->mh->cputype;
	    cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK;
	    flags = object->mh->flags;
	    offset = object->seg_linkedit->fileoff;
	    addr = object->seg_linkedit->vmaddr;
	}
	else{
	    cputype = object->mh64->cputype;
	    cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK;
	    flags = object->mh64->flags;
	    offset = object->seg_linkedit64->fileoff;
	    addr = object->seg_linkedit64->vmaddr;
	}

	/*
	 * Make sure this object is valid to process.  Since the input should
	 * be a mach_kernel that is statically linked we should not see any
	 * dynamic symbol table info. Or a code signature at the point this
	 * program is called in the build process.
	 */
	if((flags & MH_DYLDLINK) == MH_DYLDLINK ||
	   object->dyld_info != NULL ||
	   object->split_info_cmd != NULL ||
	   object->hints_cmd != NULL)
	     fatal_arch(arch, member, "file is input for the dynamic linker so "
			"not a valid input for this program to process: ");
	/*
	 * Allow a dynamic symbol table load command where it only has an
	 * indirect symbol table and no other tables.
	 */
        if(object->dyst != NULL &&
	   (object->dyst->ntoc != 0 ||
	    object->dyst->nmodtab != 0 ||
	    object->dyst->nmodtab != 0 ||
	    object->dyst->nextrefsyms != 0 ||
	    object->dyst->nextrel != 0))
	     fatal_arch(arch, member, "file is input for the dynamic linker so "
			"not a valid input for this program to process: ");
	if(object->mh_filetype != MH_EXECUTE)
	     fatal_arch(arch, member, "file type is not MH_EXECUTE so "
			"not a valid input for this program to process: ");
	if(object->seg_linkedit == NULL && object->seg_linkedit64 == NULL)
	     fatal_arch(arch, member, "file type does not have a __LINKEDIT "
			"segment so not a valid input for this program to "
			"process: ");
	if(object->code_sig_cmd != NULL)
	     fatal_arch(arch, member, "file type has code signature "
			"so not a valid input for this program to process: ");

	/*
	 * Now see if one of the -arch flags matches this object.
	 */
	for(i = 0; i < narch_ctfs; i++){
	    if(arch_ctfs[i].arch_flag.cputype == cputype &&
	       arch_ctfs[i].arch_flag.cpusubtype == cpusubtype)
		break;
	}
	/*
	 * If we didn't find a matching -arch flag it is an error.
	 */
	if(i >= narch_ctfs){
	     fatal_arch(arch, member, "no matching -arch option for this slice "
			"of file: ");
	     return;
	}
	arch_ctfs[i].arch_found = TRUE;

	/*
	 * Add the section for the ctf data for this arch.  It is placed in
	 * the file where the linkedit info was and that info will then be
	 * moved.
	 */
	add_ctf_section(arch, arch_ctfs[i].arch_flag.name,
			offset, addr, arch_ctfs[i].size);

	/*
	 * Now set up all the pointers and sizes of the symbol and string table.
	 */
	if(object->st != NULL && object->st->nsyms != 0){
	    if(object->mh != NULL){
		object->output_symbols = (struct nlist *)
		    (object->object_addr + object->st->symoff);
		if(object->object_byte_sex != get_host_byte_sex())
		    swap_nlist(object->output_symbols,
			       object->st->nsyms,
			       get_host_byte_sex());
		object->output_symbols64 = NULL;
	    }
	    else{
		object->output_symbols64 = (struct nlist_64 *)
		    (object->object_addr + object->st->symoff);
		if(object->object_byte_sex != get_host_byte_sex())
		    swap_nlist_64(object->output_symbols64,
				  object->st->nsyms,
				  get_host_byte_sex());
		object->output_symbols = NULL;
	    }
	    object->output_nsymbols = object->st->nsyms;
	    object->output_strings =
		object->object_addr + object->st->stroff;
	    object->output_strings_size = object->st->strsize;
	    if(object->mh != NULL){
		object->input_sym_info_size =
		    object->st->nsyms * sizeof(struct nlist) +
		    object->st->strsize;
	    }
	    else{
		object->input_sym_info_size =
		    object->st->nsyms * sizeof(struct nlist_64) +
		    object->st->strsize;
	    }
	}
	if(object->dyst != NULL){
	    object->output_ilocalsym = object->dyst->ilocalsym;
	    object->output_nlocalsym = object->dyst->nlocalsym;
	    object->output_iextdefsym = object->dyst->iextdefsym;
	    object->output_nextdefsym = object->dyst->nextdefsym;
	    object->output_iundefsym = object->dyst->iundefsym;
	    object->output_nundefsym = object->dyst->nundefsym;
	    object->output_indirect_symtab = (uint32_t *)
		(object->object_addr + object->dyst->indirectsymoff);
	    object->output_loc_relocs = (struct relocation_info *)
		(object->object_addr + object->dyst->locreloff);
	    if(object->mh != NULL){
		object->input_sym_info_size +=
		    object->dyst->nindirectsyms *
			sizeof(uint32_t);
	    }
	    else{
		object->input_sym_info_size +=
		    object->dyst->nindirectsyms *
			sizeof(uint32_t) +
		    object->input_indirectsym_pad;
	    }
	    object->input_sym_info_size +=
		object->dyst->nlocrel *
		    sizeof(struct relocation_info);
	}
	if(object->func_starts_info_cmd != NULL){
	    object->output_func_start_info_data = object->object_addr +
		object->func_starts_info_cmd->dataoff;
	    object->output_func_start_info_data_size = 
		object->func_starts_info_cmd->datasize;
	    object->input_sym_info_size +=
		object->func_starts_info_cmd->datasize;
	}
	if(object->data_in_code_cmd != NULL){
	    object->output_data_in_code_info_data = object->object_addr +
		object->data_in_code_cmd->dataoff;
	    object->output_data_in_code_info_data_size = 
		object->data_in_code_cmd->datasize;
	    object->input_sym_info_size +=
		object->data_in_code_cmd->datasize;
	}
	if(object->code_sign_drs_cmd != NULL){
	    object->output_code_sign_drs_info_data = object->object_addr +
		object->code_sign_drs_cmd->dataoff;
	    object->output_code_sign_drs_info_data_size = 
		object->code_sign_drs_cmd->datasize;
	    object->input_sym_info_size +=
		object->code_sign_drs_cmd->datasize;
	}
	if(object->link_opt_hint_cmd != NULL){
	    object->output_link_opt_hint_info_data = object->object_addr +
		object->link_opt_hint_cmd->dataoff;
	    object->output_link_opt_hint_info_data_size = 
		object->link_opt_hint_cmd->datasize;
	    object->input_sym_info_size +=
		object->link_opt_hint_cmd->datasize;
	}
	object->output_sym_info_size = object->input_sym_info_size;

	/*
	 * Now move the link edit info by the size of the ctf for this arch
	 * rounded to the load command size for this arch.
	 */
	if(object->mh != NULL){
	    move_size = rnd(arch_ctfs[i].size, sizeof(uint32_t));
	    object->seg_linkedit->fileoff += move_size;
	}
	else{
	    move_size = rnd(arch_ctfs[i].size, sizeof(uint64_t));
	    object->seg_linkedit64->fileoff += move_size;
	}
	if(object->st != NULL && object->st->nsyms != 0){
	    object->st->symoff += move_size;
	    object->st->stroff += move_size;
	}
	if(object->dyst != NULL){
	    if(object->dyst->nindirectsyms != 0)
	        object->dyst->indirectsymoff += move_size;
	    if(object->dyst->nlocrel != 0)
		object->dyst->locreloff += move_size;
	}
	if(object->func_starts_info_cmd != NULL)
	    object->func_starts_info_cmd->dataoff += move_size;
	if(object->data_in_code_cmd != NULL)
	    object->data_in_code_cmd->dataoff += move_size;
	if(object->code_sign_drs_cmd != NULL)
	    object->code_sign_drs_cmd->dataoff += move_size;
	if(object->link_opt_hint_cmd != NULL)
	    object->link_opt_hint_cmd->dataoff += move_size;

	/*
	 * Record the new content for writeout() to put in to the output file.
	 */
	object->output_new_content = arch_ctfs[i].contents;
	object->output_new_content_size = move_size;
}
Beispiel #5
0
static int register_mach_header(const char* build, const char* project, const char* path, struct fat_arch* fa, int fd, int* isMachO) {
	ssize_t res;
	uint32_t magic;
	int swap = 0;
	
	struct mach_header* mh = NULL;
	struct mach_header_64* mh64 = NULL;

	if (isMachO) *isMachO = 0;

	res = read(fd, &magic, sizeof(uint32_t));
	if (res < sizeof(uint32_t)) { return 0; }
	
	//
	// 32-bit, read the rest of the header
	//
	if (magic == MH_MAGIC || magic == MH_CIGAM) {
		if (isMachO) *isMachO = 1;
		mh = malloc(sizeof(struct mach_header));
		if (mh == NULL) return -1;
		memset(mh, 0, sizeof(struct mach_header));
		mh->magic = magic;
		res = read(fd, &mh->cputype, sizeof(struct mach_header) - sizeof(uint32_t));
		if (res < sizeof(struct mach_header) - sizeof(uint32_t)) { return 0; }
		if (magic == MH_CIGAM) {
			swap = 1;
			swap_mach_header(mh, NXHostByteOrder());
		}
	//
	// 64-bit, read the rest of the header
	//
	} else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
		if (isMachO) *isMachO = 1;
		mh64 = malloc(sizeof(struct mach_header_64));
		if (mh64 == NULL) return -1;
		memset(mh64, 0, sizeof(struct mach_header_64));
		mh64->magic = magic;
		res = read(fd, &mh64->cputype, sizeof(struct mach_header_64) - sizeof(uint32_t));
		if (res < sizeof(struct mach_header_64) - sizeof(uint32_t)) { return 0; }
		if (magic == MH_CIGAM_64) {
			swap = 1;
			swap_mach_header_64(mh64, NXHostByteOrder());
		}
	//
	// Not a Mach-O
	//
	} else {
		return 0;
	}


	switch (mh64 ? mh64->filetype : mh->filetype) {
		case MH_EXECUTE:
		case MH_DYLIB:
		case MH_BUNDLE:
			break;
		case MH_OBJECT:
		default:
			return 0;
	}

	res = SQL("INSERT INTO mach_o_objects (magic, type, cputype, cpusubtype, flags, build, project, path) VALUES (%u, %u, %u, %u, %u, %Q, %Q, %Q)",
		mh64 ? mh64->magic : mh->magic,
		mh64 ? mh64->filetype : mh->filetype,
		mh64 ? mh64->cputype : mh->cputype,
		mh64 ? mh64->cpusubtype : mh->cpusubtype,
		mh64 ? mh64->flags : mh->flags,
		build, project, path);
	uint64_t serial = sqlite3_last_insert_rowid((sqlite3*)_DBPluginGetDataStorePtr());

	//
	// Information needed to parse the symbol table
	//
	int count_nsect = 0;
	unsigned char text_nsect = NO_SECT;
	unsigned char data_nsect = NO_SECT;
	unsigned char bss_nsect = NO_SECT;

	uint32_t nsyms = 0;
	uint8_t *symbols = NULL;
	
	uint32_t strsize = 0;
	uint8_t *strings = NULL;


	int i;
	uint32_t ncmds = mh64 ? mh64->ncmds : mh->ncmds;
	for (i = 0; i < ncmds; ++i) {
		//
		// Read a generic load command into memory.
		// At first, we only know it has a type and size.
		//
		struct load_command lctmp;

		ssize_t res = read(fd, &lctmp, sizeof(struct load_command));
		if (res < sizeof(struct load_command)) { return 0; }

		uint32_t cmd = swap ? OSSwapInt32(lctmp.cmd) : lctmp.cmd;
		uint32_t cmdsize = swap ? OSSwapInt32(lctmp.cmdsize) : lctmp.cmdsize;
		if (cmdsize == 0) continue;
		
		struct load_command* lc = malloc(cmdsize);
		if (lc == NULL) { return 0; }
		memset(lc, 0, cmdsize);
		memcpy(lc, &lctmp, sizeof(lctmp));
		
		// Read the remainder of the load command.
		res = read(fd, (uint8_t*)lc + sizeof(struct load_command), cmdsize - sizeof(struct load_command));
		if (res < (cmdsize - sizeof(struct load_command))) { free(lc); return 0; }

		//
		// LC_LOAD_DYLIB and LC_LOAD_WEAK_DYLIB
		// Add dylibs as unresolved "lib" dependencies.
		//
		if (cmd == LC_LOAD_DYLIB || cmd == LC_LOAD_WEAK_DYLIB) {
			struct dylib_command *dylib = (struct dylib_command*)lc;
			if (swap) swap_dylib_command(dylib, NXHostByteOrder());

			// sections immediately follow the dylib_command structure, and are
			// reflected in the cmdsize.

			int strsize = dylib->cmdsize - sizeof(struct dylib_command);
			char* str = malloc(strsize+1);
			strncpy(str, (char*)((uint8_t*)dylib + dylib->dylib.name.offset), strsize);
			str[strsize] = 0; // NUL-terminate

			res = SQL("INSERT INTO unresolved_dependencies (build,project,type,dependency) VALUES (%Q,%Q,%Q,%Q)",
			build, project, "lib", str);
			
			free(str);
		
		//
		// LC_LOAD_DYLINKER
		// Add the dynamic linker (usually dyld) as an unresolved "lib" dependency.
		//
		} else if (cmd == LC_LOAD_DYLINKER) {
			struct dylinker_command *dylinker = (struct dylinker_command*)lc;
			if (swap) swap_dylinker_command(dylinker, NXHostByteOrder());

			// sections immediately follow the dylib_command structure, and are
			// reflected in the cmdsize.

			int strsize = dylinker->cmdsize - sizeof(struct dylinker_command);
			char* str = malloc(strsize+1);
			strncpy(str, (char*)((uint8_t*)dylinker + dylinker->name.offset), strsize);
			str[strsize] = 0; // NUL-terminate

			res = SQL("INSERT INTO unresolved_dependencies (build,project,type,dependency) VALUES (%Q,%Q,%Q,%Q)",
			build, project, "lib", str);
			
			free(str);
		
		//
		// LC_SYMTAB
		// Read the symbol table into memory, we'll process it after we're
		// done with the load commands.
		//
		} else if (cmd == LC_SYMTAB && symbols == NULL) {
			struct symtab_command *symtab = (struct symtab_command*)lc;
			if (swap) swap_symtab_command(symtab, NXHostByteOrder());

			nsyms = symtab->nsyms;
			uint32_t symsize = nsyms * (mh64 ? sizeof(struct nlist_64) : sizeof(struct nlist));
			symbols = malloc(symsize);
			
			strsize = symtab->strsize;
			// XXX: check strsize != 0
			strings = malloc(strsize);

			off_t save = lseek(fd, 0, SEEK_CUR);

			off_t origin = fa ? fa->offset : 0;

			lseek(fd, (off_t)symtab->symoff + origin, SEEK_SET);
			res = read(fd, symbols, symsize);
			if (res < symsize) { /* XXX: leaks */ return 0; }
			
			lseek(fd, (off_t)symtab->stroff + origin, SEEK_SET);
			res = read(fd, strings, strsize);
			if (res < strsize) { /* XXX: leaks */ return 0; }
			
			lseek(fd, save, SEEK_SET);
		
		//
		// LC_SEGMENT
		// We're looking for the section number of the text, data, and bss segments
		// in order to parse symbols.
		//
		} else if (cmd == LC_SEGMENT) {
			struct segment_command* seg = (struct segment_command*)lc;
			if (swap) swap_segment_command(seg, NXHostByteOrder());
			
			// sections immediately follow the segment_command structure, and are
			// reflected in the cmdsize.
			int k;
			for (k = 0; k < seg->nsects; ++k) {
				struct section* sect = (struct section*)((uint8_t*)seg + sizeof(struct segment_command) + k * sizeof(struct section));
				if (swap) swap_section(sect, 1, NXHostByteOrder());
				if (strcmp(sect->sectname, SECT_TEXT) == 0 && strcmp(sect->segname, SEG_TEXT) == 0) {
					text_nsect = ++count_nsect;
				} else if (strcmp(sect->sectname, SECT_DATA) == 0 && strcmp(sect->segname, SEG_DATA) == 0) {
					data_nsect = ++count_nsect;
				} else if (strcmp(sect->sectname, SECT_BSS) == 0 && strcmp(sect->segname, SEG_DATA) == 0) {
					bss_nsect = ++count_nsect;
				} else {
					++count_nsect;
				}
			}

		//
		// LC_SEGMENT_64
		// Same as LC_SEGMENT, but for 64-bit binaries.
		//
		} else if (lc->cmd == LC_SEGMENT_64) {
			struct segment_command_64* seg = (struct segment_command_64*)lc;
			if (swap) swap_segment_command_64(seg, NXHostByteOrder());
			
			// sections immediately follow the segment_command structure, and are
			// reflected in the cmdsize.
			int k;
			for (k = 0; k < seg->nsects; ++k) {
				struct section_64* sect = (struct section_64*)((uint8_t*)seg + sizeof(struct segment_command_64) + k * sizeof(struct section_64));
				if (swap) swap_section_64(sect, 1, NXHostByteOrder());
				if (strcmp(sect->sectname, SECT_TEXT) == 0 && strcmp(sect->segname, SEG_TEXT) == 0) {
					text_nsect = ++count_nsect;
				} else if (strcmp(sect->sectname, SECT_DATA) == 0 && strcmp(sect->segname, SEG_DATA) == 0) {
					data_nsect = ++count_nsect;
				} else if (strcmp(sect->sectname, SECT_BSS) == 0 && strcmp(sect->segname, SEG_DATA) == 0) {
					bss_nsect = ++count_nsect;
				} else {
					++count_nsect;
				}
			}
		}
		
		free(lc);
	}

	//
	// Finished processing the load commands, now insert symbols into the database.
	//
	int j;
	for (j = 0; j < nsyms; ++j) {
		struct nlist_64 symbol;
		if (mh64) {
			memcpy(&symbol, (symbols + j * sizeof(struct nlist_64)), sizeof(struct nlist_64));
			if (swap) swap_nlist_64(&symbol, 1, NXHostByteOrder());
		} else {
			symbol.n_value = 0;
			memcpy(&symbol, (symbols + j * sizeof(struct nlist)), sizeof(struct nlist));
			if (swap) swap_nlist_64(&symbol, 1, NXHostByteOrder());
			// we copied a 32-bit nlist into a 64-bit one, adjust the value accordingly
			// all other fields are identical sizes
			symbol.n_value >>= 32;
		}
		char type = '?';
		switch (symbol.n_type & N_TYPE) {
			case N_UNDF:
			case N_PBUD:
				type = 'u';
				if (symbol.n_value != 0) {
					type = 'c';
				}
				break;
			case N_ABS:
				type = 'a';
				break;
			case N_SECT:
				if (symbol.n_sect == text_nsect) {
					type = 't';
				} else if (symbol.n_sect == data_nsect) {
					type = 'd';
				} else if (symbol.n_sect == bss_nsect) {
					type = 'b';
				} else {
					type = 's';
				}
				break;
			case N_INDR:
				type = 'i';
				break;
		}

		// uppercase indicates an externally visible symbol
		if ((symbol.n_type & N_EXT) && type != '?') {
			type = toupper(type);
		}

		if (type != '?' && type != 'u' && type != 'c') {
			const uint8_t* name = (const uint8_t*)"";
			if (symbol.n_un.n_strx != 0) {
				name = (uint8_t*)(strings + symbol.n_un.n_strx);
			}
			res = SQL("INSERT INTO mach_o_symbols VALUES (%lld, \'%c\', %lld, %Q)",
				serial,
				type,
				symbol.n_value,
				name);
		}
	}

	return 0;
}