Mark Wielaard [Tue, 24 Feb 2026 21:19:48 +0000 (22:19 +0100)]
aarch64: Recognize SHT_AARCH64_ATTRIBUTES
Recognize SHT_AARCH64_ATTRIBUTES. This is enough to stop elflint
complaining about unknown section types. But doesn't implement parsing
the attributes.
* backends/aarch64_symbol.c (aarch64_section_type_name):
New function.
* backends/aarch64_init.c (aarch64_init): Hook
section_type_name.
Aaron Merey [Tue, 24 Feb 2026 21:08:07 +0000 (16:08 -0500)]
dwarf_begin_elf.c: Fix lock resource leak
dwarf_begin_elf might free memory for a struct Dwarf after its rwlock and
mutex fields have been initialized without calling the corresponding
destroy functions to release the lock resources.
Fix this by moving lock inits to the end of the valid_p function, after
the struct Dwarf being intialized has passed all error checking.
Samuel Dainard [Tue, 17 Feb 2026 22:07:06 +0000 (23:07 +0100)]
readelf: Fix NULL pointer dereference in process_symtab with -D flag
When using eu-readelf with the -D (use_dynamic_segment) flag on malformed
ELF files, process_symtab can receive a NULL symstr_data pointer if
elf_getdata_rawchunk fails or the dynamic segment is malformed.
The function then dereferences symstr_data->d_buf without checking,
causing a segmentation fault.
Add NULL check before accessing symstr_data fields.
Fixes regression introduced in 0.194 where process_symtab was refactored
to handle dynamic segment symbol tables.
Signed-off-by: Samuel Dainard <sdainard@amazon.com>
Mark Wielaard [Tue, 10 Feb 2026 17:25:42 +0000 (18:25 +0100)]
tests: Skip tests on non-ELF bitcode object files
clang with -flto produces object files that contain bitcode. This
breaks various (self) testcases that expect those .o files are ELF
files. eu-readelf, eu-nm, eu-elfline and eu-elfcompress won't work on
such files.
Add a helper function is_obj_bitcode in test-subr.sh that tests can
use to possibly skip a check on an .o file.
* tests/test-subr.sh (is_obj_bitcode): New function.
(testrun_on_self): Use is_obj_bitcode to possibly skip a file.
(testrun_on_self_obj): Likewise.
(testrun_on_self_compressed): Likewise.
(testrun_on_self_quiet): Likewise.
* tests/run-elfclassify-self.sh: Check if the object files are
actually ELF files.
* tests/run-nm-self.sh: Use is_obj_bitcode to possibly skip file.
* tests/run-reverse-sections-self.sh: Likewise.
* tests/run-strip-reloc-self.sh: Likewise.
* tests/run-strip-strmerge.sh: Likewise.
* tests/strip-reloc-subr.sh: Likewise.
Mark Wielaard [Thu, 5 Feb 2026 18:58:05 +0000 (19:58 +0100)]
readelf: Handle CUs that share an addr_base or str_offsets_base
readelf assumed each .debug_addr and .debug_str_offsets was associated
with precisely one CU DIE. But CU DIEs can have the same
DW_AT_addr_base or DW_AT_str_offsets_base. Change the code to find the
first CU associated with the offset.
* src/readelf.c (print_debug_addr_section): Skip CUs that
have an addr_base already handled.
(print_debug_str_offsets_section): Likewise for
str_offsets_base.
Mark Wielaard [Mon, 9 Feb 2026 22:18:40 +0000 (23:18 +0100)]
elflint, readelf, support SHT_LLVM_LTO and SHT_LLVM_ADDRSIG
An SHT_LLVM_LTO section contains LLVM bitcode. An SHT_LLVM_ADDRSIG
section contains ULEB128 integers referring to the symbol table
indexes of address-significant symbols. This patch just recognizes the
SHT constants but doesn't handle the section contents.
* libebl/eblsectiontypename.c (ebl_section_type_name):
Recognize SHT_LLVM_ADDRSIG and SHT_LLVM_LTO.
Mark Wielaard [Mon, 9 Feb 2026 22:17:19 +0000 (23:17 +0100)]
elflint: Accept R_X86_64_DTPOFF64 in ET_REL files
Normally R_X86_64_DTPOFF32, which takes a 32bit TLS offset, is used,
but R_X86_64_DTPOFF64, which takes a 64bit TLS offset may also be used
in ET_REL files.
Aaron Merey [Tue, 3 Feb 2026 21:31:00 +0000 (16:31 -0500)]
src/elfclassify.c: Fix memory leak in check_ar_members
If current_path needs to be reallocated, full_path is assigned a newly
malloced buffer and then full_path is assigned to current_path. This
leaks the previous value of full_path.
Mark Wielaard [Sat, 7 Feb 2026 17:25:09 +0000 (18:25 +0100)]
configure: Add -Wdeprecated-non-prototype and -Wfree-labels if available
Calling a function with one or more arguments declared with an empty
parameter list is an error in C23. In C23 labels applied to
non-statements are allowed, but not in earlier standards (they are as
GNU extension in GCC). Add -Wdeprecated-non-prototype and
-Wfree-labels (available since GCC 15) to catch this.
* configure.ac: Add HAVE_DEPRECATED_NON_PROTOTYPE_WARNING
and HAVE_FREE_LABELS_WARNING check.
* config/eu.am: Set FREE_LABELS_WARNING and
FREE_LABELS_WARNING.
(AM_CFLAGS): Add DEPRECATED_NON_PROTOTYPE_WARNING and
FREE_LABELS_WARNING.
Signed-off-by: Mark Wielaard <mark@klomp.org> Reviewed-by: Sam James <sam@gentoo.org>
Mark Wielaard [Sat, 7 Feb 2026 00:48:26 +0000 (01:48 +0100)]
configure: Add -Wmissing-parameter-name if available
Before C23 omitting parameter names in function definitions isn't
supported. Add -Wmissing-parameter-name (available since GCC 15) to
catch this.
* configure.ac: Add HAVE_MISSING_PARAMETER_NAME_WARNING check.
* config/eu.am: Set MISSING_PARAMETER_NAME_WARNING based on
HAVE_MISSING_PARAMETER_NAME_WARNING.
(AM_CFLAGS): Add MISSING_PARAMETER_NAME_WARNING.
Signed-off-by: Mark Wielaard <mark@klomp.org> Reviewed-by: Sam James <sam@gentoo.org>
Mark Wielaard [Wed, 4 Feb 2026 14:09:06 +0000 (15:09 +0100)]
stacktrace: fix a C23-ism in sigint_handler
clang 21 doesn't like ommitting a parameter name when not in C23 mode.
stacktrace.c:1138:44: error: omitting the parameter name in a function definition is a C23 extension [-Werror,-Wc23-extensions]
1138 | static void sigint_handler (int /* signo */)
| ^
1 error generated.
* src/stacktrace.c (sigint_handler): Use attribute unused.
Serhei Makarov [Thu, 29 Jan 2026 17:27:50 +0000 (12:27 -0500)]
PR33854: fix regression in dwflst_perf_sample_getframes
In commit 3ce0d5ed, I missed the fact that
dwflst_perf_sample_getframes needs to handle the case of an unattached
Dwfl, when dwfl->process->ebl is not yet available to translate the
registers. Thus, it can't be a straightforward wrapper of
dwfl_sample_getframes, but should instead handle the attaching logic
identically to that function.
Also fix a leakage of sample_arg in dwflst_sample_getframes that was
happening on attach failure.
* libdwfl_stacktrace (dwflst_sample_getframes): Fix a leak of
sample_arg on attach failure.
* libdwfl_stacktrace (dwflst_perf_sample_getframes): Implement
attaching the Dwfl identically to dwflst_sample_getframes.
Avoid leaking sample_arg on attach failure.
Aaron Merey [Fri, 19 Dec 2025 22:39:36 +0000 (17:39 -0500)]
Make __libdwfl_debuginfod_find_* functions thread safe
Individual debuginfod_client objects and their underlying CURLM handles
should not be used concurrently during calls to
__libdwfl_debuginfod_find_debuginfo and
__libdwfl_debuginfod_find_executable.
Add a mutex field to struct Dwfl to serialize calls to
__libdwfl_debuginfod_find_*.
Aaron Merey [Wed, 7 Jan 2026 23:43:49 +0000 (18:43 -0500)]
gelf_getmove.c: Handle ELFCLASS32 and ELFCLASS64 separately
Currently gelf_getmove does not distinguish between ELFCLASS32 and
ELFCLASS64 binaries. This is assumes that Elf32_Move and Elf64_Move
structs are the same size.
This assumption is false since the m_info and m_poffset fields have
type uint32_t for Elf32_Move but uint64_t for Elf64_Move.
Fix this by handling ELFCLASS32 and ELFCLASS64 cases separately when
copying Elfxx_Move fields to dst.
Mark Wielaard [Sat, 20 Dec 2025 02:19:36 +0000 (03:19 +0100)]
forge: Add a forgejo workflow to run various tests
This adds a check-debian.yaml file which will run various tests under
Debian and Fedora for new merge requests.
* CONTRIBUTING: Explain how to contribute through the forge.
* .forgejo/workflows/check-debian.yaml: New Debian based workflow.
* .forgejo/workflows/check-fedora.yaml: New Fedora based workflow.
Mark Wielaard [Thu, 18 Dec 2025 15:35:06 +0000 (16:35 +0100)]
tests: Disable valgrind for run-large-elf-file and run-compress-test
Both run-compress-test and run-large-elf-file create really big
files. Processing these under valgrind take a very long time. To
encourage more testing under valgrind memcheck or helgrind disable
valgrind for these two test so people don't have to wait 10 minutes
for make check results.
Mark Wielaard [Mon, 8 Dec 2025 10:44:45 +0000 (11:44 +0100)]
libelf: Add gelf_fsize main check
This test itself isn't super interesting, it just checks that all
Elf_Types are handled by gelf_fsize and that the 32 vs 64 variant
sizes make sense. The interesting part is that it uses the internal
interface (__libelf_type_sizes) to do it. So you don't have to
contruct a whole Elf handle.
It mimics the support for "main checks" in libdw. It adds a way to
compile an individual source file with an optional main function that
can directly access the internal/static functions.
To add new main check tests you have to add an #ifdef MAIN_CHECK with
a main function that calls the test functions to the source file. And
add two make file rules after .SECONDEXPANSION. One starting with
<source_basename>_checks$(EXEEXT) and one starting with
nodist_<source_basename>_check_SOURCES.
Mark Wielaard [Fri, 5 Dec 2025 15:27:04 +0000 (16:27 +0100)]
libdw: Make sure to get .eh_frame_hdr with .eh_frame in getcfi_shdr
If we find a .eh_frame section we want to make sure to also get the
search table section .eh_frame_hdr. Otherwise lookups will be very
slow. Only create a Dwarf_CFI without a search table as a last resort.
* libdw/dwarf_getcfi_elf.c (getcfi_shdr): Keep iterating
through the shdrs till both .eh_frame and .eh_frame_hdr are
found. Check both aren't SHT_NOBITS.
Arnout Engelen [Fri, 5 Dec 2025 14:52:41 +0000 (15:52 +0100)]
tests: improve reliability of run-sysroot.sh
Previously, the 'second' test would test the `RESOLVE_IN_ROOT` feature
when the current libc supports it, even when the currently running
kernel did not yet support it.
Martin Cermak [Fri, 5 Dec 2025 13:33:57 +0000 (14:33 +0100)]
PR33635: Introduce debuginfod --home-redirect and --home-html
NEWS: New entry
debuginfod/debuginfod.cxx: Feature implementation
doc/debuginfod.8: Doc text
tests/Makefile.am: New testcase
tests/run-debuginfod-homesite.sh: New testcase
Mark Wielaard [Fri, 5 Dec 2025 11:56:22 +0000 (12:56 +0100)]
libdw: Translate DW_LANG_Algol68 to DW_LNAME_Algol68 with lversion 1978
1978 is the year of the publication of the Revised Report that defines
the revised language. And this is the version set by gcc a68. So when
we see DW_LANG_Algol68 we translate it to DW_LNAME_Algol68 with
lversion set to 1978 to match gcc a68.
* libdw/dwarf_srclang.c (srclang_to_language): Set lversion to
1978 for DW_LANG_Algol68.
Mark Wielaard [Tue, 2 Dec 2025 14:41:23 +0000 (15:41 +0100)]
libdw: Add Erlang, Elixir and Gleam language constants
The DWARF standard recently added language constants for Erlang,
Elixir and Gleam. https://dwarfstd.org/languages.html
https://dwarfstd.org/languages-v6.html
* libdw/dwarf.h: Add DW_LANG_Erlang, DW_LNAME_Erlang,
DW_LANG_Elixir, DW_LNAME_Elixir, DW_LANG_Gleam and
DW_LNAME_Gleam.
* libdw/dwarf_default_lower_bound.c
(dwarf_default_lower_bound): Add DW_LANG_Gleam, DW_LANG_Erlang
and DW_LANG_Elixir.
(dwarf_language_lower_bound): Add DW_LNAME_Gleam, DW_LNAME_Erlang
and DW_LNAME_Elixir.
* libdw/dwarf_srclang.c (srclang_to_language): Handle
DW_LANG_Erlang, DW_LANG_Elixir and DW_LANG_Gleam.
(language_to_srclang): Handle DW_LNAME_Erlang, DW_LNAME_Elixir
and Add DW_LNAME_Gleam.
Without the change the build fails on `gcc-16` as:
i386_parse.y: In function 'instrtable_out':
i386_parse.y:1245:10: error: variable 'cnt' set but not used [-Werror=unused-but-set-variable=]
1245 | size_t cnt = 0;
| ^~~
Signed-off-by: Sergei Trofimovich <slyich@gmail.com>
Mark Wielaard [Thu, 30 Oct 2025 10:43:44 +0000 (11:43 +0100)]
debuginfod: Mark internal debuginfod-client.c functions static
The init_server_urls, init_handle and perform_queries functions are
only used internally by other debuginfod-client.c and shouldn't be
exported. Make sure they aren't by marking them static.
* debuginfod/debuginfod-client.c (init_server_urls): Mark static.
(init_handle): Likewise.
(perform_queries): Likewise.
Reported-by: Matthias Klose <doko@ubuntu.com> Signed-off-by: Mark Wielaard <mark@klomp.org>
Aaron Merey [Tue, 28 Oct 2025 02:00:12 +0000 (22:00 -0400)]
readelf: Allocate job_data one-by-one as needed
Currently, job_data is stored in an array whose size is equal to the
number of debug sections (.debug_*, .eh_frame, .gdb_index, etc.).
This size may be too small if a binary contains multiple debug sections
with the same name. For example an ET_REL binary compiled with -ggdb3
can contain multiple .debug_macro sections.
Fix this by allocating job_data on the fly when preparing to read a
debug section. This supports an arbitrary number of debug sections
while also avoiding unnecessary memory allocation.
Aaron Merey [Fri, 24 Oct 2025 16:17:57 +0000 (12:17 -0400)]
backends: Guard x86_sample_* function calls behind HAVE_X86_INITREG_SAMPLE
Avoid "implicit declaration" compile errors on non-x86_64/i386 arches
by calling x86_sample_* functions only when x86_initreg_sample.c is
included in the build.
Serhei Makarov [Fri, 24 Oct 2025 14:26:03 +0000 (10:26 -0400)]
libdwfl_stacktrace + libebl: dwflst_sample_getframes non-perf api
This patch adds a generic dwflst_sample_getframes() API that does not
depend on perf_events concepts, in particular the
linux-kernel-specific enum defining the perf_regs_mask register order.
This involves reworking the register-handling backend to use
regs_mapping arrays rather than perf_regs_mask, and provide a way to
translate perf_regs_mask to regs_mapping.
A regs_mapping array, for each item in a provided regs[] array,
specifies its position in the full register file expected by the DWARF
functionality.
* libdwfl_stacktrace/Makefile.am: Rename dwflst_sample_frame.c from
dwflst_perf_frame.c.
* libdwfl_stacktrace/libdwfl_stacktrace.h (dwflst_sample_getframes):
New function providing unwinding functionality with a regs_mapping
array rather than a linux-kernel-dependent perf_regs_mask.
* libdw/libdw.map (ELFUTILS_0.194_EXPERIMENTAL): Add dwflst_sample_getframes.
* libdwfl_stacktrace/dwflst_sample_frame.c: Renamed from
dwflst_perf_frame.c. Remove linux/perf_event.h dependency.
(struct sample_info): Rename from perf_sample_info, include
regs_mapping field, replace abi with elfclass field.
(sample_next_thread): Renamed struct sample_info.
(sample_getthread): Renamed struct sample_info.
(copy_word): Use elfclass instead of perf abi field.
(elf_memory_read): Renamed struct sample_info, use elfclass.
(sample_memory_read): Renamed struct sample_info, use elfclass.
(sample_set_initial_registers): Renamed struct sample_info,
pass regs_mapping to ebl_set_initial_registers_sample.
(dwflst_sample_getframes): New function.
(dwflst_perf_sample_getframes): Reimplement in terms of
dwflst_sample_getframes and ebl_sample_perf_regs_mapping.
* libebl/ebl-hooks.h (set_initial_registers_sample): Now
takes regs_mapping instead of regs_mask.
(sample_base_addr): Removed.
(sample_pc): Removed.
(sample_sp_pc): New function combining the removed functions for
efficiency.
(sample_perf_regs_mapping): New function translating
perf_regs_mask to regs_mapping array.
* libebl/eblinitreg_sample.c (ebl_sample_base_addr): Removed.
(ebl_sample_pc): Removed.
(ebl_sample_sp_pc): New function.
(ebl_set_initial_registers_sample): Take regs_mapping, provide
a default implementation for contiguous dwarf_regs array.
(ebl_sample_perf_regs_mapping): New function.
* libebl/eblclosebackend.c (ebl_closebackend):
Free cached_regs_mapping.
* libebl/libebl.h (ebl_set_initial_registers_sample): Now takes
regs_mapping instead of regs_mask.
(ebl_sample_base_addr): Removed.
(ebl_sample_pc): Removed.
(ebl_sample_sp_pc): New function.
(ebl_sample_perf_regs_mapping): New function.
* libebl/libeblP.h (struct ebl): Add caching fields to remove the
need to repeat a sample_perf_regs_mapping() computation for
every frame when the perf_regs_mask is consistent.
* backends/Makefile.am: Remove no-longer-needed linux-perf-regs.c.
* backends/i386_init.c (i386_init): Renamed sample_* functions,
added cached_regs_mapping and related fields/functions.
* backends/i386_initreg_sample.c (i386_sample_base_addr): Removed.
(i386_sample_pc): Removed.
(i386_sample_sp_pc): New function combining the removed functions.
(i386_set_initial_registers_sample): Removed.
(i386_sample_perf_regs_mapping): New function translating
perf_regs_mask to regs_mapping array.
* backends/linux-perf-regs.c: Removed as perf_sample_find_reg is no
longer needed.
* backends/x86_64_init.c (x86_64_init): Renamed sample_* functions,
added cached_regs_mapping and related fields/functions.
* backends/x86_64_initreg_sample.c (x86_64_sample_base_addr): Removed.
(x86_64_sample_pc): Removed.
(x86_64_sample_sp_pc): New function combining the removed functions.
(x86_64_set_initial_registers_sample): Removed.
(x86_64_sample_perf_regs_mapping): New function translating
perf_regs_mask to regs_mapping array.
* backends/x86_initreg_sample.c (x86_set_initial_registers_sample):
Removed.
(x86_sample_sp_pc): New function.
(x86_sample_perf_regs_mapping): New function translating
perf_regs_mask to regs_mapping array.
Aaron Merey [Fri, 24 Oct 2025 02:25:25 +0000 (22:25 -0400)]
elf_getarhdr.c: Return correct header for archive within an archive
If elf_getarhdr is called on a descriptor that refers to an archive
which is itself a member of another archive, it may return the Elf_Arhdr
of the current member (i.e., the member selected by elf_next or elf_rand)
of the inner archive instead of Elf_Arhdr of the inner archive itself.
This also causes a memory leak: elf_end only attempts to free
Elf_Arhdr fields ar_name and ar_rawname for descriptors that are not
ELF_K_AR.
To fix this, replace the state.elf[32|64] field elf_ar_hdr with new
struct Elf field elf_ar_hdr. This field stores the Elf_Arhdr for all
descriptors of archive members, including those with kind ELF_K_AR.
Also rename the state.ar field elf_ar_hdr to cur_ar_hdr to clarify that
this is the header of an archive's current member.
Andreas Schwab [Wed, 22 Oct 2025 10:17:53 +0000 (12:17 +0200)]
readelf: use PRIu16 instead of PRId16 for uint16_t
The Elfxx_Half type is unsigned, thus it should be printed as an unsigned
type. This fixes the formatting of such a value if it is bigger than
32767, which would be printed as a negative number with the PRId16 format,
due to a recent change in glibc that properly converts the value to the
narrow type before printing.
Fixes this testsuite failure:
@@ -14,7 +14,7 @@
Flags:
Size of this header: 64 (bytes)
Size of program header entries: 56 (bytes)
- Number of program headers entries: -1 (66000 in [0].sh_info)
+ Number of program headers entries: 65535 (66000 in [0].sh_info)
Size of section header entries: 64 (bytes)
Number of section headers entries: 1
Section header string table index: 0
FAIL run-getphdrnum.sh (exit status: 1)
Aaron Merey [Thu, 9 Oct 2025 21:08:30 +0000 (17:08 -0400)]
elflint: Do not raise an error when note type is unrecognized
check_note_data compares the type of a given ELF note to a list of known
types. If the type is not recognized then an "unknown note" error is
raised.
Unknown note types do not necessarily indicate a gABI/psABI compliance
issue so an error should not be raised for this reason alone.
Additionally some common note types are missing from the list of known
types (NT_FILE for example).
Fix this by removing the "unknown note" error from check_note_data.
This patch preserves existing type-specific format checks and adds a
check for the presence of the null terminator in the note name, if
applicable. If one of these checks fails, a "malformed note" or
"missing null terminator" error is raised.
Since there are currently no type-specific checks for any ET_CORE
notes, these checks are only performed when the given binary does not
have e_type ET_CORE.
libdwfl_stacktrace: fix non-Linux build dep on PERF_SAMPLE_REGS_ABI
Reported on a GNU Hurd build of elfutils. This is a quick fix pending
my more complex patch to reduce dependency on linux perf concepts for
the libdwfl_stacktrace code.
* libdwfl_stacktrace/dwflst_perf_frame.c (perf_sample_regs_abi):
Define this Linux enum on non-Linux platforms.
Mark Wielaard [Tue, 14 Oct 2025 16:21:54 +0000 (18:21 +0200)]
libelf: elf[32|64]_offscn shouldn't return a result for empty sections
offscn sets the result before checking the section isn't empty. It
assumes the result will be reset for the next section that matches the
given offset. But this might not be the case, for example if this was
the last section. It will then return that section (and set elf_errno)
instead of returning NULL to indicate no non-empty section matched.
* libelf/elf32_offscn.c (offscn): Move assignment to result
after empty size check.
Aaron Merey [Thu, 9 Oct 2025 00:31:20 +0000 (20:31 -0400)]
configure.ac: Add option --with-libarchive
libarchive is required to build debuginfod server and optional for
eu-srcfiles (it enables the --zip option). If neither debuginfod server
nor eu-srcfiles --zip are needed, libarchive can be excluded from the
build.
Currently there is no way to exclude libarchive from the build if
PKG_CHECK_MODULES finds it at configure time. While debuginfod server
can be disabled with --disable-debuginfod, eu-srcfiles is
unconditionally built with libarchive if it is found.
Add configure option --with-libarchive so that this behavior can be
overridden.
--without-libarchive and --enable-debuginfod cannot be used together.
Aaron Merey [Tue, 7 Oct 2025 16:34:17 +0000 (12:34 -0400)]
gelf_getnote.c: Replace assert with eu_static_assert
Two runtime asserts in gelf_getnote() compare sizeof GElf_Nhdr with
Elf32_Ndhr and Elf64_Nhdr. This can be done at compile time using
eu_static_assert.
readelf.c: Avoid repeating calls to gettext _() in hotpath
Calls to the gettext _() macro in hotpaths results in unnecessary lookups
of the same translation strings during runtime.
Avoid this performance cost by calling _() for hotpath strings just once
and storing the results. Runtime speedup of up to 17% has been observed
with this patch applied.
readelf.c: Close dwfl if dwfl_report_offline fails
Within create_dwfl, if dwfl_begin is successful but dwfl_report_offline
fails, the dwfl * pointer being reported is reset to NULL without calling
dwfl_end, causing a memory leak.
Update create_dwfl to call dwfl_end in this case, preventing the leak.
elf_begin.c: Use relative offset in archive size check
Before creating an elf descriptor for an archive member, dup_elf
verifies that the size of an archive is large enough to contain the
member. This check uses the member's offset relative to the map_address
of the top-level archive containing the member.
This check can incorrectly fail when an archive contains another
archive as a member. For members of the inner archive, their offset
relative to the outer archive might be significantly larger than
the max_size of the inner archive. This appears as if the offset and
max_size values are inconsistent and the creation of the member's elf
descriptor is stopped unnecessarily.
Fix this by accounting for the inner archive's non-zero start_offset
when judging whether the member can fit within it.
Also perform this size check before creating a copy of the member's
Elf_Arhdr to prevent leaking the header's ar_name and ar_rawname if
the size check fails.
Mark Wielaard [Sat, 6 Sep 2025 10:39:15 +0000 (12:39 +0200)]
libelf: Check ELF parent size can contain ar member
Don't trust the ar header offset and size. When creating an Elf
descriptor for an ar member check the offset isn't past the end of the
containing Elf and don't use/set the member maximum_size larger than
the remaining size of the parent.
* libelf/elf_begin.c (dup_elf): Only call read_file if the
offset isn't past the end and with a maximum_size not too large.
If libdw_open_elf detects an invalid ELF file, it may attempt to
temporarily treat it as an ELF archive in order to check if there's
a valid ELF file following a header.
When doing this, the elf descriptor for the invalid file is given
the dummy state.ar.elf_ar_hdr.ar_name "libdwfl is faking you out".
Afterwards libdw_open_elf will call elf_end on the elf descriptor
for the invalid ELF file. elf_end will attempt to free the address
of the "libdwfl is faking you out" literal, causing an invalid free.
Fix this by setting the ar_name to NULL before libdw_open_elf calls
elf_end on the descriptor of the invalid ELF file.
When elf_getdata_rawchunk aquires a new chunk for the first time, it
inserts a stack-allocated dummy chunk into a search_tree with a rdlock
held. When the real chunk is prepared to replace the dummy chunk, the
rdlock is released and a wrlock is then held while replacing the
dummy with the real chunk.
Before the wrlock is held, other threads could incorrectly acquire the
dummy chunk as if it were a real chunk.
Fix this by holding a wrlock throughout elf_getdata_rawchunk.
__libdw_dieabbrev: Replace rwlock with __atomic builtins
__libdw_dieabbrev uses the abbrev_lock rwlock to synchronize access to the
Dwarf_Die abbrev field as well as its lazy loading. Calls to rwlock_wrlock
and unlock incur significant performance overhead even in single-threaded
cases.
This patch implements thread safety in __libdw_dieabbrev with GCC __atomic
builtins instead of an rwlock, improving performance. abbrev_lock has been
changed to a mutex and now synchronizes access to the Dwarf_CU field
last_abbrev_offset in __libdw_findabbrev.
libdw/
* dwarf_begin_elf.c (valid_p): Change type of abbrev_lock from
rwlock to mutex.
* dwarf_end.c (cu_free): Ditto.
* dwarf_tag.c (__libdw_findabbrev): Protect
cu->last_abbrev_offset with mutex.
* libdwP.h (struct Dwarf_CU): Change type of abbrev_lock from
rwlock to mutex.
(__libdw_dieabbrev): Use __atomic builtins instead of rwlock.
* libdw_findcu.c (__libdw_intern_next_unit): Change type of
abbrev_lock from rwlock to mutex.
Mark Wielaard [Sat, 30 Aug 2025 13:47:24 +0000 (15:47 +0200)]
elfclassify: Use (void) for no-argument static functions, not ()
In -std=gnu11 mode gcc will error out on nor argument () static
functions:
src/elfclassify.c:757:1: error: function declaration isn’t a prototype
[-Werror=strict-prototypes]
757 | check_checks ()
| ^~~~~~~~~~~~
src/elfclassify.c: In function ‘check_checks’:
src/elfclassify.c:757:1: error: old-style function definition
[-Werror=old-style-definition]
This isn't an issue in -std=gnu23 mode (the default with GCC 15):
A definition using () is not considered an old-style definition in
C23 mode, because it is equivalent to (void) in that case, but is
considered an old-style definition for older standards
So just always use (void) instead of () for an empty argument list.
* src/elfclassify.c (check_checks): Define as check_checks (void).
(check_ar_members): Define as check_ar_members (void).
There is --unstripped but that is whether the ELF file can be stripped
(further) by removing any .[z]debug_* sections or symbol table
(.symtab section). The --has-debug-sections option only checks
whether there are .[z]debug sections present.
* src/elfclassify.c (is_has_debug_sections): New function.
(enum classify_check): Add classify_has_debug_sections.
(check_checks): Add and print (if verbose)
classify_has_debug_sections value.
(main): Add ar-member to options. Update argp.doc to explain
different debug options (--unstripped, --has-debug-section and
--debug-only).
* tests/run-elfclassify.sh: Add various --has-debug-sections
tests.
Mark Wielaard [Tue, 26 Aug 2025 12:51:54 +0000 (14:51 +0200)]
elfclassify: Add --any-ar-member option to classify archive member
To determine whether an ELF archive contains a member of a particular
type add a new input option to eu-elfclassify --any-ar-member.
eu-elfclassify will match if a given file is an ELF archive and the
classification options apply to at least one of the members.
This can be used for example to check whether an ELF archive file
contains ELF members that can be stripped by using:
eu-elfclassify --ar-member --unstripped <ar-file>
* src/elfclassify.c (current_path): Drop const.
(flag_ar_member): New static bool.
(classify_flag_ar_member): new enum member.
(parse_opt): Handle classify_flag_ar_member.
(check_checks): New function taken from...
(process_current_path): ...here.
(check_ar_members): New function.
(main): Add ar-member to options. Update argp.doc.
* tests/run-elfclassify.sh: Add various --any-ar-member tests.
Aaron Merey [Mon, 11 Aug 2025 00:26:35 +0000 (20:26 -0400)]
elf_getarhdr: Replace per-archive Elf_Arhdr storage with per-member storage
Currently each archive descriptor maintains a single Elf_Arhdr for the
current archive member (as determined by elf_next or elf_rand) which is
returned by elf_getarhdr.
A single per-archive Elf_Arhdr is not ideal since elf_next and elf_rand
can invalidate an archive member's reference to its own Elf_Arhdr.
Avoid this possible invalidation by storing each Elf_Arhdr in its
archive member descriptor.
The existing Elf_Arhdr parsing and storage in the archive descriptor
internal state is left mostly untouched. When an archive member is
created with elf_begin it is given its own copy of its Elf_Arhdr from
the archive descriptor.
Also update tests/arextract.c with verification that each Elf_Arhdr
is distinct and remains valid after calls to elf_next that would
have previously invalidated the Elf_Arhdr.
Aaron Merey [Tue, 12 Aug 2025 14:39:58 +0000 (10:39 -0400)]
Makefile.am: Add errors to lcov ignore list
Recent versions of lcov may raise the following errors during
make coverage:
genhtml: ERROR: (corrupt) unable to read trace file 'elfutils.lcov':
genhtml: ERROR: (inconsistent) [...] line is hit but no branches on line have been evaluated.
Add "inconsistent,corrupt" to the --ignore-errors list so that
make coverage exits without error.
Aaron Merey [Tue, 5 Aug 2025 03:20:54 +0000 (23:20 -0400)]
src/readelf.c: Support concurrency for -w, --debug-dump
Implement concurrent execution of print_debug_* functions during handling
of -w, --debug-dump using libthread.a.
A new `-C, --concurrency=NUM` command line option controls the maximum
number of threads that may be used. This value defaults to the number of CPUs.
Job output is buffered and printed in the order that jobs were added to
the queue. This helps preserve the existing order of stdout output.
* src/readelf.c (default_concurrency): Function estimating the
maximum number of threads.
(parse_opt): Handle -C, --concurrency=NUM.
(do_job): Entry point function for threads.
(schedule_job): If thread safety is enabled, add job to the
job queue. Otherwise just run the job from the main thread.
(print_debug): Pass print_debug_* function pointers and
args to schedule_job. Also call run_jobs if thread safety
is enabled.
Aaron Merey [Tue, 5 Aug 2025 03:20:53 +0000 (23:20 -0400)]
src/readelf.c: Add support for print_debug_* output buffering
Safely handle stdout output during concurrent calls to print_debug_*
functions.
For any print_debug_* function and any function that could be called
from print_debug_* which also prints to stdout: add a FILE * argument
and replace all printf, puts, putchar with fprintf. All printing
to stdout will now be written to this FILE instead.
The FILE * is an interface to a per-thread dynamically-sized buffer.
libthread.a manages the allocation, printing and deallocation of
these buffers.
Aaron Merey [Tue, 5 Aug 2025 03:20:52 +0000 (23:20 -0400)]
src: Add threadlib library for parallel job execution
Add new internal static library libthread.a that provides infrastructure
for eu-* tools to run functions concurrently using pthreads.
threadlib.c manages per-job threads as well as per-job buffers for stdout
output. Output for each job is printed to stdout in the order that the
jobs were added to the job queue. This helps preserve the order of
output when parallelization is added to an eu-* tool.
threadlib.h declares functions add_job and run_jobs. Jobs are added to
a threadlib.c internal job queue using add_job. run_jobs concurrently
executes jobs in parallel.
eu-readelf now links against libthread.a when elfutils is configured
with --enable-thread-safety.
* src/Makefile.am: libthread.a is compiled and and linked with
readelf when USE_LOCKS is defined.
* src/threadlib.c: New file. Manages job creation, concurrent
execution and output handling.
* src/threadlib.h: New file. Declares functions add_job and
run_jobs.
Archives are usually not meant to be executable and hence should not
need the executable bit set. Drop it consistently to avoid unintential
(and potentially harmful) execution.
Note, no binary in this repository has been identified as harmful in any
way; this is just a drive-by change.
Suggested-by: Philipp Reichart <reichart@google.com> Signed-off-by: Matthias Maennich <maennich@google.com>
Aaron Merey [Sun, 10 Aug 2025 19:25:39 +0000 (15:25 -0400)]
debuginfod-find.c: Avoid leaving temp files in the cache
Add a SIGINT handler to debuginfod-find so that ctrl-c during
a download causes clean up to occur instead of immediately killing
the process and possibly leaving temp files in the client cache.
This change requires setting the client progressfn unconditionally
instead of only when --verbose is given. This in turn requires a small
change to a debuginfod-find testcase in run-debuginfod-artifact-running.sh
to account for output differences between the debuginfod-find progressfn
and the debuginfod_client default_progressfn which was previously used
when debuginfod-find lacked -v but had DEBUGINFOD_PROGRESS=1 set.
Aaron Merey [Sun, 10 Aug 2025 19:25:17 +0000 (15:25 -0400)]
debuginfod-client.c: Skip negative cache entry for cancelled downloads
The debuginfod client cache uses empty files to indicate that a download
was unsuccessful and should not be attempted again.
Commit 5527216460c61 skips the creation of empty files when a downloaded
is cancelled by the user. This works by setting
client->progressfn_cancel to true when progressfn returns a non-zero value.
Commit d47d93b1049ec appears to have accidentally removed this setting of
client->progressfn_cancel.
Restore setting client->progressfn_cancel to true when progressfn
returns a non-zero value. Also set client->progressfn_cancel to false
at the beginning of debuginfod_find_metadata to avoid previous
cancellations affecting the current metadata query.