]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
nm: Explicitly print weak 'V' or 'T' and common 'C' symbols.
authorMark Wielaard <mark@klomp.org>
Sat, 6 Jun 2020 23:02:52 +0000 (01:02 +0200)
committerMark Wielaard <mark@klomp.org>
Sat, 6 Jun 2020 23:02:52 +0000 (01:02 +0200)
Mimic binutils nm for bsd and posix formats which uses 'V' for weak
symbols, 'C' for common symbols and 'T' for weak functions. Also fix
some formatting issues. Don't print undefined addresses as zeros, but
make sure there is enough padding instead. Just print UNIQUE for
GNU_UNIQUE to make it fit 6 chars, like other binding names in sysv
format.

https://sourceware.org/bugzilla/show_bug.cgi?id=25227

Signed-off-by: Mark Wielaard <mark@klomp.org>
src/ChangeLog
src/nm.c
tests/ChangeLog
tests/Makefile.am
tests/run-nm-syms.sh [new file with mode: 0755]
tests/testfilesyms32.bz2 [new file with mode: 0644]
tests/testfilesyms64.bz2 [new file with mode: 0644]

index c8e6b4e88e70cda31ca67173f02defb90483191c..4684d332cd3432ccaaff5175add7d083638c6665 100644 (file)
@@ -1,3 +1,13 @@
+2020-06-06  Mark Wielaard  <mark@klomp.org>
+
+       * nm.c (show_symbols_sysv): Skip no name and STT_FILE symbols.
+       When not printing address and size pad strings. Strip "GNU_"
+       prefix from binding name.
+       (class_type_char): Use 'V' for weak symbols, 'C' for common
+       symbols and 'T' for weak functions.
+       (show_symbols_posix): Skip STT_FILE symbols. Don't print value and
+       size when undefined.
+
 2020-06-04  Mark Wielaard  <mark@klomp.org>
 
        * elflint.c (check_program_header): Remove PT_GNU_PROPERTY define.
index f6ca3b0aff6b3e758b4176fd85dacdf846150a8f..8302a98c442e724ba3b204f1f4dddfc935881fa2 100644 (file)
--- a/src/nm.c
+++ b/src/nm.c
@@ -797,6 +797,16 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
       const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name,
                                     symstrbuf, sizeof symstrbuf);
 
+      /* Printing entries with a zero-length name makes the output
+        not very well parseable.  Since these entries don't carry
+        much information we leave them out.  */
+      if (symstr[0] == '\0')
+       continue;
+
+      /* We do not print the entries for files.  */
+      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
+       continue;
+
 #ifdef USE_DEMANGLE
       /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
       if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
@@ -825,7 +835,10 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
 
       /* Covert the address.  */
       if (syms[cnt].sym.st_shndx == SHN_UNDEF)
-       addressbuf[0] = sizebuf[0] = '\0';
+       {
+         sprintf (addressbuf, "%*c", digits, ' ');
+         sprintf (sizebuf, "%*c", digits, ' ');
+       }
       else
        {
          snprintf (addressbuf, sizeof (addressbuf),
@@ -841,11 +854,14 @@ show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
        }
 
       /* Print the actual string.  */
+      const char *bind;
+      bind = ebl_symbol_binding_name (ebl,
+                                     GELF_ST_BIND (syms[cnt].sym.st_info),
+                                     symbindbuf, sizeof (symbindbuf));
+      if (bind != NULL && strncmp (bind, "GNU_", strlen ("GNU_")) == 0)
+       bind += strlen ("GNU_");
       printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n",
-             longest_name, symstr, addressbuf,
-             ebl_symbol_binding_name (ebl,
-                                      GELF_ST_BIND (syms[cnt].sym.st_info),
-                                      symbindbuf, sizeof (symbindbuf)),
+             longest_name, symstr, addressbuf, bind,
              ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info),
                                    symtypebuf, sizeof (symtypebuf)),
              sizebuf, longest_where, syms[cnt].where,
