[binutils-gdb] Add demangling support to readelf.

Nick Clifton nickc@sourceware.org
Wed Aug 12 12:32:22 GMT 2020


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=79bc120c7be00596098c09cecd25383ae6ddce34

commit 79bc120c7be00596098c09cecd25383ae6ddce34
Author: Nick Clifton <nickc@redhat.com>
Date:   Wed Aug 12 13:31:59 2020 +0100

    Add demangling support to readelf.
    
            PR binutils/26331
            * readelf.c (do_demangle): New option flag.
            (print_symbol): If do_demangle is enabled, demangle the symbol.
            (enum long_option_values): New enum to hold long option values.
            (options): Add demangle, no-demangle, recursion-limit and
            no-recursion-limit options.  Alpha sort the table.
            (usage): Describe the new options.
            (parse_args): Handle the new options.
            * NEWS: Mention the new feature.
            * doc/binutils.texi: Document the new feature.
            * testsuite/binutils-all/readelf.exp: Test the new feature.
            * testsuite/binutils-all/mangled.s: New file - assembler source.
            * testsuite/binutils-all/readelf.demangled: New file - expected
            output from readelf.

Diff:
---
 binutils/ChangeLog                                |  17 +++
 binutils/NEWS                                     |   4 +
 binutils/doc/binutils.texi                        |  30 +++++
 binutils/readelf.c                                | 132 +++++++++++++++-------
 binutils/testsuite/binutils-all/mangled.s         |   6 +
 binutils/testsuite/binutils-all/readelf.demangled |   5 +
 binutils/testsuite/binutils-all/readelf.exp       |  16 +++
 7 files changed, 172 insertions(+), 38 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 4d2ac2b63e3..162159f5cf8 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,20 @@
+2020-08-12  Nick Clifton  <nickc@redhat.com>
+
+	PR binutils/26331
+	* readelf.c (do_demangle): New option flag.
+	(print_symbol): If do_demangle is enabled, demangle the symbol.
+	(enum long_option_values): New enum to hold long option values.
+	(options): Add demangle, no-demangle, recursion-limit and
+	no-recursion-limit options.  Alpha sort the table.
+	(usage): Describe the new options.
+	(parse_args): Handle the new options.
+	* NEWS: Mention the new feature.
+	* doc/binutils.texi: Document the new feature.
+	* testsuite/binutils-all/readelf.exp: Test the new feature.
+	* testsuite/binutils-all/mangled.s: New file - assembler source.
+	* testsuite/binutils-all/readelf.demangled: New file - expected
+	output from readelf.
+
 2020-08-12  Nick Clifton  <nickc@redhat.com>
 
 	* po/sr.po: Updated Serbian translation.
diff --git a/binutils/NEWS b/binutils/NEWS
index e776f5a8267..c0dc73d7d8f 100644
--- a/binutils/NEWS
+++ b/binutils/NEWS
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* Readelf now accepts the -C command line option to enable the demangling of
+  symbol names.  In addition the --demangle=<style>, --no-demangle,
+  --recurse-limit and --no-recurse-limit options are also now availale.
+
 Changes in 2.35:
 
 * Changed readelf's display of symbol names when wide mode is not enabled.
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 0822b5c8b39..968da2cb28e 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -4694,6 +4694,8 @@ readelf [@option{-a}|@option{--all}]
         [@option{-e}|@option{--headers}]
         [@option{-s}|@option{--syms}|@option{--symbols}]
         [@option{--dyn-syms}]
+        [@option{--demangle@var{=style}}|@option{--no-demangle}]
+        [@option{--recurse-limit}|@option{--no-recurse-limit}]
         [@option{-n}|@option{--notes}]
         [@option{-r}|@option{--relocs}]
         [@option{-u}|@option{--unwind}]
@@ -4809,6 +4811,34 @@ Displays the entries in dynamic symbol table section of the file, if it
 has one.  The output format is the same as the format used by the
 @option{--syms} option.
 
