home *** CD-ROM | disk | FTP | other *** search
- /* nm.c -- Describe symbol table of a rel file.
- Copyright 1991, 1992 Free Software Foundation, Inc.
-
- This file is part of GNU Binutils.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "bfd.h"
- #include "sysdep.h"
- #include "bucomm.h"
- #include "getopt.h"
- #include "aout/stab_gnu.h"
- #include "aout/ranlib.h"
-
- static boolean
- display_file PARAMS ((char *filename));
-
- static void
- do_one_rel_file PARAMS ((bfd* file, bfd *archive));
-
- static unsigned int
- filter_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount));
-
- static void
- print_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount,
- bfd *archive));
-
- static void
- print_symdef_entry PARAMS ((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 */
- int show_version = 0; /* show the version number */
-
- boolean print_each_filename = false; /* Ick. Used in archives. */
-
- /* IMPORT */
- extern char *program_name;
- extern char *program_version;
- extern char *target;
- extern int print_version;
-
- struct option long_options[] = {
- {"debug-syms", no_argument, &print_debug_syms, 1},
- {"extern-only", no_argument, &external_only, 1},
- {"no-sort", no_argument, &no_sort, 1},
- {"numeric-sort", no_argument, &sort_numerically, 1},
- {"print-armap", no_argument, &print_armap, 1},
- {"print-file-name", no_argument, &file_on_each_line, 1},
- {"reverse-sort", no_argument, &reverse_sort, 1},
- {"target", optional_argument, 0, 200},
- {"undefined-only", no_argument, &undefined_only, 1},
- {"version", no_argument, &show_version, 1},
- {0, no_argument, 0, 0}
- };
-
- int show_names = 0;
-
- /* Some error-reporting functions */
-
- void
- usage ()
- {
- fprintf(stderr, "\
- Usage: %s [-agnoprsuV] [--debug-syms] [--extern-only] [--print-armap]\n\
- [--print-file-name] [--numeric-sort] [--no-sort] [--reverse-sort]\n\
- [--undefined-only] [--target=bfdname] [file...]\n", program_name);
- exit(1);
- }
-
- int
- main (argc, argv)
- int argc;
- char **argv;
- {
- int c; /* sez which option char */
- int retval;
- program_name = *argv;
-
- bfd_init();
-
- while ((c = getopt_long(argc, argv, "agnoprsuvABV", long_options, (int *) 0)) != 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 'v':
- case 'V': show_version = 1; break;
-
- /* For MIPS compatibility, -A selects System V style output, -B
- selects BSD style output. These are not implemented. When
- they are, they should be added to usage (). */
- case 'A': break;
- case 'B': break;
-
- case 200: /* --target */
- target = optarg;
- break;
-
- default:
- usage ();
- }
- }
-
- if (show_version)
- printf ("%s version %s\n", program_name, program_version);
-
- /* 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");
-
- retval = 0;
- show_names = (argc -optind)>1;
- /* We were given several filenames to do: */
- while (optind < argc) {
- if (!display_file (argv[optind++])) {
- retval++;
- }
- }
-
- return retval;
- }
-
- /* Display a file's stats */
-
- /* goto here is marginally cleaner than the nested if syntax */
-
- static boolean
- display_file (filename)
- char *filename;
- {
- boolean retval = true;
- bfd *file;
- bfd *arfile = NULL;
-
- file = bfd_openr(filename, target);
- if (file == NULL) {
- fprintf (stderr, "%s: ", program_name);
- bfd_perror (filename);
- return false;
- }
-
- if (bfd_check_format(file, bfd_object))
- {
- if (show_names) {
- printf ("\n%s:\n",filename);
- }
- do_one_rel_file (file, NULL);
- }
- else if (bfd_check_format (file, bfd_archive)) {
- if (!bfd_check_format (file, bfd_archive)) {
- fprintf (stderr, "%s: %s: unknown format\n", program_name, filename);
- retval = false;
- goto closer;
- }
-
- if (!file_on_each_line)
- printf("\n%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 {
- if (!file_on_each_line)
- printf ("\n%s:\n", arfile->filename);
- do_one_rel_file (arfile, file) ;
- }
- }
- }
- else {
- fprintf (stderr, "\n%s: %s: unknown format\n", program_name, filename);
- retval = false;
- }
-
- closer:
- if (bfd_close(file) == false)
- bfd_fatal (filename);
-
- return retval;
- }
-
- /* Symbol-sorting predicates */
- #define valueof(x) ((x)->section->vma + (x)->value)
- int
- numeric_forward (x, y)
- CONST void *x;
- CONST void *y;
- {
- return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));
- }
-
- int
- numeric_reverse (x, y)
- CONST void *x;
- CONST void *y;
- {
- return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
- }
-
- int
- non_numeric_forward (x, y)
- CONST void *x;
- CONST void *y;
- {
- CONST char *xn = (*(asymbol **) x)->name;
- CONST char *yn = (*(asymbol **) y)->name;
-
- return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
- ((yn == NULL) ? 1 : strcmp (xn, yn)));
- }
-
- int
- non_numeric_reverse (x, y)
- CONST void *x;
- CONST void *y;
- {
- return -(non_numeric_forward (x, y));
- }
-
- int (*(sorters[2][2])) PARAMS ((CONST void *, CONST void *)) = {
- {non_numeric_forward, non_numeric_reverse},
- {numeric_forward, numeric_reverse},
- };
-
- static void
- do_one_rel_file (abfd, archive_bfd)
- bfd *abfd;
- bfd *archive_bfd; /* If non-NULL: archive containing 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;
- }
-
- storage = get_symtab_upper_bound (abfd);
- if (storage == 0) {
- nosymz:
- fprintf (stderr, "%s: Symflags set but there are none?\n",
- bfd_get_filename (abfd));
- return;
- }
-
- 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, archive_bfd);
- free (syms);
- }
-
- /* 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;
- asymbol *sym;
-
- 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;
- sym = from[src_count];
- if (undefined_only) {
- keep = sym->section == &bfd_und_section;
- } else if (external_only) {
- keep = ((flags & BSF_GLOBAL)
- || (sym->section == &bfd_und_section)
- || (bfd_is_com_section (sym->section)));
- } else {
- keep = 1;
- }
-
- if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
- keep = 0;
- }
-
- if (keep) {
- to[dst_count++] = from[src_count];
- }
- }
-
- return dst_count;
- }
-
- static void
- print_symbols (abfd, syms, symcount, archive_bfd)
- bfd *abfd;
- asymbol **syms;
- unsigned long symcount;
- bfd *archive_bfd;
- {
- asymbol **sym = syms, **end = syms + symcount;
-
- for (; sym < end; ++sym) {
- if (file_on_each_line) {
- if (archive_bfd)
- printf("%s:", bfd_get_filename(archive_bfd));
- printf("%s:", bfd_get_filename(abfd));
- }
-
- if (undefined_only) {
- if ((*sym)->section == &bfd_und_section)
- puts ((*sym)->name);
- }
- else {
- asymbol *p = *sym;
- if (p) {
- bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm);
- putchar('\n');
- }
- }
- }
- }
-
- 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));
- }
- }
- }
-