]> git.ipfire.org Git - thirdparty/elfutils.git/log
thirdparty/elfutils.git
2 weeks agoelfutils.spec.in: Add gelf man pages to %{_mandir} main
Aaron Merey [Wed, 17 Sep 2025 03:09:52 +0000 (23:09 -0400)] 
elfutils.spec.in: Add gelf man pages to %{_mandir}

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 weeks agodoc: Add gelf_getehdr.3
Aaron Merey [Sun, 14 Sep 2025 23:21:02 +0000 (19:21 -0400)] 
doc: Add gelf_getehdr.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 weeks agodoc: Add gelf_getclass.3
Aaron Merey [Sun, 14 Sep 2025 23:21:01 +0000 (19:21 -0400)] 
doc: Add gelf_getclass.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 weeks agodoc: Add elf_memory.3
Aaron Merey [Sun, 14 Sep 2025 23:21:00 +0000 (19:21 -0400)] 
doc: Add elf_memory.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 weeks agodoc: Add elf_flag*.3
Aaron Merey [Sun, 14 Sep 2025 23:20:59 +0000 (19:20 -0400)] 
doc: Add elf_flag*.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 weeks agolibelf: check ehdr isn't NULL before calling default_ehdr
Mark Wielaard [Mon, 15 Sep 2025 21:58:08 +0000 (23:58 +0200)] 
libelf: check ehdr isn't NULL before calling default_ehdr

default_ehdr assumes the passed ehdr pointer is not NULL and can be
directly dereferenced. But getehdr can return NULL. So explicitly
check.

* libelf/elf32_updatenull.c (updatenull_wrlock): Check ehdr is
        not NULL.

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

Signed-off-by: Mark Wielaard <mark@klomp.org>
3 weeks agoreadelf.c: Close dwfl if dwfl_report_offline fails
Aaron Merey [Mon, 8 Sep 2025 02:17:29 +0000 (22:17 -0400)] 
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
3 weeks agoelf_begin.c: Use relative offset in archive size check
Aaron Merey [Mon, 8 Sep 2025 02:17:28 +0000 (22:17 -0400)] 
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agolibelf: Check ELF parent size can contain ar member
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.

Signed-off-by: Mark Wielaard <mark@klomp.org>
4 weeks agolibdw_open_elf: Avoid invalid free
Aaron Merey [Fri, 5 Sep 2025 19:27:52 +0000 (15:27 -0400)] 
libdw_open_elf: Avoid invalid free

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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_next.3
Aaron Merey [Tue, 5 Aug 2025 03:24:43 +0000 (23:24 -0400)] 
doc: Add elf_next.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_rawdata.3
Aaron Merey [Tue, 5 Aug 2025 03:24:42 +0000 (23:24 -0400)] 
doc: Add elf_rawdata.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_rand.3
Aaron Merey [Tue, 5 Aug 2025 03:24:41 +0000 (23:24 -0400)] 
doc: Add elf_rand.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_newscn.3
Aaron Merey [Fri, 5 Sep 2025 15:28:15 +0000 (11:28 -0400)] 
doc: Add elf_newscn.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_newdata.3
Aaron Merey [Fri, 5 Sep 2025 15:18:11 +0000 (11:18 -0400)] 
doc: Add elf_newdata.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_gnu_hash.3
Aaron Merey [Fri, 5 Sep 2025 15:16:57 +0000 (11:16 -0400)] 
doc: Add elf_gnu_hash.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_getshdrstrndx.3 and elf_getshstrndx.3
Aaron Merey [Fri, 5 Sep 2025 14:21:20 +0000 (10:21 -0400)] 
doc: Add elf_getshdrstrndx.3 and elf_getshstrndx.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_getshdrnum.3 and elf_getshnum.3
Aaron Merey [Fri, 5 Sep 2025 14:18:42 +0000 (10:18 -0400)] 
doc: Add elf_getshdrnum.3 and elf_getshnum.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_getphdrnum.3
Aaron Merey [Tue, 5 Aug 2025 03:24:35 +0000 (23:24 -0400)] 
doc: Add elf_getphdrnum.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_getident.3
Aaron Merey [Tue, 5 Aug 2025 03:24:34 +0000 (23:24 -0400)] 
doc: Add elf_getident.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agodoc: Add elf_getdata_rawchunk.3
Aaron Merey [Tue, 5 Aug 2025 03:24:33 +0000 (23:24 -0400)] 
doc: Add elf_getdata_rawchunk.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks agoelf_getdata_rawchunk.c: Fix dummy chunk insertion race condition
Aaron Merey [Mon, 28 Jul 2025 20:32:28 +0000 (16:32 -0400)] 
elf_getdata_rawchunk.c: Fix dummy chunk insertion race condition

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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 weeks ago__libdw_dieabbrev: Replace rwlock with __atomic builtins
Aaron Merey [Tue, 2 Sep 2025 00:31:28 +0000 (20:31 -0400)] 
__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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
5 weeks agoelfclassify: Use (void) for no-argument static functions, not ()
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).

Signed-off-by: Mark Wielaard <mark@klomp.org>
5 weeks agoelfclassify: Add --has-debug-sections classification option
Mark Wielaard [Wed, 27 Aug 2025 12:57:44 +0000 (14:57 +0200)] 
elfclassify: Add --has-debug-sections classification option

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.

Signed-off-by: Mark Wielaard <mark@klomp.org>
5 weeks agoelfclassify: Add --any-ar-member option to classify archive member
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.

Signed-off-by: Mark Wielaard <mark@klomp.org>
6 weeks agoelf_getarhdr: Replace per-archive Elf_Arhdr storage with per-member storage users/amerey/try-arhdr
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agoreadelf.c: Declare num_jobs as ssize_t instead of size_t users/amerey/try-lcov-and-ssize_t
Aaron Merey [Tue, 12 Aug 2025 14:52:35 +0000 (10:52 -0400)] 
readelf.c: Declare num_jobs as ssize_t instead of size_t

Use of ssize_t prevents gcc error -Werror=sign-compare when comparing
num_jobs to ndebug_sections.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agoMakefile.am: Add errors to lcov ignore list
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agosrc/readelf.c: Support concurrency for -w, --debug-dump
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agosrc/readelf.c: Add support for print_debug_* output buffering
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agosrc: Add threadlib library for parallel job execution
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agodrop executable bits from **/*.bz2
Matthias Maennich [Mon, 11 Aug 2025 14:46:09 +0000 (14:46 +0000)] 
drop executable bits from **/*.bz2

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>
7 weeks agodebuginfod-find.c: Avoid leaving temp files in the cache
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.

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

Signed-off-by: Aaron Merey <amerey@redhat.com>
7 weeks agodebuginfod-client.c: Skip negative cache entry for cancelled downloads
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.

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_cntl.3
Aaron Merey [Thu, 17 Jul 2025 21:07:27 +0000 (17:07 -0400)] 
doc: Add elf_cntl.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_getarhdr.3
Aaron Merey [Thu, 17 Jul 2025 21:06:47 +0000 (17:06 -0400)] 
doc: Add elf_getarhdr.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_getaroff.3
Aaron Merey [Thu, 17 Jul 2025 21:03:27 +0000 (17:03 -0400)] 
doc: Add elf_getaroff.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agoelf_getaroff: Fix elf_getaroff error return value
Aaron Merey [Tue, 15 Jul 2025 04:25:51 +0000 (00:25 -0400)] 
elf_getaroff: Fix elf_getaroff error return value

