diff --git a/src/ChangeLog b/src/ChangeLog index c8e6b4e8..4684d332 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,13 @@ +2020-06-06 Mark Wielaard + + * 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 * elflint.c (check_program_header): Remove PT_GNU_PROPERTY define. diff --git a/src/nm.c b/src/nm.c index f6ca3b0a..8302a98c 100644 --- 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 diff --git a/tests/ChangeLog b/tests/ChangeLog index 05aab3ef..99f9da9d 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2020-06-06 Mark Wielaard + + * 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 * elfputzdata.c (main): Explicitly check orig_buf is not NULL diff --git a/tests/Makefile.am b/tests/Makefile.am index a7ad07d0..7db7db16 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 00000000..ddf09222 --- /dev/null +++ b/tests/run-nm-syms.sh @@ -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 . + +. $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 index 00000000..b3b7812c Binary files /dev/null and b/tests/testfilesyms32.bz2 differ diff --git a/tests/testfilesyms64.bz2 b/tests/testfilesyms64.bz2 new file mode 100644 index 00000000..cdec3817 Binary files /dev/null and b/tests/testfilesyms64.bz2 differ