+@item -C
+@itemx --demangle[=@var{style}]
+@cindex demangling in nm
+Decode (@dfn{demangle}) low-level symbol names into user-level names.
+This makes C++ function names readable.  Different compilers have
+different mangling styles.  The optional demangling style argument can
+be used to choose an appropriate demangling style for your
+compiler. @xref{c++filt}, for more information on demangling.
+
+@item --no-demangle
+Do not demangle low-level symbol names.  This is the default.
+
+@item --recurse-limit
+@itemx --no-recurse-limit
+@itemx --recursion-limit
+@itemx --no-recursion-limit
+Enables or disables a limit on the amount of recursion performed
+whilst demangling strings.  Since the name mangling formats allow for
+an inifinite level of recursion it is possible to create strings whose
+decoding will exhaust the amount of stack space available on the host
+machine, triggering a memory fault.  The limit tries to prevent this
+from happening by restricting recursion to 2048 levels of nesting.
+
+The default is for this limit to be enabled, but disabling it may be
+necessary in order to demangle truly complicated names.  Note however
+that if the recursion limit is disabled then stack exhaustion is
+possible and any bug reports about such an event will be rejected.
+
 @item -e
 @itemx --headers
 Display all the headers in the file.  Equivalent to @option{-h -l -S}.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 421992d12d9..17868e2ac9b 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -61,6 +61,7 @@
 #include "elfcomm.h"
 #include "dwarf.h"
 #include "ctf-api.h"
+#include "demangle.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
@@ -235,6 +236,8 @@ static bfd_boolean check_all = FALSE;
 static bfd_boolean is_32bit_elf = FALSE;
 static bfd_boolean decompress_dumps = FALSE;
 static bfd_boolean do_not_show_symbol_truncation = FALSE;
+static bfd_boolean do_demangle = FALSE;	/* Pretty print C++ symbol names.  */
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
 
 static char *dump_ctf_parent_name;
 static char *dump_ctf_symtab_name;
@@ -552,6 +555,7 @@ print_symbol (signed int width, const char * symbol)
   mbstate_t state;
 #endif
   unsigned int width_remaining;
+  const void * alloced_symbol = NULL;
 
   if (width < 0)
     {
@@ -584,6 +588,14 @@ print_symbol (signed int width, const char * symbol)
   memset (& state, 0, sizeof (state));
 #endif
 
+  if (do_demangle && *symbol)
+    {
+      const char * res = cplus_demangle (symbol, demangle_flags);
+
+      if (res != NULL)
+	alloced_symbol = symbol = res;
+    }
+
   while (width_remaining)
     {
       size_t  n;
@@ -643,6 +655,7 @@ print_symbol (signed int width, const char * symbol)
       num_printed = width;
     }
 
+  free ((void *) alloced_symbol);
   return num_printed;
 }
 
@@ -4471,67 +4484,76 @@ get_section_type_name (Filedata * filedata, unsigned int sh_type)
     }
 }
 