elf_getaroff currently returns ELF_C_NULL (0) to indicate that an error
occured (ex. the Elf descriptor is not associated with an archive).

However elf_getaroff is intended to return -1 if an error occurs.
eu-ar assumes -1 indicates an error and other libelf implementations
use -1 to indicate an error in elf_getaroff.

Replace ELF_C_NULL with -1 as elf_getaroff's error return value.

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_strptr.3
Aaron Merey [Thu, 17 Jul 2025 21:01:51 +0000 (17:01 -0400)] 
doc: Add elf_strptr.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_scnshndx.3
Aaron Merey [Thu, 17 Jul 2025 21:01:08 +0000 (17:01 -0400)] 
doc: Add elf_scnshndx.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_rawfile.3
Aaron Merey [Thu, 17 Jul 2025 21:00:17 +0000 (17:00 -0400)] 
doc: Add elf_rawfile.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_nextscn.3
Aaron Merey [Thu, 17 Jul 2025 20:56:46 +0000 (16:56 -0400)] 
doc: Add elf_nextscn.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
2 months agodoc: Add elf_getarsym.3
Aaron Merey [Thu, 17 Jul 2025 20:45:12 +0000 (16:45 -0400)] 
doc: Add elf_getarsym.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
3 months agolibdw: Add DEFAULT_INCLUDES to CHECK_DEF_FLAGS
Mark Wielaard [Thu, 26 Jun 2025 19:36:04 +0000 (21:36 +0200)] 
libdw: Add DEFAULT_INCLUDES to CHECK_DEF_FLAGS

DEFAULT_INCLUDES includes -I. which is needed for compiling the
testcases with -DMAIN_CHECK=1.

This fixes make check after commit 76bd5f6bea9b "config: Adjust
AM_CPPFLAGS for srcdir and .. path includes"

* libdw/Makefile.am (CHECK_DEF_FLAGS): Add DEFAULT_INCLUDES.

Signed-off-by: Mark Wielaard <mark@klomp.org>
3 months agoconfig: Adjust AM_CPPFLAGS for srcdir and .. path includes
Mark Wielaard [Thu, 26 Jun 2025 13:06:07 +0000 (15:06 +0200)] 
config: Adjust AM_CPPFLAGS for srcdir and .. path includes

When building with clang and libc++ some standard headers might try
including <stack> even when no source file requests such include
directly. When building with srcdir == builddir this might clash in
the src dir since we then build a stack binary there and the src dir
also has srcfiles.cxx which might include some standard c++ headers.

Work around this by removing -I.. from AM_CPPFLAGS and replacing it
with -I(abs_top_builddir) where the <config.h> file can be found. And
use -iquote for srcdir so it doesn't get included in the search path
for the system <header> includes (only for "header" includes).

Note that DEFAULT_INCLUDES might add . and srcdir back.  So
DEFAULT_INCLUDES is disabled explicitly in src/Makefile.am (where the
stack binary is build). We could also use the nostdinc automake option
to completely suppress that, but that needs more auditing of various
installed vs not-installed header files.

* config/eu.am (AM_CPPFLAGS): Use -iquote for $(srcdir) and
        replace -I.. with -I$(abs_top_builddir).
* libdw/libdwP.h: Include "libdw.h" and "dwarf.h" instead of
        the system headers <libdw.h> and <dwarf.h>.

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

Signed-off-by: Mark Wielaard <mark@klomp.org>
3 months agolibdwl: Add validate_strdata to limit Elf_Data d_size to valid strings.
Mark Wielaard [Sat, 21 Jun 2025 11:43:51 +0000 (13:43 +0200)] 
libdwl: Add validate_strdata to limit Elf_Data d_size to valid strings.

dwfl_module_getsym returns the name of a symbol as found in the
corresponding (symbol) string section. Make sure all names are
correctly zero terminated by making sure the last valid index in a
section/segment Elf_Data contains a zero character.

* libdwfl/dwfl_module_getdwarf.c (validate_strdata): New
function taking Elf_Data and restricting d_size to last zero
char.
(translate_offs): Call validate_strdata.
(find_symtab): Likewise for both symstrdata and aux_symstrdata.

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

Signed-off-by: Mark Wielaard <mark@klomp.org>
3 months agodoc: Update elf_begin.3
Aaron Merey [Tue, 3 Jun 2025 01:22:45 +0000 (21:22 -0400)] 
doc: Update elf_begin.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agolibdw: Make __libdw_fde_by_offset static in libdw/fde.c
Mark Wielaard [Sat, 31 May 2025 22:16:51 +0000 (00:16 +0200)] 
libdw: Make __libdw_fde_by_offset static in libdw/fde.c

__libdw_fde_by_offset is marked as an extern internal function in
libdw/cfi.h (a not public header file). But it is (now) only used in
libdw/fde.c, called from __libdw_find_fde. It was originally used for
dwarf_cfi_validate_fde, but that function was deleted and never made
public. So simplify things and make it static in libdw/fde.c.

* libdw/cfi.h (__libdw_fde_by_offset): Remove.
* libdw/fde.c (__libdw_fde_by_offset): Make static.

4 months agounstrip: update unstripped_shnum when adding a new section
Mark Wielaard [Tue, 3 Jun 2025 12:06:36 +0000 (14:06 +0200)] 
unstrip: update unstripped_shnum when adding a new section

If some section doesn't match between the stripped and unstripped file
we invent a new one. Make sure to also update the shnum value.

   * src/unstrip.c (copy_elided_sections): Update unstripped_shnum.

Signed-off-by: Mark Wielaard <mark@klomp.org>
4 months agolibcpu: riscv_disasm use 50 char mnebuf
Mark Wielaard [Mon, 2 Jun 2025 23:50:07 +0000 (01:50 +0200)] 
libcpu: riscv_disasm use 50 char mnebuf

Some "illegal" instructions can be up to 24 chars (192 bits), We'll
print this as 0x<48 hex chars>. So make sure the mnebuf is 50 chars
(no terminating zero is needed).

This shows up with _FORTIFY_SOURCE which would immediate terminate on
such "illegal" instructions. Without we just use a few extra bytes on
the stack (which aren't used afterwards, without any issue, even
though it is technically UB).

* libcpu/riscv_disasm.c (riscv_disasm): Extend char mnebuf
        array to 50.

Signed-off-by: Mark Wielaard <mark@klomp.org>
4 months agolibdw: Fix eu_search_tree TOCTOU bugs
Aaron Merey [Mon, 2 Jun 2025 21:06:31 +0000 (17:06 -0400)] 
libdw: Fix eu_search_tree TOCTOU bugs

eu_tfind is used to facilitate lazy loading throughout libdw.
If a result is not found via eu_tfind, work is done to load
the result and cache it in an eu_search_tree.

