-/*** nm.c -- Describe symbol table of a rel file. */
-#include "sysdep.h"
+/* 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 "stab.gnu.h"
-#include <ranlib.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));
-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));
+static void
+print_symbols PARAMS ((bfd *file, asymbol **syms, unsigned long symcount,
+ bfd *archive));
-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));
+static void
+print_symdef_entry PARAMS ((bfd * abfd));
/* Command options. */
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. */
extern char *program_name;
extern char *program_version;
extern char *target;
+extern int print_version;
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}
+ {"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;
\f
/* Some error-reporting functions */
void
usage ()
{
- fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n",
+ fprintf(stderr, "nm %s\n\
+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_version, program_name);
- exit(0);
+ exit(1);
}
int
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 */
-
+ int c; /* sez which option char */
+ int retval;
program_name = *argv;
-
- while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) {
+
+ 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 '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 */
-
+ 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++])) return 1;
+ while (optind < argc) {
+ if (!display_file (argv[optind++])) {
+ retval++;
+ }
+ }
- return 0;
+ return retval;
}
\f
-/** Display a file's stats */
+/* Display a file's stats */
/* goto here is marginally cleaner than the nested if syntax */
display_file (filename)
char *filename;
{
- boolean retval = false;
+ boolean retval = true;
bfd *file;
bfd *arfile = NULL;
-
+
file = bfd_openr(filename, target);
if (file == NULL) {
- bfd_fatal (filename);
+ fprintf (stderr, "%s: ", program_name);
+ bfd_perror (filename);
+ return false;
}
- if (bfd_check_format(file, bfd_object)) {
- retval = do_one_rel_file (file);
- goto closer;
- }
+ 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 (!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);
- 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 (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;
+ 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)
return retval;
}
\f
+/* 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));
+}
-static boolean
-do_one_rel_file (abfd)
+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},
+};
+\f
+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;
if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
(void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
- return true;
+ 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));
- exit (1);
+ return;
}
syms = (asymbol **) xmalloc (storage);
(after printing) */
symcount = filter_symbols (abfd, syms, symcount);
-
- if (!no_sort)
+
+ 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;
-}
-\f
-/* 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));
+ print_symbols (abfd, syms, symcount, archive_bfd);
+ free (syms);
}
-
-int (*sorters[2][2])() = {
- {non_numeric_forward, non_numeric_reverse},
- {numeric_forward, numeric_reverse},
-};
\f
-
/* Choose which symbol entries to print;
compact them downward to get rid of the rest.
Return the number of symbols to be printed. */
{
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;
+ flagword flags = (from[src_count])->flags;
+ sym = from[src_count];
if (undefined_only) {
- keep = (flags & BSF_UNDEFINED);
+ keep = sym->section == &bfd_und_section;
} else if (external_only) {
- keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) ||
- (flags & BSF_FORT_COMM));
+ 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;
}
to[dst_count++] = from[src_count];
}
}
-
+
return dst_count;
}
\f
-
-/* 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)
+print_symbols (abfd, syms, symcount, archive_bfd)
bfd *abfd;
asymbol **syms;
unsigned long symcount;
+ bfd *archive_bfd;
{
asymbol **sym = syms, **end = syms + symcount;
- char class;
for (; sym < end; ++sym) {
- if (file_on_each_line) printf("%s:", bfd_get_filename(abfd));
+ 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)->flags & BSF_UNDEFINED)
+ if ((*sym)->section == &bfd_und_section)
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);
- }
+ bfd_print_symbol(abfd, stdout, p, bfd_print_symbol_nm);
+ putchar('\n');
+ }
}
}
}
}
elt = bfd_get_elt_at_index (abfd, idx);
if (thesym->name != (char *)NULL) {
- printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
-}
+ printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
+ }
}
}