diff options
Diffstat (limited to 'binutils/nm.c')
-rw-r--r-- | binutils/nm.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/binutils/nm.c b/binutils/nm.c new file mode 100644 index 0000000..ac490f7 --- /dev/null +++ b/binutils/nm.c @@ -0,0 +1,387 @@ +/*** nm.c -- Describe symbol table of a rel file. */ +#include "sysdep.h" +#include "bfd.h" +#include "getopt.h" +#include "stab.gnu.h" +#include <ranlib.h> + + + +PROTO(static boolean, display_file, (char *filename)); +PROTO(static boolean, do_one_rel_file, (bfd *file)); +PROTO(static unsigned int, filter_symbols, (bfd *file, asymbol **syms, + unsigned long symcount)); + +PROTO(static void, print_symbols, (bfd *file, asymbol **syms, + unsigned long symcount)); +extern PROTO(int, (*sorters[2][2]), (char *x, char *y)); +PROTO(static void, print_symdef_entry, (bfd * abfd)); + +/* Command options. */ + +int external_only = 0; /* print external symbols only */ +int file_on_each_line = 0; /* print file name on each line */ +int no_sort = 0; /* don't sort; print syms in order found */ +int print_debug_syms = 0; /* print debugger-only symbols too */ +int print_armap = 0; /* describe __.SYMDEF data in archive files. */ +int reverse_sort = 0; /* sort in downward(alpha or numeric) order */ +int sort_numerically = 0; /* sort in numeric rather than alpha order */ +int undefined_only = 0; /* print undefined symbols only */ + +boolean print_each_filename = false; /* Ick. Used in archives. */ + +/* IMPORT */ +extern char *program_name; +extern char *program_version; +extern char *target; + +struct option long_options[] = { + {"debug-syms", 0, &print_debug_syms, 1}, + {"extern-only", 0, &external_only, 1}, + {"no-sort", 0, &no_sort, 1}, + {"numeric-sort", 0, &sort_numerically, 1}, + {"print-armap", 0, &print_armap, 1}, + {"print-file-name", 0, &file_on_each_line, 1}, + {"reverse-sort", 0, &reverse_sort, 1}, + {"target", 2, NULL, NULL}, + {"undefined-only", 0, &undefined_only, 1}, + {0, 0, 0, 0} +}; + +/* Some error-reporting functions */ + +void +usage () +{ + fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n", + program_version, program_name); + exit(0); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; /* sez which option char */ + int ind = 0; /* used by getopt and ignored by us */ + extern int optind; /* steps thru options */ + + program_name = *argv; + + while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) { + switch (c) { + case 'a': print_debug_syms = 1; break; + case 'g': external_only = 1; break; + case 'n': sort_numerically = 1; break; + case 'o': file_on_each_line = 1; break; + case 'p': no_sort = 1; break; + case 'r': reverse_sort = 1; break; + case 's': print_armap = 1; break; + case 'u': undefined_only = 1; break; + + case 0: + if (!strcmp("target",(long_options[option_index]).name)) { + target = optarg; + } + + break; /* we've been given a long option */ + + default: + usage (); + } + } + + /* Strangely, for the shell you should return only a nonzero value + on sucess -- the inverse of the C sense. */ + + /* OK, all options now parsed. If no filename specified, do a.out. */ + if (optind == argc) return !display_file ("a.out"); + + /* We were given several filenames to do: */ + while (optind < argc) + if (!display_file (argv[optind++])) return 1; + + return 0; +} + +/** Display a file's stats */ + +/* goto here is marginally cleaner than the nested if syntax */ + +static boolean +display_file (filename) + char *filename; +{ + boolean retval = false; + bfd *file; + bfd *arfile = NULL; + + file = bfd_openr(filename, target); + if (file == NULL) { + bfd_fatal (filename); + } + + if (bfd_check_format(file, bfd_object)) { + retval = do_one_rel_file (file); + goto closer; + } + + if (!bfd_check_format (file, bfd_archive)) { + fprintf (stderr, "%s: %s: unknown format.\n", program_name, filename); + retval = false; + goto closer; + } + + printf("In archive %s:\n", filename); + if (print_armap) print_symdef_entry (file); + for (;;) { + arfile = bfd_openr_next_archived_file (file, arfile); + + if (arfile == NULL) { + if (bfd_error != no_more_archived_files) + bfd_fatal (filename); + goto closer; + } + + if (!bfd_check_format(arfile, bfd_object)) + printf("%s: not an object file\n", arfile->filename); + else { + printf ("\n%s:\n", arfile->filename); + if (!do_one_rel_file (arfile)) return false; + } + } + + closer: + if (bfd_close(file) == false) + bfd_fatal (filename); + + return retval; +} + + +static boolean +do_one_rel_file (abfd) + bfd *abfd; +{ + unsigned int storage; + asymbol **syms; + unsigned int symcount = 0; + + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { + (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); + return true; + } + + + storage = get_symtab_upper_bound (abfd); + if (storage == 0) { + nosymz: + fprintf (stderr, "%s: Symflags set but there are none?\n", + bfd_get_filename (abfd)); + exit (1); + } + + syms = (asymbol **) xmalloc (storage); + + symcount = bfd_canonicalize_symtab (abfd, syms); + if (symcount == 0) goto nosymz; + + /* Discard the symbols we don't want to print. + It's OK to do this in place; we'll free the storage anyway + (after printing) */ + + symcount = filter_symbols (abfd, syms, symcount); + + if (!no_sort) + qsort((char *) syms, symcount, sizeof (asymbol *), + sorters[sort_numerically][reverse_sort]); + + if (print_each_filename && !file_on_each_line) + printf("\n%s:\n", bfd_get_filename(abfd)); + + print_symbols (abfd, syms, symcount); + free (syms); + return true; +} + +/* Symbol-sorting predicates */ +#define valueof(x) ((x)->section ? (x)->section->vma + (x)->value : (x)->value) +int +numeric_forward (x, y) + char *x; + char *y; +{ + + return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));; +} + +int +numeric_reverse (x, y) + char *x; + char *y; +{ + return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x)); + +} + +int +non_numeric_forward (x, y) + char *x; + char *y; +{ + char *xn = (*(asymbol **) x)->name; + char *yn = (*(asymbol **) y)->name; + + return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) : + ((yn == NULL) ? 1 : strcmp (xn, yn))); +} + +int +non_numeric_reverse (x, y) + char *x; + char *y; +{ + return -(non_numeric_forward (x, y)); +} + +int (*sorters[2][2])() = { + {non_numeric_forward, non_numeric_reverse}, + {numeric_forward, numeric_reverse}, +}; + + +/* Choose which symbol entries to print; + compact them downward to get rid of the rest. + Return the number of symbols to be printed. */ +static unsigned int +filter_symbols (abfd, syms, symcount) + bfd *abfd; + asymbol **syms; + unsigned long symcount; +{ + asymbol **from, **to; + unsigned int dst_count = 0; + unsigned int src_count; + for (from = to = syms, src_count = 0; src_count <symcount; src_count++) { + int keep = 0; + flagword flags = (from[src_count])->flags; + + if (undefined_only) { + keep = (flags & BSF_UNDEFINED); + } else if (external_only) { + keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) || + (flags & BSF_FORT_COMM)); + } else { + keep = 1; + } + + if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) { + keep = 0; + } + + if (keep) { + to[dst_count++] = from[src_count]; + } + } + + return dst_count; +} + + +/* Return a lower-case character corresponding to the symbol class of sym */ +char +decode_symclass (sym) + asymbol *sym; +{ + flagword flags = sym->flags; + + if ((sym->value == 0) && (sym->section != NULL)) + /* Huh? All section names don't begin with "." */ + return (sym->section->name)[1]; + + if (flags & BSF_FORT_COMM) return 'C'; + if (flags & BSF_UNDEFINED) return 'U'; + if (flags & BSF_ABSOLUTE) return 'a'; + + + if ( (flags & BSF_GLOBAL) || (flags & BSF_LOCAL) ){ + if ( !strcmp(sym->section->name, ".text") ){ + return 't'; + } else if ( !strcmp(sym->section->name, ".data") ){ + return 'd'; + } else if ( !strcmp(sym->section->name, ".bss") ){ + return 'b'; + } else { + return 'o'; + } + } + + /* We don't have to handle these cases just yet, but we will soon: + N_SETV: 'v'; + N_SETA: 'l'; + N_SETT: 'x'; + N_SETD: 'z'; + N_SETB: 's'; + N_INDR: 'i'; + */ + + return '?'; +} + +static void +print_symbols (abfd, syms, symcount) + bfd *abfd; + asymbol **syms; + unsigned long symcount; +{ + asymbol **sym = syms, **end = syms + symcount; + char class; + + for (; sym < end; ++sym) { + if (file_on_each_line) printf("%s:", bfd_get_filename(abfd)); + + if (undefined_only) { + if ((*sym)->flags & BSF_UNDEFINED) + puts ((*sym)->name); + } + else { + asymbol *p = *sym; + if (p) { + class = decode_symclass (p); + + if (p->flags & BSF_GLOBAL) + class = toupper (class); + + if (p->value || ((p->flags & BSF_UNDEFINED) != BSF_UNDEFINED)) + printf ("%08lx ", (p->section ? p->value + p->section->vma : p->value)); + else fputs (" ", stdout); + + printf ("%c %s\n", class, p->name); + } + } + } +} + +static void +print_symdef_entry (abfd) + bfd * abfd; +{ + symindex idx = BFD_NO_MORE_SYMBOLS; + carsym *thesym; + boolean everprinted = false; + + for (idx = bfd_get_next_mapent (abfd, idx, &thesym); + idx != BFD_NO_MORE_SYMBOLS; + idx = bfd_get_next_mapent (abfd, idx, &thesym)) { + bfd *elt; + if (!everprinted) { + printf ("\nArchive index:\n"); + everprinted = true; + } + elt = bfd_get_elt_at_index (abfd, idx); + if (thesym->name != (char *)NULL) { + printf ("%s in %s\n", thesym->name, bfd_get_filename (elt)); +} + } +} |