mirror of
https://github.com/darlinghq/cctools-port.git
synced 2024-11-23 12:19:40 +00:00
713 lines
20 KiB
C
713 lines
20 KiB
C
/*
|
|
* 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 <stdlib.h>
|
|
|
|
#include "stuff/ofile.h"
|
|
#include "stuff/errors.h"
|
|
#include "stuff/bytesex.h"
|
|
#include "stuff/allocate.h"
|
|
|
|
/* name of the program for error messages (argv[0]) */
|
|
__private_extern__ char *progname = NULL;
|
|
|
|
/* The filenames of the old and new dylib */
|
|
static char *old_dylib = NULL;
|
|
static char *new_dylib = NULL;
|
|
|
|
/*
|
|
* This is a flag use by process_old() and compare() to make sure each
|
|
* architecture in the old library is in the new library.
|
|
*/
|
|
static enum bool arch_processed = FALSE;
|
|
static char *arch_name_being_processed = NULL;
|
|
|
|
/* The result of the dylib comparison */
|
|
static enum bool compatible = TRUE;
|
|
|
|
/* the byte sex of the machine this program is running on */
|
|
static enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX;
|
|
|
|
/*
|
|
* These are pointers to strings and symbols used to search of the table of
|
|
* contents of a library. These have to be static and not local so that
|
|
* check_global_symbols() can set them and that dylib_bsearch() can use them.
|
|
*/
|
|
static char *strings = NULL;
|
|
static struct nlist *symbols = NULL;
|
|
static struct nlist_64 *symbols64 = NULL;
|
|
|
|
static void process_old(
|
|
struct ofile *ofile,
|
|
char *arch_name,
|
|
void *cookie);
|
|
|
|
static void compare(
|
|
struct ofile *new_ofile,
|
|
char *arch_name,
|
|
void *cookie);
|
|
|
|
static void check_dylib(
|
|
struct ofile *ofile,
|
|
char *arch_name);
|
|
|
|
static void check_global_symbols(
|
|
struct ofile *new_ofile,
|
|
struct ofile *old_ofile,
|
|
char *arch_name,
|
|
enum bool new_api_allowed);
|
|
|
|
static int dylib_bsearch(
|
|
const char *symbol_name,
|
|
const struct dylib_table_of_contents *toc);
|
|
|
|
static int dylib_bsearch64(
|
|
const char *symbol_name,
|
|
const struct dylib_table_of_contents *toc);
|
|
|
|
static int nlist_bsearch(
|
|
const char *symbol_name,
|
|
const struct nlist *sym);
|
|
|
|
static int nlist_bsearch64(
|
|
const char *symbol_name,
|
|
const struct nlist_64 *sym64);
|
|
|
|
/* apple_version is created by the libstuff/Makefile */
|
|
extern char apple_version[];
|
|
char *version = apple_version;
|
|
|
|
/*
|
|
* The program cmpdylib. This compares an old and an new dynamic shared library
|
|
* for compatiblity. Usage:
|
|
*
|
|
* cmpdylib old_dylib new_dylib
|
|
*
|
|
* It exits non-zero for incompatible libraries and prints why the libraries are
|
|
* incompatible. It exit zero and prints nothing for compatible libraries.
|
|
*/
|
|
int
|
|
main(
|
|
int argc,
|
|
char *argv[],
|
|
char *envp[])
|
|
{
|
|
progname = argv[0];
|
|
host_byte_sex = get_host_byte_sex();
|
|
|
|
if(argc != 3){
|
|
fprintf(stderr, "Usage: %s old_dylib new_dylib\n", progname);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
old_dylib = argv[1];
|
|
new_dylib = argv[2];
|
|
|
|
ofile_process(old_dylib, NULL, 0, TRUE, TRUE, TRUE, FALSE, process_old,
|
|
NULL);
|
|
|
|
if(compatible == TRUE)
|
|
return(EXIT_SUCCESS);
|
|
else
|
|
return(EXIT_FAILURE);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* check_dylib() checks to make sure this is a dynamic shared library. If not
|
|
* it prints an error and exits.
|
|
*/
|
|
static
|
|
void
|
|
check_dylib(
|
|
struct ofile *ofile,
|
|
char *arch_name)
|
|
{
|
|
if(ofile->file_type == OFILE_FAT){
|
|
if(ofile->arch_type != OFILE_Mach_O ||
|
|
(ofile->mh_filetype != MH_DYLIB &&
|
|
ofile->mh_filetype != MH_DYLIB_STUB))
|
|
fatal("for architecture %s file: %s is not a dynamic shared "
|
|
"library", ofile->arch_flag.name, ofile->file_name);
|
|
}
|
|
else
|
|
if(ofile->file_type != OFILE_Mach_O ||
|
|
(ofile->mh_filetype != MH_DYLIB &&
|
|
ofile->mh_filetype != MH_DYLIB_STUB))
|
|
fatal("file: %s is not a dynamic shared library",
|
|
ofile->file_name);
|
|
}
|
|
|
|
/*
|
|
* check_global_symbols() checks to see if all the global symbols defined in the
|
|
* old library are defined in the new library. If not it prints the ones not
|
|
* defined and sets compatible to FALSE. If new_api_allowed is FALSE then it
|
|
* checks to see if there are any global symbols that are in the new library
|
|
* that are not in the old library. If so it prints those and sets compatible
|
|
* to FALSE.
|
|
*/
|
|
static
|
|
void
|
|
check_global_symbols(
|
|
struct ofile *new_ofile,
|
|
struct ofile *old_ofile,
|
|
char *arch_name,
|
|
enum bool new_api_allowed)
|
|
{
|
|
uint32_t i;
|
|
struct load_command *lc;
|
|
enum bool new_api, missing_symbols, found;
|
|
|
|
struct symtab_command *old_st, *new_st;
|
|
struct dysymtab_command *old_dyst, *new_dyst;
|
|
struct nlist *old_symbols, *new_symbols, *sym;
|
|
struct nlist_64 *old_symbols64, *new_symbols64, *sym64;
|
|
char *old_strings, *new_strings;
|
|
struct dylib_table_of_contents *old_tocs, *new_tocs, *toc;
|
|
char *symbol_name;
|
|
uint32_t ncmds, n_strx;
|
|
|
|
/*
|
|
* Pickup the symbolic info for the old dylib.
|
|
*/
|
|
old_st = NULL;
|
|
old_dyst = 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_st == NULL && lc->cmd == LC_SYMTAB){
|
|
old_st = (struct symtab_command *)lc;
|
|
}
|
|
else if(old_dyst == NULL && lc->cmd == LC_DYSYMTAB){
|
|
old_dyst = (struct dysymtab_command *)lc;
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
if(old_st == NULL || old_st->nsyms == 0){
|
|
if(arch_name != NULL)
|
|
fatal("old dynamic shared library: %s (for architecture %s) "
|
|
"has no symbol table", old_dylib, arch_name);
|
|
else
|
|
fatal("old dynamic shared library: %s has no symbol table",
|
|
old_dylib);
|
|
}
|
|
if(old_ofile->mh != NULL){
|
|
old_symbols = (struct nlist *)
|
|
(old_ofile->object_addr + old_st->symoff);
|
|
old_symbols64 = NULL;
|
|
}
|
|
else{
|
|
old_symbols64 = (struct nlist_64 *)
|
|
(old_ofile->object_addr + old_st->symoff);
|
|
old_symbols = NULL;
|
|
}
|
|
old_tocs = (struct dylib_table_of_contents *)
|
|
(old_ofile->object_addr + old_dyst->tocoff);
|
|
old_strings = (char *)
|
|
(old_ofile->object_addr + old_st->stroff);
|
|
if(old_ofile->object_byte_sex != host_byte_sex){
|
|
if(old_ofile->mh != NULL)
|
|
swap_nlist(old_symbols, old_st->nsyms, host_byte_sex);
|
|
else
|
|
swap_nlist_64(old_symbols64, old_st->nsyms, host_byte_sex);
|
|
swap_dylib_table_of_contents(old_tocs, old_dyst->ntoc,
|
|
host_byte_sex);
|
|
}
|
|
for(i = 0; i < old_st->nsyms; i++){
|
|
if(old_ofile->mh != NULL)
|
|
n_strx = old_symbols[i].n_un.n_strx;
|
|
else
|
|
n_strx = old_symbols64[i].n_un.n_strx;
|
|
if(n_strx != 0 && n_strx > old_st->strsize){
|
|
if(arch_name != NULL)
|
|
fatal("malformed dynamic shared library: %s (for "
|
|
"architecture %s) (bad string table index for symbol "
|
|
"%u)", old_dylib, arch_name, i);
|
|
else
|
|
fatal("malformed dynamic shared library: %s (bad string "
|
|
"table index for symbol %u)", old_dylib, i);
|
|
}
|
|
}
|
|
for(i = 0; i < old_dyst->ntoc; i++){
|
|
if(old_tocs[i].symbol_index > old_st->nsyms){
|
|
if(arch_name != NULL)
|
|
fatal("malformed dynamic shared library: %s (for "
|
|
"architecture %s) (symbol_index field of table of "
|
|
"contents entry %u past the end of the symbol table)",
|
|
old_dylib, arch_name, i);
|
|
else
|
|
fatal("malformed dynamic shared library: %s (symbol_index "
|
|
"field of table of contents entry %u past the end of "
|
|
"the symbol table)", old_dylib, i);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Pickup the symbolic info for the new dylib.
|
|
*/
|
|
new_st = NULL;
|
|
new_dyst = 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_st == NULL && lc->cmd == LC_SYMTAB){
|
|
new_st = (struct symtab_command *)lc;
|
|
}
|
|
else if(new_dyst == NULL && lc->cmd == LC_DYSYMTAB){
|
|
new_dyst = (struct dysymtab_command *)lc;
|
|
}
|
|
lc = (struct load_command *)((char *)lc + lc->cmdsize);
|
|
}
|
|
if(new_st == NULL || new_st->nsyms == 0){
|
|
if(arch_name != NULL)
|
|
fatal("new dynamic shared library: %s (for architecture %s) "
|
|
"has no symbol table", new_dylib, arch_name);
|
|
else
|
|
fatal("new dynamic shared library: %s has no symbol table",
|
|
new_dylib);
|
|
}
|
|
if(new_ofile->mh != NULL){
|
|
new_symbols = (struct nlist *)
|
|
(new_ofile->object_addr + new_st->symoff);
|
|
new_symbols64 = NULL;
|
|
}
|
|
else{
|
|
new_symbols64 = (struct nlist_64 *)
|
|
(new_ofile->object_addr + new_st->symoff);
|
|
new_symbols = NULL;
|
|
}
|
|
new_strings = (char *)
|
|
(new_ofile->object_addr + new_st->stroff);
|
|
new_tocs = (struct dylib_table_of_contents *)
|
|
(new_ofile->object_addr + new_dyst->tocoff);
|
|
if(new_ofile->object_byte_sex != host_byte_sex){
|
|
if(new_ofile->mh != NULL)
|
|
swap_nlist(new_symbols, new_st->nsyms, host_byte_sex);
|
|
else
|
|
swap_nlist_64(new_symbols64, new_st->nsyms, host_byte_sex);
|
|
swap_dylib_table_of_contents(new_tocs, new_dyst->ntoc,
|
|
host_byte_sex);
|
|
}
|
|
for(i = 0; i < new_st->nsyms; i++){
|
|
if(new_ofile->mh != NULL)
|
|
n_strx = new_symbols[i].n_un.n_strx;
|
|
else
|
|
n_strx = new_symbols64[i].n_un.n_strx;
|
|
if(n_strx != 0 && n_strx > new_st->strsize){
|
|
if(arch_name != NULL)
|
|
fatal("malformed dynamic shared library: %s (for "
|
|
"architecture %s) (bad string table index for symbol "
|
|
"%u)", new_dylib, arch_name, i);
|
|
else
|
|
fatal("malformed dynamic shared library: %s (bad string "
|
|
"table index for symbol %u)", new_dylib, i);
|
|
}
|
|
}
|
|
for(i = 0; i < new_dyst->ntoc; i++){
|
|
if(new_tocs[i].symbol_index > new_st->nsyms){
|
|
if(arch_name != NULL)
|
|
fatal("malformed dynamic shared library: %s (for "
|
|
"architecture %s) (symbol_index field of table of "
|
|
"contents entry %u past the end of the symbol table)",
|
|
new_dylib, arch_name, i);
|
|
else
|
|
fatal("malformed dynamic shared library: %s (symbol_index "
|
|
"field of table of contents entry %u past the end of "
|
|
"the symbol table)", new_dylib, i);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now check to see if all the global symbols defined in the old library
|
|
* are defined in the new library. Prints the ones that are not and
|
|
* sets compatible to FALSE.
|
|
*/
|
|
missing_symbols = FALSE;
|
|
strings = new_strings;
|
|
if(new_dyst->ntoc != 0){
|
|
symbols = new_symbols;
|
|
symbols64 = new_symbols64;
|
|
}
|
|
else{
|
|
if(new_ofile->mh != NULL){
|
|
symbols = new_symbols + new_dyst->iextdefsym;
|
|
symbols64 = NULL;
|
|
}
|
|
else{
|
|
symbols64 = new_symbols64 + new_dyst->iextdefsym;
|
|
symbols = NULL;
|
|
}
|
|
}
|
|
for(i = 0; i < old_dyst->nextdefsym; i++){
|
|
if(new_ofile->mh != NULL)
|
|
n_strx = old_symbols[i + old_dyst->iextdefsym].n_un.n_strx;
|
|
else
|
|
n_strx = old_symbols64[i + old_dyst->iextdefsym].n_un.n_strx;
|
|
symbol_name = old_strings + n_strx;
|
|
if(new_dyst->ntoc != 0){
|
|
if(new_ofile->mh != NULL){
|
|
toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc,
|
|
sizeof(struct dylib_table_of_contents),
|
|
(int (*)(const void *, const void *))
|
|
dylib_bsearch);
|
|
}
|
|
else{
|
|
toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc,
|
|
sizeof(struct dylib_table_of_contents),
|
|
(int (*)(const void *, const void *))
|
|
dylib_bsearch64);
|
|
}
|
|
found = toc != NULL;
|
|
}
|
|
else{
|
|
if(new_ofile->mh != NULL){
|
|
sym = bsearch(symbol_name, symbols, new_dyst->nextdefsym,
|
|
sizeof(struct nlist),
|
|
(int (*)(const void *, const void *))
|
|
nlist_bsearch);
|
|
found = sym != NULL;
|
|
}
|
|
else{
|
|
sym64 = bsearch(symbol_name, symbols64,new_dyst->nextdefsym,
|
|
sizeof(struct nlist_64),
|
|
(int (*)(const void *, const void *))
|
|
nlist_bsearch64);
|
|
found = sym64 != NULL;
|
|
}
|
|
}
|
|
if(found == FALSE){
|
|
if(missing_symbols == FALSE){
|
|
if(arch_name != NULL)
|
|
printf("For architecture %s symbols defined in %s "
|
|
"not defined in %s:\n", arch_name, old_dylib,
|
|
new_dylib);
|
|
else
|
|
printf("symbols defined in %s not defined in %s:\n",
|
|
old_dylib, new_dylib);
|
|
missing_symbols = TRUE;
|
|
compatible = FALSE;
|
|
}
|
|
printf("%s\n", symbol_name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If new api is allowed then checking of global symbols is done.
|
|
*/
|
|
if(new_api_allowed == TRUE)
|
|
return;
|
|
|
|
/*
|
|
* New api is not allowed so check to make sure no symbols in the new
|
|
* library are not in the old library.
|
|
*/
|
|
new_api = FALSE;
|
|
strings = old_strings;
|
|
if(old_dyst->ntoc != 0){
|
|
symbols = old_symbols;
|
|
symbols64 = old_symbols64;
|
|
}
|
|
else{
|
|
if(old_ofile->mh != NULL){
|
|
symbols = old_symbols + old_dyst->iextdefsym;
|
|
symbols64 = NULL;
|
|
}
|
|
else{
|
|
symbols64 = old_symbols64 + old_dyst->iextdefsym;
|
|
symbols = NULL;
|
|
}
|
|
}
|
|
for(i = 0; i < new_dyst->nextdefsym; i++){
|
|
if(new_ofile->mh != NULL)
|
|
n_strx = new_symbols[i + new_dyst->iextdefsym].n_un.n_strx;
|
|
else
|
|
n_strx = new_symbols64[i + new_dyst->iextdefsym].n_un.n_strx;
|
|
symbol_name = new_strings + n_strx;
|
|
if(old_dyst->ntoc != 0){
|
|
if(new_ofile->mh != NULL){
|
|
toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc,
|
|
sizeof(struct dylib_table_of_contents),
|
|
(int (*)(const void *, const void *))
|
|
dylib_bsearch);
|
|
}
|
|
else{
|
|
toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc,
|
|
sizeof(struct dylib_table_of_contents),
|
|
(int (*)(const void *, const void *))
|
|
dylib_bsearch64);
|
|
}
|
|
found = toc != NULL;
|
|
}
|
|
else{
|
|
if(new_ofile->mh != NULL){
|
|
sym = bsearch(symbol_name, symbols, old_dyst->nextdefsym,
|
|
sizeof(struct nlist),
|
|
(int (*)(const void *, const void *))
|
|
nlist_bsearch);
|
|
found = sym != NULL;
|
|
}
|
|
else{
|
|
sym64 = bsearch(symbol_name, symbols64,old_dyst->nextdefsym,
|
|
sizeof(struct nlist_64),
|
|
(int (*)(const void *, const void *))
|
|
nlist_bsearch64);
|
|
found = sym64 != NULL;
|
|
}
|
|
}
|
|
if(found == FALSE){
|
|
if(new_api == FALSE){
|
|
if(arch_name != NULL)
|
|
printf("For architecture %s compatibility versions are "
|
|
"the same but new symbols defined in %s not "
|
|
"defined in %s:\n",arch_name, new_dylib, old_dylib);
|
|
else
|
|
printf("compatibility versions are the same but new "
|
|
"symbols defined in %s not defined in %s:\n",
|
|
new_dylib, old_dylib);
|
|
new_api = TRUE;
|
|
compatible = FALSE;
|
|
}
|
|
printf("%s\n", symbol_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function for bsearch() for finding a symbol name in a dylib table of
|
|
* contents.
|
|
*/
|
|
static
|
|
int
|
|
dylib_bsearch(
|
|
const char *symbol_name,
|
|
const struct dylib_table_of_contents *toc)
|
|
{
|
|
return(strcmp(symbol_name,
|
|
strings + symbols[toc->symbol_index].n_un.n_strx));
|
|
}
|
|
|
|
static
|
|
int
|
|
dylib_bsearch64(
|
|
const char *symbol_name,
|
|
const struct dylib_table_of_contents *toc)
|
|
{
|
|
return(strcmp(symbol_name,
|
|
strings + symbols64[toc->symbol_index].n_un.n_strx));
|
|
}
|
|
|
|
/*
|
|
* Function for bsearch() for finding a symbol name in the sorted list of
|
|
* defined external symbols.
|
|
*/
|
|
static
|
|
int
|
|
nlist_bsearch(
|
|
const char *symbol_name,
|
|
const struct nlist *sym)
|
|
{
|
|
return(strcmp(symbol_name, strings + sym->n_un.n_strx));
|
|
}
|
|
|
|
static
|
|
int
|
|
nlist_bsearch64(
|
|
const char *symbol_name,
|
|
const struct nlist_64 *sym64)
|
|
{
|
|
return(strcmp(symbol_name, strings + sym64->n_un.n_strx));
|
|
}
|