]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
addr2line: Add demangler support.
authorMark Wielaard <mjw@redhat.com>
Wed, 20 May 2015 09:52:27 +0000 (11:52 +0200)
committerMark Wielaard <mjw@redhat.com>
Wed, 27 May 2015 15:17:51 +0000 (17:17 +0200)
Makes the -C, --demangle option visible and implements it (ignoring the
demangle style argument). Adds a new test with sample output.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
NEWS
src/ChangeLog
src/Makefile.am
src/addr2line.c
tests/ChangeLog
tests/Makefile.am
tests/run-addr2line-i-demangle-test.sh [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 88d622adad6d54bd62c58fd64bab17e610b63cc4..6304d88d0094fee24c25f26d4e8fa55a24b265a8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ libdw: Install new header elfutils/known-dwarf.h.
 addr2line: Input addresses are now always interpreted as hexadecimal
            numbers, never as octal or decimal numbers.
            New option -a, --addresses to print address before each entry.
+           New option -C, --demangle to show demangled symbols.
 
 Version 0.161
 
index 127e60132159343ffd5e3e19c83d6b702b3a4357..fe6f6f16e20dac17589253b13309d42c2b148d00 100644 (file)
@@ -1,3 +1,18 @@
+2015-05-20  Mark Wielaard  <mjw@redhat.com>
+
+       * Makefile.am (addr2line_LDADD): Add demanglelib.
+       * addr2line.c (argp_option): Move demangle under output format.
+       (demangle): New static bool.
+       (demangle_buffer_len): New static size_t.
+       (demangle_buffer): New static char *.
+       (main): free demangle_buffer.
+       (parse_opt): Set demangle.
+       (symname): New static function.
+       (get_diename): Use symname.
+       (print_dwarf_function): Likewise.
+       (print_addrsym): Likewise.
+       (handle_address): Likewise.
+
 2015-05-20  Mark Wielaard  <mjw@redhat.com>
 
        * addr2line.c (argp_option): Add "addresses", 'a'.
index ab5364fe7385b7ed5e04ec4b59ee1eac41ec179e..58cbe76400ee0d84282c4c19085595439c2d3815 100644 (file)
@@ -102,7 +102,7 @@ endif
 ld_LDFLAGS = -rdynamic
 elflint_LDADD  = $(libebl) $(libelf) $(libeu) $(argp_LDADD) -ldl
 findtextrel_LDADD = $(libdw) $(libelf) $(argp_LDADD)
-addr2line_LDADD = $(libdw) $(libelf) $(argp_LDADD)
+addr2line_LDADD = $(libdw) $(libelf) $(argp_LDADD) $(demanglelib)
 elfcmp_LDADD = $(libebl) $(libelf) $(argp_LDADD) -ldl
 objdump_LDADD  = $(libasm) $(libebl) $(libelf) $(libeu) $(argp_LDADD) -ldl
 ranlib_LDADD = libar.a $(libelf) $(libeu) $(argp_LDADD)
index 720a087eea3438c7844c59acb05feaa9e3aa4e7e..786afd344c464f239322878376467c3d597b6473 100644 (file)
@@ -70,11 +70,12 @@ static const struct argp_option options[] =
   { "inlines", 'i', NULL, 0,
     N_("Show all source locations that caused inline expansion of subroutines at the address."),
     0 },
+  { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL,
+    N_("Show demangled symbols (ARG is always ignored)"), 0 },
 
   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
   /* Unsupported options.  */
   { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
-  { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 },
   { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
   { NULL, 0, NULL, 0, NULL, 0 }
 };
@@ -128,6 +129,13 @@ static const char *just_section;
 /* True if all inlined subroutines of the current address should be shown.  */
 static bool show_inlines;
 
+/* True if all names need to be demangled.  */
+static bool demangle;
+
+#ifdef USE_DEMANGLE
+static size_t demangle_buffer_len = 0;
+static char *demangle_buffer = NULL;
+#endif
 
 int
 main (int argc, char *argv[])
@@ -185,6 +193,11 @@ main (int argc, char *argv[])
     }
 
   dwfl_end (dwfl);
+
+#ifdef USE_DEMANGLE
+  free (demangle_buffer);
+#endif
+
   return result;
 }
 
@@ -220,7 +233,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'b':
     case 'C':
     case OPT_DEMANGLER:
-      /* Ignored for compatibility.  */
+      demangle = true;
       break;
 
     case 's':
@@ -262,6 +275,22 @@ parse_opt (int key, char *arg, struct argp_state *state)
   return 0;
 }
 
+static const char *
+symname (const char *name)
+{
+#ifdef USE_DEMANGLE
+  // Require GNU v3 ABI by the "_Z" prefix.
+  if (demangle && name[0] == '_' && name[1] == 'Z')
+    {
+      int status = -1;
+      char *dsymname = __cxa_demangle (name, demangle_buffer,
+                                      &demangle_buffer_len, &status);
+      if (status == 0)
+       name = demangle_buffer = dsymname;
+    }
+#endif
+  return name;
+}
 
 static const char *
 get_diename (Dwarf_Die *die)
@@ -299,7 +328,7 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
          const char *name = get_diename (&scopes[i]);
          if (name == NULL)
            return false;
-         puts (name);
+         puts (symname (name));
          return true;
        }
 
