/* * Copyright (c) 1999-2003 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@ */ /* $OpenBSD: nm.c,v 1.4 1997/01/15 23:42:59 millert Exp $ */ /* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Hans Huebner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * The NeXT Computer, Inc. nm(1) program that handles fat files, archives and * Mach-O objects files (no BSD a.out files). A few lines of code were taken * and adapted from the BSD release. * * When processing multiple files which are archives the BSD version of nm * would only print the archive member name (without the -o option) of the * object files before printing the symbols. This version of nm will print the * archive name with the member name in ()'s in this case which makes it clear * which symbols belong to which arguments in the case that multiple arguments * are archives and have members of the same name. * * To allow the "-arch " command line argument the processing of * command line arguments was changed to allow the options to be specified * in more than one group of arguments with each group preceded by a '-'. This * change in behavior would only be noticed if a command line of the form * "nm -n -Q" was used where the BSD version would open a file of the name * "-Q" to process. To do this with this version of nm the new command line * argument "-" would be used to treat all remaining arguments as file names. * So the equivalent command would be "nm -n - -Q". This should not be a * problem as the BSD would treat the command "nm -Q" by saying "-Q" is an * invalid argument which was slightly inconsistant. */ #include /* first so to get rid of a precomp warning */ #include #include #include #include #include #include #include #include "stuff/bool.h" #include "stuff/ofile.h" #include "stuff/errors.h" #include "stuff/allocate.h" #include "stuff/guess_short_name.h" #ifdef LTO_SUPPORT #include "stuff/lto.h" #endif /* LTO_SUPPORT */ /* used by error routines as the name of the program */ char *progname = NULL; /* flags set from the command line arguments */ struct cmd_flags { uint32_t nfiles; enum bool a; /* print all symbol table entries including stabs */ enum bool g; /* print only global symbols */ enum bool n; /* sort numericly rather than alphabetically */ enum bool o; /* prepend file or archive element name to each line */ enum bool p; /* don't sort; print in symbol table order */ enum bool r; /* sort in reverse direction */ enum bool u; /* print only undefined symbols */ enum bool U; /* only undefined symbols */ enum bool m; /* print symbol in Mach-O symbol format */ enum bool x; /* print the symbol table entry in hex and the name */ enum bool j; /* just print the symbol name (no value or type) */ enum bool s; /* print only symbol in the following section */ char *segname, /* segment name for -s */ *sectname; /* section name for -s */ enum bool l; /* print a .section_start symbol if none exists (-s) */ enum bool f; /* print a dynamic shared library flat */ enum bool v; /* sort and print by value diffences ,used with -n -s */ enum bool b; /* print only stabs for the following include */ char *bincl_name; /* the begin include name for -b */ enum bool i; /* start searching for begin include at -iN index */ uint32_t index; /* the index to start searching at */ enum bool A; /* pathname or library name of an object on each line */ enum bool P; /* portable output format */ char *format; /* the -t format */ }; /* These need to be static because of the qsort compare function */ static struct cmd_flags cmd_flags = { 0 }; static char *strings = NULL; static uint32_t strsize = 0; static enum bool compare_lto = FALSE; /* flags set by processing a specific object file */ struct process_flags { uint32_t nsect; /* The nsect, address and size for the */ uint64_t sect_addr, /* section specified by the -s flag */ sect_size; enum bool sect_start_symbol;/* For processing the -l flag, set if a */ /* symbol with the start address of the */ /* section is found */ uint32_t nsects; /* For printing the symbol types, the number */ struct section **sections; /* of sections and an array of section ptrs */ struct section_64 **sections64; unsigned char text_nsect, /* For printing symbols types, T, D, and B */ data_nsect, /* for text, data and bss symbols */ bss_nsect; uint32_t nlibs; /* For printing the twolevel namespace */ char **lib_names; /* references types, the number of libraries */ /* an array of pointers to library names */ }; struct symbol { char *name; char *indr_name; struct nlist_64 nl; }; struct value_diff { uint64_t size; struct symbol symbol; }; static void usage( void); static void nm( struct ofile *ofile, char *arch_name, void *cookie); #ifdef LTO_SUPPORT static void nm_lto( struct ofile *ofile, char *arch_name, struct cmd_flags *cmd_flags); #endif /* LTO_SUPPORT */ static void print_header( struct ofile *ofile, char *arch_name, struct cmd_flags *cmd_flags); static struct symbol *select_symbols( struct ofile *ofile, struct symtab_command *st, struct dysymtab_command *dyst, struct cmd_flags *cmd_flags, struct process_flags *process_flags, uint32_t *nsymbols); static void make_symbol_32( struct symbol *symbol, struct nlist *nl); static void make_symbol_64( struct symbol *symbol, struct nlist_64 *nl); static enum bool select_symbol( struct symbol *symbol, struct cmd_flags *cmd_flags, struct process_flags *process_flags); static void print_mach_symbols( struct ofile *ofile, struct symbol *symbols, uint32_t nsymbols, char *strings, uint32_t strsize, struct cmd_flags *cmd_flags, struct process_flags *process_flags, char *arch_name); static void print_symbols( struct ofile *ofile, struct symbol *symbols, uint32_t nsymbols, char *strings, uint32_t strsize, struct cmd_flags *cmd_flags, struct process_flags *process_flags, char *arch_name, struct value_diff *value_diffs); static char * stab( unsigned char n_type); static int compare( struct symbol *p1, struct symbol *p2); static int value_diff_compare( struct value_diff *p1, struct value_diff *p2); /* apple_version is created by the libstuff/Makefile */ extern char apple_version[]; char *version = apple_version; int main( int argc, char **argv, char **envp) { int i; uint32_t j; struct arch_flag *arch_flags; uint32_t narch_flags; enum bool all_archs; char **files; progname = argv[0]; arch_flags = NULL; narch_flags = 0; all_archs = FALSE; cmd_flags.nfiles = 0; cmd_flags.a = FALSE; cmd_flags.g = FALSE; cmd_flags.n = FALSE; cmd_flags.o = FALSE; cmd_flags.p = FALSE; cmd_flags.r = FALSE; cmd_flags.u = FALSE; cmd_flags.U = FALSE; cmd_flags.m = FALSE; cmd_flags.x = FALSE; cmd_flags.j = FALSE; cmd_flags.s = FALSE; cmd_flags.segname = NULL; cmd_flags.sectname = NULL; cmd_flags.l = FALSE; cmd_flags.f = FALSE; cmd_flags.bincl_name = NULL; cmd_flags.A = FALSE; cmd_flags.P = FALSE; cmd_flags.format = "%llx"; files = allocate(sizeof(char *) * argc); for(i = 1; i < argc; i++){ if(argv[i][0] == '-'){ if(argv[i][1] == '\0' || (argv[i][1] == '-' && argv[i][2] == '\0')){ i++; for( ; i < argc; i++) files[cmd_flags.nfiles++] = argv[i]; break; } if(strcmp(argv[i], "-arch") == 0){ if(i + 1 == argc){ error("missing argument(s) to %s option", argv[i]); usage(); } if(strcmp("all", argv[i+1]) == 0){ all_archs = TRUE; } else{ arch_flags = reallocate(arch_flags, (narch_flags + 1) * sizeof(struct arch_flag)); if(get_arch_from_flag(argv[i+1], arch_flags + narch_flags) == 0){ error("unknown architecture specification flag: " "%s %s", argv[i], argv[i+1]); arch_usage(); usage(); } narch_flags++; } i++; } else if(strcmp(argv[i], "-t") == 0){ if(i + 1 == argc){ error("missing argument to %s option", argv[i]); usage(); } if(argv[i+1][1] != '\0'){ error("invalid argument to option: %s %s", argv[i], argv[i+1]); usage(); } switch(argv[i+1][0]){ case 'd': cmd_flags.format = "%lld"; break; case 'o': cmd_flags.format = "%llo"; break; case 'x': cmd_flags.format = "%llx"; break; default: error("invalid argument to option: %s %s", argv[i], argv[i+1]); usage(); } i++; } else{ for(j = 1; argv[i][j] != '\0'; j++){ switch(argv[i][j]){ case 'a': cmd_flags.a = TRUE; break; case 'g': cmd_flags.g = TRUE; break; case 'n': cmd_flags.n = TRUE; break; case 'o': cmd_flags.o = TRUE; break; case 'p': cmd_flags.p = TRUE; break; case 'r': cmd_flags.r = TRUE; break; case 'u': if(cmd_flags.U == TRUE){ error("can't specifiy both -u and -U"); usage(); } cmd_flags.u = TRUE; break; case 'U': if(cmd_flags.u == TRUE){ error("can't specifiy both -U and -u"); usage(); } cmd_flags.U = TRUE; break; case 'm': cmd_flags.m = TRUE; break; case 'x': cmd_flags.x = TRUE; break; case 'j': cmd_flags.j = TRUE; break; case 's': if(cmd_flags.s == TRUE){ error("more than one -s option specified"); usage(); } cmd_flags.s = TRUE; break; case 'b': if(cmd_flags.b == TRUE){ error("more than one -b option specified"); usage(); } cmd_flags.b = TRUE; break; case 'i': if(cmd_flags.i == TRUE){ error("more than one -i option specified"); usage(); } cmd_flags.i = TRUE; while(isdigit(argv[i][j+1])){ cmd_flags.index = cmd_flags.index * 10 + (argv[i][j+1] - '0'); j++; } case 'l': cmd_flags.l = TRUE; break; case 'f': cmd_flags.f = TRUE; break; case 'v': cmd_flags.v = TRUE; break; case 'A': cmd_flags.A = TRUE; break; case 'P': cmd_flags.P = TRUE; break; default: error("invalid argument -%c", argv[i][j]); usage(); } } if(cmd_flags.s == TRUE && cmd_flags.segname == NULL){ if(i + 2 == argc){ error("missing arguments to -s"); usage(); } cmd_flags.segname = argv[i+1]; cmd_flags.sectname = argv[i+2]; i += 2; } if(cmd_flags.b == TRUE && cmd_flags.bincl_name == NULL){ if(i + 1 == argc){ error("missing arguments to -b"); usage(); } cmd_flags.bincl_name = argv[i+1]; i += 1; } } continue; } files[cmd_flags.nfiles++] = argv[i]; } for(j = 0; j < cmd_flags.nfiles; j++) ofile_process(files[j], arch_flags, narch_flags, all_archs, TRUE, cmd_flags.f, TRUE, nm, &cmd_flags); if(cmd_flags.nfiles == 0) ofile_process("a.out", arch_flags, narch_flags, all_archs, TRUE, cmd_flags.f, TRUE, nm, &cmd_flags); if(errors == 0) return(EXIT_SUCCESS); else return(EXIT_FAILURE); } /* * usage() prints the current usage message and exits indicating failure. */ static void usage( void) { fprintf(stderr, "Usage: %s [-agnopruUmxjlfAP[s segname sectname] [-] " "[-t format] [[-arch ] ...] [file ...]\n", progname); exit(EXIT_FAILURE); } /* * nm() is the routine that gets called by ofile_process() to process single * object files. */ static void nm( struct ofile *ofile, char *arch_name, void *cookie) { uint32_t ncmds, mh_flags; struct cmd_flags *cmd_flags; struct process_flags process_flags; uint32_t i, j, k; struct load_command *lc; struct symtab_command *st; struct dysymtab_command *dyst; struct segment_command *sg; struct segment_command_64 *sg64; struct section *s; struct section_64 *s64; struct dylib_command *dl; struct symbol *symbols; uint32_t nsymbols; struct value_diff *value_diffs; char *short_name, *has_suffix; enum bool is_framework; cmd_flags = (struct cmd_flags *)cookie; process_flags.nsect = -1; process_flags.sect_addr = 0; process_flags.sect_size = 0; process_flags.sect_start_symbol = FALSE; process_flags.nsects = 0; process_flags.sections = NULL; process_flags.text_nsect = NO_SECT; process_flags.data_nsect = NO_SECT; process_flags.bss_nsect = NO_SECT; process_flags.nlibs = 0; process_flags.lib_names = NULL; if(ofile->mh == NULL && ofile->mh64 == NULL){ #ifdef LTO_SUPPORT if(ofile->lto != NULL) nm_lto(ofile, arch_name, cmd_flags); #endif /* LTO_SUPPORT */ return; } st = NULL; dyst = NULL; lc = ofile->load_commands; if(ofile->mh != NULL){ ncmds = ofile->mh->ncmds; mh_flags = ofile->mh->flags; } else{ ncmds = ofile->mh64->ncmds; mh_flags = ofile->mh64->flags; } for(i = 0; i < ncmds; i++){ if(st == NULL && lc->cmd == LC_SYMTAB){ st = (struct symtab_command *)lc; } else if(dyst == NULL && lc->cmd == LC_DYSYMTAB){ dyst = (struct dysymtab_command *)lc; } else if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; process_flags.nsects += sg->nsects; } else if(lc->cmd == LC_SEGMENT_64){ sg64 = (struct segment_command_64 *)lc; process_flags.nsects += sg64->nsects; } else if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL && (lc->cmd == LC_LOAD_DYLIB || lc->cmd == LC_LOAD_WEAK_DYLIB || lc->cmd == LC_LAZY_LOAD_DYLIB || lc->cmd == LC_REEXPORT_DYLIB || lc->cmd == LC_LOAD_UPWARD_DYLIB)){ process_flags.nlibs++; } lc = (struct load_command *)((char *)lc + lc->cmdsize); } if(st == NULL || st->nsyms == 0){ warning("no name list"); return; } if(process_flags.nsects > 0){ if(ofile->mh != NULL){ process_flags.sections = (struct section **) malloc(sizeof(struct section *) * process_flags.nsects); process_flags.sections64 = NULL; } else{ process_flags.sections64 = (struct section_64 **) malloc(sizeof(struct section_64 *) * process_flags.nsects); process_flags.sections = NULL; } k = 0; lc = ofile->load_commands; for (i = 0; i < ncmds; i++){ if(lc->cmd == LC_SEGMENT){ sg = (struct segment_command *)lc; s = (struct section *) ((char *)sg + sizeof(struct segment_command)); for(j = 0; j < sg->nsects; j++){ if(strcmp((s + j)->sectname, SECT_TEXT) == 0 && strcmp((s + j)->segname, SEG_TEXT) == 0) process_flags.text_nsect = k + 1; else if(strcmp((s + j)->sectname, SECT_DATA) == 0 && strcmp((s + j)->segname, SEG_DATA) == 0) process_flags.data_nsect = k + 1; else if(strcmp((s + j)->sectname, SECT_BSS) == 0 && strcmp((s + j)->segname, SEG_DATA) == 0) process_flags.bss_nsect = k + 1; if(cmd_flags->segname != NULL){ if(strncmp((s + j)->sectname, cmd_flags->sectname, sizeof(s->sectname)) == 0 && strncmp((s + j)->segname, cmd_flags->segname, sizeof(s->segname)) == 0){ process_flags.nsect = k + 1; process_flags.sect_addr = (s + j)->addr; process_flags.sect_size = (s + j)->size; } } process_flags.sections[k++] = s + j; } } else if(lc->cmd == LC_SEGMENT_64){ sg64 = (struct segment_command_64 *)lc; s64 = (struct section_64 *) ((char *)sg64 + sizeof(struct segment_command_64)); for(j = 0; j < sg64->nsects; j++){ if(strcmp((s64 + j)->sectname, SECT_TEXT) == 0 && strcmp((s64 + j)->segname, SEG_TEXT) == 0) process_flags.text_nsect = k + 1; else if(strcmp((s64 + j)->sectname, SECT_DATA) == 0 && strcmp((s64 + j)->segname, SEG_DATA) == 0) process_flags.data_nsect = k + 1; else if(strcmp((s64 + j)->sectname, SECT_BSS) == 0 && strcmp((s64 + j)->segname, SEG_DATA) == 0) process_flags.bss_nsect = k + 1; if(cmd_flags->segname != NULL){ if(strncmp((s64 + j)->sectname, cmd_flags->sectname, sizeof(s64->sectname)) == 0 && strncmp((s64 + j)->segname, cmd_flags->segname, sizeof(s64->segname)) == 0){ process_flags.nsect = k + 1; process_flags.sect_addr = (s64 + j)->addr; process_flags.sect_size = (s64 + j)->size; } } process_flags.sections64[k++] = s64 + j; } } lc = (struct load_command *) ((char *)lc + lc->cmdsize); } } if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL && process_flags.nlibs > 0){ process_flags.lib_names = (char **) malloc(sizeof(char *) * process_flags.nlibs); j = 0; lc = ofile->load_commands; for (i = 0; i < ncmds; i++){ if(lc->cmd == LC_LOAD_DYLIB || lc->cmd == LC_LOAD_WEAK_DYLIB || lc->cmd == LC_LAZY_LOAD_DYLIB || lc->cmd == LC_REEXPORT_DYLIB || lc->cmd == LC_LOAD_UPWARD_DYLIB){ dl = (struct dylib_command *)lc; process_flags.lib_names[j] = (char *)dl + dl->dylib.name.offset; short_name = guess_short_name(process_flags.lib_names[j], &is_framework, &has_suffix); if(short_name != NULL) process_flags.lib_names[j] = short_name; j++; } lc = (struct load_command *) ((char *)lc + lc->cmdsize); } } /* select symbols to print */ symbols = select_symbols(ofile, st, dyst, cmd_flags, &process_flags, &nsymbols); /* set names in the symbols to be printed */ strings = ofile->object_addr + st->stroff; strsize = st->strsize; compare_lto = FALSE; if(cmd_flags->x == FALSE){ for(i = 0; i < nsymbols; i++){ if(symbols[i].nl.n_un.n_strx == 0) symbols[i].name = ""; else if((int)symbols[i].nl.n_un.n_strx < 0 || (uint32_t)symbols[i].nl.n_un.n_strx > st->strsize) symbols[i].name = "bad string index"; else symbols[i].name = symbols[i].nl.n_un.n_strx + strings; if((symbols[i].nl.n_type & N_STAB) == 0 && (symbols[i].nl.n_type & N_TYPE) == N_INDR){ if(symbols[i].nl.n_value == 0) symbols[i].indr_name = ""; else if(symbols[i].nl.n_value > st->strsize) symbols[i].indr_name = "bad string index"; else symbols[i].indr_name = strings + symbols[i].nl.n_value; } } if(cmd_flags->l == TRUE && (int32_t)process_flags.nsect != -1 && process_flags.sect_start_symbol == FALSE && process_flags.sect_size != 0){ symbols = reallocate(symbols, (nsymbols + 1) * sizeof(struct symbol)); symbols[nsymbols].name = ".section_start"; symbols[nsymbols].nl.n_type = N_SECT; symbols[nsymbols].nl.n_sect = process_flags.nsect; symbols[nsymbols].nl.n_value = process_flags.sect_addr; nsymbols++; } } /* print header if needed */ print_header(ofile, arch_name, cmd_flags); /* sort the symbols if needed */ if(cmd_flags->p == FALSE && cmd_flags->b == FALSE) qsort(symbols, nsymbols, sizeof(struct symbol), (int (*)(const void *, const void *))compare); value_diffs = NULL; if(cmd_flags->v == TRUE && cmd_flags->n == TRUE && cmd_flags->r == FALSE && cmd_flags->s == TRUE && nsymbols != 0){ value_diffs = allocate(sizeof(struct value_diff) * nsymbols); for(i = 0; i < nsymbols - 1; i++){ value_diffs[i].symbol = symbols[i]; value_diffs[i].size = symbols[i+1].nl.n_value - symbols[i].nl.n_value; } value_diffs[i].symbol = symbols[i]; value_diffs[i].size = process_flags.sect_addr + process_flags.sect_size - symbols[i].nl.n_value; qsort(value_diffs, nsymbols, sizeof(struct value_diff), (int (*)(const void *, const void *))value_diff_compare); for(i = 0; i < nsymbols; i++) symbols[i] = value_diffs[i].symbol; } /* now print the symbols as specified by the flags */ if(cmd_flags->m == TRUE) print_mach_symbols(ofile, symbols, nsymbols, strings, st->strsize, cmd_flags, &process_flags, arch_name); else print_symbols(ofile, symbols, nsymbols, strings, st->strsize, cmd_flags, &process_flags, arch_name, value_diffs); free(symbols); if(process_flags.sections != NULL){ if(process_flags.sections != NULL){ free(process_flags.sections); process_flags.sections = NULL; } if(process_flags.sections64 != NULL){ free(process_flags.sections64); process_flags.sections64 = NULL; } } } #ifdef LTO_SUPPORT /* * In translating the information in an lto bitcode file to something that looks * like what would be in a Mach-O file for use by print_mach_symbols() we use * these sections for the CODE, DATA and RODATA defined symbols. */ static struct section lto_code_section = { "CODE", "LTO" }; static struct section lto_data_section = { "DATA", "LTO" }; static struct section lto_rodata_section = { "RODATA", "LTO" }; static struct section *lto_sections[3] = { <o_code_section, <o_data_section, <o_rodata_section }; static struct section_64 lto_code_section64 = { "CODE", "LTO" }; static struct section_64 lto_data_section64 = { "DATA", "LTO" }; static struct section_64 lto_rodata_section64 = { "RODATA", "LTO" }; static struct section_64 *lto_sections64[3] = { <o_code_section64, <o_data_section64, <o_rodata_section64 }; /* * nm_lto() is called by nm() to process an lto bitcode file. */ static void nm_lto( struct ofile *ofile, char *arch_name, struct cmd_flags *cmd_flags) { uint32_t nsyms, nsymbols, i; struct symbol symbol, *symbols; struct process_flags process_flags; process_flags.nsect = -1; if(cmd_flags->segname != NULL && strcmp(cmd_flags->segname, "LTO") == 0){ if(strcmp(cmd_flags->sectname, "CODE") == 0) process_flags.nsect = 1; else if(strcmp(cmd_flags->sectname, "DATA") == 0) process_flags.nsect = 2; else if(strcmp(cmd_flags->sectname, "RODATA") == 0) process_flags.nsect = 3; } process_flags.sect_addr = 0; process_flags.sect_size = 0; process_flags.sect_start_symbol = FALSE; process_flags.nsects = 3; if((ofile->lto_cputype & CPU_ARCH_ABI64) != CPU_ARCH_ABI64){ process_flags.sections = lto_sections; process_flags.sections64 = NULL; } else{ process_flags.sections64 = lto_sections64; process_flags.sections = NULL; } process_flags.text_nsect = 1; process_flags.data_nsect = 2; process_flags.bss_nsect = NO_SECT; process_flags.nlibs = 0; process_flags.lib_names = NULL; nsyms = lto_get_nsyms(ofile->lto); symbols = allocate(sizeof(struct symbol) * nsyms); nsymbols = 0; for(i = 0; i < nsyms; i++){ symbol.name = lto_symbol_name(ofile->lto, i); symbol.indr_name = NULL; lto_get_nlist_64(&(symbol.nl), ofile->lto, i); if(select_symbol(&symbol, cmd_flags, &process_flags)) symbols[nsymbols++] = symbol; } print_header(ofile, arch_name, cmd_flags); /* reset these as the can be used by compare() with -x */ strings = NULL; strsize = 0; compare_lto = TRUE; /* sort the symbols if needed */ if(cmd_flags->p == FALSE) qsort(symbols, nsymbols, sizeof(struct symbol), (int (*)(const void *, const void *))compare); /* now print the symbols as specified by the flags */ if(cmd_flags->m == TRUE) print_mach_symbols(ofile, symbols, nsymbols, NULL, 0, cmd_flags, &process_flags, arch_name); else print_symbols(ofile, symbols, nsymbols, NULL, 0, cmd_flags, &process_flags, arch_name, NULL); free(symbols); } #endif /* LTO_SUPPORT */ /* print header if needed */ static void print_header( struct ofile *ofile, char *arch_name, struct cmd_flags *cmd_flags) { if((ofile->member_ar_hdr != NULL || ofile->dylib_module_name != NULL || cmd_flags->nfiles > 1 || arch_name != NULL) && (cmd_flags->o == FALSE && cmd_flags->A == FALSE)){ if(ofile->dylib_module_name != NULL){ printf("\n%s(%s)", ofile->file_name, ofile->dylib_module_name); } else if(ofile->member_ar_hdr != NULL){ printf("\n%s(%.*s)", ofile->file_name, (int)ofile->member_name_size, ofile->member_name); } else printf("\n%s", ofile->file_name); if(arch_name != NULL) printf(" (for architecture %s):\n", arch_name); else printf(":\n"); } } /* * select_symbols returns an allocated array of symbol structs as the symbols * that are to be printed based on the flags. The number of symbols in the * array returned in returned indirectly through nsymbols. */ static struct symbol * select_symbols( struct ofile *ofile, struct symtab_command *st, struct dysymtab_command *dyst, struct cmd_flags *cmd_flags, struct process_flags *process_flags, uint32_t *nsymbols) { uint32_t i, flags, nest; struct nlist *all_symbols; struct nlist_64 *all_symbols64; struct symbol *selected_symbols, symbol; struct dylib_module m; struct dylib_module_64 m64; struct dylib_reference *refs; enum bool found; uint32_t irefsym, nrefsym, nextdefsym, iextdefsym, nlocalsym, ilocalsym; if(ofile->mh != NULL){ all_symbols = (struct nlist *)(ofile->object_addr + st->symoff); all_symbols64 = NULL; } else{ all_symbols = NULL; all_symbols64 = (struct nlist_64 *)(ofile->object_addr +st->symoff); } selected_symbols = allocate(sizeof(struct symbol) * st->nsyms); *nsymbols = 0; if(ofile->object_byte_sex != get_host_byte_sex()){ if(ofile->mh != NULL) swap_nlist(all_symbols, st->nsyms, get_host_byte_sex()); else swap_nlist_64(all_symbols64, st->nsyms, get_host_byte_sex()); } if(ofile->dylib_module != NULL){ if(ofile->mh != NULL){ m = *ofile->dylib_module; if(ofile->object_byte_sex != get_host_byte_sex()) swap_dylib_module(&m, 1, get_host_byte_sex()); irefsym = m.irefsym; nrefsym = m.nrefsym; nextdefsym = m.nextdefsym; iextdefsym = m.iextdefsym; nlocalsym = m.nlocalsym; ilocalsym = m.ilocalsym; } else{ m64 = *ofile->dylib_module64; if(ofile->object_byte_sex != get_host_byte_sex()) swap_dylib_module_64(&m64, 1, get_host_byte_sex()); irefsym = m64.irefsym; nrefsym = m64.nrefsym; nextdefsym = m64.nextdefsym; iextdefsym = m64.iextdefsym; nlocalsym = m64.nlocalsym; ilocalsym = m64.ilocalsym; } refs = (struct dylib_reference *)(ofile->object_addr + dyst->extrefsymoff); if(ofile->object_byte_sex != get_host_byte_sex()){ swap_dylib_reference(refs + irefsym, nrefsym, get_host_byte_sex()); } for(i = 0; i < nrefsym; i++){ flags = refs[i + irefsym].flags; if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + refs[i + irefsym].isym); else make_symbol_64(&symbol, all_symbols64 + refs[i + irefsym].isym); if(flags == REFERENCE_FLAG_UNDEFINED_NON_LAZY || flags == REFERENCE_FLAG_UNDEFINED_LAZY || cmd_flags->m == TRUE) symbol.nl.n_type = N_UNDF | N_EXT; else symbol.nl.n_type = N_UNDF; symbol.nl.n_desc = (symbol.nl.n_desc &~ REFERENCE_TYPE) | flags; symbol.nl.n_value = 0; if(select_symbol(&symbol, cmd_flags, process_flags)) selected_symbols[(*nsymbols)++] = symbol; } } for(i = 0; i < nextdefsym && iextdefsym + i < st->nsyms; i++){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + iextdefsym + i); else make_symbol_64(&symbol, all_symbols64 + iextdefsym + i); if(select_symbol(&symbol, cmd_flags, process_flags)) selected_symbols[(*nsymbols)++] = symbol; } for(i = 0; i < nlocalsym && ilocalsym + i < st->nsyms; i++){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + ilocalsym + i); else make_symbol_64(&symbol, all_symbols64 + ilocalsym + i); if(select_symbol(&symbol, cmd_flags, process_flags)) selected_symbols[(*nsymbols)++] = symbol; } } else if(cmd_flags->b == TRUE){ found = FALSE; strings = ofile->object_addr + st->stroff; if(cmd_flags->i == TRUE) i = cmd_flags->index; else i = 0; for( ; i < st->nsyms; i++){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + i); else make_symbol_64(&symbol, all_symbols64 + i); if(symbol.nl.n_type == N_BINCL && symbol.nl.n_un.n_strx != 0 && (uint32_t)symbol.nl.n_un.n_strx < st->strsize && strcmp(cmd_flags->bincl_name, strings + symbol.nl.n_un.n_strx) == 0){ selected_symbols[(*nsymbols)++] = symbol; found = TRUE; nest = 0; for(i = i + 1 ; i < st->nsyms; i++){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + i); else make_symbol_64(&symbol, all_symbols64 + i); if(symbol.nl.n_type == N_BINCL) nest++; else if(symbol.nl.n_type == N_EINCL){ if(nest == 0){ selected_symbols[(*nsymbols)++] = symbol; break; } nest--; } else if(nest == 0) selected_symbols[(*nsymbols)++] = symbol; } } if(found == TRUE) break; } } else{ for(i = 0; i < st->nsyms; i++){ if(ofile->mh != NULL) make_symbol_32(&symbol, all_symbols + i); else make_symbol_64(&symbol, all_symbols64 + i); if(select_symbol(&symbol, cmd_flags, process_flags)) selected_symbols[(*nsymbols)++] = symbol; } } if(ofile->object_byte_sex != get_host_byte_sex()){ if(ofile->mh != NULL) swap_nlist(all_symbols, st->nsyms, ofile->object_byte_sex); else swap_nlist_64(all_symbols64, st->nsyms, ofile->object_byte_sex); } /* * Could reallocate selected symbols to the exact size but it is more * of a time waste than a memory savings. */ return(selected_symbols); } static void make_symbol_32( struct symbol *symbol, struct nlist *nl) { symbol->nl.n_un.n_strx = nl->n_un.n_strx; symbol->nl.n_type = nl->n_type; symbol->nl.n_sect = nl->n_sect; symbol->nl.n_desc = nl->n_desc; symbol->nl.n_value = nl->n_value; } static void make_symbol_64( struct symbol *symbol, struct nlist_64 *nl) { symbol->nl = *nl; } /* * select_symbol() returns TRUE or FALSE if the specified symbol is to be * printed based on the flags. */ static enum bool select_symbol( struct symbol *symbol, struct cmd_flags *cmd_flags, struct process_flags *process_flags) { if(cmd_flags->u == TRUE){ if((symbol->nl.n_type == (N_UNDF | N_EXT) && symbol->nl.n_value == 0) || symbol->nl.n_type == (N_PBUD | N_EXT)) return(TRUE); else return(FALSE); } if(cmd_flags->U == TRUE){ if((symbol->nl.n_type == (N_UNDF | N_EXT) && symbol->nl.n_value == 0) || symbol->nl.n_type == (N_PBUD | N_EXT)) return(FALSE); else return(TRUE); } if(cmd_flags->g == TRUE && (symbol->nl.n_type & N_EXT) == 0) return(FALSE); if(cmd_flags->s == TRUE){ if(((symbol->nl.n_type & N_TYPE) == N_SECT) && (symbol->nl.n_sect == process_flags->nsect)){ if(cmd_flags->l && symbol->nl.n_value == process_flags->sect_addr){ process_flags->sect_start_symbol = TRUE; } } else return(FALSE); } if((symbol->nl.n_type & N_STAB) && (cmd_flags->a == FALSE || cmd_flags->g == TRUE || cmd_flags->u == TRUE)) return(FALSE); return(TRUE); } /* * print_mach_symbols() is called when the -m flag is specified and prints * symbols in the extended Mach-O style format. */ static void print_mach_symbols( struct ofile *ofile, struct symbol *symbols, uint32_t nsymbols, char *strings, uint32_t strsize, struct cmd_flags *cmd_flags, struct process_flags *process_flags, char *arch_name) { uint32_t i, library_ordinal; char *ta_xfmt, *i_xfmt, *dashes, *spaces; uint32_t mh_flags; mh_flags = 0; if(ofile->mh != NULL || (ofile->lto != NULL && (ofile->lto_cputype & CPU_ARCH_ABI64) != CPU_ARCH_ABI64)){ ta_xfmt = "%08llx"; i_xfmt = "%08x"; if(ofile->mh != NULL) mh_flags = ofile->mh->flags; spaces = " "; dashes = "--------"; } else{ ta_xfmt = "%016llx"; i_xfmt = "%016x"; if(ofile->mh64 != NULL) mh_flags = ofile->mh64->flags; spaces = " "; dashes = "----------------"; } for(i = 0; i < nsymbols; i++){ if(cmd_flags->x == TRUE){ printf(ta_xfmt, symbols[i].nl.n_value); printf(" %02x %02x %04x ", (unsigned int)(symbols[i].nl.n_type & 0xff), (unsigned int)(symbols[i].nl.n_sect & 0xff), (unsigned int)(symbols[i].nl.n_desc & 0xffff)); if(symbols[i].nl.n_un.n_strx == 0){ printf(i_xfmt, symbols[i].nl.n_un.n_strx); if(ofile->lto != NULL) printf(" %s", symbols[i].name); else printf(" (null)"); } else if((uint32_t)symbols[i].nl.n_un.n_strx > strsize){ printf(i_xfmt, symbols[i].nl.n_un.n_strx); printf(" (bad string index)"); } else{ printf(i_xfmt, symbols[i].nl.n_un.n_strx); printf(" %s", symbols[i].nl.n_un.n_strx + strings); } if((symbols[i].nl.n_type & N_STAB) == 0 && (symbols[i].nl.n_type & N_TYPE) == N_INDR){ if(symbols[i].nl.n_value == 0){ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" (null))\n"); } else if(symbols[i].nl.n_value > strsize){ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" (bad string index))\n"); } else{ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" %s)\n", symbols[i].indr_name); } } else printf("\n"); continue; } if(symbols[i].nl.n_type & N_STAB){ if(cmd_flags->o == TRUE || cmd_flags->A == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->dylib_module_name != NULL){ printf("%s:%s: ", ofile->file_name, ofile->dylib_module_name); } else 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(ta_xfmt, symbols[i].nl.n_value); printf(" - %02x %04x %5.5s %s\n", (unsigned int)symbols[i].nl.n_sect & 0xff, (unsigned int)symbols[i].nl.n_desc & 0xffff, stab(symbols[i].nl.n_type), symbols[i].name); continue; } if(cmd_flags->o == TRUE || cmd_flags->A == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->dylib_module_name != NULL){ printf("%s:%s: ", ofile->file_name, ofile->dylib_module_name); } else 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); } if(((symbols[i].nl.n_type & N_TYPE) == N_UNDF && symbols[i].nl.n_value == 0) || (symbols[i].nl.n_type & N_TYPE) == N_INDR) printf("%s", spaces); else{ if(ofile->lto) printf("%s", dashes); else printf(ta_xfmt, symbols[i].nl.n_value); } switch(symbols[i].nl.n_type & N_TYPE){ case N_UNDF: case N_PBUD: if((symbols[i].nl.n_type & N_TYPE) == N_UNDF && symbols[i].nl.n_value != 0){ printf(" (common) "); if(GET_COMM_ALIGN(symbols[i].nl.n_desc) != 0) printf("(alignment 2^%d) ", GET_COMM_ALIGN(symbols[i].nl.n_desc)); } else{ if((symbols[i].nl.n_type & N_TYPE) == N_PBUD) printf(" (prebound "); else printf(" ("); if((symbols[i].nl.n_desc & REFERENCE_TYPE) == REFERENCE_FLAG_UNDEFINED_LAZY) printf("undefined [lazy bound]) "); else if((symbols[i].nl.n_desc & REFERENCE_TYPE) == REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY) printf("undefined [private lazy bound]) "); else if((symbols[i].nl.n_desc & REFERENCE_TYPE) == REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY) printf("undefined [private]) "); else printf("undefined) "); } break; case N_ABS: printf(" (absolute) "); break; case N_INDR: printf(" (indirect) "); break; case N_SECT: if(symbols[i].nl.n_sect >= 1 && symbols[i].nl.n_sect <= process_flags->nsects){ if(ofile->mh != NULL || (ofile->lto != NULL && (ofile->lto_cputype & CPU_ARCH_ABI64) != CPU_ARCH_ABI64)){ printf(" (%.16s,%.16s) ", process_flags->sections[ symbols[i].nl.n_sect-1]->segname, process_flags->sections[ symbols[i].nl.n_sect-1]->sectname); } else{ printf(" (%.16s,%.16s) ", process_flags->sections64[ symbols[i].nl.n_sect-1]->segname, process_flags->sections64[ symbols[i].nl.n_sect-1]->sectname); } } else printf(" (?,?) "); break; default: printf(" (?) "); break; } if(symbols[i].nl.n_type & N_EXT){ if(symbols[i].nl.n_desc & REFERENCED_DYNAMICALLY) printf("[referenced dynamically] "); if(symbols[i].nl.n_type & N_PEXT){ if((symbols[i].nl.n_desc & N_WEAK_DEF) == N_WEAK_DEF) printf("weak private external "); else printf("private external "); } else{ if((symbols[i].nl.n_desc & N_WEAK_REF) == N_WEAK_REF || (symbols[i].nl.n_desc & N_WEAK_DEF) == N_WEAK_DEF){ if((symbols[i].nl.n_desc & (N_WEAK_REF | N_WEAK_DEF)) == (N_WEAK_REF | N_WEAK_DEF)) printf("weak external automatically hidden "); else printf("weak external "); } else printf("external "); } } else{ if(symbols[i].nl.n_type & N_PEXT) printf("non-external (was a private external) "); else printf("non-external "); } if(ofile->mh_filetype == MH_OBJECT && (symbols[i].nl.n_desc & N_NO_DEAD_STRIP) == N_NO_DEAD_STRIP) printf("[no dead strip] "); if(ofile->mh_filetype == MH_OBJECT && ((symbols[i].nl.n_type & N_TYPE) != N_UNDF) && (symbols[i].nl.n_desc & N_SYMBOL_RESOLVER) == N_SYMBOL_RESOLVER) printf("[symbol resolver] "); if((symbols[i].nl.n_desc & N_ARM_THUMB_DEF) == N_ARM_THUMB_DEF) printf("[Thumb] "); if((symbols[i].nl.n_type & N_TYPE) == N_INDR) printf("%s (for %s)", symbols[i].name, symbols[i].indr_name); else printf("%s", symbols[i].name); if((mh_flags & MH_TWOLEVEL) == MH_TWOLEVEL && (((symbols[i].nl.n_type & N_TYPE) == N_UNDF && symbols[i].nl.n_value == 0) || (symbols[i].nl.n_type & N_TYPE) == N_PBUD)){ library_ordinal = GET_LIBRARY_ORDINAL(symbols[i].nl.n_desc); if(library_ordinal != 0){ if(library_ordinal == EXECUTABLE_ORDINAL) printf(" (from executable)"); else if(process_flags->nlibs != DYNAMIC_LOOKUP_ORDINAL && library_ordinal == DYNAMIC_LOOKUP_ORDINAL) printf(" (dynamically looked up)"); else if(library_ordinal-1 >= process_flags->nlibs) printf(" (from bad library ordinal %u)", library_ordinal); else printf(" (from %s)", process_flags->lib_names[ library_ordinal-1]); } } printf("\n"); } } /* * print_symbols() is called with the -m flag is not specified and prints * symbols in the standard BSD format. */ static void print_symbols( struct ofile *ofile, struct symbol *symbols, uint32_t nsymbols, char *strings, uint32_t strsize, struct cmd_flags *cmd_flags, struct process_flags *process_flags, char *arch_name, struct value_diff *value_diffs) { uint32_t i; unsigned char c; char *ta_xfmt, *i_xfmt, *spaces, *dashes, *p; if(ofile->mh != NULL || (ofile->lto != NULL && (ofile->lto_cputype & CPU_ARCH_ABI64) != CPU_ARCH_ABI64)){ ta_xfmt = "%08llx"; i_xfmt = "%08x"; spaces = " "; dashes = "--------"; } else{ ta_xfmt = "%016llx"; i_xfmt = "%016x"; spaces = " "; dashes = "----------------"; } for(i = 0; i < nsymbols; i++){ if(cmd_flags->x == TRUE){ printf(ta_xfmt, symbols[i].nl.n_value); printf(" %02x %02x %04x ", (unsigned int)(symbols[i].nl.n_type & 0xff), (unsigned int)(symbols[i].nl.n_sect & 0xff), (unsigned int)(symbols[i].nl.n_desc & 0xffff)); if(symbols[i].nl.n_un.n_strx == 0){ printf(i_xfmt, symbols[i].nl.n_un.n_strx); if(ofile->lto != NULL) printf(" %s", symbols[i].name); else printf(" (null)"); } else if((uint32_t)symbols[i].nl.n_un.n_strx > strsize){ printf(i_xfmt, symbols[i].nl.n_un.n_strx); printf(" (bad string index)"); } else{ printf(i_xfmt, symbols[i].nl.n_un.n_strx); printf(" %s", symbols[i].nl.n_un.n_strx + strings); } if((symbols[i].nl.n_type & N_STAB) == 0 && (symbols[i].nl.n_type & N_TYPE) == N_INDR){ if(symbols[i].nl.n_value == 0){ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" (null))\n"); } else if(symbols[i].nl.n_value > strsize){ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" (bad string index))\n"); } else{ printf(" (indirect for "); printf(ta_xfmt, symbols[i].nl.n_value); printf(" %s)\n", symbols[i].indr_name); } } else printf("\n"); continue; } if(cmd_flags->P == TRUE){ if(cmd_flags->A == TRUE){ if(arch_name != NULL) printf("(for architecture %s): ", arch_name); if(ofile->dylib_module_name != NULL){ printf("%s[%s]: ", ofile->file_name, ofile->dylib_module_name); } else 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("%s ", symbols[i].name); /* type */ c = symbols[i].nl.n_type; if(c & N_STAB) c = '-'; else{ switch(c & N_TYPE){ case N_UNDF: c = 'u'; if(symbols[i].nl.n_value != 0) c = 'c'; break; case N_PBUD: c = 'u'; break; case N_ABS: c = 'a'; break; case N_SECT: if(symbols[i].nl.n_sect == process_flags->text_nsect) c = 't'; else if(symbols[i].nl.n_sect == process_flags->data_nsect) c = 'd'; else if(symbols[i].nl.n_sect == process_flags->bss_nsect) c = 'b'; else c = 's'; break; case N_INDR: c = 'i'; break; default: c = '?'; break; } } if((symbols[i].nl.n_type & N_EXT) && c != '?') c = toupper(c); printf("%c ", c); printf(cmd_flags->format, symbols[i].nl.n_value); printf(" 0\n"); /* the 0 is the size for conformance */ continue; } c = symbols[i].nl.n_type; if(c & N_STAB){ if(cmd_flags->o == TRUE || cmd_flags->A == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->dylib_module_name != NULL){ printf("%s:%s: ", ofile->file_name, ofile->dylib_module_name); } else 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(ta_xfmt, symbols[i].nl.n_value); printf(" - %02x %04x %5.5s ", (unsigned int)symbols[i].nl.n_sect & 0xff, (unsigned int)symbols[i].nl.n_desc & 0xffff, stab(symbols[i].nl.n_type)); if(cmd_flags->b == TRUE){ for(p = symbols[i].name; *p != '\0'; p++){ printf("%c", *p); if(*p == '('){ p++; while(isdigit((unsigned char)*p)) p++; p--; } if(*p == '.' && p[1] != '\0' && p[1] == '_'){ p++; /* one for the '.' */ p++; /* and one for the '_' */ while(isdigit((unsigned char)*p)) p++; p--; } } printf("\n"); } else{ printf("%s\n", symbols[i].name); } continue; } switch(c & N_TYPE){ case N_UNDF: c = 'u'; if(symbols[i].nl.n_value != 0) c = 'c'; break; case N_PBUD: c = 'u'; break; case N_ABS: c = 'a'; break; case N_SECT: if(symbols[i].nl.n_sect == process_flags->text_nsect) c = 't'; else if(symbols[i].nl.n_sect == process_flags->data_nsect) c = 'd'; else if(symbols[i].nl.n_sect == process_flags->bss_nsect) c = 'b'; else c = 's'; break; case N_INDR: c = 'i'; break; default: c = '?'; break; } if(cmd_flags->u == TRUE && c != 'u') continue; if(cmd_flags->o == TRUE || cmd_flags->A == TRUE){ if(arch_name != NULL) printf("(for architecture %s):", arch_name); if(ofile->dylib_module_name != NULL){ printf("%s:%s: ", ofile->file_name, ofile->dylib_module_name); } else 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); } if((symbols[i].nl.n_type & N_EXT) && c != '?') c = toupper(c); if(cmd_flags->u == FALSE && cmd_flags->j == FALSE){ if(c == 'u' || c == 'U' || c == 'i' || c == 'I') printf("%s", spaces); else{ if(cmd_flags->v && value_diffs != NULL){ printf(ta_xfmt, value_diffs[i].size); printf(" "); } if(ofile->lto) printf("%s", dashes); else printf(ta_xfmt, symbols[i].nl.n_value); } printf(" %c ", c); } if(cmd_flags->j == FALSE && (symbols[i].nl.n_type & N_TYPE) == N_INDR) printf("%s (indirect for %s)\n", symbols[i].name, symbols[i].indr_name); else printf("%s\n", symbols[i].name); } } struct stabnames { unsigned char n_type; char *name; }; static const struct stabnames stabnames[] = { { N_GSYM, "GSYM" }, { N_FNAME, "FNAME" }, { N_FUN, "FUN" }, { N_STSYM, "STSYM" }, { N_LCSYM, "LCSYM" }, { N_BNSYM, "BNSYM" }, { N_OPT, "OPT" }, { N_RSYM, "RSYM" }, { N_SLINE, "SLINE" }, { N_ENSYM, "ENSYM" }, { N_SSYM, "SSYM" }, { N_SO, "SO" }, { N_OSO, "OSO" }, { N_LSYM, "LSYM" }, { N_BINCL, "BINCL" }, { N_SOL, "SOL" }, { N_PARAMS,"PARAM" }, { N_VERSION,"VERS" }, { N_OLEVEL,"OLEV" }, { N_PSYM, "PSYM" }, { N_EINCL, "EINCL" }, { N_ENTRY, "ENTRY" }, { N_LBRAC, "LBRAC" }, { N_EXCL, "EXCL" }, { N_RBRAC, "RBRAC" }, { N_BCOMM, "BCOMM" }, { N_ECOMM, "ECOMM" }, { N_ECOML, "ECOML" }, { N_LENG, "LENG" }, { N_PC, "PC" }, { 0, 0 } }; /* * stab() returns the name of the specified stab n_type. */ static char * stab( unsigned char n_type) { const struct stabnames *p; static char prbuf[32]; for(p = stabnames; p->name; p++) if(p->n_type == n_type) return(p->name); sprintf(prbuf, "%02x", (unsigned int)n_type); return(prbuf); } /* * compare is the function used by qsort if any sorting of symbols is to be * done. */ static int compare( struct symbol *p1, struct symbol *p2) { int r; r = 0; if(cmd_flags.n == TRUE){ if(p1->nl.n_value > p2->nl.n_value) return(cmd_flags.r == FALSE ? 1 : -1); else if(p1->nl.n_value < p2->nl.n_value) return(cmd_flags.r == FALSE ? -1 : 1); /* * If p1->nl.n_value == p2->nl.n_value fall through * and sort by name */ } if(cmd_flags.x == TRUE && compare_lto == FALSE){ if((uint32_t)p1->nl.n_un.n_strx > strsize || (uint32_t)p2->nl.n_un.n_strx > strsize){ if((uint32_t)p1->nl.n_un.n_strx > strsize) r = -1; else if((uint32_t)p2->nl.n_un.n_strx > strsize) r = 1; } else r = strcmp(p1->nl.n_un.n_strx + strings, p2->nl.n_un.n_strx + strings); } else r = strcmp(p1->name, p2->name); if(cmd_flags.r == TRUE) return(-r); else return(r); } static int value_diff_compare( struct value_diff *p1, struct value_diff *p2) { if(p1->size < p2->size) return(-1); else if(p1->size > p2->size) return(1); /* if p1->size == p2->size */ return(0); }