Bug 510365

Summary: debuginfo: persevere even when missing ElfXX_Shdr
Product: [Developer tools] valgrind Reporter: John Reiser <jreiser>
Component: memcheckAssignee: Paul Floyd <pjfloyd>
Status: REPORTED ---    
Severity: normal CC: pjfloyd
Priority: NOR    
Version First Reported In: 3.24.0   
Target Milestone: ---   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed/Implemented In:
Sentry Crash Report:

Description John Reiser 2025-10-07 23:16:57 UTC
SUMMARY
ML_(read_elf_object) should not abandon so readily when .e_shoff or .e_shnum is zero. (The code is in file coregrind/m_debuginfo/readelf.c). Today it complains "Missing or invalid ELF Section Header Table" and then gives up, often leading to subsequent SIGSEGV.  A typical situation occurs when a shared library is compressed by upx, which removes all ElfXX_Shdr tables in order to reduce the size of the library as a file.  ['XX" is '64' or '32'.] This is allowed by the ELF specification, which provides two views of a module: the Execution view in ElfXX_Phdr, and the Linking view in ElfXX_Shdr.  "Mere" execution should rely only on Phdrs ("segment" info) and never depend on Shdrs ("section" info).  Memcheck still should work even without ElfXX_Shdr.

Even when there are no Shdrs, nevertheless there is other information that can be used as the basis for debuginfo.  Memcheck has the program counter (instruction pointer) which is enough to determine a file by lookup in the coregrind internal pagemap of the process.  Also, the dynamic linker of both libc and musl exports a subroutine dl_iterate_phdr (see "man 3 dl_iterate_phdr") which returns filename, base address, and pointer to the ElfXX_Phdr for each module. From the Phdr then find the PT_DYNAMIC region, which has DT_GNU_HASH,  DT_SYMTAB, DT_STRTAB, and related info.  The tables are in the SAME format (and perhaps even the same memory bytes) as SHT_SYMTAB, SHT_STRTAB, SHT_DYNSYM, etc, although the DT_ info usually is a subset, namely the exported global symbols.  Although typically more sparse than all the subroutines, the exported global symbol names are a lot better than nothing (or a bare hex address).

Beyond that, a PT_NOTE Phdr that contains a type NT_GNU_BUILD_ID often designates the same bytes as a Shdr with name .note.gnu.build-id.  The contents is the globally-unique build id, such as c3754b3a5dac8e587a355f3445043826d959604e. This corresponds to a file such as /usr/lib/.build-id/c3/754b3a5dac8e587a355f3445043826d959604e: symbolic link to ../../../../usr/bin/date  (Note the left-most byte of the build-id string is used as a directory name for a file named by the rest of the build-id.)  This is the key to some globally-known catalog of build info, such as used by --extra-debuginfo-path=.

The optional Shdr with name .gnu_debuglink hints at a software package name such as "date-9.4-9.fc40.x86_64.debug".  In current output from the static binder /bin/ld, then the .sh_flags is 0, which has no SHT_ALLOC flag, and so is not a part of the process memory image.

STEPS TO REPRODUCE
1.  Compress a shared library plugin using upx.
2.  Apply memcheck (valgrind) to a main program which uses the compressed plugin, such as a go-lang plugin.
3. 

OBSERVED RESULT
--2721452-- WARNING: Serious error when reading debug info
--2721452-- When reading debug info from /var/www/golang/plugin-server/plugins/date_time.so:
--2721452-- Missing or invalid ELF Section Header Table

then:
SIGSEGV: segmentation violation PC=0x5977d5 m=0 sigcode=2 addr=0x5977d5
signal arrived during cgo execution goroutine 1
 gp=0xc000002540 m=0 mp=0xfae580 [syscall]: runtime.cgocall(0xbb6550, 0xc000026e18) /usr/local/go/src/runtime/cgocall.go:167 +0x4b fp=0xc000026df0 sp  [[snip]]


EXPECTED RESULT
No complaint, and no SIGSEGV.

SOFTWARE/OS VERSIONS
Windows:  Parsibox Windows 11
macOS: 
(available in the Info Center app, or by running `kinfo` in a terminal window)
Linux/KDE Plasma: Linux fedora 6.14.5-100.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Fri May  2 14:22:13 UTC 2025 x86_64 GNU/Linux

KDE Plasma Version: 
KDE Frameworks Version: 
Qt Version: 

$ valgrind --version
valgrind-3.24.0

ADDITIONAL INFORMATION
Initially seen in  https://github.com/upx/upx/issues/934 .

Possibly related to KDE bug:
https://bugs.kde.org/show_bug.cgi?id=397238   valgrind   Look up of separate debuginfo does not search by build-id in --extra-debuginfo-path