]> git.ipfire.org Git - thirdparty/elfutils.git/commit
libdwfl_stacktrace [6/12]: Elf* caching via dwflst_process_tracker
authorSerhei Makarov <serhei@serhei.io>
Tue, 22 Apr 2025 22:30:50 +0000 (18:30 -0400)
committerSerhei Makarov <serhei@serhei.io>
Fri, 25 Apr 2025 14:10:01 +0000 (10:10 -0400)
commit343dcb44be11649339c8debb9c916408ecd7ee5b
treea1c7ed4e80433a20de63f1afd2aede117e0bbbd7
parent3dc8d7cc21bcb70e6ea049e621da22b546992429
libdwfl_stacktrace [6/12]: Elf* caching via dwflst_process_tracker

Changes for v6:

- Minor fixes as requested.

Changes for v5:

- Bugfixes in dwflst_tracker_find_elf.c.

Changes for v4:

- Separate out libdwfl_stacktrace, as requested.

- dwfl_module_getdwarf.c now uses the dwflst_tracker_cache_elf()
  interface instead of editing the elftab directly.

Changes for v3:

- Reworked elftab to incorporate dev/ino into the caching key
  (to allow caching modules from different filesystems
  e.g. a main filesystem and a container filesystem)
  and guard more carefully against collisions.

- Add external API for implementing a custom
  find_elf callback that reads/writes the cache.

Changes for v2:

- Add locking for elftab. This is needed in addition to the
  intrinsic locking in dynamicsizehash_concurrent to avoid
  having cache_elf expose an incomplete dwfltracker_elf_info*
  entry to other threads while its data is being populated /
  replaced.

- Tidy dwfl_process_tracker_find_elf.c into the main find_elf
  callback and two functions to consider (in future) making into
  a public api for custom cached callbacks.

* * *

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 *.
libdw/libdw.map
libdwfl/Makefile.am
libdwfl/dwfl_module_getdwarf.c
libdwfl_stacktrace/Makefile.am
libdwfl_stacktrace/dwflst_process_tracker.c
libdwfl_stacktrace/dwflst_tracker_elftab.c [new file with mode: 0644]
libdwfl_stacktrace/dwflst_tracker_elftab.h [new file with mode: 0644]
libdwfl_stacktrace/dwflst_tracker_find_elf.c [new file with mode: 0644]
libdwfl_stacktrace/libdwfl_stacktrace.h
libdwfl_stacktrace/libdwfl_stacktraceP.h
libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c [new file with mode: 0644]