/* nm.c -- Describe symbol table of a rel file.
- Copyright (C) 1991-2020 Free Software Foundation, Inc.
+ Copyright (C) 1991-2023 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "sysdep.h"
#include "bfd.h"
-#include "progress.h"
#include "getopt.h"
#include "aout/stab_gnu.h"
#include "aout/ranlib.h"
#include "coff/internal.h"
#include "libcoff.h"
#include "bucomm.h"
+#include "demanguse.h"
#include "plugin-api.h"
#include "plugin.h"
+#include "safe-ctype.h"
+
+#ifndef streq
+#define streq(a,b) (strcmp ((a),(b)) == 0)
+#endif
/* When sorting by size, we use this structure to hold the size and a
pointer to the minisymbol. */
bfd_vma size;
};
-/* When fetching relocs, we use this structure to pass information to
- get_relocs. */
+/* line number related info cached in bfd usrdata. */
-struct get_relocs_info
+struct lineno_cache
{
asection **secs;
arelent ***relocs;
long *relcount;
asymbol **syms;
+ long symcount;
+ unsigned int seccount;
};
struct extended_symbol_info
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 const 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 const struct output_fns *format = &formats[FORMAT_DEFAULT];
static unsigned int print_format = FORMAT_DEFAULT;
static const char *print_format_string = NULL;
static int do_demangle = 0; /* Pretty print C++ symbol names. */
static int external_only = 0; /* Print external symbols only. */
static int defined_only = 0; /* Print defined symbols only. */
+static int non_weak = 0; /* Ignore weak symbols. */
static int no_sort = 0; /* Don't sort; print syms in order found. */
static int print_debug_syms = 0;/* Print debugger-only symbols too. */
static int print_armap = 0; /* Describe __.SYMDEF data in archive files. */
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;
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;
+typedef enum unicode_display_type
+{
+ unicode_default = 0,
+ unicode_locale,
+ unicode_escape,
+ unicode_hex,
+ unicode_highlight,
+ unicode_invalid
+} unicode_display_type;
+
+static unicode_display_type unicode_display = unicode_default;
enum long_option_values
{
OPTION_PLUGIN,
OPTION_SIZE_SORT,
OPTION_RECURSE_LIMIT,
- OPTION_NO_RECURSE_LIMIT
+ OPTION_NO_RECURSE_LIMIT,
+ OPTION_IFUNC_CHARS,
+ OPTION_UNICODE,
+ 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},
{"special-syms", no_argument, &allow_special_symbols, 1},
{"synthetic", no_argument, &show_synthetic, 1},
{"target", required_argument, 0, OPTION_TARGET},
- {"defined-only", no_argument, &defined_only, 1},
- {"undefined-only", no_argument, &undefined_only, 1},
+ {"defined-only", no_argument, 0, 'U'},
+ {"undefined-only", no_argument, 0, 'u'},
+ {"unicode", required_argument, NULL, OPTION_UNICODE},
{"version", no_argument, &show_version, 1},
+ {"no-weak", no_argument, 0, 'W'},
{"with-symbol-versions", no_argument, &with_symbol_versions, 1},
+ {"without-symbol-versions", no_argument, &with_symbol_versions, 0},
{0, no_argument, 0, 0}
};
\f
{
fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name);
fprintf (stream, _(" List symbols in [file(s)] (a.out by default).\n"));
- fprintf (stream, _(" The options are:\n\
- -a, --debug-syms Display debugger-only symbols\n\
- -A, --print-file-name Print name of the input file before every symbol\n\
- -B Same as --format=bsd\n\
- -C, --demangle[=STYLE] Decode low-level symbol names into user-level names\n\
- The STYLE, if specified, can be `auto' (the default),\n\
- `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
- or `gnat'\n\
- --no-demangle Do not demangle low-level symbol names\n\
- --recurse-limit Enable a demangling recursion limit. This is the default.\n\
- --no-recurse-limit Disable a demangling recursion limit.\n\
- -D, --dynamic Display dynamic symbols instead of normal symbols\n\
- --defined-only Display only defined symbols\n\
- -e (ignored)\n\
+ fprintf (stream, _(" The options are:\n"));
+ fprintf (stream, _("\
+ -a, --debug-syms Display debugger-only symbols\n"));
+ fprintf (stream, _("\
+ -A, --print-file-name Print name of the input file before every symbol\n"));
+ fprintf (stream, _("\
+ -B Same as --format=bsd\n"));
+ fprintf (stream, _("\
+ -C, --demangle[=STYLE] Decode mangled/processed symbol names\n"));
+ display_demangler_styles (stream, _("\
+ STYLE can be "));
+ fprintf (stream, _("\
+ --no-demangle Do not demangle low-level symbol names\n"));
+ fprintf (stream, _("\
+ --recurse-limit Enable a demangling recursion limit. (default)\n"));
+ fprintf (stream, _("\
+ --no-recurse-limit Disable a demangling recursion limit.\n"));
+ fprintf (stream, _("\
+ -D, --dynamic Display dynamic symbols instead of normal symbols\n"));
+ fprintf (stream, _("\
+ -e (ignored)\n"));
+ fprintf (stream, _("\
-f, --format=FORMAT Use the output format FORMAT. FORMAT can be `bsd',\n\
- `sysv' or `posix'. The default is `bsd'\n\
- -g, --extern-only Display only external symbols\n\
+ `sysv', `posix' or 'just-symbols'.\n\
+ The default is `bsd'\n"));
+ fprintf (stream, _("\
+ -g, --extern-only Display only external symbols\n"));
+ fprintf (stream, _("\
+ --ifunc-chars=CHARS Characters to use when displaying ifunc symbols\n"));
+ fprintf (stream, _("\
+ -j, --just-symbols Same as --format=just-symbols\n"));
+ fprintf (stream, _("\
-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\
- -o Same as -A\n\
- -p, --no-sort Do not sort the symbols\n\
- -P, --portability Same as --format=posix\n\
+ line number for each symbol\n"));
+ fprintf (stream, _("\
+ -n, --numeric-sort Sort symbols numerically by address\n"));
+ fprintf (stream, _("\
+ -o Same as -A\n"));
+ fprintf (stream, _("\
+ -p, --no-sort Do not sort the symbols\n"));
+ fprintf (stream, _("\
+ -P, --portability Same as --format=posix\n"));
+ fprintf (stream, _("\
-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\
- --special-syms Include special symbols in the output\n\
- --synthetic Display synthetic symbols as well\n\
- -t, --radix=RADIX Use RADIX for printing symbol values\n\
- --target=BFDNAME Specify the target object format as BFDNAME\n\
- -u, --undefined-only Display only undefined symbols\n\
- --with-symbol-versions Display version strings after symbol names\n\
- -X 32_64 (ignored)\n\
- @FILE Read options from FILE\n\
- -h, --help Display this information\n\
- -V, --version Display this program's version number\n\
-\n"));
+ -S, --print-size Print size of defined symbols\n"));
+ fprintf (stream, _("\
+ -s, --print-armap Include index for symbols from archive members\n"));
+ fprintf (stream, _("\
+ --quiet Suppress \"no symbols\" diagnostic\n"));
+ fprintf (stream, _("\
+ --size-sort Sort symbols by size\n"));
+ fprintf (stream, _("\
+ --special-syms Include special symbols in the output\n"));
+ fprintf (stream, _("\
+ --synthetic Display synthetic symbols as well\n"));
+ fprintf (stream, _("\
+ -t, --radix=RADIX Use RADIX for printing symbol values\n"));
+ fprintf (stream, _("\
+ --target=BFDNAME Specify the target object format as BFDNAME\n"));
+ fprintf (stream, _("\
+ -u, --undefined-only Display only undefined symbols\n"));
+ fprintf (stream, _("\
+ -U, --defined-only Display only defined symbols\n"));
+ fprintf (stream, _("\
+ --unicode={default|show|invalid|hex|escape|highlight}\n\
+ Specify how to treat UTF-8 encoded unicode characters\n"));
+ fprintf (stream, _("\
+ -W, --no-weak Ignore weak symbols\n"));
+ fprintf (stream, _("\
+ --with-symbol-versions Display version strings after symbol names\n"));
+ fprintf (stream, _("\
+ -X 32_64 (ignored)\n"));
+ fprintf (stream, _("\
+ @FILE Read options from FILE\n"));
+ fprintf (stream, _("\
+ -h, --help Display this information\n"));
+ fprintf (stream, _("\
+ -V, --version Display this program's version number\n"));
+
list_supported_targets (program_name, stream);
if (REPORT_BUGS_TO[0] && status == 0)
fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
case 'S':
i = FORMAT_SYSV;
break;
+ case 'j':
+ case 'J':
+ i = FORMAT_JUST_SYMBOLS;
+ break;
default:
fatal (_("%s: invalid output format"), f);
}
return bufp;
}
\f
+/* Convert a potential UTF-8 encoded sequence in IN into characters in OUT.
+ The conversion format is controlled by the unicode_display variable.
+ Returns the number of characters added to OUT.
+ Returns the number of bytes consumed from IN in CONSUMED.
+ Always consumes at least one byte and displays at least one character. */
+
+static unsigned int
+display_utf8 (const unsigned char * in, char * out, unsigned int * consumed)
+{
+ char * orig_out = out;
+ unsigned int nchars = 0;
+ unsigned int j;
+
+ if (unicode_display == unicode_default)
+ goto invalid;
+
+ if (in[0] < 0xc0)
+ goto invalid;
+
+ if ((in[1] & 0xc0) != 0x80)
+ goto invalid;
+
+ if ((in[0] & 0x20) == 0)
+ {
+ nchars = 2;
+ goto valid;
+ }
+
+ if ((in[2] & 0xc0) != 0x80)
+ goto invalid;
+
+ if ((in[0] & 0x10) == 0)
+ {
+ nchars = 3;
+ goto valid;
+ }
+
+ if ((in[3] & 0xc0) != 0x80)
+ goto invalid;
+
+ nchars = 4;
+
+ valid:
+ switch (unicode_display)
+ {
+ case unicode_locale:
+ /* Copy the bytes into the output buffer as is. */
+ memcpy (out, in, nchars);
+ out += nchars;
+ break;
+
+ case unicode_invalid:
+ case unicode_hex:
+ out += sprintf (out, "%c", unicode_display == unicode_hex ? '<' : '{');
+ out += sprintf (out, "0x");
+ for (j = 0; j < nchars; j++)
+ out += sprintf (out, "%02x", in [j]);
+ out += sprintf (out, "%c", unicode_display == unicode_hex ? '>' : '}');
+ break;
+
+ case unicode_highlight:
+ if (isatty (1))
+ out += sprintf (out, "\x1B[31;47m"); /* Red. */
+ /* Fall through. */
+ case unicode_escape:
+ switch (nchars)
+ {
+ case 2:
+ out += sprintf (out, "\\u%02x%02x",
+ ((in[0] & 0x1c) >> 2),
+ ((in[0] & 0x03) << 6) | (in[1] & 0x3f));
+ break;
+
+ case 3:
+ out += sprintf (out, "\\u%02x%02x",
+ ((in[0] & 0x0f) << 4) | ((in[1] & 0x3c) >> 2),
+ ((in[1] & 0x03) << 6) | ((in[2] & 0x3f)));
+ break;
+
+ case 4:
+ out += sprintf (out, "\\u%02x%02x%02x",
+ ((in[0] & 0x07) << 6) | ((in[1] & 0x3c) >> 2),
+ ((in[1] & 0x03) << 6) | ((in[2] & 0x3c) >> 2),
+ ((in[2] & 0x03) << 6) | ((in[3] & 0x3f)));
+ break;
+ default:
+ /* URG. */
+ break;
+ }
+
+ if (unicode_display == unicode_highlight && isatty (1))
+ out += sprintf (out, "\033[0m"); /* Default colour. */
+ break;
+
+ default:
+ /* URG */
+ break;
+ }
+
+ * consumed = nchars;
+ return out - orig_out;
+
+ invalid:
+ /* Not a valid UTF-8 sequence. */
+ *out = *in;
+ * consumed = 1;
+ return 1;
+}
+
+/* Convert any UTF-8 encoded characters in NAME into the form specified by
+ unicode_display. Also converts control characters. Returns a static
+ buffer if conversion was necessary.
+ Code stolen from objdump.c:sanitize_string(). */
+
+static const char *
+convert_utf8 (const char * in)
+{
+ static char * buffer = NULL;
+ static size_t buffer_len = 0;
+ const char * original = in;
+ char * out;
+
+ /* Paranoia. */
+ if (in == NULL)
+ return "";
+
+ /* See if any conversion is necessary.
+ In the majority of cases it will not be needed. */
+ do
+ {
+ unsigned char c = *in++;
+
+ if (c == 0)
+ return original;
+
+ if (ISCNTRL (c))
+ break;
+
+ if (unicode_display != unicode_default && c >= 0xc0)
+ break;
+ }
+ while (1);
+
+ /* Copy the input, translating as needed. */
+ in = original;
+ if (buffer_len < (strlen (in) * 9))
+ {
+ free ((void *) buffer);
+ buffer_len = strlen (in) * 9;
+ buffer = xmalloc (buffer_len + 1);
+ }
+
+ out = buffer;
+ do
+ {
+ unsigned char c = *in++;
+
+ if (c == 0)
+ break;
+
+ if (ISCNTRL (c))
+ {
+ *out++ = '^';
+ *out++ = c + 0x40;
+ }
+ else if (unicode_display != unicode_default && c >= 0xc0)
+ {
+ unsigned int num_consumed;
+
+ out += display_utf8 ((const unsigned char *)(in - 1), out, & num_consumed);
+ in += num_consumed - 1;
+ }
+ else
+ *out++ = c;
+ }
+ while (1);
+
+ *out = 0;
+ return buffer;
+}
+
/* Print symbol name NAME, read from ABFD, with printf format FORM,
demangling it if requested. */
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 (res != NULL)
- {
- printf (form, res);
- free (res);
- return;
- }
+ if (unicode_display != unicode_default)
+ {
+ name = convert_utf8 (name);
}
- printf (form, name);
- if (info != NULL && info->elfinfo)
+ if (info != NULL && info->elfinfo && with_symbol_versions)
{
const char *version_string;
- bfd_boolean hidden;
+ bool hidden;
version_string
= bfd_get_symbol_version_string (abfd, &info->elfinfo->symbol,
- FALSE, &hidden);
+ false, &hidden);
if (version_string && version_string[0])
- printf ("%s%s", hidden ? "@" : "@@", version_string);
+ {
+ 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
{
symindex idx = BFD_NO_MORE_SYMBOLS;
carsym *thesym;
- bfd_boolean everprinted = FALSE;
+ bool 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;
+ everprinted = true;
}
- elt = bfd_get_elt_at_index (abfd, idx);
- if (elt == NULL)
- bfd_fatal ("bfd_get_elt_at_index");
- if (thesym->name != (char *) NULL)
+ if (thesym->name != NULL)
{
print_symname ("%s", NULL, thesym->name, abfd);
- printf (" in %s\n", bfd_get_filename (elt));
+ bfd *elt = bfd_get_elt_at_index (abfd, idx);
+ if (elt)
+ printf (" in %s\n", bfd_get_filename (elt));
+ else
+ printf ("\n");
}
}
}
\f
/* True when we can report missing plugin error. */
-bfd_boolean report_plugin_err = TRUE;
+bool report_plugin_err = true;
/* Choose which symbol entries to print;
compact them downward to get rid of the rest.
Return the number of symbols to be printed. */
static long
-filter_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
+filter_symbols (bfd *abfd, bool is_dynamic, void *minisyms,
long symcount, unsigned int size)
{
bfd_byte *from, *fromend, *to;
int keep = 0;
asymbol *sym;
- PROGRESS (1);
-
- sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, (const void *) from, store);
+ sym = bfd_minisymbol_to_symbol (abfd, is_dynamic, from, store);
if (sym == NULL)
- bfd_fatal (bfd_get_filename (abfd));
+ continue;
- if (sym->name[0] == '_'
+ if (sym->name != NULL
+ && sym->name[0] == '_'
&& sym->name[1] == '_'
&& strcmp (sym->name + (sym->name[2] == '_'), "__gnu_lto_slim") == 0
&& report_plugin_err)
{
- report_plugin_err = FALSE;
+ report_plugin_err = false;
non_fatal (_("%s: plugin needed to handle lto object"),
bfd_get_filename (abfd));
}
| BSF_GNU_UNIQUE)) != 0
|| bfd_is_und_section (sym->section)
|| bfd_is_com_section (sym->section));
+ else if (non_weak)
+ keep = ((sym->flags & BSF_WEAK) == 0);
else
keep = 1;
/* These globals are used to pass information into the sorting
routines. */
static bfd *sort_bfd;
-static bfd_boolean sort_dynamic;
+static bool sort_dynamic;
static asymbol *sort_x;
static asymbol *sort_y;
if (xn == NULL)
return -1;
-#ifdef HAVE_STRCOLL
/* Solaris 2.5 has a bug in strcoll.
strcoll returns invalid values when confronted with empty strings. */
if (*yn == '\0')
return -1;
return strcoll (xn, yn);
-#else
- return strcmp (xn, yn);
-#endif
}
static int
size. */
static long
-sort_symbols_by_size (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
+sort_symbols_by_size (bfd *abfd, bool is_dynamic, void *minisyms,
long symcount, unsigned int size,
struct size_sym **symsizesp)
{
static void
get_relocs (bfd *abfd, asection *sec, void *dataarg)
{
- struct get_relocs_info *data = (struct get_relocs_info *) dataarg;
+ struct lineno_cache *data = (struct lineno_cache *) dataarg;
*data->secs = sec;
+ *data->relocs = NULL;
+ *data->relcount = 0;
- if ((sec->flags & SEC_RELOC) == 0)
- {
- *data->relocs = NULL;
- *data->relcount = 0;
- }
- else
+ if ((sec->flags & SEC_RELOC) != 0)
{
- long relsize;
-
- relsize = bfd_get_reloc_upper_bound (abfd, sec);
- if (relsize < 0)
- bfd_fatal (bfd_get_filename (abfd));
-
- *data->relocs = (arelent **) xmalloc (relsize);
- *data->relcount = bfd_canonicalize_reloc (abfd, sec, *data->relocs,
- data->syms);
- if (*data->relcount < 0)
- bfd_fatal (bfd_get_filename (abfd));
+ long relsize = bfd_get_reloc_upper_bound (abfd, sec);
+ if (relsize > 0)
+ {
+ *data->relocs = (arelent **) xmalloc (relsize);
+ *data->relcount = bfd_canonicalize_reloc (abfd, sec, *data->relocs,
+ data->syms);
+ }
}
++data->secs;
++data->relcount;
}
+static void
+free_lineno_cache (bfd *abfd)
+{
+ struct lineno_cache *lc = bfd_usrdata (abfd);
+
+ if (lc)
+ {
+ if (lc->relocs)
+ for (unsigned int i = 0; i < lc->seccount; i++)
+ free (lc->relocs[i]);
+ free (lc->relcount);
+ free (lc->relocs);
+ free (lc->secs);
+ free (lc->syms);
+ free (lc);
+ bfd_set_usrdata (abfd, NULL);
+ }
+}
+
/* Print a single symbol. */
static void
symbol_info syminfo;
struct extended_symbol_info info;
- PROGRESS (1);
-
format->print_symbol_filename (archive_bfd, abfd);
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,
- TRUE, &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;
- static long symcount;
+ struct lineno_cache *lc = bfd_usrdata (abfd);
const char *filename, *functionname;
unsigned int lineno;
/* We need to get the canonical symbols in order to call
bfd_find_nearest_line. This is inefficient, but, then, you
don't have to use --line-numbers. */
- if (abfd != lineno_cache_bfd && syms != NULL)
+ if (lc == NULL)
{
- free (syms);
- syms = NULL;
+ lc = xcalloc (1, sizeof (*lc));
+ bfd_set_usrdata (abfd, lc);
}
- if (syms == NULL)
+ if (lc->syms == NULL && lc->symcount == 0)
{
- long symsize;
-
- symsize = bfd_get_symtab_upper_bound (abfd);
- if (symsize < 0)
- bfd_fatal (bfd_get_filename (abfd));
- syms = (asymbol **) xmalloc (symsize);
- symcount = bfd_canonicalize_symtab (abfd, syms);
- if (symcount < 0)
- bfd_fatal (bfd_get_filename (abfd));
- lineno_cache_bfd = abfd;
+ long symsize = bfd_get_symtab_upper_bound (abfd);
+ if (symsize <= 0)
+ lc->symcount = -1;
+ else
+ {
+ lc->syms = xmalloc (symsize);
+ lc->symcount = bfd_canonicalize_symtab (abfd, lc->syms);
+ }
}
- if (bfd_is_und_section (bfd_asymbol_section (sym)))
+ if (lc->symcount <= 0)
+ ;
+ else if (bfd_is_und_section (bfd_asymbol_section (sym)))
{
- static asection **secs;
- static arelent ***relocs;
- static long *relcount;
- static unsigned int seccount;
unsigned int i;
const char *symname;
/* For an undefined symbol, we try to find a reloc for the
symbol, and print the line number of the reloc. */
- if (abfd != lineno_cache_rel_bfd && relocs != NULL)
+ if (lc->relocs == NULL)
{
- for (i = 0; i < seccount; i++)
- if (relocs[i] != NULL)
- free (relocs[i]);
- free (secs);
- free (relocs);
- free (relcount);
- secs = NULL;
- relocs = NULL;
- relcount = NULL;
- }
-
- if (relocs == NULL)
- {
- struct get_relocs_info rinfo;
-
- seccount = bfd_count_sections (abfd);
-
- secs = (asection **) xmalloc (seccount * sizeof *secs);
- relocs = (arelent ***) xmalloc (seccount * sizeof *relocs);
- relcount = (long *) xmalloc (seccount * sizeof *relcount);
-
- 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;
+ unsigned int seccount = bfd_count_sections (abfd);
+ lc->seccount = seccount;
+ lc->secs = xmalloc (seccount * sizeof (*lc->secs));
+ lc->relocs = xmalloc (seccount * sizeof (*lc->relocs));
+ lc->relcount = xmalloc (seccount * sizeof (*lc->relcount));
+
+ struct lineno_cache rinfo = *lc;
+ bfd_map_over_sections (abfd, get_relocs, &rinfo);
}
symname = bfd_asymbol_name (sym);
- for (i = 0; i < seccount; i++)
+ for (i = 0; i < lc->seccount; i++)
{
long j;
- for (j = 0; j < relcount[i]; j++)
+ for (j = 0; j < lc->relcount[i]; j++)
{
arelent *r;
- r = relocs[i][j];
+ r = lc->relocs[i][j];
if (r->sym_ptr_ptr != NULL
&& (*r->sym_ptr_ptr)->section == sym->section
&& (*r->sym_ptr_ptr)->value == sym->value
&& strcmp (symname,
bfd_asymbol_name (*r->sym_ptr_ptr)) == 0
- && bfd_find_nearest_line (abfd, secs[i], syms,
+ && bfd_find_nearest_line (abfd, lc->secs[i], lc->syms,
r->address, &filename,
&functionname, &lineno)
&& filename != NULL)
{
/* We only print the first one we find. */
printf ("\t%s:%u", filename, lineno);
- i = seccount;
+ i = lc->seccount;
break;
}
}
}
else if (bfd_asymbol_section (sym)->owner == abfd)
{
- if ((bfd_find_line (abfd, syms, sym, &filename, &lineno)
+ if ((bfd_find_line (abfd, lc->syms, sym, &filename, &lineno)
|| bfd_find_nearest_line (abfd, bfd_asymbol_section (sym),
- syms, sym->value, &filename,
+ lc->syms, sym->value, &filename,
&functionname, &lineno))
&& filename != NULL
&& lineno != 0)
/* Print the symbols when sorting by size. */
static void
-print_size_symbols (bfd * abfd,
- bfd_boolean is_dynamic,
- struct size_sym * symsizes,
- long symcount,
- bfd * archive_bfd)
+print_size_symbols (bfd *abfd,
+ bool is_dynamic,
+ struct size_sym *symsizes,
+ long symcount,
+ bfd *archive_bfd)
{
asymbol *store;
struct size_sym *from;
SIZE is the size of a symbol in MINISYMS. */
static void
-print_symbols (bfd * abfd,
- bfd_boolean is_dynamic,
- void * minisyms,
- long symcount,
- unsigned int size,
- bfd * archive_bfd)
+print_symbols (bfd *abfd,
+ bool is_dynamic,
+ void *minisyms,
+ long symcount,
+ unsigned int size,
+ bfd *archive_bfd)
{
asymbol *store;
bfd_byte *from;
{
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;
}
}
symcount = bfd_read_minisymbols (abfd, dynamic, &minisyms, &size);
- if (symcount < 0)
+ if (symcount <= 0)
{
- 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)
- {
- non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
+ if (!quiet)
+ non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
return;
}
dyn_syms = (asymbol **) xmalloc (storage);
dyn_count = bfd_canonicalize_dynamic_symtab (abfd, dyn_syms);
if (dyn_count < 0)
- bfd_fatal (bfd_get_filename (abfd));
+ dyn_count = 0;
}
}
LTO plugin. */
if (abfd->lto_slim_object)
{
- report_plugin_err = FALSE;
+ report_plugin_err = false;
non_fatal (_("%s: plugin needed to handle lto object"),
bfd_get_filename (abfd));
}
get_print_format (void)
{
const char * padding;
- if (print_format == FORMAT_POSIX)
+ if (print_format == FORMAT_POSIX || print_format == FORMAT_JUST_SYMBOLS)
{
/* POSIX compatible output does not have any padding. */
padding = "";
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;
+ case 8: radix = PRIo64; break;
+ case 10: radix = PRId64; break;
+ case 16: radix = PRIx64; break;
}
- return concat ("%", padding, length, radix, NULL);
+ return concat ("%", padding, radix, NULL);
}
static void
for (;;)
{
- PROGRESS (1);
-
arfile = bfd_openr_next_archived_file (file, arfile);
if (arfile == NULL)
{
if (bfd_get_error () != bfd_error_no_more_archived_files)
- bfd_fatal (bfd_get_filename (file));
+ bfd_nonfatal (bfd_get_filename (file));
break;
}
{
bfd_nonfatal (bfd_get_filename (arfile));
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
- {
- list_matching_formats (matching);
- free (matching);
- }
+ list_matching_formats (matching);
}
if (last_arfile != NULL)
{
+ free_lineno_cache (last_arfile);
bfd_close (last_arfile);
- lineno_cache_bfd = NULL;
- lineno_cache_rel_bfd = NULL;
if (arfile == last_arfile)
return;
}
if (last_arfile != NULL)
{
+ free_lineno_cache (last_arfile);
bfd_close (last_arfile);
- lineno_cache_bfd = NULL;
- lineno_cache_rel_bfd = NULL;
}
}
-static bfd_boolean
+static bool
display_file (char *filename)
{
- bfd_boolean retval = TRUE;
+ bool retval = true;
bfd *file;
char **matching;
if (get_file_size (filename) < 1)
- return FALSE;
+ return false;
file = bfd_openr (filename, target ? target : plugin_target);
if (file == NULL)
{
bfd_nonfatal (filename);
- return FALSE;
+ return false;
}
/* If printing line numbers, decompress the debug sections. */
{
bfd_nonfatal (filename);
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
- {
- list_matching_formats (matching);
- free (matching);
- }
- retval = FALSE;
+ list_matching_formats (matching);
+ retval = false;
}
+ free_lineno_cache (file);
if (!bfd_close (file))
- bfd_fatal (filename);
-
- lineno_cache_bfd = NULL;
- lineno_cache_rel_bfd = NULL;
+ retval = false;
return retval;
}
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));
}
}
+
+static void
+do_not_print_symbol_filename (bfd *archive_bfd ATTRIBUTE_UNUSED,
+ bfd *abfd ATTRIBUTE_UNUSED)
+{
+}
+
\f
/* Print a symbol value. */
switch (print_width)
{
case 32:
- printf (print_format_string, (unsigned long) val);
- break;
-
case 64:
-#if BFD_HOST_64BIT_LONG || BFD_HOST_64BIT_LONG_LONG
- 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)
- bfd_fprintf_vma (abfd, stdout, val);
- else
- {
- char buf[30];
- char *s;
-
- s = buf + sizeof buf;
- *--s = '\0';
- while (val > 0)
- {
- *--s = (val % print_radix) + '0';
- val /= print_radix;
- }
- while ((buf + sizeof buf - 1) - s < 16)
- *--s = '0';
- printf ("%s", s);
- }
-#endif
+ printf (print_format_string, (uint64_t) val);
break;
default:
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)
int c;
int retval;
-#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+#ifdef HAVE_LC_MESSAGES
setlocale (LC_MESSAGES, "");
#endif
-#if defined (HAVE_SETLOCALE)
setlocale (LC_CTYPE, "");
setlocale (LC_COLLATE, "");
-#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
bfd_plugin_set_program_name (program_name);
#endif
- START_PROGRESS (program_name, 0);
-
expandargv (&argc, &argv);
if (bfd_init () != BFD_INIT_MAGIC)
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:uU:vVvWX:",
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;
break;
case 'u':
undefined_only = 1;
+ defined_only = 0;
break;
+ case 'U':
+ defined_only = 1;
+ undefined_only = 0;
+ break;
+
+ case OPTION_UNICODE:
+ if (streq (optarg, "default") || streq (optarg, "d"))
+ unicode_display = unicode_default;
+ else if (streq (optarg, "locale") || streq (optarg, "l"))
+ unicode_display = unicode_locale;
+ else if (streq (optarg, "escape") || streq (optarg, "e"))
+ unicode_display = unicode_escape;
+ else if (streq (optarg, "invalid") || streq (optarg, "i"))
+ unicode_display = unicode_invalid;
+ else if (streq (optarg, "hex") || streq (optarg, "x"))
+ unicode_display = unicode_hex;
+ else if (streq (optarg, "highlight") || streq (optarg, "h"))
+ unicode_display = unicode_highlight;
+ else
+ fatal (_("invalid argument to -U/--unicode: %s"), optarg);
+ break;
+
case 'V':
show_version = 1;
break;
+ case 'W':
+ non_weak = 1;
+ break;
case 'X':
/* Ignored for (partial) AIX compatibility. On AIX, the
argument has values 32, 64, or 32_64, and specifies that
#endif
break;
+ case OPTION_IFUNC_CHARS:
+ ifunc_type_chars = optarg;
+ break;
+
case 0: /* A long option that just sets a flag. */
break;
/* We were given several filenames to do. */
while (optind < argc)
{
- PROGRESS (1);
if (!display_file (argv[optind++]))
retval++;
}
- END_PROGRESS (program_name);
-
exit (retval);
return retval;
}