1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#import <stdio.h>
24#import <stdlib.h>
25
26#import "stuff/ofile.h"
27#import "stuff/errors.h"
28#import "stuff/bytesex.h"
29#import "stuff/allocate.h"
30
31/* name of the program for error messages (argv[0]) */
32__private_extern__ char *progname = NULL;
33
34/* The filenames of the old and new dylib */
35static char *old_dylib = NULL;
36static char *new_dylib = NULL;
37
38/*
39 * This is a flag use by process_old() and compare() to make sure each
40 * architecture in the old library is in the new library.
41 */
42static enum bool arch_processed = FALSE;
43static char *arch_name_being_processed = NULL;
44
45/* The result of the dylib comparison */
46static enum bool compatible = TRUE;
47
48/* the byte sex of the machine this program is running on */
49static enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX;
50
51/*
52 * These are pointers to strings and symbols used to search of the table of
53 * contents of a library.  These have to be static and not local so that
54 * check_global_symbols() can set them and that dylib_bsearch() can use them.
55 */
56static char *strings = NULL;
57static struct nlist *symbols = NULL;
58static struct nlist_64 *symbols64 = NULL;
59
60static void process_old(
61    struct ofile *ofile,
62    char *arch_name,
63    void *cookie);
64
65static void compare(
66    struct ofile *new_ofile,
67    char *arch_name,
68    void *cookie);
69
70static void check_dylib(
71    struct ofile *ofile,
72    char *arch_name);
73
74static void check_global_symbols(
75    struct ofile *new_ofile,
76    struct ofile *old_ofile,
77    char *arch_name,
78    enum bool new_api_allowed);
79
80static int dylib_bsearch(
81    const char *symbol_name,
82    const struct dylib_table_of_contents *toc);
83
84static int dylib_bsearch64(
85    const char *symbol_name,
86    const struct dylib_table_of_contents *toc);
87
88static int nlist_bsearch(
89    const char *symbol_name,
90    const struct nlist *sym);
91
92static int nlist_bsearch64(
93    const char *symbol_name,
94    const struct nlist_64 *sym64);
95
96/* apple_version is created by the libstuff/Makefile */
97extern char apple_version[];
98char *version = apple_version;
99
100/*
101 * The program cmpdylib.  This compares an old and an new dynamic shared library
102 * for compatiblity.  Usage:
103 *
104 *	cmpdylib old_dylib new_dylib
105 *
106 * It exits non-zero for incompatible libraries and prints why the libraries are
107 * incompatible.  It exit zero and prints nothing for compatible libraries.
108 */
109int
110main(
111int argc,
112char *argv[],
113char *envp[])
114{
115	progname = argv[0];
116	host_byte_sex = get_host_byte_sex();
117
118	if(argc != 3){
119	    fprintf(stderr, "Usage: %s old_dylib new_dylib\n", progname);
120	    exit(EXIT_FAILURE);
121	}
122	old_dylib = argv[1];
123	new_dylib = argv[2];
124
125	ofile_process(old_dylib, NULL, 0, TRUE, TRUE, TRUE, FALSE, process_old,
126		      NULL);
127
128	if(compatible == TRUE)
129	    return(EXIT_SUCCESS);
130	else
131	    return(EXIT_FAILURE);
132}
133
134/*
135 * process_old() is called once for each architecture in the old dynamic shared
136 * library and then causes compare() to be called for the same architecture
137 * in the new dynamic shared library.
138 */
139static
140void
141process_old(
142struct ofile *old_ofile,
143char *arch_name,
144void *cookie)
145{
146    struct arch_flag arch_flag;
147
148	/* check to make sure this is a dynamic shared library */
149	check_dylib(old_ofile, arch_name);
150
151	/* fill in the architecure info */
152	arch_flag.name = (char *)get_arch_name_from_types(
153						old_ofile->mh_cputype,
154						old_ofile->mh_cpusubtype);
155	arch_flag.cputype = old_ofile->mh_cputype;
156	arch_flag.cpusubtype = old_ofile->mh_cpusubtype;
157
158	arch_processed = FALSE;
159	arch_name_being_processed = arch_name;
160
161	ofile_process(new_dylib, &arch_flag, 1, FALSE, TRUE, TRUE, FALSE,
162		      compare, old_ofile);
163
164	if(arch_processed == FALSE)
165	    fatal("new dynamic shared library: %s  does not contain "
166		  "architecture %s\n", new_dylib, arch_flag.name);
167}
168
169/*
170 * compare() checks the new dynamic shared library against the old one for the
171 * same architecture.  The old dynamic shared library's ofile struct is passed
172 * as the cookie.
173 */
174static
175void
176compare(
177struct ofile *new_ofile,
178char *arch_name,
179void *cookie)
180{
181    uint32_t i;
182    struct load_command *lc;
183    struct ofile *old_ofile;
184    struct dylib_command *old_dl, *new_dl;
185    char *old_install_name, *new_install_name;
186    enum bool new_api_allowed;
187    uint32_t ncmds;
188
189	arch_name = arch_name_being_processed;
190
191	/* check to make sure this is a dynamic shared library */
192	check_dylib(new_ofile, arch_name);
193
194	old_ofile = (struct ofile *)cookie;
195
196	/* Get the LC_ID_DYLIB from the old dylib */
197	old_dl = NULL;
198	lc = old_ofile->load_commands;
199	if(old_ofile->mh != NULL)
200	    ncmds = old_ofile->mh->ncmds;
201	else
202	    ncmds = old_ofile->mh64->ncmds;
203	for(i = 0; i < ncmds; i++){
204	    if(old_dl == NULL && lc->cmd == LC_ID_DYLIB){
205		old_dl = (struct dylib_command *)lc;
206	    }
207	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
208	}
209	if(old_dl == NULL){
210	    if(arch_name != NULL)
211		fatal("malformed dynamic shared library: %s (for architecture "
212		      "%s) (has no dylib id command)", old_dylib, arch_name);
213	    else
214		fatal("malformed dynamic shared library: %s (has no dylib id "
215		      "command)", old_dylib);
216	}
217	old_install_name = (char *)old_dl + old_dl->dylib.name.offset;
218	if(old_dl->dylib.current_version <
219	   old_dl->dylib.compatibility_version){
220	    if(arch_name != NULL)
221		fatal("malformed dynamic shared library: %s (for architecture "
222		      "%s) (current version less than compatibility_version)",
223		      old_dylib, arch_name);
224	    else
225		fatal("malformed dynamic shared library: %s (current version "
226		      "less than compatibility_version)", old_dylib);
227	}
228
229	/* Get the LC_ID_DYLIB from the new dylib */
230	new_dl = NULL;
231	lc = new_ofile->load_commands;
232	if(new_ofile->mh != NULL)
233	    ncmds = new_ofile->mh->ncmds;
234	else
235	    ncmds = new_ofile->mh64->ncmds;
236	for(i = 0; i < ncmds; i++){
237	    if(new_dl == NULL && lc->cmd == LC_ID_DYLIB){
238		new_dl = (struct dylib_command *)lc;
239	    }
240	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
241	}
242	if(new_dl == NULL){
243	    if(arch_name != NULL)
244		fatal("malformed dynamic shared library: %s (for architecture "
245		      "%s) (has no dylib id command)", new_dylib, arch_name);
246	    else
247		fatal("malformed dynamic shared library: %s (has no dylib id "
248		      "command)", new_dylib);
249	}
250	new_install_name = (char *)new_dl + new_dl->dylib.name.offset;
251	if(new_dl->dylib.current_version <
252	   new_dl->dylib.compatibility_version){
253	    if(arch_name != NULL)
254		fatal("malformed dynamic shared library: %s (for architecture "
255		      "%s) (current version less than compatibility_version)",
256		      new_dylib, arch_name);
257	    else
258		fatal("malformed dynamic shared library: %s (current version "
259		      "less than compatibility_version)", new_dylib);
260	}
261
262	/* check the values of the LC_ID_DYLIB's */
263	if(strcmp(old_install_name, new_install_name) != 0){
264	    if(arch_name != NULL)
265		printf("For architecture %s ", arch_name);
266	    printf("dynamic shared libraries have different install names (%s "
267		   "and %s)\n", old_install_name, new_install_name);
268	    compatible = FALSE;
269	}
270	if(old_dl->dylib.current_version >
271	   new_dl->dylib.current_version){
272	    if(arch_name != NULL)
273		printf("For architecture %s ", arch_name);
274	    printf("current version of old dynamic shared library (%u) "
275		   "greater than new dynamic shared library (%u)\n",
276		   old_dl->dylib.current_version,new_dl->dylib.current_version);
277	    compatible = FALSE;
278	}
279	if(old_dl->dylib.compatibility_version >
280	   new_dl->dylib.compatibility_version){
281	    if(arch_name != NULL)
282		printf("For architecture %s ", arch_name);
283	    printf("compatibility version of old dynamic shared library (%u) "
284		   "greater than new dynamic shared library (%u)\n",
285		   old_dl->dylib.compatibility_version,
286		   new_dl->dylib.compatibility_version);
287	    compatible = FALSE;
288	    new_api_allowed = TRUE;
289	}
290	else{
291	    if(new_dl->dylib.compatibility_version !=
292	       old_dl->dylib.compatibility_version)
293		new_api_allowed = TRUE;
294	    else
295		new_api_allowed = FALSE;
296	}
297
298	check_global_symbols(new_ofile, old_ofile, arch_name, new_api_allowed);
299
300	arch_processed = TRUE;
301}
302
303/*
304 * check_dylib() checks to make sure this is a dynamic shared library.  If not
305 * it prints an error and exits.
306 */
307static
308void
309check_dylib(
310struct ofile *ofile,
311char *arch_name)
312{
313	if(ofile->file_type == OFILE_FAT){
314	    if(ofile->arch_type != OFILE_Mach_O ||
315	       (ofile->mh_filetype != MH_DYLIB &&
316	        ofile->mh_filetype != MH_DYLIB_STUB))
317	    fatal("for architecture %s file: %s is not a dynamic shared "
318		  "library", ofile->arch_flag.name, ofile->file_name);
319	}
320	else
321	    if(ofile->file_type != OFILE_Mach_O ||
322	       (ofile->mh_filetype != MH_DYLIB &&
323	        ofile->mh_filetype != MH_DYLIB_STUB))
324		fatal("file: %s is not a dynamic shared library",
325		      ofile->file_name);
326}
327
328/*
329 * check_global_symbols() checks to see if all the global symbols defined in the
330 * old library are defined in the new library.  If not it prints the ones not
331 * defined and sets compatible to FALSE.  If new_api_allowed is FALSE then it
332 * checks to see if there are any global symbols that are in the new library
333 * that are not in the old library.  If so it prints those and sets compatible
334 * to FALSE.
335 */
336static
337void
338check_global_symbols(
339struct ofile *new_ofile,
340struct ofile *old_ofile,
341char *arch_name,
342enum bool new_api_allowed)
343{
344    uint32_t i;
345    struct load_command *lc;
346    enum bool new_api, missing_symbols, found;
347
348    struct symtab_command *old_st, *new_st;
349    struct dysymtab_command *old_dyst, *new_dyst;
350    struct nlist *old_symbols, *new_symbols, *sym;
351    struct nlist_64 *old_symbols64, *new_symbols64, *sym64;
352    char *old_strings, *new_strings;
353    struct dylib_table_of_contents *old_tocs, *new_tocs, *toc;
354    char *symbol_name;
355    uint32_t ncmds, n_strx;
356
357	/*
358	 * Pickup the symbolic info for the old dylib.
359	 */
360	old_st = NULL;
361	old_dyst = NULL;
362	lc = old_ofile->load_commands;
363	if(old_ofile->mh != NULL)
364	    ncmds = old_ofile->mh->ncmds;
365	else
366	    ncmds = old_ofile->mh64->ncmds;
367	for(i = 0; i < ncmds; i++){
368	    if(old_st == NULL && lc->cmd == LC_SYMTAB){
369		old_st = (struct symtab_command *)lc;
370	    }
371	    else if(old_dyst == NULL && lc->cmd == LC_DYSYMTAB){
372		old_dyst = (struct dysymtab_command *)lc;
373	    }
374	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
375	}
376	if(old_st == NULL || old_st->nsyms == 0){
377	    if(arch_name != NULL)
378		fatal("old dynamic shared library: %s (for architecture %s) "
379		      "has no symbol table", old_dylib, arch_name);
380	    else
381		fatal("old dynamic shared library: %s has no symbol table",
382		      old_dylib);
383	}
384	if(old_ofile->mh != NULL){
385	    old_symbols = (struct nlist *)
386		(old_ofile->object_addr + old_st->symoff);
387	    old_symbols64 = NULL;
388	}
389	else{
390	    old_symbols64 = (struct nlist_64 *)
391		(old_ofile->object_addr + old_st->symoff);
392	    old_symbols = NULL;
393	}
394	old_tocs = (struct dylib_table_of_contents *)
395		(old_ofile->object_addr + old_dyst->tocoff);
396	old_strings = (char *)
397		(old_ofile->object_addr + old_st->stroff);
398	if(old_ofile->object_byte_sex != host_byte_sex){
399	    if(old_ofile->mh != NULL)
400		swap_nlist(old_symbols, old_st->nsyms, host_byte_sex);
401	    else
402		swap_nlist_64(old_symbols64, old_st->nsyms, host_byte_sex);
403	    swap_dylib_table_of_contents(old_tocs, old_dyst->ntoc,
404		    host_byte_sex);
405	}
406	for(i = 0; i < old_st->nsyms; i++){
407	    if(old_ofile->mh != NULL)
408		n_strx = old_symbols[i].n_un.n_strx;
409	    else
410		n_strx = old_symbols64[i].n_un.n_strx;
411	    if(n_strx != 0 && n_strx > old_st->strsize){
412		if(arch_name != NULL)
413		    fatal("malformed dynamic shared library: %s (for "
414			"architecture %s) (bad string table index for symbol "
415			"%u)", old_dylib, arch_name, i);
416		else
417		    fatal("malformed dynamic shared library: %s (bad string "
418			"table index for symbol %u)", old_dylib, i);
419	    }
420	}
421	for(i = 0; i < old_dyst->ntoc; i++){
422	    if(old_tocs[i].symbol_index > old_st->nsyms){
423		if(arch_name != NULL)
424		    fatal("malformed dynamic shared library: %s (for "
425			"architecture %s) (symbol_index field of table of "
426			"contents entry %u past the end of the symbol table)",
427			old_dylib, arch_name, i);
428		else
429		    fatal("malformed dynamic shared library: %s (symbol_index "
430			"field of table of contents entry %u past the end of "
431			"the symbol table)", old_dylib, i);
432	    }
433	}
434
435	/*
436	 * Pickup the symbolic info for the new dylib.
437	 */
438	new_st = NULL;
439	new_dyst = NULL;
440	lc = new_ofile->load_commands;
441	if(new_ofile->mh != NULL)
442	    ncmds = new_ofile->mh->ncmds;
443	else
444	    ncmds = new_ofile->mh64->ncmds;
445	for(i = 0; i < ncmds; i++){
446	    if(new_st == NULL && lc->cmd == LC_SYMTAB){
447		new_st = (struct symtab_command *)lc;
448	    }
449	    else if(new_dyst == NULL && lc->cmd == LC_DYSYMTAB){
450		new_dyst = (struct dysymtab_command *)lc;
451	    }
452	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
453	}
454	if(new_st == NULL || new_st->nsyms == 0){
455	    if(arch_name != NULL)
456		fatal("new dynamic shared library: %s (for architecture %s) "
457		      "has no symbol table", new_dylib, arch_name);
458	    else
459		fatal("new dynamic shared library: %s has no symbol table",
460		      new_dylib);
461	}
462	if(new_ofile->mh != NULL){
463	    new_symbols = (struct nlist *)
464		(new_ofile->object_addr + new_st->symoff);
465	    new_symbols64 = NULL;
466	}
467	else{
468	    new_symbols64 = (struct nlist_64 *)
469		(new_ofile->object_addr + new_st->symoff);
470	    new_symbols = NULL;
471	}
472	new_strings = (char *)
473		(new_ofile->object_addr + new_st->stroff);
474	new_tocs = (struct dylib_table_of_contents *)
475		(new_ofile->object_addr + new_dyst->tocoff);
476	if(new_ofile->object_byte_sex != host_byte_sex){
477	    if(new_ofile->mh != NULL)
478		swap_nlist(new_symbols, new_st->nsyms, host_byte_sex);
479	    else
480		swap_nlist_64(new_symbols64, new_st->nsyms, host_byte_sex);
481	    swap_dylib_table_of_contents(new_tocs, new_dyst->ntoc,
482		    host_byte_sex);
483	}
484	for(i = 0; i < new_st->nsyms; i++){
485	    if(new_ofile->mh != NULL)
486		n_strx = new_symbols[i].n_un.n_strx;
487	    else
488		n_strx = new_symbols64[i].n_un.n_strx;
489	    if(n_strx != 0 && n_strx > new_st->strsize){
490		if(arch_name != NULL)
491		    fatal("malformed dynamic shared library: %s (for "
492			"architecture %s) (bad string table index for symbol "
493			"%u)", new_dylib, arch_name, i);
494		else
495		    fatal("malformed dynamic shared library: %s (bad string "
496			"table index for symbol %u)", new_dylib, i);
497	    }
498	}
499	for(i = 0; i < new_dyst->ntoc; i++){
500	    if(new_tocs[i].symbol_index > new_st->nsyms){
501		if(arch_name != NULL)
502		    fatal("malformed dynamic shared library: %s (for "
503			"architecture %s) (symbol_index field of table of "
504			"contents entry %u past the end of the symbol table)",
505			new_dylib, arch_name, i);
506		else
507		    fatal("malformed dynamic shared library: %s (symbol_index "
508			"field of table of contents entry %u past the end of "
509			"the symbol table)", new_dylib, i);
510	    }
511	}
512
513	/*
514	 * Now check to see if all the global symbols defined in the old library
515	 * are defined in the new library.  Prints the ones that are not and
516	 * sets compatible to FALSE.
517	 */
518	missing_symbols = FALSE;
519	strings = new_strings;
520	if(new_dyst->ntoc != 0){
521	    symbols = new_symbols;
522	    symbols64 = new_symbols64;
523	}
524	else{
525	    if(new_ofile->mh != NULL){
526		symbols = new_symbols + new_dyst->iextdefsym;
527		symbols64 = NULL;
528	    }
529	    else{
530		symbols64 = new_symbols64 + new_dyst->iextdefsym;
531		symbols = NULL;
532	    }
533	}
534	for(i = 0; i < old_dyst->nextdefsym; i++){
535	    if(new_ofile->mh != NULL)
536		n_strx = old_symbols[i + old_dyst->iextdefsym].n_un.n_strx;
537	    else
538		n_strx = old_symbols64[i + old_dyst->iextdefsym].n_un.n_strx;
539	    symbol_name = old_strings + n_strx;
540	    if(new_dyst->ntoc != 0){
541		if(new_ofile->mh != NULL){
542		    toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc,
543			          sizeof(struct dylib_table_of_contents),
544			          (int (*)(const void *, const void *))
545				  dylib_bsearch);
546		}
547		else{
548		    toc = bsearch(symbol_name, new_tocs, new_dyst->ntoc,
549			          sizeof(struct dylib_table_of_contents),
550			          (int (*)(const void *, const void *))
551				  dylib_bsearch64);
552		}
553		found = toc != NULL;
554	    }
555	    else{
556		if(new_ofile->mh != NULL){
557		    sym = bsearch(symbol_name, symbols, new_dyst->nextdefsym,
558				  sizeof(struct nlist),
559				  (int (*)(const void *, const void *))
560				  nlist_bsearch);
561		    found = sym != NULL;
562		}
563		else{
564		    sym64 = bsearch(symbol_name, symbols64,new_dyst->nextdefsym,
565				  sizeof(struct nlist_64),
566				  (int (*)(const void *, const void *))
567				  nlist_bsearch64);
568		    found = sym64 != NULL;
569		}
570	    }
571	    if(found == FALSE){
572		if(missing_symbols == FALSE){
573		    if(arch_name != NULL)
574			printf("For architecture %s symbols defined in %s "
575			       "not defined in %s:\n", arch_name, old_dylib,
576			       new_dylib);
577		    else
578			printf("symbols defined in %s not defined in %s:\n",
579			    old_dylib, new_dylib);
580		    missing_symbols = TRUE;
581		    compatible = FALSE;
582		}
583		printf("%s\n", symbol_name);
584	    }
585	}
586
587	/*
588	 * If new api is allowed then checking of global symbols is done.
589	 */
590	if(new_api_allowed == TRUE)
591	    return;
592
593	/*
594	 * New api is not allowed so check to make sure no symbols in the new
595	 * library are not in the old library.
596	 */
597	new_api = FALSE;
598	strings = old_strings;
599	if(old_dyst->ntoc != 0){
600	    symbols = old_symbols;
601	    symbols64 = old_symbols64;
602	}
603	else{
604	    if(old_ofile->mh != NULL){
605		symbols = old_symbols + old_dyst->iextdefsym;
606		symbols64 = NULL;
607	    }
608	    else{
609		symbols64 = old_symbols64 + old_dyst->iextdefsym;
610		symbols = NULL;
611	    }
612	}
613	for(i = 0; i < new_dyst->nextdefsym; i++){
614	    if(new_ofile->mh != NULL)
615		n_strx = new_symbols[i + new_dyst->iextdefsym].n_un.n_strx;
616	    else
617		n_strx = new_symbols64[i + new_dyst->iextdefsym].n_un.n_strx;
618	    symbol_name = new_strings + n_strx;
619	    if(old_dyst->ntoc != 0){
620		if(new_ofile->mh != NULL){
621		    toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc,
622			          sizeof(struct dylib_table_of_contents),
623			          (int (*)(const void *, const void *))
624				  dylib_bsearch);
625		}
626		else{
627		    toc = bsearch(symbol_name, old_tocs, old_dyst->ntoc,
628			          sizeof(struct dylib_table_of_contents),
629			          (int (*)(const void *, const void *))
630				  dylib_bsearch64);
631		}
632		found = toc != NULL;
633	    }
634	    else{
635		if(new_ofile->mh != NULL){
636		    sym = bsearch(symbol_name, symbols, old_dyst->nextdefsym,
637				  sizeof(struct nlist),
638				  (int (*)(const void *, const void *))
639				  nlist_bsearch);
640		    found = sym != NULL;
641		}
642		else{
643		    sym64 = bsearch(symbol_name, symbols64,old_dyst->nextdefsym,
644				  sizeof(struct nlist_64),
645				  (int (*)(const void *, const void *))
646				  nlist_bsearch64);
647		    found = sym64 != NULL;
648		}
649	    }
650	    if(found == FALSE){
651		if(new_api == FALSE){
652		    if(arch_name != NULL)
653			printf("For architecture %s compatibility versions are "
654			    "the same but new symbols defined in %s not "
655			    "defined in %s:\n",arch_name, new_dylib, old_dylib);
656		    else
657			printf("compatibility versions are the same but new "
658			    "symbols defined in %s not defined in %s:\n",
659			    new_dylib, old_dylib);
660		    new_api = TRUE;
661		    compatible = FALSE;
662		}
663		printf("%s\n", symbol_name);
664	    }
665	}
666}
667
668/*
669 * Function for bsearch() for finding a symbol name in a dylib table of
670 * contents.
671 */
672static
673int
674dylib_bsearch(
675const char *symbol_name,
676const struct dylib_table_of_contents *toc)
677{
678	return(strcmp(symbol_name,
679		      strings + symbols[toc->symbol_index].n_un.n_strx));
680}
681
682static
683int
684dylib_bsearch64(
685const char *symbol_name,
686const struct dylib_table_of_contents *toc)
687{
688	return(strcmp(symbol_name,
689		      strings + symbols64[toc->symbol_index].n_un.n_strx));
690}
691
692/*
693 * Function for bsearch() for finding a symbol name in the sorted list of
694 * defined external symbols.
695 */
696static
697int
698nlist_bsearch(
699const char *symbol_name,
700const struct nlist *sym)
701{
702	return(strcmp(symbol_name, strings + sym->n_un.n_strx));
703}
704
705static
706int
707nlist_bsearch64(
708const char *symbol_name,
709const struct nlist_64 *sym64)
710{
711	return(strcmp(symbol_name, strings + sym64->n_un.n_strx));
712}
713