@@ -884,6 +900,10 @@ class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym)
       if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX
          && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
        result = 'u';
+      else if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
+       result = 'V';
+      else if (sym->st_shndx == SHN_COMMON)
+       result = 'C';
       else
        {
          GElf_Shdr shdr_mem;
@@ -898,6 +918,11 @@ class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym)
            }
        }
     }
+  else if (result == 'T')
+    {
+      if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
+       result = 'W';
+    }
 
   return local_p ? tolower (result) : result;
 }
@@ -1063,6 +1088,10 @@ show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
       if (symstr[0] == '\0')
        continue;
 
+      /* We do not print the entries for files.  */
+      if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
+       continue;
+
 #ifdef USE_DEMANGLE
       /* Demangle if necessary.  Require GNU v3 ABI by the "_Z" prefix.  */
       if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
@@ -1084,21 +1113,23 @@ show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
          putchar_unlocked (' ');
        }
 
-      printf ((radix == radix_hex
-              ? "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n"
-              : (radix == radix_decimal
-                 ? "%s %c%s %*" PRId64 " %*" PRId64 "\n"
-                 : "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n")),
-             symstr,
+      printf ("%s %c%s", symstr,
              class_type_char (elf, ehdr, &syms[cnt].sym),
              mark_special
              ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS
                 ? "@"
                 : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
                    ? "*" : " "))
-             : "",
-             digits, syms[cnt].sym.st_value,
-             digits, syms[cnt].sym.st_size);
+             : "");
+      if (syms[cnt].sym.st_shndx != SHN_UNDEF)
+       printf ((radix == radix_hex
+                ? " %0*" PRIx64 " %0*" PRIx64
+                : (radix == radix_decimal
+                   ? " %*" PRId64 " %*" PRId64
+                   : " %0*" PRIo64 " %0*" PRIo64)),
+               digits, syms[cnt].sym.st_value,
+               digits, syms[cnt].sym.st_size);
+      putchar ('\n');
     }
 
 #ifdef USE_DEMANGLE
index 05aab3ef41e5e5f5a025ee264697fbb7aed44b29..99f9da9daa6eb7541999f7895411b6df693e82f4 100644 (file)
@@ -1,3 +1,12 @@
+2020-06-06  Mark Wielaard  <mark@klomp.org>
+
+       * testfilesyms32.bz2: New test file.
+       * testfilesyms64.bz2: Likewise.
+       * run-nm-syms.sh: New test.
+       * Makefile.am (TESTS): Add run-nm-syms.sh.
+       (EXTRA_DIST): run-nm-syms.sh, testfilesyms32.bz2 and
+       testfilesyms64.bz2
+
 2020-05-08  Mark Wielaard  <mark@klomp.org>
 
        * elfputzdata.c (main): Explicitly check orig_buf is not NULL
index a7ad07d0d77fc55c7c1b4c612637262773d4b40e..7db7db1666580c508c887702c44c80f194eb114d 100644 (file)
@@ -110,7 +110,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
        run-ranlib-test2.sh run-ranlib-test3.sh run-ranlib-test4.sh \
        run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
        run-find-prologues.sh run-allregs.sh run-addrcfi.sh \
-       run-dwarfcfi.sh \
+       run-dwarfcfi.sh run-nm-syms.sh \
        run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \
        run-readelf-compressed.sh \
        run-readelf-const-values.sh \
@@ -243,6 +243,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
             run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \
             run-ranlib-test3.sh run-ranlib-test4.sh \
             run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
+            run-nm-syms.sh testfilesyms32.bz2 testfilesyms64.bz2 \
             run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \
             run-readelf-compressed.sh \
             run-readelf-const-values.sh testfile-const-values.debug.bz2 \
