/* * process_old() is called once for each architecture in the old dynamic shared * library and then causes compare() to be called for the same architecture * in the new dynamic shared library. */ static void process_old( struct ofile *old_ofile, char *arch_name, void *cookie) { struct arch_flag arch_flag; /* check to make sure this is a dynamic shared library */ check_dylib(old_ofile, arch_name); /* fill in the architecure info */ arch_flag.name = (char *)get_arch_name_from_types( old_ofile->mh_cputype, old_ofile->mh_cpusubtype); arch_flag.cputype = old_ofile->mh_cputype; arch_flag.cpusubtype = old_ofile->mh_cpusubtype; arch_processed = FALSE; arch_name_being_processed = arch_name; ofile_process(new_dylib, &arch_flag, 1, FALSE, TRUE, TRUE, FALSE, compare, old_ofile); if(arch_processed == FALSE) fatal("new dynamic shared library: %s does not contain " "architecture %s\n", new_dylib, arch_flag.name); }
/* * compare() checks the new dynamic shared library against the old one for the * same architecture. The old dynamic shared library's ofile struct is passed * as the cookie. */ static void compare( struct ofile *new_ofile, char *arch_name, void *cookie) { uint32_t i; struct load_command *lc; struct ofile *old_ofile; struct dylib_command *old_dl, *new_dl; char *old_install_name, *new_install_name; enum bool new_api_allowed; uint32_t ncmds; arch_name = arch_name_being_processed; /* check to make sure this is a dynamic shared library */ check_dylib(new_ofile, arch_name); old_ofile = (struct ofile *)cookie; /* Get the LC_ID_DYLIB from the old dylib */ old_dl = NULL; lc = old_ofile->load_commands; if(old_ofile->mh != NULL) ncmds = old_ofile->mh->ncmds; else ncmds = old_ofile->mh64->ncmds; for(i = 0; i < ncmds; i++){ if(old_dl == NULL && lc->cmd == LC_ID_DYLIB){ old_dl = (struct dylib_command *)lc; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(old_dl == NULL){ if(arch_name != NULL) fatal("malformed dynamic shared library: %s (for architecture " "%s) (has no dylib id command)", old_dylib, arch_name); else fatal("malformed dynamic shared library: %s (has no dylib id " "command)", old_dylib); } old_install_name = (char *)old_dl + old_dl->dylib.name.offset; if(old_dl->dylib.current_version < old_dl->dylib.compatibility_version){ if(arch_name != NULL) fatal("malformed dynamic shared library: %s (for architecture " "%s) (current version less than compatibility_version)", old_dylib, arch_name); else fatal("malformed dynamic shared library: %s (current version " "less than compatibility_version)", old_dylib); } /* Get the LC_ID_DYLIB from the new dylib */ new_dl = NULL; lc = new_ofile->load_commands; if(new_ofile->mh != NULL) ncmds = new_ofile->mh->ncmds; else ncmds = new_ofile->mh64->ncmds; for(i = 0; i < ncmds; i++){ if(new_dl == NULL && lc->cmd == LC_ID_DYLIB){ new_dl = (struct dylib_command *)lc; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(new_dl == NULL){ if(arch_name != NULL) fatal("malformed dynamic shared library: %s (for architecture " "%s) (has no dylib id command)", new_dylib, arch_name); else fatal("malformed dynamic shared library: %s (has no dylib id " "command)", new_dylib); } new_install_name = (char *)new_dl + new_dl->dylib.name.offset; if(new_dl->dylib.current_version < new_dl->dylib.compatibility_version){ if(arch_name != NULL) fatal("malformed dynamic shared library: %s (for architecture " "%s) (current version less than compatibility_version)", new_dylib, arch_name); else fatal("malformed dynamic shared library: %s (current version " "less than compatibility_version)", new_dylib); } /* check the values of the LC_ID_DYLIB's */ if(strcmp(old_install_name, new_install_name) != 0){ if(arch_name != NULL) printf("For architecture %s ", arch_name); printf("dynamic shared libraries have different install names (%s " "and %s)\n", old_install_name, new_install_name); compatible = FALSE; } if(old_dl->dylib.current_version > new_dl->dylib.current_version){ if(arch_name != NULL) printf("For architecture %s ", arch_name); printf("current version of old dynamic shared library (%u) " "greater than new dynamic shared library (%u)\n", old_dl->dylib.current_version,new_dl->dylib.current_version); compatible = FALSE; } if(old_dl->dylib.compatibility_version > new_dl->dylib.compatibility_version){ if(arch_name != NULL) printf("For architecture %s ", arch_name); printf("compatibility version of old dynamic shared library (%u) " "greater than new dynamic shared library (%u)\n", old_dl->dylib.compatibility_version, new_dl->dylib.compatibility_version); compatible = FALSE; new_api_allowed = TRUE; } else{ if(new_dl->dylib.compatibility_version != old_dl->dylib.compatibility_version) new_api_allowed = TRUE; else new_api_allowed = FALSE; } check_global_symbols(new_ofile, old_ofile, arch_name, new_api_allowed); arch_processed = TRUE; }
/* * checksyms() is the routine that gets called by ofile_process() to process * single object files. */ static void checksyms( struct ofile *ofile, char *arch_name, void *cookie) { struct cmd_flags *cmd_flags; unsigned long i; struct load_command *lc; struct symtab_command *st; struct nlist *symbols; unsigned long nsymbols; char *strings; unsigned long strsize; unsigned long nfiledefs, ncats, nlocal, nstabs, nfun; unsigned long filedef_strings, cat_strings, local_strings, stab_strings; enum bool debug; if(ofile->mh == NULL) return; debug = FALSE; cmd_flags = (struct cmd_flags *)cookie; if(cmd_flags->check_dynamic_binary == TRUE) if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK) check_dynamic_binary(ofile, arch_name, cmd_flags->detail, cmd_flags->verification); if(ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB) check_dylib(ofile, arch_name, cmd_flags->detail, cmd_flags->verification, &debug); st = NULL; lc = ofile->load_commands; for(i = 0; i < ofile->mh->ncmds; i++){ if(st == NULL && lc->cmd == LC_SYMTAB){ st = (struct symtab_command *)lc; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(st == NULL || st->nsyms == 0){ return; } if(cmd_flags->rldtype == FALSE && cmd_flags->trey == FALSE && (ofile->mh->flags & MH_DYLDLINK) == 0 && (ofile->file_type != OFILE_FAT || ofile->arch_type != OFILE_ARCHIVE) && ofile->file_type != OFILE_ARCHIVE && ofile->mh->filetype != MH_FVMLIB){ if(st->nsyms == 0) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf(" has %u symbols and %u string bytes\n", st->nsyms, st->strsize); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); exit_status = EXIT_FAILURE; return; } symbols = (struct nlist *)(ofile->object_addr + st->symoff); nsymbols = st->nsyms; if(ofile->object_byte_sex != get_host_byte_sex()) swap_nlist(symbols, nsymbols, get_host_byte_sex()); strings = ofile->object_addr + st->stroff; strsize = st->strsize; for(i = 0; i < nsymbols; i++){ if(symbols[i].n_un.n_strx == 0) symbols[i].n_un.n_name = ""; else if(symbols[i].n_un.n_strx < 0 || (unsigned long)symbols[i].n_un.n_strx > st->strsize) symbols[i].n_un.n_name = "bad string index"; else symbols[i].n_un.n_name = symbols[i].n_un.n_strx + strings; if((symbols[i].n_type & N_TYPE) == N_INDR){ if(symbols[i].n_value == 0) symbols[i].n_value = (long)""; else if(symbols[i].n_value > st->strsize) symbols[i].n_value = (long)"bad string index"; else symbols[i].n_value = (long)(symbols[i].n_value + strings); } } nfiledefs = 0; ncats = 0; nlocal = 0; nstabs = 0; nfun = 0; filedef_strings = 0; cat_strings = 0; local_strings = 0; stab_strings = 0; for(i = 0; i < nsymbols; i++){ if(ofile->mh->filetype == MH_EXECUTE){ if(symbols[i].n_type == (N_ABS | N_EXT) && symbols[i].n_value == 0){ if(strncmp(symbols[i].n_un.n_name, ".file_definition_", sizeof(".file_definition_") - 1) == 0){ nfiledefs++; filedef_strings += strlen(symbols[i].n_un.n_name); } if(strncmp(symbols[i].n_un.n_name, ".objc_category_name_", sizeof(".objc_category_name_") - 1) == 0){ ncats++; cat_strings += strlen(symbols[i].n_un.n_name); } } } if((symbols[i].n_type & N_EXT) == 0){ nlocal++; local_strings += strlen(symbols[i].n_un.n_name); } if(symbols[i].n_type & N_STAB){ nstabs++; stab_strings += strlen(symbols[i].n_un.n_name); if(symbols[i].n_type == N_FUN) nfun++; } } if(nfiledefs == 0 && ncats == 0 && nlocal == 0 && nstabs == 0) return; if(cmd_flags->rldtype == TRUE && nstabs == 0) return; if((ofile->mh->flags & MH_DYLDLINK) == MH_DYLDLINK && (nstabs == 0 && nlocal == 0)) return; if(nstabs == 0 && ((ofile->file_type == OFILE_FAT && ofile->arch_type == OFILE_ARCHIVE) || ofile->file_type == OFILE_ARCHIVE || ofile->mh->filetype == MH_FVMLIB)) return; if((ofile->mh->filetype == MH_DYLIB || ofile->mh->filetype == MH_DYLIB_STUB || ofile->mh->filetype == MH_FVMLIB) && (nfun == 0 || debug == TRUE)) return; if(cmd_flags->detail == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->member_ar_hdr != NULL){ printf("%s:%.*s:", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("%s:", ofile->file_name); printf("\n"); if(nfiledefs != 0) printf(" has %lu .file_definition_ symbols and %lu string " "bytes\n", nfiledefs, filedef_strings); if(ncats != 0) printf(" has %lu .objc_category_name_ symbols and %lu string " "bytes\n", ncats, cat_strings); if(nlocal != 0) printf(" has %lu local symbols and %lu string " "bytes\n", nlocal, local_strings); if(nstabs != 0) printf(" has %lu debugging symbols and %lu string " "bytes\n", nstabs, stab_strings); } if(cmd_flags->verification == TRUE) printf("unstripped_binary\n"); if(cmd_flags->trey == TRUE && nstabs == 0) return; exit_status = EXIT_FAILURE; return; }