-#define OPTION_DEBUG_DUMP	512
-#define OPTION_DYN_SYMS		513
-#define OPTION_DWARF_DEPTH	514
-#define OPTION_DWARF_START	515
-#define OPTION_DWARF_CHECK	516
-#define OPTION_CTF_DUMP		517
-#define OPTION_CTF_PARENT	518
-#define OPTION_CTF_SYMBOLS	519
-#define OPTION_CTF_STRINGS	520
+enum long_option_values
+{
+  OPTION_DEBUG_DUMP = 512,
+  OPTION_DYN_SYMS,
+  OPTION_DWARF_DEPTH,
+  OPTION_DWARF_START,
+  OPTION_DWARF_CHECK,
+  OPTION_CTF_DUMP,
+  OPTION_CTF_PARENT,
+  OPTION_CTF_SYMBOLS,
+  OPTION_CTF_STRINGS,
+  OPTION_WITH_SYMBOL_VERSIONS,
+  OPTION_RECURSE_LIMIT,
+  OPTION_NO_RECURSE_LIMIT,
+  OPTION_NO_DEMANGLING
+};
 
 static struct option options[] =
 {
+ /* Note - This table is alpha-sorted on the 'val'
+    field in order to make adding new options easier.  */
+  {"arch-specific",    no_argument, 0, 'A'},
   {"all",	       no_argument, 0, 'a'},
-  {"file-header",      no_argument, 0, 'h'},
-  {"program-headers",  no_argument, 0, 'l'},
+  {"demangle",         optional_argument, 0, 'C'},
+  {"archive-index",    no_argument, 0, 'c'},
+  {"use-dynamic",      no_argument, 0, 'D'},
+  {"dynamic",	       no_argument, 0, 'd'},
   {"headers",	       no_argument, 0, 'e'},
+  {"section-groups",   no_argument, 0, 'g'},
+  {"help",	       no_argument, 0, 'H'},
+  {"file-header",      no_argument, 0, 'h'},
   {"histogram",	       no_argument, 0, 'I'},
+  {"lint",             no_argument, 0, 'L'},
+  {"enable-checks",    no_argument, 0, 'L'},
+  {"program-headers",  no_argument, 0, 'l'},
   {"segments",	       no_argument, 0, 'l'},
-  {"sections",	       no_argument, 0, 'S'},
-  {"section-headers",  no_argument, 0, 'S'},
-  {"section-groups",   no_argument, 0, 'g'},
-  {"section-details",  no_argument, 0, 't'},
   {"full-section-name",no_argument, 0, 'N'},
+  {"notes",	       no_argument, 0, 'n'},
+  {"string-dump",      required_argument, 0, 'p'},
+  {"relocated-dump",   required_argument, 0, 'R'},
+  {"relocs",	       no_argument, 0, 'r'},
+  {"section-headers",  no_argument, 0, 'S'},
+  {"sections",	       no_argument, 0, 'S'},
   {"symbols",	       no_argument, 0, 's'},
   {"syms",	       no_argument, 0, 's'},
-  {"dyn-syms",	       no_argument, 0, OPTION_DYN_SYMS},
-  {"relocs",	       no_argument, 0, 'r'},
-  {"notes",	       no_argument, 0, 'n'},
-  {"dynamic",	       no_argument, 0, 'd'},
-  {"lint",             no_argument, 0, 'L'},
-  {"enable-checks",    no_argument, 0, 'L'},
-  {"arch-specific",    no_argument, 0, 'A'},
-  {"version-info",     no_argument, 0, 'V'},
-  {"use-dynamic",      no_argument, 0, 'D'},
+  {"silent-truncation",no_argument, 0, 'T'},
+  {"section-details",  no_argument, 0, 't'},
   {"unwind",	       no_argument, 0, 'u'},
-  {"archive-index",    no_argument, 0, 'c'},
+  {"version-info",     no_argument, 0, 'V'},
+  {"version",	       no_argument, 0, 'v'},
+  {"wide",	       no_argument, 0, 'W'},
   {"hex-dump",	       required_argument, 0, 'x'},
-  {"relocated-dump",   required_argument, 0, 'R'},
-  {"string-dump",      required_argument, 0, 'p'},
   {"decompress",       no_argument, 0, 'z'},
-#ifdef SUPPORT_DISASSEMBLY
-  {"instruction-dump", required_argument, 0, 'i'},
-#endif
-  {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
 
+  {"no-demangle",      no_argument, 0, OPTION_NO_DEMANGLING},
+  {"recurse-limit",    no_argument, NULL, OPTION_RECURSE_LIMIT},
+  {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
+  {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
+  {"dyn-syms",	       no_argument, 0, OPTION_DYN_SYMS},
+  {"debug-dump",       optional_argument, 0, OPTION_DEBUG_DUMP},
   {"dwarf-depth",      required_argument, 0, OPTION_DWARF_DEPTH},
   {"dwarf-start",      required_argument, 0, OPTION_DWARF_START},
   {"dwarf-check",      no_argument, 0, OPTION_DWARF_CHECK},
-
 #ifdef ENABLE_LIBCTF
   {"ctf",	       required_argument, 0, OPTION_CTF_DUMP},
-
   {"ctf-symbols",      required_argument, 0, OPTION_CTF_SYMBOLS},
   {"ctf-strings",      required_argument, 0, OPTION_CTF_STRINGS},
   {"ctf-parent",       required_argument, 0, OPTION_CTF_PARENT},
 #endif
 
-  {"version",	       no_argument, 0, 'v'},
-  {"wide",	       no_argument, 0, 'W'},
-  {"silent-truncation",no_argument, 0, 'T'},
-  {"help",	       no_argument, 0, 'H'},
   {0,		       no_argument, 0, 0}
 };
 
@@ -4553,6 +4575,13 @@ usage (FILE * stream)
   -s --syms              Display the symbol table\n\
      --symbols           An alias for --syms\n\
      --dyn-syms          Display the dynamic symbol table\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.  (This is the default)\n\
+     --recurse-limit     Enable a demangling recursion limit.  (This is the default)\n\
+     --no-recurse-limit  Disable a demangling recursion limit\n\
   -n --notes             Display the core notes (if present)\n\
   -r --relocs            Display the relocations (if present)\n\
   -u --unwind            Display the unwind info (if present)\n\
@@ -4693,7 +4722,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
     usage (stderr);
 
   while ((c = getopt_long
-	  (argc, argv, "ADHILNR:STVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
+	  (argc, argv, "ACDHILNR:STVWacdeghi:lnp:rstuvw::x:z", options, NULL)) != EOF)
     {
       switch (c)
 	{
@@ -4718,6 +4747,7 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
 	  do_arch = TRUE;
 	  do_notes = TRUE;
 	  break;
+
 	case 'g':
 	  do_section_groups = TRUE;
 	  break;
@@ -4858,6 +4888,32 @@ parse_args (struct dump_data *dumpdata, int argc, char ** argv)
 	case 'T':
 	  do_not_show_symbol_truncation = TRUE;
 	  break;
+	case 'C':
+	  do_demangle = TRUE;
+	  if (optarg != NULL)
+	    {
+	      enum demangling_styles style;
+
+	      style = cplus_demangle_name_to_style (optarg);
+	      if (style == unknown_demangling)
+		error (_("unknown demangling style `%s'"), optarg);
+
+	      cplus_demangle_set_style (style);
+	    }
+	  break;
+	case OPTION_NO_DEMANGLING:
+	  do_demangle = FALSE;
+	  break;
+	case OPTION_RECURSE_LIMIT:
+	  demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT;
+	  break;
+	case OPTION_NO_RECURSE_LIMIT:
+	  demangle_flags |= DMGL_NO_RECURSE_LIMIT;
+	  break;
+	case OPTION_WITH_SYMBOL_VERSIONS:
+	  /* Ignored for backward compatibility.  */
+	  break;
+	  
 	default:
 	  /* xgettext:c-format */
 	  error (_("Invalid option '-%c'\n"), c);
diff --git a/binutils/testsuite/binutils-all/mangled.s b/binutils/testsuite/binutils-all/mangled.s
new file mode 100644
index 00000000000..0a28d6d4f55
--- /dev/null
+++ b/binutils/testsuite/binutils-all/mangled.s
@@ -0,0 +1,6 @@
+	.text
+		
+	.global _ZN4gold12Output_relocILi9ELb1ELi64ELb0EEC2EPNS_12Sized_relobjILi64ELb0EEEjjPNS_11Output_dataEmbbbb
+_ZN4gold12Output_relocILi9ELb1ELi64ELb0EEC2EPNS_12Sized_relobjILi64ELb0EEEjjPNS_11Output_dataEmbbbb:
+	.dc.d 0
+	
diff --git a/binutils/testsuite/binutils-all/readelf.demangled b/binutils/testsuite/binutils-all/readelf.demangled
new file mode 100644
index 00000000000..a137cedc1bb
--- /dev/null
+++ b/binutils/testsuite/binutils-all/readelf.demangled
@@ -0,0 +1,5 @@
+
+Symbol table '.symtab' contains .* entries:
+#...
+.*gold::Output_reloc<9, true, 64, false>::Output_reloc\(gold::Sized_relobj<64, false>\*, unsigned int, unsigned int, gold::Output_data\*, unsigned long, bool, bool, bool, bool\)
+#pass
diff --git a/binutils/testsuite/binutils-all/readelf.exp b/binutils/testsuite/binutils-all/readelf.exp
index 0ca27482229..d7f47da68de 100644
--- a/binutils/testsuite/binutils-all/readelf.exp
+++ b/binutils/testsuite/binutils-all/readelf.exp
@@ -345,12 +345,28 @@ if {![binutils_assemble $srcdir/$subdir/bintest.s tmpdir/bintest.o]} then {
     readelf_test -r $tempfile readelf.r  {}
 }
 
+# Test demangling symbol names.
+if {![binutils_assemble $srcdir/$subdir/mangled.s tmpdir/mangled.o]} then {
+    unresolved "readelf -s -C bintest (failed to assemble)"
+} else {
+
+    if ![is_remote host] {
+	set tempfile tmpdir/mangled.o
+    } else {
+	set tempfile [remote_download host tmpdir/mangled.o]
+    }
+
+    # Run the test.
+    readelf_test {--syms --demangle --wide} $tempfile readelf.demangled {}
+}
+
 readelf_wi_test
 readelf_compressed_wa_test
 
 readelf_dump_test
 run_dump_test "pr25543"
 
+
 # PR 13482 - Check for off-by-one errors when dumping .note sections.
 if {![binutils_assemble $srcdir/$subdir/version.s tmpdir/version.o]} then {
     unresolved "readelf -n version (failed to assemble)"


More information about the Binutils-cvs mailing list