Some calls to eu_tfind allow for TOCTOU bugs.  Multiple threads
might race to call eu_tfind on some result that hasn't yet been
cached.  Multiple threads may then attempt to load the result
which might cause an unnecessary amount of memory to be allocated.
Additionally this memory may not get released when the associated
libdw data structure is freed.

Fix this by adding additional locking to ensure that only one
thread performs lazy loading.

One approach used in this patch is to preserve calls to eu_tfind
without additional locking, but when the result isn't found then
a lock is then used to synchronize access to the lazy loading code.
An extra eu_tfind call has been added at the start of these critical
section to synchronize verification that lazy loading should proceed.

Another approach used is to simply synchronize entire calls to
functions where lazy loading via eu_tfind might occur (__libdw_find_fde
and __libdw_intern_expression).  In this case, new _nolock variants of
the eu_t* functions are used to avoid unnecessary double locking.

lib/
* eu-search.c: Add eu_tsearch_nolock, eu_tfind_nolock and
eu_tdelete_nolock functions.
* eu-search.h: Ditto.

libdw/
* cfi.h (struct Dwarf_CFI_s): Declare new mutex.
* dwarf_begin_elf.c (valid_p): Initialize all locks for fake CUs.
* dwarf_cfi_addrframe.c (dwarf_cfi_addrframe): Place lock around
__libdw_find_fde.
* dwarf_end.c (cu_free): Deallocate all locks unconditionally,
whether or not the CU is fake.
* dwarf_frame_cfa.c (dwarf_frame_cfa): Place lock around
__libdw_intern_expression.
* dwarf_frame_register.c (dwarf_frame_register): Ditto.
* dwarf_getcfi.c (dwarf_getcfi): Initialize cfi lock.
* dwarf_getlocation.c (is_constant_offset): Synchronize access
to lazy loading section.
(getlocation): Place lock around __libdw_intern_expression.
* dwarf_getmacros.c (cache_op_table): Synchronize access to lazy
loading section.
* frame-cache.c (__libdw_destroy_frame_cache): Free Dwarf_CFI
mutex.
* libdwP.h (struct Dwarf): Update macro_lock comment.
(struct Dwarf_CU): Declare new mutex.
libdw_findcu.c (__libdw_intern_next_unit): Initialize
intern_lock.
(__libdw_findcu): Adjust locking so that the first eu_tfind
can be done without extra lock overhead.

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agolibdwfl: resolve all paths relative to sysroot
Michal Sekletar [Mon, 2 Jun 2025 12:46:20 +0000 (14:46 +0200)] 
libdwfl: resolve all paths relative to sysroot

Whenever possible, resolve all symlinks as if the sysroot path were a
chroot environment. This prevents potential interactions with files from
the host filesystem.

Signed-off-by: Michal Sekletar <msekleta@redhat.com>
4 months agounstrip: exit early if there are no sections in the stripped file
Mark Wielaard [Sun, 1 Jun 2025 23:35:16 +0000 (01:35 +0200)] 
unstrip: exit early if there are no sections in the stripped file

If there is only section zero that shouldn't count. Then we would
still try to work on an empty set of sections and give an obscure
error later.

    * src/unstrip.c (copy_elided_sections): Check stripped_shnum <= 1.

Signed-off-by: Mark Wielaard <mark@klomp.org>
4 months agobackends/ppc_attrs.c: Add PPC long double tags
A. Wilcox [Tue, 27 May 2025 05:05:44 +0000 (00:05 -0500)] 
backends/ppc_attrs.c: Add PPC long double tags

When an explicit type of long double is specified in the ELF
GNU_Power_ABI_FP attribute, elflint and friends were erroring out:

    section [36] '.gnu.attributes': offset 15: unrecognized GNU_Power_ABI_FP attribute value 9

Add the different long double tags to fp_kinds so that these values
are correctly recognised and printed.

Signed-off-by: A. Wilcox <AWilcox@Wilcox-Tech.com>
4 months agosrc/readelf.c: Access symbol and version data only if available
Aaron Merey [Mon, 19 May 2025 19:02:07 +0000 (15:02 -0400)] 
src/readelf.c: Access symbol and version data only if available

handle_dynamic_symtab can attempt to read symbol and version data from
file offset of 0 or address of 0 if the associated DT_ tags aren't found.

Fix this by only reading symbol and version data when non-zero file
offsets/addresses have been found.

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

Suggested-by: Constantine Bytensky <cbytensky@gmail.com>
Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc: Add elf_kind.3
Aaron Merey [Tue, 13 May 2025 00:33:41 +0000 (20:33 -0400)] 
doc: Add elf_kind.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc: Add elf_hash.3
Aaron Merey [Tue, 13 May 2025 00:33:40 +0000 (20:33 -0400)] 
doc: Add elf_hash.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc: Add elf_getbase.3
Aaron Merey [Tue, 13 May 2025 00:33:39 +0000 (20:33 -0400)] 
doc: Add elf_getbase.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc: Add elf_fill.3
Aaron Merey [Tue, 13 May 2025 00:33:38 +0000 (20:33 -0400)] 
doc: Add elf_fill.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc: Add elf_end.3
Aaron Merey [Tue, 13 May 2025 00:33:37 +0000 (20:33 -0400)] 
doc: Add elf_end.3

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agodoc/Makefile.am: Sort manpages in alphabetical order
Aaron Merey [Tue, 13 May 2025 00:33:36 +0000 (20:33 -0400)] 
doc/Makefile.am: Sort manpages in alphabetical order

Signed-off-by: Aaron Merey <amerey@redhat.com>
4 months agotests: Create random test_dir name
Mark Wielaard [Tue, 6 May 2025 09:50:12 +0000 (11:50 +0200)] 
tests: Create random test_dir name

The testsuite relies on there being no files in the test directory
after the test finishes. A test will fail if the test dir cannot be
removed. But the test dir isn't really random, it uses the pid of the
shell script that executes the test. On some of the buildbots that
execute a lot of tests it can happen that the pid number wraps around
and a pid of a previous pid is reused. To prevent that happening
generate a real random number (8 bytes) using od /dev/urandom and
xargs (to trim away spaces left by od).

      * tests/test-subr.sh: Define test_name and random_number and use
      those to define test_dir.

Signed-off-by: Mark Wielaard <mark@klomp.org>
4 months agoRevert "tests/run-stack-live-test.sh: prototype 'live' eu-stack testing"
Serhei Makarov [Thu, 8 May 2025 22:30:49 +0000 (18:30 -0400)] 
Revert "tests/run-stack-live-test.sh: prototype 'live' eu-stack testing"

This reverts commit deca125665a76cf024bd063ff4f477cb675ad41e.

4 months agotests/run-stack-live-test.sh: prototype 'live' eu-stack testing
Serhei Makarov [Thu, 8 May 2025 22:17:45 +0000 (18:17 -0400)] 
tests/run-stack-live-test.sh: prototype 'live' eu-stack testing

Missing a few pieces, but worth sharing as an RFC. My idea is to
ensure better test coverage for eu-stack and then
eu-stacktrace+libdwfl_stacktrace by running against a live process
with known content, stopped at a known location, and aggressively
scrubbing output that's known to vary from testrun to testrun.

