/* nm.c -- Describe symbol table of a rel file.
- Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 1991-2016 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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
#include "libiberty.h"
#include "elf-bfd.h"
#include "elf/common.h"
+#define DO_NOT_DEFINE_AOUTHDR
+#define DO_NOT_DEFINE_FILHDR
+#define DO_NOT_DEFINE_LINENO
+#define DO_NOT_DEFINE_SCNHDR
+#include "coff/external.h"
+#include "coff/internal.h"
+#include "libcoff.h"
#include "bucomm.h"
+#include "plugin.h"
/* When sorting by size, we use this structure to hold the size and a
pointer to the minisymbol. */
symbol_info *sinfo;
bfd_vma ssize;
elf_symbol_type *elfinfo;
+ coff_symbol_type *coffinfo;
/* FIXME: We should add more fields for Type, Line, Section. */
};
#define SYM_NAME(sym) (sym->sinfo->name)
/* Print formats for printing a symbol value. */
static char value_format_32bit[] = "%08lx";
+#if BFD_HOST_64BIT_LONG
static char value_format_64bit[] = "%016lx";
+#elif BFD_HOST_64BIT_LONG_LONG
+#ifndef __MSVCRT__
+static char value_format_64bit[] = "%016llx";
+#else
+static char value_format_64bit[] = "%016I64x";
+#endif
+#endif
static int print_width = 0;
static int print_radix = 16;
/* Print formats for printing stab info. */
static char desc_format[] = "%04x";
static char *target = NULL;
+#if BFD_SUPPORTS_PLUGINS
+static const char *plugin_target = "plugin";
+#else
+static const char *plugin_target = NULL;
+#endif
/* Used to cache the line numbers for a BFD. */
static bfd *lineno_cache_bfd;
static bfd *lineno_cache_rel_bfd;
#define OPTION_TARGET 200
+#define OPTION_PLUGIN (OPTION_TARGET + 1)
+#define OPTION_SIZE_SORT (OPTION_PLUGIN + 1)
static struct option long_options[] =
{
{"line-numbers", no_argument, 0, 'l'},
{"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */
{"no-demangle", no_argument, &do_demangle, 0},
- {"no-sort", no_argument, &no_sort, 1},
- {"numeric-sort", no_argument, &sort_numerically, 1},
+ {"no-sort", no_argument, 0, 'p'},
+ {"numeric-sort", no_argument, 0, 'n'},
+ {"plugin", required_argument, 0, OPTION_PLUGIN},
{"portability", no_argument, 0, 'P'},
{"print-armap", no_argument, &print_armap, 1},
{"print-file-name", no_argument, 0, 'o'},
{"print-size", no_argument, 0, 'S'},
{"radix", required_argument, 0, 't'},
{"reverse-sort", no_argument, &reverse_sort, 1},
- {"size-sort", no_argument, &sort_by_size, 1},
+ {"size-sort", no_argument, 0, OPTION_SIZE_SORT},
{"special-syms", no_argument, &allow_special_symbols, 1},
{"stats", no_argument, &show_stats, 1},
{"synthetic", no_argument, &show_synthetic, 1},
-o Same as -A\n\
-p, --no-sort Do not sort the symbols\n\
-P, --portability Same as --format=posix\n\
- -r, --reverse-sort Reverse the sense of the sort\n\
+ -r, --reverse-sort Reverse the sense of the sort\n"));
+#if BFD_SUPPORTS_PLUGINS
+ fprintf (stream, _("\
+ --plugin NAME Load the specified plugin\n"));
+#endif
+ fprintf (stream, _("\
-S, --print-size Print size of defined symbols\n\
-s, --print-armap Include index for symbols from archive members\n\
--size-sort Sort symbols by size\n\
else
print_radix = 8;
value_format_32bit[4] = *radix;
+#if BFD_HOST_64BIT_LONG
value_format_64bit[5] = *radix;
+#elif BFD_HOST_64BIT_LONG_LONG
+#ifndef __MSVCRT__
+ value_format_64bit[6] = *radix;
+#else
+ value_format_64bit[7] = *radix;
+#endif
+#endif
other_format[3] = desc_format[3] = *radix;
break;
default:
}
\f
static const char *
-get_symbol_type (unsigned int type)
+get_elf_symbol_type (unsigned int type)
{
static char buff [32];
return buff;
}
}
+
+static const char *
+get_coff_symbol_type (const struct internal_syment *sym)
+{
+ static char buff [32];
+
+ switch (sym->n_sclass)
+ {
+ case C_BLOCK: return "Block";
+ case C_FILE: return "File";
+ case C_LINE: return "Line";
+ }
+
+ if (!sym->n_type)
+ return "None";
+
+ switch (DTYPE(sym->n_type))
+ {
+ case DT_FCN: return "Function";
+ case DT_PTR: return "Pointer";
+ case DT_ARY: return "Array";
+ }
+
+ sprintf (buff, _("<unknown>: %d/%d"), sym->n_sclass, sym->n_type);
+ return buff;
+}
\f
-/* Print symbol name NAME, read from ABFD, with printf format FORMAT,
+/* Print symbol name NAME, read from ABFD, with printf format FORM,
demangling it if requested. */
static void
-print_symname (const char *format, const char *name, bfd *abfd)
+print_symname (const char *form, const char *name, bfd *abfd)
{
if (do_demangle && *name)
{
if (res != NULL)
{
- printf (format, res);
+ printf (form, res);
free (res);
return;
}
}
- printf (format, name);
+ printf (form, name);
}
static void
Return the number of symbols to be printed. */
static long
-filter_symbols (bfd *abfd, bfd_boolean dynamic, void *minisyms,
+filter_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
long symcount, unsigned int size)
{
bfd_byte *from, *fromend, *to;
PROGRESS (1);
- sym = bfd_minisymbol_to_symbol (abfd, dynamic, (const void *) from, store);
+ sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, (const void *) from, store);
if (sym == NULL)
bfd_fatal (bfd_get_filename (abfd));
+ if (strcmp (sym->name, "__gnu_lto_slim") == 0)
+ non_fatal (_("%s: plugin needed to handle lto object"),
+ bfd_get_filename (abfd));
+
if (undefined_only)
keep = bfd_is_und_section (sym->section);
else if (external_only)
- keep = ((sym->flags & BSF_GLOBAL) != 0
- || (sym->flags & BSF_WEAK) != 0
+ /* PR binutls/12753: Unique symbols are global too. */
+ keep = ((sym->flags & (BSF_GLOBAL
+ | BSF_WEAK
+ | BSF_GNU_UNIQUE)) != 0
|| bfd_is_und_section (sym->section)
|| bfd_is_com_section (sym->section));
else
if (keep)
{
- memcpy (to, from, size);
+ if (to != from)
+ memcpy (to, from, size);
to += size;
}
}
size. */
static long
-sort_symbols_by_size (bfd *abfd, bfd_boolean dynamic, void *minisyms,
+sort_symbols_by_size (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
long symcount, unsigned int size,
struct size_sym **symsizesp)
{
/* We are going to return a special set of symbols and sizes to
print. */
- symsizes = xmalloc (symcount * sizeof (struct size_sym));
+ symsizes = (struct size_sym *) xmalloc (symcount * sizeof (struct size_sym));
*symsizesp = symsizes;
/* Note that filter_symbols has already removed all absolute and
if (from < fromend)
{
- sym = bfd_minisymbol_to_symbol (abfd, dynamic, (const void *) from,
+ sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, (const void *) from,
store_sym);
if (sym == NULL)
bfd_fatal (bfd_get_filename (abfd));
if (from + size < fromend)
{
next = bfd_minisymbol_to_symbol (abfd,
- dynamic,
+ is_dynamic,
(const void *) (from + size),
store_next);
if (next == NULL)
if (relsize < 0)
bfd_fatal (bfd_get_filename (abfd));
- *data->relocs = xmalloc (relsize);
+ *data->relocs = (arelent **) xmalloc (relsize);
*data->relcount = bfd_canonicalize_reloc (abfd, sec, *data->relocs,
data->syms);
if (*data->relcount < 0)
/* Print a single symbol. */
static void
-print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
+print_symbol (bfd * abfd,
+ asymbol * sym,
+ bfd_vma ssize,
+ bfd * archive_bfd,
+ bfd_boolean is_synthetic)
{
symbol_info syminfo;
struct extended_symbol_info info;
format->print_symbol_filename (archive_bfd, abfd);
bfd_get_symbol_info (abfd, sym, &syminfo);
+
info.sinfo = &syminfo;
info.ssize = ssize;
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- info.elfinfo = (elf_symbol_type *) sym;
+ /* Synthetic symbols do not have a full symbol type set of data available. */
+ if (is_synthetic)
+ {
+ info.elfinfo = NULL;
+ info.coffinfo = NULL;
+ }
else
- info.elfinfo = NULL;
+ {
+ info.elfinfo = elf_symbol_from (abfd, sym);
+ info.coffinfo = coff_symbol_from (sym);
+ }
+
format->print_symbol_info (&info, abfd);
if (line_numbers)
symsize = bfd_get_symtab_upper_bound (abfd);
if (symsize < 0)
bfd_fatal (bfd_get_filename (abfd));
- syms = xmalloc (symsize);
+ syms = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (abfd, syms);
if (symcount < 0)
bfd_fatal (bfd_get_filename (abfd));
if (relocs == NULL)
{
- struct get_relocs_info info;
+ struct get_relocs_info rinfo;
seccount = bfd_count_sections (abfd);
- secs = xmalloc (seccount * sizeof *secs);
- relocs = xmalloc (seccount * sizeof *relocs);
- relcount = xmalloc (seccount * sizeof *relcount);
+ secs = (asection **) xmalloc (seccount * sizeof *secs);
+ relocs = (arelent ***) xmalloc (seccount * sizeof *relocs);
+ relcount = (long *) xmalloc (seccount * sizeof *relcount);
- info.secs = secs;
- info.relocs = relocs;
- info.relcount = relcount;
- info.syms = syms;
- bfd_map_over_sections (abfd, get_relocs, (void *) &info);
+ rinfo.secs = secs;
+ rinfo.relocs = relocs;
+ rinfo.relcount = relcount;
+ rinfo.syms = syms;
+ bfd_map_over_sections (abfd, get_relocs, (void *) &rinfo);
lineno_cache_rel_bfd = abfd;
}
/* Print the symbols when sorting by size. */
static void
-print_size_symbols (bfd *abfd, bfd_boolean dynamic,
- struct size_sym *symsizes, long symcount,
- bfd *archive_bfd)
+print_size_symbols (bfd * abfd,
+ bfd_boolean is_dynamic,
+ struct size_sym * symsizes,
+ long symcount,
+ long synth_count,
+ bfd * archive_bfd)
{
asymbol *store;
- struct size_sym *from, *fromend;
+ struct size_sym *from;
+ struct size_sym *fromend;
+ struct size_sym *fromsynth;
store = bfd_make_empty_symbol (abfd);
if (store == NULL)
from = symsizes;
fromend = from + symcount;
+ fromsynth = symsizes + (symcount - synth_count);
+
for (; from < fromend; from++)
{
asymbol *sym;
- bfd_vma ssize;
- sym = bfd_minisymbol_to_symbol (abfd, dynamic, from->minisym, store);
+ sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, from->minisym, store);
if (sym == NULL)
bfd_fatal (bfd_get_filename (abfd));
- /* For elf we have already computed the correct symbol size. */
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
- ssize = from->size;
- else
- ssize = from->size - bfd_section_vma (abfd, bfd_get_section (sym));
-
- print_symbol (abfd, sym, ssize, archive_bfd);
+ print_symbol (abfd, sym, from->size, archive_bfd, from >= fromsynth);
}
}
\f
-/* Print the symbols. If ARCHIVE_BFD is non-NULL, it is the archive
- containing ABFD. */
+/* Print the symbols of ABFD that are held in MINISYMS.
+
+ If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD.
+
+ SYMCOUNT is the number of symbols in MINISYMS and SYNTH_COUNT
+ is the number of these that are synthetic. Synthetic symbols,
+ if any are present, always come at the end of the MINISYMS.
+
+ SIZE is the size of a symbol in MINISYMS. */
static void
-print_symbols (bfd *abfd, bfd_boolean dynamic, void *minisyms, long symcount,
- unsigned int size, bfd *archive_bfd)
+print_symbols (bfd * abfd,
+ bfd_boolean is_dynamic,
+ void * minisyms,
+ long symcount,
+ long synth_count,
+ unsigned int size,
+ bfd * archive_bfd)
{
asymbol *store;
- bfd_byte *from, *fromend;
+ bfd_byte *from;
+ bfd_byte *fromend;
+ bfd_byte *fromsynth;
store = bfd_make_empty_symbol (abfd);
if (store == NULL)
from = (bfd_byte *) minisyms;
fromend = from + symcount * size;
+ fromsynth = (bfd_byte *) minisyms + ((symcount - synth_count) * size);
+
for (; from < fromend; from += size)
{
asymbol *sym;
- sym = bfd_minisymbol_to_symbol (abfd, dynamic, from, store);
+ sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, from, store);
if (sym == NULL)
bfd_fatal (bfd_get_filename (abfd));
- print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd);
+ print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd, from >= fromsynth);
}
}
display_rel_file (bfd *abfd, bfd *archive_bfd)
{
long symcount;
+ long synth_count = 0;
void *minisyms;
unsigned int size;
struct size_sym *symsizes;
symcount = bfd_read_minisymbols (abfd, dynamic, &minisyms, &size);
if (symcount < 0)
- bfd_fatal (bfd_get_filename (abfd));
+ {
+ if (dynamic && bfd_get_error () == bfd_error_no_symbols)
+ {
+ non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
+ return;
+ }
+
+ bfd_fatal (bfd_get_filename (abfd));
+ }
if (symcount == 0)
{
if (show_synthetic && size == sizeof (asymbol *))
{
asymbol *synthsyms;
- long synth_count;
asymbol **static_syms = NULL;
asymbol **dyn_syms = NULL;
long static_count = 0;
if (dynamic)
{
dyn_count = symcount;
- dyn_syms = minisyms;
+ dyn_syms = (asymbol **) minisyms;
}
else
{
long storage = bfd_get_dynamic_symtab_upper_bound (abfd);
static_count = symcount;
- static_syms = minisyms;
+ static_syms = (asymbol **) minisyms;
if (storage > 0)
{
- dyn_syms = xmalloc (storage);
+ dyn_syms = (asymbol **) xmalloc (storage);
dyn_count = bfd_canonicalize_dynamic_symtab (abfd, dyn_syms);
if (dyn_count < 0)
bfd_fatal (bfd_get_filename (abfd));
}
}
+
synth_count = bfd_get_synthetic_symtab (abfd, static_count, static_syms,
dyn_count, dyn_syms, &synthsyms);
if (synth_count > 0)
long i;
new_mini = xmalloc ((symcount + synth_count + 1) * sizeof (*symp));
- symp = new_mini;
+ symp = (asymbol **) new_mini;
memcpy (symp, minisyms, symcount * sizeof (*symp));
symp += symcount;
for (i = 0; i < synth_count; i++)
}
if (! sort_by_size)
- print_symbols (abfd, dynamic, minisyms, symcount, size, archive_bfd);
+ print_symbols (abfd, dynamic, minisyms, symcount, synth_count, size, archive_bfd);
else
- print_size_symbols (abfd, dynamic, symsizes, symcount, archive_bfd);
+ print_size_symbols (abfd, dynamic, symsizes, symcount, synth_count, archive_bfd);
free (minisyms);
+ free (symsizes);
}
static void
bfd_close (last_arfile);
lineno_cache_bfd = NULL;
lineno_cache_rel_bfd = NULL;
+ if (arfile == last_arfile)
+ return;
}
last_arfile = arfile;
}
if (get_file_size (filename) < 1)
return FALSE;
- file = bfd_openr (filename, target);
+ file = bfd_openr (filename, target ? target : plugin_target);
if (file == NULL)
{
bfd_nonfatal (filename);
return FALSE;
}
+ /* If printing line numbers, decompress the debug sections. */
+ if (line_numbers)
+ file->flags |= BFD_DECOMPRESS;
+
if (bfd_check_format (file, bfd_archive))
{
display_archive (file);
break;
case 64:
-#if BFD_HOST_64BIT_LONG
+#if BFD_HOST_64BIT_LONG || BFD_HOST_64BIT_LONG_LONG
printf (value_format_64bit, val);
#else
/* We have a 64 bit value to print, but the host is only 32 bit. */
print_value (abfd, SYM_SIZE (info));
else
print_value (abfd, SYM_VALUE (info));
-
if (print_size && SYM_SIZE (info))
{
printf (" ");
/* Type, Size, Line, Section */
if (info->elfinfo)
printf ("%18s|",
- get_symbol_type (ELF_ST_TYPE (info->elfinfo->internal_elf_sym.st_info)));
+ get_elf_symbol_type (ELF_ST_TYPE (info->elfinfo->internal_elf_sym.st_info)));
+ else if (info->coffinfo)
+ printf ("%18s|",
+ get_coff_symbol_type (&info->coffinfo->native->u.syment));
else
printf (" |");
if (info->elfinfo)
printf("| |%s", info->elfinfo->symbol.section->name);
+ else if (info->coffinfo)
+ printf("| |%s", info->coffinfo->symbol.section->name);
else
printf("| |");
}
program_name = *argv;
xmalloc_set_program_name (program_name);
+ bfd_set_error_program_name (program_name);
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_program_name (program_name);
+#endif
START_PROGRESS (program_name, 0);
break;
case 'n':
case 'v':
+ no_sort = 0;
sort_numerically = 1;
+ sort_by_size = 0;
break;
case 'p':
no_sort = 1;
+ sort_numerically = 0;
+ sort_by_size = 0;
+ break;
+ case OPTION_SIZE_SORT:
+ no_sort = 0;
+ sort_numerically = 0;
+ sort_by_size = 1;
break;
case 'P':
set_output_format ("posix");
target = optarg;
break;
+ case OPTION_PLUGIN: /* --plugin */
+#if BFD_SUPPORTS_PLUGINS
+ bfd_plugin_set_plugin (optarg);
+#else
+ fatal (_("sorry - this program has been built without plugin support\n"));
+#endif
+ break;
+
case 0: /* A long option that just sets a flag. */
break;