cctools-port/cctools/misc/nm.c

1775 lines
50 KiB
C

/*
* 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 <arch_flag>" 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 <mach/mach.h> /* first so to get rid of a precomp warning */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <mach-o/stab.h>
#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 <arch_flag>] ...] [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] = {
&lto_code_section,
&lto_data_section,
&lto_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] = {
&lto_code_section64,
&lto_data_section64,
&lto_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);
}