Noticed when poking at bug 549092. Apparently scanelf can't handle pre-stripped binaries for symbol searches. I'm guessing it's trying to parse the debugging information and fails, whereas once stripped, it falls back & it works fine. readelf (binutils) is fine. ``` $ file /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, not stripped $ readelf -s /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash | grep limit 155: 0001f8c0 208 OBJECT LOCAL DEFAULT 21 limits 442: 00000000 0 FUNC GLOBAL DEFAULT UND getrlimit@GLIBC_2.2 490: 00000000 0 FUNC GLOBAL DEFAULT UND setrlimit@GLIBC_2.2 510: 0000cbd0 820 FUNC GLOBAL DEFAULT 14 ulimitcmd $ scanelf -F '%s %p' -qyRgs '-^(aio_cancel|aio_error|aio_fsync|aio_read|aio_return|aio_suspend|aio_write|lio_listio|alphasort|getdirentries|readdir|readdir_r|scandir|scandirat|versionsort|creat|fallocate|fopen|fopenat|freopen|open|openat|posix_fadvise|posix_fallocate|__open|__open_2|__openat_2|ftw|nftw|glob|globfree|fgetpos|fopen|freopen|fseeko|fsetpos|ftello|tmpfile|mkostemp|mkostemps|mkstemp|mkstemps|mmap|getrlimit|prlimit|setrlimit|sendfile|fstat|fstatat|lstat|stat|__fxstat|__fxstatat|__lxstat|__xstat|fstatfs|statvfs|fstatvfs|lockf|lseek|ftruncate|pread|preadv|pwrite|pwritev|truncate|__pread_chk)(@@.*)?$' /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash $ strip /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash $ scanelf -F '%s %p' -qyRgs' ... /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash # same as above getrlimit,setrlimit /var/tmp/portage/app-shells/dash-0.5.11.5/image/bin/dash ```
We actually forgot to increment the version number. This is 1.3.4: $ scanelf --version pax-utils-v1.3.3: scanelf written for Gentoo by <solar and vapier @ gentoo.org>
Seems to be down to symbol versioning, you have two @s in your regex so it doesn't match. Unsure why we see the symbol versions in scanelf_match_symname on a binary built on an x86 system and not on an amd64 system building with -m32. $ file dash* dash: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, not stripped dash-stripped: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, stripped $ scanelf -F '%s %p' -qyRgs '-^(aio_cancel|aio_error|aio_fsync|aio_read|aio_return|aio_suspend|aio_write|lio_listio|alphasort|getdirentries|readdir|readdir_r|scandir|scandirat|versionsort|creat|fallocate|fopen|fopenat|freopen|open|openat|posix_fadvise|posix_fallocate|__open|__open_2|__openat_2|ftw|nftw|glob|globfree|fgetpos|fopen|freopen|fseeko|fsetpos|ftello|tmpfile|mkostemp|mkostemps|mkstemp|mkstemps|mmap|getrlimit|prlimit|setrlimit|sendfile|fstat|fstatat|lstat|stat|__fxstat|__fxstatat|__lxstat|__xstat|fstatfs|statvfs|fstatvfs|lockf|lseek|ftruncate|pread|preadv|pwrite|pwritev|truncate|__pread_chk)(@.*)?$' dash* getrlimit@GLIBC_2.2,setrlimit@GLIBC_2.2 dash getrlimit,setrlimit dash-stripped
AFAICT, the difference is whether scanelf peeks into symtab or not.
Smaller reproducer that works (for me :p) when compiled on x86_64: $ cat test.c #include <stdio.h> int main() { puts("Hello!"); } $ gcc test.c -o test $ scanelf -F '%s %p' -qyRgs '-^(puts)(@@.*)?$' test $ strip test $ scanelf -F '%s %p' -qyRgs '-^(puts)(@@.*)?$' test puts test $ Seems like it is what Arsen mentioned, as the "strip" gets rid of .symtab (and leaves .dynsym behind) according to "readelf -s".
Looking a bit further into this, AFAICS we need to look into both .dynsym and .symtab in places that call "scanelf_file_get_symtabs", since .symtab contains the local symbols, and the versioned external symbols, while .dynsym contains unversioned external symbols (with the versions stored in .gnu.version).