This is a very basic preview of how that might look. If the approach
is sound, I hope to make it more sophisticated/reliable.

Unanswered questions:
- Scrub more data (e.g. libc symvers) from a more known program.
  Scrub stack frame numbers to account for a case where extra frames
  appear / are missing at the bottom of the stack?
- Something better than sed for the scrubbing?
- An equivalent eu-stacktrace test will require privileged perf_events
  access for profiling data and therefore likely to be skipped by
  default. How feasible is it to be enabled on the buildbots, though?

* tests/run-stack-live-test.sh: New test with wild and fuzzy
  testrun_compare variant that scrubs inherently unpredictable parts of
  the data. Needs to scrub even more.
* tests/Makefile.am (TESTS): Add run-stack-live-test.sh.

5 months agoPR32930 backends/: guard asm/perf_regs.h include
Serhei Makarov [Mon, 5 May 2025 16:08:55 +0000 (12:08 -0400)] 
PR32930 backends/: guard asm/perf_regs.h include

asm/perf_regs.h is an arch-specific linux include, not present on
architectures like hppa and m68k that lack perf_events support.

Only one place we need to fix; others already guard the include by
architecture, or use architecture-independent headers (e.g.
linux/perf_events.h).

* backends/libebl_PERF_FLAGS.h: Only include asm/perf_regs.h on
  architectures where we use it.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdw: Add RPATH to MAIN_CHECK programs
Mark Wielaard [Sat, 3 May 2025 00:46:40 +0000 (02:46 +0200)] 
libdw: Add RPATH to MAIN_CHECK programs

We want to test the program against the just build libelf.so not the
system installed one. So add an RPATH to ../libelf.

       * libdw/Makefile.am (CHECK_DEF_FLAGS): Add -Wl,-rpath,../libelf.

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

Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agounstrip: Check symtab and strtab sections have data before use.
Mark Wielaard [Tue, 29 Apr 2025 22:22:59 +0000 (00:22 +0200)] 
unstrip: Check symtab and strtab sections have data before use.

* src/unstrip.c (copy_elided_sections): Check elf_getdata result
for symtab and strtab sections.

Suggested-by: Anton Moryakov <ant.v.moryakov@gmail.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agoreadelf: Pass around GElf_Ehdr instead of calling gelf_getehdr
Mark Wielaard [Tue, 29 Apr 2025 21:19:47 +0000 (23:19 +0200)] 
readelf: Pass around GElf_Ehdr instead of calling gelf_getehdr

handle_core_item calls gelf_getehdr for each item without checking if
the call succeeds. It should always succeed because process_elf_file
already checked gelf_getehdr returned a valid Ehdr before passing it
to handle_notes. Just pass the Ehdr down a couple more function calls.

* readelf.c (handle_core_item): Take const Gelf_Ehdr and use it.
(handle_core_items): Take const Gelf_Ehdr and pass it to
handle_core_item.
(handle_core_note): Take const Gelf_Ehdr and pass it to
handle_core_items.
(handle_notes_data): Pass ehdr to handle_core_note.

Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agoar: Check elf_getahdr doesn't return NULL
Mark Wielaard [Tue, 29 Apr 2025 20:16:58 +0000 (22:16 +0200)] 
ar: Check elf_getahdr doesn't return NULL

When elf_getahdr returns NULL we shouldn't even try to handle the ar
header, but immediately go to the next entry.

* src/ar.c (do_oper_extract): If elf_getahdr goto next.
(do_oper_delete): Likewise.
(do_oper_insert): Likewise.

Suggested-by: Anton Moryakov <ant.v.moryakov@gmail.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agoPrepare for 0.193 elfutils-0.193
Aaron Merey [Fri, 25 Apr 2025 19:26:36 +0000 (15:26 -0400)] 
Prepare for 0.193