diff --git a/tests/run-nm-syms.sh b/tests/run-nm-syms.sh
new file mode 100755 (executable)
index 0000000..ddf0922
--- /dev/null
@@ -0,0 +1,166 @@
+#! /bin/sh
+# Copyright (C) 2020 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/>.
+
+. $srcdir/test-subr.sh
+
+# void *SYM1;
+# void *SYM2 = 0;
+# extern void *SYM3;
+# static void *SYM4;
+#
+# void *SYM6 = &SYM3;
+# static void *SYM7 = &SYM3;
+#
+# void *SYM8 __attribute__((__weak__));
+#
+# void FUN1 (void) { }
+# static void FUN2 (void) { }
+# extern void FUN3 (void);
+#
+# void *FREF = FUN3;
+#
+# void __attribute__((__weak__)) FUN4 (void) { };
+#
+# int NUM0 = 0; __asm__(".type NUM0,%gnu_unique_object");
+# int __thread NUM1 = 1;
+#
+# gcc -m64 -c syms.c -o testfilesyms64
+# gcc -m32 -c syms.c -o testfilesyms32
+
+testfiles testfilesyms32 testfilesyms64
+
+testrun_compare ${abs_top_builddir}/src/nm --format=bsd testfilesyms32 <<\EOF
+00000008 D FREF
+00000000 T FUN1
+00000010 t FUN2
+         U FUN3
+00000020 W FUN4
+00000008 u NUM0
+00000000 D NUM1
+00000004 C SYM1
+00000000 B SYM2
+         U SYM3
+0000000c b SYM4
+00000000 D SYM6
+00000004 d SYM7
+00000004 V SYM8
+         U _GLOBAL_OFFSET_TABLE_
+00000000 T __x86.get_pc_thunk.ax
+EOF
+
+testrun_compare ${abs_top_builddir}/src/nm --format=posix testfilesyms32 <<\EOF
+FREF D 00000008 00000004
+FUN1 T 00000000 00000010
+FUN2 t 00000010 00000010
+FUN3 U
+FUN4 W 00000020 00000010
+NUM0 u 00000008 00000004
+NUM1 D 00000000 00000004
+SYM1 C 00000004 00000004
+SYM2 B 00000000 00000004
+SYM3 U
+SYM4 b 0000000c 00000004
+SYM6 D 00000000 00000004
+SYM7 d 00000004 00000004
+SYM8 V 00000004 00000004
+_GLOBAL_OFFSET_TABLE_ U
+__x86.get_pc_thunk.ax T 00000000 00000000
+EOF
+
+testrun_compare ${abs_top_builddir}/src/nm --format=sysv testfilesyms32 <<\EOF
+
+
+Symbols from testfilesyms32:
+
+Name                  Value    Class  Type     Size     Line Section
+
+FREF                 |00000008|GLOBAL|OBJECT  |00000004|    |.data.rel
+FUN1                 |00000000|GLOBAL|FUNC    |00000010|    |.text
+FUN2                 |00000010|LOCAL |FUNC    |00000010|    |.text
+FUN3                 |        |GLOBAL|NOTYPE  |        |    |UNDEF
+FUN4                 |00000020|WEAK  |FUNC    |00000010|    |.text
+NUM0                 |00000008|UNIQUE|OBJECT  |00000004|    |.bss
+NUM1                 |00000000|GLOBAL|TLS     |00000004|    |.tdata
+SYM1                 |00000004|GLOBAL|OBJECT  |00000004|    |COMMON
+SYM2                 |00000000|GLOBAL|OBJECT  |00000004|    |.bss
+SYM3                 |        |GLOBAL|NOTYPE  |        |    |UNDEF
+SYM4                 |0000000c|LOCAL |OBJECT  |00000004|    |.bss
+SYM6                 |00000000|GLOBAL|OBJECT  |00000004|    |.data.rel
+SYM7                 |00000004|LOCAL |OBJECT  |00000004|    |.data.rel
+SYM8                 |00000004|WEAK  |OBJECT  |00000004|    |.bss
+_GLOBAL_OFFSET_TABLE_|        |GLOBAL|NOTYPE  |        |    |UNDEF
+__x86.get_pc_thunk.ax|00000000|GLOBAL|FUNC    |00000000|    |.text.__x86.get_pc_thunk.ax
+EOF
+
+testrun_compare ${abs_top_builddir}/src/nm --format=bsd testfilesyms64 <<\EOF
+0000000000000010 D FREF
+0000000000000000 T FUN1
+0000000000000007 t FUN2
+                 U FUN3
+000000000000000e W FUN4
+0000000000000010 u NUM0
+0000000000000000 D NUM1
+0000000000000008 C SYM1
+0000000000000000 B SYM2
+                 U SYM3
+0000000000000018 b SYM4
+0000000000000000 D SYM6
+0000000000000008 d SYM7
+0000000000000008 V SYM8
+EOF
+
+testrun_compare ${abs_top_builddir}/src/nm --format=posix testfilesyms64 <<\EOF
+FREF D 0000000000000010 0000000000000008
+FUN1 T 0000000000000000 0000000000000007
+FUN2 t 0000000000000007 0000000000000007
+FUN3 U
+FUN4 W 000000000000000e 0000000000000007
+NUM0 u 0000000000000010 0000000000000004
+NUM1 D 0000000000000000 0000000000000004
+SYM1 C 0000000000000008 0000000000000008
+SYM2 B 0000000000000000 0000000000000008
+SYM3 U
+SYM4 b 0000000000000018 0000000000000008
+SYM6 D 0000000000000000 0000000000000008
+SYM7 d 0000000000000008 0000000000000008
+SYM8 V 0000000000000008 0000000000000008
+EOF
+
+testrun_compare ${abs_top_builddir}/src/nm --format=sysv testfilesyms64 <<\EOF
+
+
+Symbols from testfilesyms64:
+
+Name   Value            Class  Type     Size             Line Section
+
+FREF  |0000000000000010|GLOBAL|OBJECT  |0000000000000008|    |.data.rel
+FUN1  |0000000000000000|GLOBAL|FUNC    |0000000000000007|    |.text
+FUN2  |0000000000000007|LOCAL |FUNC    |0000000000000007|    |.text
+FUN3  |                |GLOBAL|NOTYPE  |                |    |UNDEF
+FUN4  |000000000000000e|WEAK  |FUNC    |0000000000000007|    |.text
+NUM0  |0000000000000010|UNIQUE|OBJECT  |0000000000000004|    |.bss
+NUM1  |0000000000000000|GLOBAL|TLS     |0000000000000004|    |.tdata
+SYM1  |0000000000000008|GLOBAL|OBJECT  |0000000000000008|    |COMMON
+SYM2  |0000000000000000|GLOBAL|OBJECT  |0000000000000008|    |.bss
+SYM3  |                |GLOBAL|NOTYPE  |                |    |UNDEF
+SYM4  |0000000000000018|LOCAL |OBJECT  |0000000000000008|    |.bss
+SYM6  |0000000000000000|GLOBAL|OBJECT  |0000000000000008|    |.data.rel
+SYM7  |0000000000000008|LOCAL |OBJECT  |0000000000000008|    |.data.rel
+SYM8  |0000000000000008|WEAK  |OBJECT  |0000000000000008|    |.bss
+EOF
+
+exit 0
diff --git a/tests/testfilesyms32.bz2 b/tests/testfilesyms32.bz2
new file mode 100644 (file)
index 0000000..b3b7812
Binary files /dev/null and b/tests/testfilesyms32.bz2 differ
diff --git a/tests/testfilesyms64.bz2 b/tests/testfilesyms64.bz2
new file mode 100644 (file)
index 0000000..cdec381
Binary files /dev/null and b/tests/testfilesyms64.bz2 differ