/* nm.c -- Describe symbol table of a rel file.
- Copyright (C) 1991-2019 Free Software Foundation, Inc.
+ Copyright (C) 1991-2021 Free Software Foundation, Inc.
This file is part of GNU Binutils.
coff_symbol_type *coffinfo;
/* FIXME: We should add more fields for Type, Line, Section. */
};
-#define SYM_NAME(sym) (sym->sinfo->name)
#define SYM_VALUE(sym) (sym->sinfo->value)
#define SYM_TYPE(sym) (sym->sinfo->type)
#define SYM_STAB_NAME(sym) (sym->sinfo->stab_name)
static void print_object_filename_bsd (const char *);
static void print_object_filename_sysv (const char *);
static void print_object_filename_posix (const char *);
+static void do_not_print_object_filename (const char *);
+
static void print_archive_filename_bsd (const char *);
static void print_archive_filename_sysv (const char *);
static void print_archive_filename_posix (const char *);
+static void do_not_print_archive_filename (const char *);
+
static void print_archive_member_bsd (const char *, const char *);
static void print_archive_member_sysv (const char *, const char *);
static void print_archive_member_posix (const char *, const char *);
+static void do_not_print_archive_member (const char *, const char *);
+
static void print_symbol_filename_bsd (bfd *, bfd *);
static void print_symbol_filename_sysv (bfd *, bfd *);
static void print_symbol_filename_posix (bfd *, bfd *);
-static void print_value (bfd *, bfd_vma);
+static void do_not_print_symbol_filename (bfd *, bfd *);
+
static void print_symbol_info_bsd (struct extended_symbol_info *, bfd *);
static void print_symbol_info_sysv (struct extended_symbol_info *, bfd *);
static void print_symbol_info_posix (struct extended_symbol_info *, bfd *);
+static void just_print_symbol_name (struct extended_symbol_info *, bfd *);
+
+static void print_value (bfd *, bfd_vma);
/* Support for different output formats. */
struct output_fns
- {
- /* Print the name of an object file given on the command line. */
- void (*print_object_filename) (const char *);
+{
+ /* Print the name of an object file given on the command line. */
+ void (*print_object_filename) (const char *);
- /* Print the name of an archive file given on the command line. */
- void (*print_archive_filename) (const char *);
+ /* Print the name of an archive file given on the command line. */
+ void (*print_archive_filename) (const char *);
- /* Print the name of an archive member file. */
- void (*print_archive_member) (const char *, const char *);
+ /* Print the name of an archive member file. */
+ void (*print_archive_member) (const char *, const char *);
- /* Print the name of the file (and archive, if there is one)
- containing a symbol. */
- void (*print_symbol_filename) (bfd *, bfd *);
+ /* Print the name of the file (and archive, if there is one)
+ containing a symbol. */
+ void (*print_symbol_filename) (bfd *, bfd *);
- /* Print a line of information about a symbol. */
- void (*print_symbol_info) (struct extended_symbol_info *, bfd *);
- };
+ /* Print a line of information about a symbol. */
+ void (*print_symbol_info) (struct extended_symbol_info *, bfd *);
+};
-static struct output_fns formats[] =
+/* Indices in `formats'. */
+enum formats
+{
+ FORMAT_BSD = 0,
+ FORMAT_SYSV,
+ FORMAT_POSIX,
+ FORMAT_JUST_SYMBOLS,
+ FORMAT_MAX
+};
+
+#define FORMAT_DEFAULT FORMAT_BSD
+
+static struct output_fns formats[FORMAT_MAX] =
{
{print_object_filename_bsd,
print_archive_filename_bsd,
print_archive_filename_posix,
print_archive_member_posix,
print_symbol_filename_posix,
- print_symbol_info_posix}
+ print_symbol_info_posix},
+ {do_not_print_object_filename,
+ do_not_print_archive_filename,
+ do_not_print_archive_member,
+ do_not_print_symbol_filename,
+ just_print_symbol_name}
};
-/* Indices in `formats'. */
-#define FORMAT_BSD 0
-#define FORMAT_SYSV 1
-#define FORMAT_POSIX 2
-#define FORMAT_DEFAULT FORMAT_BSD
/* The output format to use. */
static struct output_fns *format = &formats[FORMAT_DEFAULT];
static unsigned int print_format = FORMAT_DEFAULT;
+static const char *print_format_string = NULL;
/* Command options. */
static int show_synthetic = 0; /* Display synthesized symbols too. */
static int line_numbers = 0; /* Print line numbers for symbols. */
static int allow_special_symbols = 0; /* Allow special symbols. */
-static int with_symbol_versions = 0; /* Include symbol version information in the output. */
+static int with_symbol_versions = -1; /* Output symbol version information. */
+static int quiet = 0; /* Suppress "no symbols" diagnostic. */
+
+/* The characters to use for global and local ifunc symbols. */
+#if DEFAULT_F_FOR_IFUNC_SYMBOLS
+static const char * ifunc_type_chars = "Ff";
+#else
+static const char * ifunc_type_chars = NULL;
+#endif
static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
OPTION_PLUGIN,
OPTION_SIZE_SORT,
OPTION_RECURSE_LIMIT,
- OPTION_NO_RECURSE_LIMIT
+ OPTION_NO_RECURSE_LIMIT,
+ OPTION_IFUNC_CHARS,
+ OPTION_QUIET
};
static struct option long_options[] =
{"extern-only", no_argument, &external_only, 1},
{"format", required_argument, 0, 'f'},
{"help", no_argument, 0, 'h'},
+ {"ifunc-chars", required_argument, 0, OPTION_IFUNC_CHARS},
+ {"just-symbols", no_argument, 0, 'j'},
{"line-numbers", no_argument, 0, 'l'},
{"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */
{"no-demangle", no_argument, &do_demangle, 0},
{"print-armap", no_argument, &print_armap, 1},
{"print-file-name", no_argument, 0, 'o'},
{"print-size", no_argument, 0, 'S'},
+ {"quiet", no_argument, 0, OPTION_QUIET},
{"radix", required_argument, 0, 't'},
{"recurse-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
{"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
{"undefined-only", no_argument, &undefined_only, 1},
{"version", no_argument, &show_version, 1},
{"with-symbol-versions", no_argument, &with_symbol_versions, 1},
+ {"without-symbol-versions", no_argument, &with_symbol_versions, 0},
{0, no_argument, 0, 0}
};
\f
--defined-only Display only defined symbols\n\
-e (ignored)\n\
-f, --format=FORMAT Use the output format FORMAT. FORMAT can be `bsd',\n\
- `sysv' or `posix'. The default is `bsd'\n\
+ `sysv', `posix' or 'just-symbols'. The default is `bsd'\n\
-g, --extern-only Display only external symbols\n\
+ --ifunc-chars=CHARS Characters to use when displaying ifunc symbols\n\
+ -j, --just-symbols Same as --format=just-symbols\n\
-l, --line-numbers Use debugging information to find a filename and\n\
line number for each symbol\n\
-n, --numeric-sort Sort symbols numerically by address\n\
fprintf (stream, _("\
-S, --print-size Print size of defined symbols\n\
-s, --print-armap Include index for symbols from archive members\n\
+ --quiet Suppress \"no symbols\" diagnostic\n\
--size-sort Sort symbols by size\n\
--special-syms Include special symbols in the output\n\
--synthetic Display synthetic symbols as well\n\
case 'S':
i = FORMAT_SYSV;
break;
+ case 'j':
+ case 'J':
+ i = FORMAT_JUST_SYMBOLS;
+ break;
default:
fatal (_("%s: invalid output format"), f);
}
demangling it if requested. */
static void
-print_symname (const char *form, const char *name, bfd *abfd)
+print_symname (const char *form, struct extended_symbol_info *info,
+ const char *name, bfd *abfd)
{
+ char *alloc = NULL;
+ char *atver = NULL;
+
+ if (name == NULL)
+ name = info->sinfo->name;
+ if (!with_symbol_versions
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+ {
+ atver = strchr (name, '@');
+ if (atver)
+ *atver = 0;
+ }
if (do_demangle && *name)
{
- char *res = bfd_demangle (abfd, name, demangle_flags);
+ alloc = bfd_demangle (abfd, name, demangle_flags);
+ if (alloc != NULL)
+ name = alloc;
+ }
+
+ if (info != NULL && info->elfinfo && with_symbol_versions)
+ {
+ const char *version_string;
+ bfd_boolean hidden;
- if (res != NULL)
+ version_string
+ = bfd_get_symbol_version_string (abfd, &info->elfinfo->symbol,
+ FALSE, &hidden);
+ if (version_string && version_string[0])
{
- printf (form, res);
- free (res);
- return;
+ const char *at = "@@";
+ if (hidden || bfd_is_und_section (info->elfinfo->symbol.section))
+ at = "@";
+ alloc = reconcat (alloc, name, at, version_string, NULL);
+ if (alloc != NULL)
+ name = alloc;
}
}
-
printf (form, name);
+ if (atver)
+ *atver = '@';
+ free (alloc);
}
static void
bfd_fatal ("bfd_get_elt_at_index");
if (thesym->name != (char *) NULL)
{
- print_symname ("%s", thesym->name, abfd);
+ print_symname ("%s", NULL, thesym->name, abfd);
printf (" in %s\n", bfd_get_filename (elt));
}
}
&& sec == bfd_asymbol_section (next))
sz = valueof (next) - valueof (sym);
else
- sz = (bfd_get_section_vma (abfd, sec)
- + bfd_section_size (abfd, sec)
+ sz = (bfd_section_vma (sec)
+ + bfd_section_size (sec)
- valueof (sym));
}
bfd_get_symbol_info (abfd, sym, &syminfo);
+ /* PR 22967 - Distinguish between local and global ifunc symbols. */
+ if (syminfo.type == 'i'
+ && sym->flags & BSF_GNU_INDIRECT_FUNCTION)
+ {
+ if (ifunc_type_chars == NULL || ifunc_type_chars[0] == 0)
+ ; /* Change nothing. */
+ else if (sym->flags & BSF_GLOBAL)
+ syminfo.type = ifunc_type_chars[0];
+ else if (ifunc_type_chars[1] != 0)
+ syminfo.type = ifunc_type_chars[1];
+ }
+
info.sinfo = &syminfo;
info.ssize = ssize;
/* Synthetic symbols do not have a full symbol type set of data available.
}
else
{
- info.elfinfo = elf_symbol_from (abfd, sym);
+ info.elfinfo = elf_symbol_from (sym);
info.coffinfo = coff_symbol_from (sym);
}
format->print_symbol_info (&info, abfd);
- if (with_symbol_versions)
- {
- const char * version_string = NULL;
- bfd_boolean hidden = FALSE;
-
- if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0)
- version_string = bfd_get_symbol_version_string (abfd, sym, &hidden);
-
- if (bfd_is_und_section (bfd_asymbol_section (sym)))
- hidden = TRUE;
-
- if (version_string && *version_string != '\0')
- printf (hidden ? "@%s" : "@@%s", version_string);
- }
-
if (line_numbers)
{
static asymbol **syms;
{
if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
{
- non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
+ if (!quiet)
+ non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
return;
}
}
{
if (dynamic && bfd_get_error () == bfd_error_no_symbols)
{
- non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
+ if (!quiet)
+ non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
return;
}
if (symcount == 0)
{
- non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
+ if (!quiet)
+ non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
return;
}
*symp = 0;
symcount += synth_count;
}
+ if (!dynamic && dyn_syms != NULL)
+ free (dyn_syms);
}
/* lto_slim_object is set to false when a bfd is loaded with a compiler
free (symsizes);
}
+/* Construct a formatting string for printing symbol values. */
+
+static const char *
+get_print_format (void)
+{
+ const char * padding;
+ if (print_format == FORMAT_POSIX || print_format == FORMAT_JUST_SYMBOLS)
+ {
+ /* POSIX compatible output does not have any padding. */
+ padding = "";
+ }
+ else if (print_width == 32)
+ {
+ padding ="08";
+ }
+ else /* print_width == 64 */
+ {
+ padding = "016";
+ }
+
+ const char * length = "l";
+ if (print_width == 64)
+ {
+#if BFD_HOST_64BIT_LONG
+ ;
+#elif BFD_HOST_64BIT_LONG_LONG
+#ifndef __MSVCRT__
+ length = "ll";
+#else
+ length = "I64";
+#endif
+#endif
+ }
+
+ const char * radix = NULL;
+ switch (print_radix)
+ {
+ case 8: radix = "o"; break;
+ case 10: radix = "d"; break;
+ case 16: radix = "x"; break;
+ }
+
+ return concat ("%", padding, length, radix, NULL);
+}
+
static void
set_print_width (bfd *file)
{
else
print_width = 32;
}
+ free ((char *) print_format_string);
+ print_format_string = get_print_format ();
}
static void
if (filename_per_file && !filename_per_symbol)
printf ("%s:\n", filename);
}
+
+static void
+do_not_print_object_filename (const char *filename ATTRIBUTE_UNUSED)
+{
+}
\f
/* Print the name of an archive file given on the command line. */
print_archive_filename_posix (const char *filename ATTRIBUTE_UNUSED)
{
}
+
+static void
+do_not_print_archive_filename (const char *filename ATTRIBUTE_UNUSED)
+{
+}
\f
/* Print the name of an archive member file. */
if (!filename_per_symbol)
printf ("%s[%s]:\n", archive, filename);
}
+
+static void
+do_not_print_archive_member (const char *archive ATTRIBUTE_UNUSED,
+ const char *filename ATTRIBUTE_UNUSED)
+{
+}
+
\f
/* Print the name of the file (and archive, if there is one)
containing a symbol. */
printf ("%s: ", bfd_get_filename (abfd));
}
}
-\f
-/* Construct a formatting string for printing symbol values. */
-static const char *
-get_print_format (void)
+static void
+do_not_print_symbol_filename (bfd *archive_bfd ATTRIBUTE_UNUSED,
+ bfd *abfd ATTRIBUTE_UNUSED)
{
- static const char * saved_format = NULL;
-
- /* See if we have already constructed the format. */
- if (saved_format)
- return saved_format;
-
- const char * padding;
- if (print_format == FORMAT_POSIX)
- {
- /* POSIX compatible output does not have any padding. */
- padding = "";
- }
- else if (print_width == 32)
- {
- padding ="08";
- }
- else /* print_width == 64 */
- {
- padding = "016";
- }
-
- const char * length = "l";
- if (print_width == 64)
- {
-#if BFD_HOST_64BIT_LONG
- ;
-#elif BFD_HOST_64BIT_LONG_LONG
-#ifndef __MSVCRT__
- length = "ll";
-#else
- length = "I64";
-#endif
-#endif
- }
-
- const char * radix = NULL;
- switch (print_radix)
- {
- case 8: radix = "o"; break;
- case 10: radix = "d"; break;
- case 16: radix = "x"; break;
- }
-
- saved_format = concat ("%", padding, length, radix, NULL);
- return saved_format;
}
+\f
/* Print a symbol value. */
static void
switch (print_width)
{
case 32:
- printf (get_print_format (), (unsigned long) val);
+ printf (print_format_string, (unsigned long) val);
break;
case 64:
#if BFD_HOST_64BIT_LONG || BFD_HOST_64BIT_LONG_LONG
- printf (get_print_format (), val);
+ printf (print_format_string, val);
#else
/* We have a 64 bit value to print, but the host is only 32 bit. */
if (print_radix == 16)
printf (desc_format, SYM_STAB_DESC (info));
printf (" %5s", SYM_STAB_NAME (info));
}
- print_symname (" %s", SYM_NAME (info), abfd);
+ print_symname (" %s", info, NULL, abfd);
}
static void
print_symbol_info_sysv (struct extended_symbol_info *info, bfd *abfd)
{
- print_symname ("%-20s|", SYM_NAME (info), abfd);
+ print_symname ("%-20s|", info, NULL, abfd);
if (bfd_is_undefined_symclass (SYM_TYPE (info)))
{
static void
print_symbol_info_posix (struct extended_symbol_info *info, bfd *abfd)
{
- print_symname ("%s ", SYM_NAME (info), abfd);
+ print_symname ("%s ", info, NULL, abfd);
printf ("%c ", SYM_TYPE (info));
if (bfd_is_undefined_symclass (SYM_TYPE (info)))
print_value (abfd, SYM_SIZE (info));
}
}
+
+static void
+just_print_symbol_name (struct extended_symbol_info *info, bfd *abfd)
+{
+ print_symname ("%s", info, NULL, abfd);
+}
\f
int
main (int argc, char **argv)
fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
- while ((c = getopt_long (argc, argv, "aABCDef:gHhlnopPrSst:uvVvX:",
+ while ((c = getopt_long (argc, argv, "aABCDef:gHhjJlnopPrSst:uvVvX:",
long_options, (int *) 0)) != EOF)
{
switch (c)
case OPTION_NO_RECURSE_LIMIT:
demangle_flags |= DMGL_NO_RECURSE_LIMIT;
break;
+ case OPTION_QUIET:
+ quiet = 1;
+ break;
case 'D':
dynamic = 1;
break;
case 'P':
set_output_format ("posix");
break;
+ case 'j':
+ set_output_format ("just-symbols");
+ break;
case 'r':
reverse_sort = 1;
break;
#endif
break;
+ case OPTION_IFUNC_CHARS:
+ ifunc_type_chars = optarg;
+ break;
+
case 0: /* A long option that just sets a flag. */
break;