Set version to 0.193.
Update NEWS, elftuils.spec.in and lib/printversion.c.
Regenerate po/*.po files.

Signed-off-by: Aaron Merey <amerey@redhat.com>
5 months agosrc/.gitignore: Add stacktrace
Aaron Merey [Fri, 25 Apr 2025 19:25:30 +0000 (15:25 -0400)] 
src/.gitignore: Add stacktrace

Signed-off-by: Aaron Merey <amerey@redhat.com>
5 months agoeu-stacktrace [12/12]: use dwflst_perf_sample_getframes
Serhei Makarov [Fri, 25 Apr 2025 14:55:54 +0000 (10:55 -0400)] 
eu-stacktrace [12/12]: use dwflst_perf_sample_getframes

Remove the code from src/stacktrace.c that is now covered by
libdwfl_stacktrace/dwflst_perf_frame.c and
dwflst_perf_sample_getframes.

* src/stacktrace.c (show_memory_reads): Remove this verbose option as
  the relevant code is inside libdwfl_stacktrace now.
  (struct __sample_arg): Remove, handled by
  libdwfl_stacktrace/dwflst_perf_frame.c.
  (sample_next_thread): Ditto.
  (sample_getthread): Ditto.
  (copy_word_64): Ditto.
  (copy_word_32): Ditto.
  (elf_memory_read): Ditto.
  (sample_memory_read): Ditto.
  (sample_set_initial_registers): Ditto.
  (sample_detach): Ditto.
  (sample_thread_callbacks): Ditto.
  (sysprof_find_dwfl): Now also return the Elf* so that it can be
  passed to dwflst_perf_sample_getframes. Don't create sample_arg.  Do
  record sp in sui->last_sp. Don't dwfl_attach_state,
  dwflst_perf_sample_getframes handles that now.
  (sysprof_unwind_cb): Adapt to sysprof_find_dwfl changes,
  now invoke dwflst_perf_sample_getframes instead of
  dwfl_getthread_frames.
  (parse_opt): Remove show_memory_reads.
  (main): Remove show_memory_reads.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [11/12]: add dwflst_perf_sample_getframes
Serhei Makarov [Fri, 25 Apr 2025 14:55:53 +0000 (10:55 -0400)] 
libdwfl_stacktrace [11/12]: add dwflst_perf_sample_getframes

This is a new interface for unwinding that doesn't require the Dwfl to
be attached to a live process (via ptrace) or via corefile. Instead,
data from a perf_events stack sample is provided along with an Elf
struct used to identify the architecture. Based on code from
eu-stacktrace.

* libdwfl_stacktrace/libdwfl_stacktrace.h (dwflst_perf_sample_getframes):
  New function.
* libdwfl_stacktrace/dwflst_perf_frame.c
  (struct __libdwfl_stacktrace_perf_sample_info): New struct, based on
  src/stacktrace.c struct sample_arg.
  (sample_next_thread): New function, based on src/stacktrace.c.
  (sample_getthread): Ditto.
  (copy_word_64): New macro, based on src/stacktrace.c.
  (copy_word_32): Ditto.
  (copy_word): Ditto.
  (elf_memory_read): New function, based on src/stacktrace.c.
  (sample_memory_read): Ditto.
  (sample_set_initial_registers): Ditto.
  (sample_detach): Ditto.
  (sample_thread_callbacks): New struct, set of callbacks based on
  src/stacktrace.c sample_thread_callbacks.
  (dwflst_perf_sample_getframes): New function, based on parts of
  src/stacktrace.c sysprof_find_dwfl. If the Dwfl is not attached,
  attaches it with sample_thread_callbacks and
  __libdwfl_stacktrace_perf_sample_info. Populates the
  __libdwfl_stacktrace_perf_sample_info with data from the stack
  sample and calls dwfl_getthread_frames to unwind it using the
  sample_thread_callbacks.
* libdw/libdw.map (ELFUTILS_0.193_EXPERIMENTAL): Add
  dwflst_perf_sample_getframes.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agoeu-stacktrace [10/12]: use dwflst_tracker_find_pid
Serhei Makarov [Fri, 25 Apr 2025 14:55:52 +0000 (10:55 -0400)] 
eu-stacktrace [10/12]: use dwflst_tracker_find_pid

Initial minimal change to ensure dwflst_tracker_find_pid is
tested. For now, we keep the additional dwfltab implementation in
stacktrace.c, since it's being used to track statistics.

In future follow-ups, it will be good to switch to storing
eu-stacktrace statistics e.g. in dwfl->process->callbacks_arg. This
requires some additional design to keep the statistics from being lost
when a pid is reused and the corresponding processtracker table entry
is replaced.

* src/stacktrace.c (sysprof_init_dwfl): New function.
  (sysprof_find_dwfl): Rename the existing sysprof_init_dwfl.
  Also use dwflst_tracker_find_pid with callback.
  (sysprof_unwind_cb): Rename the existing sysprof_init_dwfl.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [9/12]: add dwflst_tracker_find_pid
Serhei Makarov [Fri, 25 Apr 2025 14:55:51 +0000 (10:55 -0400)] 
libdwfl_stacktrace [9/12]: add dwflst_tracker_find_pid

New function that retrieves the Dwfl for a particular PID, or,
if the Dwfl is absent, creates it via a provided callback
and adds it to the table later, when the PID is confirmed
via dwfl_attach_state.

* libdwfl_stacktrace/libdwfl_stacktrace.h (dwflst_tracker_find_pid):
  New function.
* libdwfl_stacktrace/dwfl_process_tracker.c (dwflst_tracker_find_pid):
  New function; find a Dwfl in the dwfltab or create one using the
  provided callback.  The newly created Dwfl will be added to the
  dwfltab automatically when its pid is confirmed by a call to
  dwfl_attach_state.
* libdw/libdw.map: Add dwflst_tracker_find_pid.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [8/12]: Dwfl* caching via Dwflst_Process_Tracker
Serhei Makarov [Fri, 25 Apr 2025 14:55:50 +0000 (10:55 -0400)] 
libdwfl_stacktrace [8/12]: Dwfl* caching via Dwflst_Process_Tracker

The Dwflst_Process_Tracker also includes a dynamicsizehash cache which
maps process ids to Dwfl * (or rather, dwflst_tracker_dwfl_info *
allowing the table entry to be replaced).  Dwfls created from
the tracker are automatically added to it, and removed on dwfl_end().

* libdwfl_stacktrace/libdwfl_stacktraceP.h (dwflst_tracker_dwfl_info):
  New typedef, provides indirection to allow a dwfltab entry to be
  invalidated.
  (struct Dwflst_Process_Tracker): add dwfltab.
  (__libdwfl_stacktrace_add_dwfl_to_tracker): New function.
  (__libdwfl_stacktrace_remove_dwfl_from_tracker): New function.
* libdwfl_stacktrace/dwflst_process_tracker.c
  (dwflst_tracker_begin): Init dwfltab.
  (__libdwfl_stacktrace_add_dwfl_to_tracker): New function; add dwfl
  to dwfltab.
  (__libdwfl_stacktrace_remove_dwfl_from_tracker): New function;
  invalidate dwfl entry, since dynamicsizehash doesn't support
  outright deletion.
  (dwflst_tracker_end): Clean up dwfltab. Lock and iterate the table
  to free tracker->dwfltab.table items.
* libdwfl_stacktrace/dwflst_tracker_dwfltab.c: New file, instantiates
  lib/dynamicsizehash_concurrent.c to store dwfltracker_dwfl_info
  structs.
* libdwfl_stacktrace/dwflst_tracker_dwfltab.h: New file, ditto.
* libdwfl_stacktrace/Makefile.am
  (libdwfl_stacktrace_a_SOURCES): Add dwflst_tracker_dwfltab.c.
  (noinst_HEADERS): Add dwflst_tracker_dwfltab.h.
* libdwfl/dwfl_frame.c (dwfl_attach_state):
  Call __libdwfl_stacktrace_add_dwfl_to_tracker.
* libdwfl/dwfl_end.c (dwfl_end): Add INTDEF.
  Call __libdwfl_stacktrace_remove_dwfl_from_tracker.
* libdwfl/libdwflP.h (INTDECLs): Add dwfl_end.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agoeu-stacktrace [7/12]: use Dwflst_Process_Tracker for Elf * caching
Serhei Makarov [Fri, 25 Apr 2025 14:55:49 +0000 (10:55 -0400)] 
eu-stacktrace [7/12]: use Dwflst_Process_Tracker for Elf * caching

* src/Makefile.am (AM_CPPFLAGS): Include headers from
  ../libdwfl_stacktrace.
* src/stacktrace.c (tracker): New global variable.
  (sample_callbacks): Use dwflst_tracker_linux_proc_find_elf for
  caching.
  (sysprof_init_dwfl): Use dwflst_tracker_dwfl_begin.
  (main): Initialize and clean up tracker.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [6/12]: Elf* caching via dwflst_process_tracker
Serhei Makarov [Fri, 25 Apr 2025 14:55:48 +0000 (10:55 -0400)] 
libdwfl_stacktrace [6/12]: Elf* caching via dwflst_process_tracker

The Dwflst_Process_Tracker includes a dynamicsizehash cache which maps
file paths to Elf * (or rather, dwflst_tracker_elf_info * storing fd
and Elf *).  We provide a dwflst_tracker_linux_proc_find_elf callback
which checks the cache for an already-loaded Elf * and, if missing,
populates the cache with the fd returned by dwfl_linux_proc_find_elf.

Later, open_elf updates the cache with the Elf * for that fd.  The
commented asserts in dwflst_tracker_cache_elf still catch some cases
where a redundant Elf * is being created without checking the cache.

Since the Elf * outlasts the Dwfl that created it, we use the
(convenient, already-existing) reference count field in Elf * to
retain the data in the table.  Then dwfl_end calling elf_end will
decrement the refcount cleanly, and dwflst_tracker_end will issue
another elf_end call.

* libdwfl_stacktrace/libdwfl_stacktrace.h
  (dwflst_tracker_find_cached_elf): New function.
  (dwflst_tracker_cache_elf): New function.
  (dwflst_module_gettracker): New function, gives external users
  a way to access Dwflst_Process_Tracker given a Dwfl_Module.
  (dwflst_tracker_linux_proc_find_elf): New function, serves as a
  cached version of the dwfl_linux_proc_find_elf callback.
* libdwfl_stacktrace/libdwfl_stacktraceP.h (dwflst_tracker_elf_info):
  New struct typedef.
  (struct Dwflst_Process_Tracker): Add dynamicsizehash table of
  dwflst_tracker_elf_info structs + associated rwlock.
  (INTDECLs): Add INTDECL for dwflst_tracker_find_cached_elf,
  dwflst_tracker_cache_elf, dwflst_module_gettracker.
* libdwfl_stacktrace/dwflst_tracker_elftab.c: New file, instantiates
  lib/dynamicsizehash_concurrent.c to store dwflst_tracker_elf_info
  structs.
* libdwfl_stacktrace/dwflst_tracker_elftab.h: New file, ditto.
* libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c: New file.
* libdwfl_stacktrace/dwflst_process_tracker.c (dwflst_tracker_begin):
  Init elftab.
  (dwflst_tracker_end): Clean up elftab.  Lock and iterate the hash to
  free tracker->elftab.table items.
* libdwfl_stacktrace/dwflst_tracker_find_elf.c: New file, implements a
  find_elf callback that wraps dwfl_linux_proc_find_elf with
  additional caching logic, and an API to access the
  Dwflst_Process_Tracker Elf cache when implementing a custom find_elf
  callback.
* libdwfl_stacktrace/Makefile.am (libdwfl_stacktrace_a_SOURCES): Add
  dwflst_tracker_find_elf.c, dwflst_tracker_elftab.c,
  libdwfl_stacktrace_next_prime.c.
  (noinst_HEADERS): Add dwflst_tracker_elftab.h.
* libdw/libdw.map: Add dwflst_tracker_find_cached_elf,
  dwflst_tracker_cache_elf,
  dwflst_module_gettracker,
  dwflst_tracker_linux_proc_find_elf.
* libdwfl/Makefile.am (AM_CPPFLAGS): Include headers from
  ../libdwfl_stacktrace.
* libdwfl/dwfl_module_getdwarf.c (open_elf): Cache file->elf in
  Dwflst_Process_Tracker. Must be done here as
  dwfl_linux_proc_find_elf opens an fd but does not yet create the
  Elf *.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [5/12]: introduce Dwflst_Process_Tracker
Serhei Makarov [Fri, 25 Apr 2025 14:55:47 +0000 (10:55 -0400)] 
libdwfl_stacktrace [5/12]: introduce Dwflst_Process_Tracker

New data structure to coordinate caching Elf data among multiple Dwfl
structs attached to different processes. Meant to reduce the overhead
for profilers that use elfutils for unwinding.

The caching is well-justified, as the prior approach (e.g. in
eu-stacktrace, sysprof-live-unwinder) of creating a separate Dwfl per
process was wildly redundant, opening ~hundreds of file descriptors
just for each common library such as libc.so and leaking the data.

Initial patch just introduces the struct, to be filled in by the rest
of the patch series.

* libdwfl_stacktrace/libdwfl_stacktrace.h
  (Dwflst_Process_Tracker): New struct.
  (dwflst_tracker_begin): New function.
  (dwflst_tracker_dwfl_begin): New function.
  (dwflst_tracker_end): New function.
* libdw/libdw.map: Add new functions.
* libdwfl_stacktrace/libdwfl_stacktraceP.h
  (struct Dwflst_Process_Tracker): New struct.
* libdwfl/libdwflP.h (Dwflst_Process_Tracker): Typedef forward decl.
  (struct Dwfl): Add 'tracker' field.
* libdwfl_stacktrace/Makefile.am (libdwfl_stacktrace_a_SOURCES):
  Add dwflst_process_tracker.c.
* libdwfl_stacktrace/dwflst_process_tracker.c: New file.
  (dwflst_tracker_begin): Initialize the tracker.
  (dwflst_tracker_dwfl_begin): Initialize Dwfl * with specified tracker.
  (dwflst_tracker_end): Deallocate the tracker.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl_stacktrace [4/12]: intro library, add dwflst_perf_sample_preferred_regs_mask
Serhei Makarov [Fri, 25 Apr 2025 14:55:46 +0000 (10:55 -0400)] 
libdwfl_stacktrace [4/12]: intro library, add dwflst_perf_sample_preferred_regs_mask

Subsequent patches in the series introduce a new library for
tracking/caching Elf structs across multiple processes and wrapping
the libebl perf register handling (since libebl is a private
interface).

In this patch, add the library and an interface to access the set of
registers that libdwfl needs to allow proper unwinding of stack sample
data.  (Unwinding with a smaller set of registers can be attempted,
but will yield a truncated call chain in most cases.)

(Accessing the set of registers feels like an implementation detail,
but the profiler invoking perf_event_open and elfutils unwinding code
need to agree on the exact set of registers being requested.  So it's
best for the profiler to ask elfutils for this detail.)

* libdwfl_stacktrace/Makefile.am: New file.
* libdwfl_stacktrace/libdwfl_stacktrace.h: New file, library for
  tracking/caching Elf structs and unwinding across multiple
  processes.
* libdwfl_stacktrace/libdwfl_stacktraceP.h: New file.
* libdwfl_stacktrace/dwflst_perf_frame.c: New file.
  (dwflst_perf_sample_preferred_regs_mask): New function.
* libdw/libdw.map: Add dwflst_perf_sample_preferred_regs_mask.
* NEWS: Add NEWS item about libdwfl_stacktrace.
* configure.ac: Add libdwfl_stacktrace/Makefile.
* Makefile.am (SUBDIRS): Add libdwfl_stacktrace.
* libdw/Makefile.am (libdw_so_LIBS): Add libdwfl_stacktrace.
  (libdwfl_stacktrace_objects): Add libdwfl_stacktrace.manifest.
  (libdw_a_LIBADD): Add libdwfl_stacktrace_objects.
* config/elfutils.spec.in (%files devel): Add libdwfl_stacktrace.h.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibebl [3/12]: eu-stacktrace: use new register handling api
Serhei Makarov [Fri, 25 Apr 2025 14:55:45 +0000 (10:55 -0400)] 
libebl [3/12]: eu-stacktrace: use new register handling api

Dummy commit to show how the sample_set_initial_registers callback in
eu-stacktrace would use the proper libebl
ebl_set_initial_registers_sample function (if it were public).

* src/Makefile.am (stacktrace_LDADD): Add libebl.
* src/stacktrace.c (sample_registers_cb): New function,
  though identical to pid_thread_state_registers_cb.
  (sample_set_initial_registers): (XXX Invoke
  ebl_set_initial_registers_sample instead of containing
  platform-specific code directly.  This is now commented out.
  Patch12 in the series replaces with code in
  libdwfl_stacktrace/dwflst_perf_frame.c.)

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdwfl [2/12]: expose setfunc callback for libdwflP+libebl clients
Serhei Makarov [Fri, 25 Apr 2025 14:55:44 +0000 (10:55 -0400)] 
libdwfl [2/12]: expose setfunc callback for libdwflP+libebl clients

Renaming pid_set_initial_registers to
__libdwfl_set_initial_registers_thread and adding to libdwflP.h.

This callback was private to one file, but now we need to access it
from the perf_events sampling code as well.

* libdwfl/libdwflP.h (__libdwfl_set_initial_registers_thread): New function.
* libdwfl/linux-pid-attach.c (__libdwfl_set_initial_registers_thread):
  Renamed from pid_thread_state_registers_cb.
  (pid_set_initial_registers): Pass the newly renamed callback.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibebl [1/12]: api for perf register handling, start with x86_64
Serhei Makarov [Fri, 25 Apr 2025 14:55:43 +0000 (10:55 -0400)] 
libebl [1/12]: api for perf register handling, start with x86_64

First patch of a series that reworks eu-stacktrace functionality
into a library interface for other profiling tools.

* * *

As it happens, Linux perf_events and DWARF can prescribe completely
different layouts for the register file, requiring non-obvious code
for translation. This makes sense to put in libebl if we want
profilers to handle perf sample data with elfutils.

Start with the x86_64/i386 implementation taken from eu-stacktrace. The
code has been generalized to accept other perf register masks besides
the 'preferred' one.

* backends/Makefile.am (i386_SRCS): Add i386_initreg_sample.c.
  (x86_64_SRCS): Add x86_64_initreg_sample.c.
  (noinst_HEADERS): Add libebl_PERF_FLAGS.h,
  linux-perf-regs.c, x86_initreg_sample.c.
* backends/libebl_PERF_FLAGS.h: New file.
* backends/linux-perf-regs.c: New file.
  (perf_sample_find_reg): Index into a perf register array whose
  contents are described by regs_mask. The target index is the index
  of the register in the enum defined by
  linux arch/N/include/uapi/asm/perf_regs.h on arch N.
* backends/x86_initreg_sample.c: New file, implements a generalized
  version of the eu-stacktrace register shuffling for x86-64/i386.
* backends/x86_64_initreg_sample.c: New file, specializes
  x86_initreg_sample.c for x86-64.
* backends/i386_initreg_sample.c: New file, specializes
  i386_initreg_sample.c for i386.
* backends/x86_64_init.c (x86_64_init): Add initialization for
  set_initial_registers_sample, perf_frame_regs_mask,
  sample_base_addr, sample_pc.
* backends/i386_init.c (i386_init): Add initialization for
  set_initial_registers_sample, perf_frame_regs_mask,
  sample_base_addr, sample_pc.
* libebl/Makefile.am (libebl_a_SOURCES): Add eblinitreg_sample.c.
* libebl/ebl-hooks.h (set_initial_registers_sample): New hook.
  (sample_base_addr): Ditto.
  (sample_pc): Ditto.
* libebl/eblinitreg_sample.c: New file, implements ebl interface to
  set_initial_registers_sample, sample_base_addr, sample_pc
  backend hooks.
* libebl/libebl.h (ebl_set_initial_registers_sample): New function.
  (ebl_perf_frame_regs_mask): New function.
  (ebl_sample_base_addr): New function.
  (ebl_sample_pc): New function.
* libebl/libeblP.h (struct ebl): Add perf_frame_regs_mask field
  giving the preferred register mask.

Signed-off-by: Serhei Makarov <serhei@serhei.io>
5 months agolibdw: Add Nim language and dwarf_srclang tests
Mark Wielaard [Wed, 2 Apr 2025 11:35:31 +0000 (13:35 +0200)] 
libdw: Add Nim language and dwarf_srclang tests

DW_LANG_Nim and DW_LNAME_Nim were added to the DWARF languages.

While adding them, and the default lower bounds, I noticed DW_LANG_V
and DW_LANG_Algol68 where missing in srclang_to_language an internal
helper function.

Testing through the public api is not that easy since you need a
Dwarf_Die with the right attributes. So this patch adds a way to
compile an individual source file with an optional main function that
can directly access the internal/static functions.

Note that it is almost generic. But even though using .SECONDEXPANSION
I couldn't figure out how to create the equivalent of a rule starting
with %_check$(EXEEXT) target. So for now the rule has to repeated for
every new _check TEST. And there needs to be a line to tell make dist
to not expect the fake source: nodist_src_check_SOURCES = src_check.c

The new test pointed out that there were a few more bugs with
DW_LANG_Dylan and DW_LNAME_Mojo. Also fix those.

* libdw/dwarf.h: Add DW_LANG_Nim and DW_LNAME_Nim.
* libdw/Makefile.am: Add check_PROGRAMS and TESTS for
dwarf_srclang_check.
* libdw/dwarf_default_lower_bound.c
        (dwarf_default_lower_bound): Add DW_LANG_Nim.
(dwarf_language_lower_bound): Add DW_LNAME_Nim.
* libdw/dwarf_srclang.c (srclang_to_language): Handle
DW_LANG_Dylan, DW_LANG_V, DW_LANG_Algol68 and DW_LANG_Nim.
(language_to_srclang): Fix DW_LNAME_Mojo. Add DW_LNAME_Nim.
(test_lang): New function guarded by MAIN_CHECK.
(main): Likewise.

Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agolib: Prevent double inclusion of config.h through system.h
Mark Wielaard [Fri, 4 Apr 2025 11:50:04 +0000 (13:50 +0200)] 
lib: Prevent double inclusion of config.h through system.h

Files that include both <config.h> and "system.h" might include
config.h twice. Prevent that by adding a guard check in system.h
before including config.h.

       * lib/crc32.c: Use #ifdef HAVE_CONFIG_H instead of #if.
       * lib/error.h: Check HAVE_CONFIG_H before including config.h.
       * lib/system.h: Check both HAVE_CONFIG_H and whether
       EU_CONFIG_H is defined before including config.h.

Suggested-by: Dmitry V. Levin <ldv@strace.io>
Signed-off-by: Mark Wielaard <mark@klomp.org>
5 months agoconfigure: Use AC_CHECK_HEADERS to detect stdatomic.h
Mark Wielaard [Sun, 6 Apr 2025 16:04:10 +0000 (18:04 +0200)] 
configure: Use AC_CHECK_HEADERS to detect stdatomic.h

* configure.ac: Use AC_CHECK_HEADERS instead of
AC_COMPILE_IFELSE.

Suggested-by: Dmitry V. Levin <ldv@strace.io>
Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoreadelf: Add 'Key to Flags' to eu-readelf --section-headers output
Samuel Zeter [Thu, 3 Apr 2025 07:24:13 +0000 (17:24 +1000)] 
readelf: Add 'Key to Flags' to eu-readelf --section-headers output

When printing section headers, also include a key to what each flag
is at the end of the section header output.

   * src/readelf.c (print_flag_info): New function.
   (print_shdr): Call print_flag_info.
   * tests/run-copyadd-sections.sh: Fix .extra grep by escaping \.
   * tests/run-large-elf-file.sh: Likewise.
   * tests/test-copymany-subr.sh: Likewise.
   * tests/run-readelf-z.sh: Add Key to Flags to expected output.
   * tests/run-retain.sh: Likewise.
   * tests/run-strip-remove-keep.sh: Likewise.

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

Signed-off-by: Samuel Zeter <samuelzeter@gmail.com>
6 months agodebuginfod: add --listen-address option
Michael Trapp [Thu, 27 Mar 2025 16:06:35 +0000 (17:06 +0100)] 
debuginfod: add --listen-address option

Use MHD_OPTION_SOCK_ADDR to bind the http listen socket to a single address.
The address should be an IPv4 or IPv6 address configured on the system:
    --listen-address=127.0.0.1
    --listen-address=::1
    --listen-address='LOCAL_IPv4|IPv6_ADDRESS'
As debuginfod does not include any security features, a listen on the
localhost address is sufficient for a HTTP/HTTPS reverse-proxy setup.

Signed-off-by: Michael Trapp <michael.trapp@sap.com>
6 months agolibdw/libdw_findcu.c: Fix TOCTOU race condition in __libdw_findcu
Aaron Merey [Thu, 27 Mar 2025 03:35:47 +0000 (23:35 -0400)] 
libdw/libdw_findcu.c: Fix TOCTOU race condition in __libdw_findcu

Ensure that dwarf_lock is held before accessing next_tu_offset and
next_cu_offset.

This fixes a TOCTOU bug in __libdw_findcu that causes NULL to be
incorrectly returned.

Signed-off-by: Aaron Merey <amerey@redhat.com>
6 months agotests/.gitignore: Add dwarf_language_lower_bound, test-manyfuncs
Aaron Merey [Thu, 27 Mar 2025 03:34:22 +0000 (23:34 -0400)] 
tests/.gitignore: Add dwarf_language_lower_bound, test-manyfuncs

Signed-off-by: Aaron Merey <amerey@redhat.com>
6 months agotests/thread-safety-subr.sh: Change if [[ ]] to if [ ]
Mark Wielaard [Wed, 26 Mar 2025 22:50:57 +0000 (23:50 +0100)] 
tests/thread-safety-subr.sh: Change if [[ ]] to if [ ]

Using [[ is a bashism. We can just use [ since this is a simple
comparision.

* tests/thread-safety-subr.sh: Use if [ instead of if [[.

Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoAdd tests/run-eu-search-die.sh
Heather S. McIntyre [Wed, 26 Mar 2025 20:13:02 +0000 (16:13 -0400)] 
Add tests/run-eu-search-die.sh

* tests/.gitignore: Add eu_search_die.
* tests/Makefile.am: Add eu_search_die, run-eu-search-die.sh.
* tests/eu_search_die.c: New file.
* tests/run-eu-search-die.sh: New file.

Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
Signed-off-by: Aaron Merey <amerey@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoAdd tests/run-eu-search-lines.sh
Heather S. McIntyre [Wed, 26 Mar 2025 19:51:32 +0000 (15:51 -0400)] 
Add tests/run-eu-search-lines.sh

* tests/.gitignore: Add eu_search-lines.
* tests/Makefile.am: Add eu_search_lines,
run-eu-search-lines.sh.
* tests/eu_search_lines.c: New file.
tests/run-eu-search-lines.sh: New file.

Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
Signed-off-by: Aaron Merey <amerey@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoAdd tests/run-eu-search-macros.sh
Heather S. McIntyre [Wed, 26 Mar 2025 19:46:10 +0000 (15:46 -0400)] 
Add tests/run-eu-search-macros.sh

* tests/.gitignore: Add eu_search_macros.sh
* tests/Makefile.am: Add eu_search_macros,
run-eu-search-macros.sh.
* tests/eu_search_macros.c: New file.
* tests/run-eu-search-macros.sh: New file.

Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
Signed-off-by: Aaron Merey <amerey@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoAdd tests/run-eu-search-cfi.sh
Heather S. McIntyre [Wed, 26 Mar 2025 19:43:08 +0000 (15:43 -0400)] 
Add tests/run-eu-search-cfi.sh

* tests/.gitignore: Add eu_search_cfi.
* tests/Makefile.am: Add eu_search_cfi, run-eu-search-cfi.sh.
* tests/eu_search_cfi.c: New file.
* tests/run-eu-search-cfi.sh: New file.

Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
Signed-off-by: Aaron Merey <amerey@redhat.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
6 months agoAdd tests/thread-safety-subr.sh
Aaron Merey [Wed, 26 Mar 2025 19:37:50 +0000 (15:37 -0400)] 
Add tests/thread-safety-subr.sh

thread-safety-subr.sh contains subroutine check_thread_safety_enabled
which skips further testing when USE_LOCKS is false.

* tests/Makefile.am (EXTRA_DIST): Add thread-safety-subr.sh.
* tests/thread-safety-subr.sh: New file.

Signed-off-by: Aaron Merey <amerey@redhat.com>
6 months agoAdd configure option --enable-helgrind
Aaron Merey [Wed, 26 Mar 2025 19:26:58 +0000 (15:26 -0400)] 
Add configure option --enable-helgrind

Like --enable-valgrind but uses helgrind instead of memcheck.

If both --enable-valgrind and --enable-helgrind are given then
helgrind takes priority.

--enable-helgrind requires --enable-valgrind-annotations.

* configure.ac: Add --enable-helgrind option.
* tests/Makefile.am: If USE_HELGRIND is true, then include
--tool=helgrind in the valgrind command that tests are run
under.

Signed-off-by: Aaron Merey <amerey@redhat.com>
6 months agolibdwP.h: Add locking to str_offsets_base_off
Aaron Merey [Mon, 17 Mar 2025 01:51:02 +0000 (21:51 -0400)] 
libdwP.h: Add locking to str_offsets_base_off

* libdw/dwarf_end.c (cu_free): Free str_off_base_lock.
* libdw/libdwP.h (struct Dwarf_CU): Add str_off_base_lock member.
(str_offsets_base_off): Add locking.
* libdw/libdw_findcu.c (__libdw_intern_next_unit): Initialize
str_off_base_lock.

Signed-off-by: Aaron Merey <amerey@redhat.com>
6 months agolibdw: Add locking to dwarf_getsrcfiles, dwarf_getsrclines, dwarf_macro_getsrcfiles
Aaron Merey [Mon, 17 Mar 2025 01:51:01 +0000 (21:51 -0400)] 
libdw: Add locking to dwarf_getsrcfiles, dwarf_getsrclines, dwarf_macro_getsrcfiles

* libdw/dwarf_begin_elf.c (dwarf_begin_elf): Init macro_lock.
* libdw/dwarf_end.c (cu_free): Free src_lock.
(dwarf_end): Free macro_lock.
* libdw/dwarf_getsrcfiles.c (dwarf_getsrcfiles): Use src_lock.
* libdw/dwarf_getsrclines.c (dwarf_getsrclines): Ditto.
* libdw/dwarf_macro_getsrclines.c (dwarf_macro_getsrclines): Use
macro_lock.
* libdw/libdwP.h (struct Dwarf): Define macro_lock.
(struct Dwarf_CU): Define src_lock.
* libdw/libdw_findcu.c (__libdw_intern_next_unit): Init src_lock.

Signed-off-by: Aaron Merey <amerey@redhat.com>