@@ -308,7 +337,7 @@ print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
          const char *name = get_diename (&scopes[i]);
          if (name == NULL)
            return false;
-         printf ("%s inlined", name);
+         printf ("%s inlined", symname (name));
 
          Dwarf_Files *files;
          if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
@@ -389,6 +418,7 @@ print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
     }
   else
     {
+      name = symname (name);
       if (off == 0)
        printf ("%s", name);
       else
@@ -623,7 +653,13 @@ handle_address (const char *string, Dwfl *dwfl)
       /* First determine the function name.  Use the DWARF information if
         possible.  */
       if (! print_dwarf_function (mod, addr) && !show_symbols)
-       puts (dwfl_module_addrname (mod, addr) ?: "??");
+       {
+         const char *name = dwfl_module_addrname (mod, addr);
+         if (name != NULL)
+           puts (symname (name));
+         else
+           puts ("??");
+       }
     }
 
   if (show_symbols)
@@ -718,7 +754,7 @@ handle_address (const char *string, Dwfl *dwfl)
                                  || tag == DW_TAG_entry_point
                                  || tag == DW_TAG_subprogram)
                                {
-                                 puts (get_diename (parent));
+                                 puts (symname (get_diename (parent)));
                                  break;
                                }
                            }
index d3a0e4b0abfc5898a36fa34c4de1d1319554b12c..30ed5f590e401bb8f5119ef8c06d216aee5e8d5c 100644 (file)
@@ -1,3 +1,9 @@
+2015-05-20  Mark Wielaard  <mjw@redhat.com>
+
+       * run-addr2line-i-demangle-test.sh: New test.
+       * Makefile.am (TESTS): Add run-addr2line-i-demangle-test.sh.
+       (EXTRA_DIST): Likewise.
+
 2015-05-20  Mark Wielaard  <mjw@redhat.com>
 
        * run-addr2line-test.sh: Add -a test variants.
index fdbf5bf29672eb437b2cb3aba7a29de30e33c0a7..55241c7d18ac3075373fa3bb994a578069819215 100644 (file)
@@ -104,6 +104,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-readelf-mixed-corenote.sh run-dwfllines.sh \
        run-dwfl-report-elf-align.sh run-addr2line-test.sh \
        run-addr2line-i-test.sh run-addr2line-i-lex-test.sh \
+       run-addr2line-i-demangle-test.sh \
        run-varlocs.sh run-funcretval.sh \
        run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \
        run-backtrace-native-biarch.sh run-backtrace-native-core.sh \
@@ -254,6 +255,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             test-core.exec.bz2 run-addr2line-test.sh \
             run-addr2line-i-test.sh testfile-inlines.bz2 \
             run-addr2line-i-lex-test.sh testfile-lex-inlines.bz2 \
+            run-addr2line-i-demangle-test.sh \
             testfileppc32.bz2 testfileppc64.bz2 \
             testfiles390.bz2 testfiles390x.bz2 \
             testfilearm.bz2 testfileaarch64.bz2 \
diff --git a/tests/run-addr2line-i-demangle-test.sh b/tests/run-addr2line-i-demangle-test.sh
new file mode 100755 (executable)
index 0000000..e709acf
--- /dev/null
@@ -0,0 +1,69 @@
+#! /bin/sh
+# Copyright (C) 2015 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file 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 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils 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, see <http://www.gnu.org/licenses/>.
+
+if test -n "$ELFUTILS_DISABLE_DEMANGLE"; then
+  exit 77
+fi
+
+. $srcdir/test-subr.sh
+
+# See run-addr2line-i-test.sh for how to generate test files.
+testfiles testfile-inlines
+
+# All together now plus (demangled) function names.
+testrun_compare ${abs_top_builddir}/src/addr2line -C -f -i -e testfile-inlines 0x00000000000005a0 0x00000000000005a1 0x00000000000005b0 0x00000000000005b1 0x00000000000005c0 0x00000000000005d0 0x00000000000005e0 0x00000000000005e1 0x00000000000005f0 0x00000000000005f1 0x00000000000005f2 <<\EOF
+foobar
+/tmp/x.cpp:5
+foobar
+/tmp/x.cpp:6
+fubar
+/tmp/x.cpp:10
+fubar
+/tmp/x.cpp:11
+foobar inlined at /tmp/x.cpp:15 in bar()
+/tmp/x.cpp:5
+bar
+/tmp/x.cpp:15
+fubar inlined at /tmp/x.cpp:20 in baz()
+/tmp/x.cpp:10
+baz
+/tmp/x.cpp:20
+foobar inlined at /tmp/x.cpp:15 in foo()
+/tmp/x.cpp:5
+bar
+/tmp/x.cpp:15
+foo()
+/tmp/x.cpp:25
+fubar inlined at /tmp/x.cpp:20 in foo()
+/tmp/x.cpp:10
+baz
+/tmp/x.cpp:20
+foo()
+/tmp/x.cpp:26
+fu()
+/tmp/x.cpp:31
+fubar inlined at /tmp/x.cpp:32 in fu()
+/tmp/x.cpp:10
+fu()
+/tmp/x.cpp:32
+foobar inlined at /tmp/x.cpp:33 in fu()
+/tmp/x.cpp:5
+fu()
+/tmp/x.cpp:33
+EOF
+
+exit 0