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                               |   4 +
 libdwfl/Makefile.am                           |   5 +-
 libdwfl/dwfl_module_getdwarf.c                |  10 +-
 libdwfl_stacktrace/Makefile.am                |   5 +-
 libdwfl_stacktrace/dwflst_process_tracker.c   |  26 +++
 libdwfl_stacktrace/dwflst_tracker_elftab.c    |  45 ++++
 libdwfl_stacktrace/dwflst_tracker_elftab.h    |  40 ++++
 libdwfl_stacktrace/dwflst_tracker_find_elf.c  | 218 ++++++++++++++++++
 libdwfl_stacktrace/libdwfl_stacktrace.h       |  37 ++-
 libdwfl_stacktrace/libdwfl_stacktraceP.h      |  24 +-
 .../libdwfl_stacktrace_next_prime.c           |   6 +
 11 files changed, 414 insertions(+), 6 deletions(-)
 create mode 100644 libdwfl_stacktrace/dwflst_tracker_elftab.c
 create mode 100644 libdwfl_stacktrace/dwflst_tracker_elftab.h
 create mode 100644 libdwfl_stacktrace/dwflst_tracker_find_elf.c
 create mode 100644 libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c

diff --git a/libdw/libdw.map b/libdw/libdw.map
index fb69a62a..46d0878a 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -400,4 +400,8 @@ ELFUTILS_0.193_EXPERIMENTAL {
     dwflst_tracker_begin;
     dwflst_tracker_dwfl_begin;
     dwflst_tracker_end;
+    dwflst_tracker_find_cached_elf;
+    dwflst_tracker_cache_elf;
+    dwflst_module_gettracker;
+    dwflst_tracker_linux_proc_find_elf;
 };
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index b30b86f0..6ad5ba10 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -2,7 +2,7 @@
 ##
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2005-2010, 2013 Red Hat, Inc.
+## Copyright (C) 2005-2010, 2013, 2025 Red Hat, Inc.
 ## This file is part of elfutils.
 ##
 ## This file is free software; you can redistribute it and/or modify
@@ -31,7 +31,8 @@
 ##
 include $(top_srcdir)/config/eu.am
 AM_CPPFLAGS += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
-          -I$(srcdir)/../libdw -I$(srcdir)/../libdwelf 
-I$(builddir)/../debuginfod
+          -I$(srcdir)/../libdw -I$(srcdir)/../libdwelf 
-I$(builddir)/../debuginfod \
+          -I$(srcdir)/../libdwfl_stacktrace
 VERSION = 1
 
 noinst_LIBRARIES = libdwfl.a
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 6f98c02b..7fd0d3aa 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc.
+   Copyright (C) 2005-2012, 2014, 2015, 2025 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include "libdwP.h"    /* DWARF_E_* values are here.  */
+#include "libdwfl_stacktraceP.h" /* want the INTDECLS */
 #include "libelfP.h"
 #include "system.h"
 
@@ -79,6 +80,13 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
   if (error != DWFL_E_NOERROR)
     return error;
 
+  /* Cache file->elf in Dwflst_Process_Tracker if available: */
+  if (mod->dwfl->tracker != NULL && file->name != NULL)
+    {
+      INTUSE(dwflst_tracker_cache_elf) (mod->dwfl->tracker, file->name,
+                                       file->name, file->elf, file->fd);
+    }
+
   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
   if (ehdr == NULL)
     {
diff --git a/libdwfl_stacktrace/Makefile.am b/libdwfl_stacktrace/Makefile.am
index d57431c0..ffddec0c 100644
--- a/libdwfl_stacktrace/Makefile.am
+++ b/libdwfl_stacktrace/Makefile.am
@@ -41,6 +41,9 @@ pkginclude_HEADERS = libdwfl_stacktrace.h
 
 
 libdwfl_stacktrace_a_SOURCES = dwflst_process_tracker.c \
+                              dwflst_tracker_find_elf.c \
+                              dwflst_tracker_elftab.c \
+                              libdwfl_stacktrace_next_prime.c \
                               dwflst_perf_frame.c
 
 libdwfl_stacktrace = $(libdw)
@@ -52,7 +55,7 @@ libeu = ../lib/libeu.a
 libdwfl_stacktrace_pic_a_SOURCES =
 am_libdwfl_stacktrace_pic_a_OBJECTS = $(libdwfl_stacktrace_a_SOURCES:.c=.os)
 
-noinst_HEADERS = libdwfl_stacktraceP.h
+noinst_HEADERS = libdwfl_stacktraceP.h dwflst_tracker_elftab.h
 
 EXTRA_libdwfl_stacktrace_a_DEPENDENCIES = libdwfl_stacktrace.manifest
 
diff --git a/libdwfl_stacktrace/dwflst_process_tracker.c 
b/libdwfl_stacktrace/dwflst_process_tracker.c
index 057c9f7a..10cd9a7c 100644
--- a/libdwfl_stacktrace/dwflst_process_tracker.c
+++ b/libdwfl_stacktrace/dwflst_process_tracker.c
@@ -32,6 +32,8 @@
 
 #include "libdwfl_stacktraceP.h"
 
+#define HTAB_DEFAULT_SIZE 1021
+
 Dwflst_Process_Tracker *dwflst_tracker_begin (const Dwfl_Callbacks *callbacks)
 {
   Dwflst_Process_Tracker *tracker = calloc (1, sizeof *tracker);
@@ -41,6 +43,9 @@ Dwflst_Process_Tracker *dwflst_tracker_begin (const 
Dwfl_Callbacks *callbacks)
       return tracker;
     }
 
+  dwflst_tracker_elftab_init (&tracker->elftab, HTAB_DEFAULT_SIZE);
+  rwlock_init (tracker->elftab_lock);
+
   tracker->callbacks = callbacks;
   return tracker;
 }
@@ -61,6 +66,27 @@ void dwflst_tracker_end (Dwflst_Process_Tracker *tracker)
   if (tracker == NULL)
     return;
 
+  /* HACK to allow iteration of dynamicsizehash_concurrent.  */
+  /* XXX Based on lib/dynamicsizehash_concurrent.c free().  */
+  rwlock_fini (tracker->elftab_lock);
+  pthread_rwlock_destroy(&tracker->elftab.resize_rwl);
+  for (size_t idx = 1; idx <= tracker->elftab.size; idx++)
+    {
+      dwflst_tracker_elftab_ent *ent = &tracker->elftab.table[idx];
+      if (ent->hashval == 0)
+       continue;
+      dwflst_tracker_elf_info *t =
+       (dwflst_tracker_elf_info *) atomic_load_explicit (&ent->val_ptr,
+                                                         memory_order_relaxed);
+      free(t->module_name);
+      if (t->fd >= 0)
+       close(t->fd);
+      if (t->elf != NULL)
+       elf_end(t->elf);
+      free(t); /* TODO: Check necessity. */
+    }
+  free (tracker->elftab.table);
+
   /* TODO: Call dwfl_end for each Dwfl connected to this tracker. */
   free (tracker);
 }
diff --git a/libdwfl_stacktrace/dwflst_tracker_elftab.c 
b/libdwfl_stacktrace/dwflst_tracker_elftab.c
new file mode 100644
index 00000000..a7ce452a
--- /dev/null
+++ b/libdwfl_stacktrace/dwflst_tracker_elftab.c
@@ -0,0 +1,45 @@
+/* Dwflst_Process_Tracker Elf table implementation.
+   Copyright (C) 2025 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+
+#include <libdwfl_stacktraceP.h>
+
+/* Definitions for the Elf table. */
+#define TYPE dwflst_tracker_elf_info *
+#define NAME dwflst_tracker_elftab
+#define ITERATE 1
+#define COMPARE(a, b) \
+  (strcmp ((a)->module_name, (b)->module_name)         \
+   && (a)->dev == (b)->dev && (a)->ino == (b)->ino)
+
+#include "../lib/dynamicsizehash_concurrent.c"
diff --git a/libdwfl_stacktrace/dwflst_tracker_elftab.h 
b/libdwfl_stacktrace/dwflst_tracker_elftab.h
new file mode 100644
index 00000000..c22ddb53
--- /dev/null
+++ b/libdwfl_stacktrace/dwflst_tracker_elftab.h
@@ -0,0 +1,40 @@
+/* Dwflst_Process_Tracker Elf table.
+   Copyright (C) 2025 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef DWFLST_TRACKER_ELFTAB_H
+#define DWFLST_TRACKER_ELFTAB_H 1
+
+/* Definitions for the Elf table.  */
+#define TYPE dwflst_tracker_elf_info *
+#define NAME dwflst_tracker_elftab
+#define ITERATE 1
+#define COMPARE(a, b) \
+  strcmp ((a)->module_name, (b)->module_name)
+#include <dynamicsizehash_concurrent.h>
+
+#endif
diff --git a/libdwfl_stacktrace/dwflst_tracker_find_elf.c 
b/libdwfl_stacktrace/dwflst_tracker_find_elf.c
new file mode 100644
index 00000000..7f9eb569
--- /dev/null
+++ b/libdwfl_stacktrace/dwflst_tracker_find_elf.c
@@ -0,0 +1,218 @@
+/* Find Elf file and cache via Dwflst_Process_Tracker.
+   Copyright (C) 2025, Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/stat.h>
+#include "../libelf/libelfP.h"
+/* XXX: Private header needed for Elf * ref_count field. */
+/* TODO: Consider dup_elf() rather than direct ref_count access. */
+
+#include "libdwfl_stacktraceP.h"
+
+unsigned long int
+__libdwfl_stacktrace_elftab_hash_st (const char *module_name,
+                                    dev_t st_dev,
+                                    ino_t st_ino)
+{
+  unsigned long int hval = elf_hash(module_name);
+  hval ^= (unsigned long int)st_dev;
+  hval ^= (unsigned long int)st_ino;
+  return hval;
+}
+
+unsigned long int
+__libdwfl_stacktrace_elftab_hash (const char *module_name,
+                                 const char *module_path,
+                                 int fd)
+{
+  struct stat sb;
+  int rc = -1;
+  if (fd >= 0)
+    rc = fstat(fd, &sb);
+  else if (module_path != NULL)
+    rc = stat(module_path, &sb);
+  if (rc < 0)
+    return elf_hash(module_name);
+  return __libdwfl_stacktrace_elftab_hash_st
+    (module_name, sb.st_dev, sb.st_ino);
+}
+
+int
+dwflst_tracker_find_cached_elf (Dwflst_Process_Tracker *tracker,
+                               const char *module_name,
+                               const char *module_path,
+                               char **file_name, Elf **elfp)
+{
+  dwflst_tracker_elf_info *ent = NULL;
+  int rc = -1;
+  struct stat sb;
+
+  if (module_path == NULL)
+    module_path = module_name;
+  unsigned long int hval =
+    __libdwfl_stacktrace_elftab_hash (module_name, module_path, -1/* no fd */);
+
+  rwlock_rdlock(tracker->elftab_lock);
+  ent = dwflst_tracker_elftab_find(&tracker->elftab, hval);
+  rwlock_unlock(tracker->elftab_lock);
+
+  /* Guard against collisions.
+     TODO: Need proper chaining, dynamicsizehash_concurrent isn't really
+     equipped for it. */
+  if (ent != NULL)
+    rc = fstat(ent->fd, &sb);
+  if (rc < 0 || strcmp (module_name, ent->module_name) != 0
+      || ent->dev != sb.st_dev || ent->ino != sb.st_ino)
+    return -1;
+
+  /* Verify that ent->fd has not been updated: */
+  if (rc < 0 || ent->dev != sb.st_dev || ent->ino != sb.st_ino
+      || ent->last_mtime != sb.st_mtime)
+    return -1;
+
+  if (ent->elf != NULL)
+    ent->elf->ref_count++;
+  *elfp = ent->elf;
+  *file_name = strdup(ent->module_name);
+  return ent->fd;
+}
+INTDEF(dwflst_tracker_find_cached_elf)
+
+bool
+dwflst_tracker_cache_elf (Dwflst_Process_Tracker *tracker,
+                         const char *module_name,
+                         const char *file_name __attribute__((unused)),
+                         Elf *elf, int fd)
+{
+  dwflst_tracker_elf_info *ent = NULL;
+  int rc = -1;
+  struct stat sb;
+
+  if (fd >= 0)
+    rc = fstat(fd, &sb);
+  if (rc < 0)
+    return false;
+  unsigned long int hval =
+    __libdwfl_stacktrace_elftab_hash_st (module_name, sb.st_dev, sb.st_ino);
+
+  rwlock_wrlock(tracker->elftab_lock);
+  ent = dwflst_tracker_elftab_find(&tracker->elftab, hval);
+  /* Guard against collisions.
+     TODO: Need proper chaining, dynamicsizehash_concurrent isn't really
+     equipped for it. */
+  if (ent != NULL && (strcmp (module_name, ent->module_name) != 0
+                     || ent->dev != sb.st_dev || ent->ino != sb.st_ino))
+    {
+      rwlock_unlock(tracker->elftab_lock);
+      return false;
+    }
+  if (ent == NULL)
+    {
+      ent = calloc (1, sizeof (dwflst_tracker_elf_info));
+      ent->module_name = strdup(module_name);
+
+      if (dwflst_tracker_elftab_insert(&tracker->elftab, hval, ent) != 0)
+       {
+         free(ent->module_name);
+         free(ent);
+         rwlock_unlock(tracker->elftab_lock);
+         assert(false); /* Should not occur due to the wrlock on elftab. */
+       }
+    }
+  else
+    {
+      /* TODO: The following assertions are still triggered on certain
+            code paths that acquire fds or create Elf structs without
+            checking the caching mechanism first.  This is not a serious
+            problem, and can be fixed incrementally. */
+
+         /* assert(ent->elf == NULL || ent->elf == elf); */ /* Guard against 
redundant/leaked Elf *. */
+         /* assert(ent->fd == fd); */ /* Guard against redundant open. */
+
+      /* For now, correct behaviour (from dwfl_module_getdwarf.c open_elf)
+         is to replace the existing elf, keep module_name. */
+      if (ent->elf != NULL && ent->elf != elf)
+       elf_end(ent->elf);
+    }
+  if (elf != NULL && ent->elf != elf)
+    elf->ref_count++;
+  ent->elf = elf;
+  ent->fd = fd;
+  if (rc == 0) /* TODO(REVIEW): Report rc != 0 via errno? */
+    {
+      ent->dev = sb.st_dev;
+      ent->ino = sb.st_ino;
+      ent->last_mtime = sb.st_mtime;
+    }
+  rwlock_unlock(tracker->elftab_lock);
+  return true;
+}
+INTDEF(dwflst_tracker_cache_elf)
+
+Dwflst_Process_Tracker *
+dwflst_module_gettracker (Dwfl_Module *mod)
+{
+  if (mod == NULL)
+    return NULL;
+  if (mod->dwfl == NULL)
+    return NULL;
+  return mod->dwfl->tracker;
+}
+INTDEF(dwflst_module_gettracker)
+
+int
+dwflst_tracker_linux_proc_find_elf (Dwfl_Module *mod,
+                                   void **userdata __attribute__ ((unused)),
+                                   const char *module_name, Dwarf_Addr base,
+                                   char **file_name, Elf **elfp)
+{
+  Dwflst_Process_Tracker *tracker = INTUSE(dwflst_module_gettracker) (mod);
+  int fd;
+
+  if (tracker != NULL)
+    {
+      fd = INTUSE(dwflst_tracker_find_cached_elf)
+       (tracker, module_name, module_name, file_name, elfp);
+      if (fd >= 0)
+       return fd;
+    }
+
+  fd = INTUSE(dwfl_linux_proc_find_elf) (mod, userdata, module_name,
+                                        base, file_name, elfp);
+
+  if (tracker != NULL && fd >= 0 && *file_name != NULL)
+    {
+      INTUSE(dwflst_tracker_cache_elf)
+       (tracker, module_name, *file_name, *elfp, fd);
+    }
+  return fd;
+}
diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h 
b/libdwfl_stacktrace/libdwfl_stacktrace.h
index f3a82d18..d29dc640 100644
--- a/libdwfl_stacktrace/libdwfl_stacktrace.h
+++ b/libdwfl_stacktrace/libdwfl_stacktrace.h
@@ -57,10 +57,45 @@ extern Dwflst_Process_Tracker *dwflst_tracker_begin (const 
Dwfl_Callbacks *callb
 extern Dwfl *dwflst_tracker_dwfl_begin (Dwflst_Process_Tracker *tracker)
   __nonnull_attribute__ (1);
 
-/* End all sessions with this tracker.  */
+/* Try to find a cached Elf corresponding to MODULE_NAME.  Verifies
+   that the cached Elf has dev/ino/mtime matching the file on disk.
+   Non-NULL MODULE_PATH specifies an alternate location for the module
+   e.g. /proc/PID/root/MODULE_NAME.  Stores FILE_NAME and ELFP values.
+   Returns fd similar to the find_elf callbacks, or -1 if cached Elf
+   was not found.  */
+extern int dwflst_tracker_find_cached_elf (Dwflst_Process_Tracker *tracker,
+                                          const char *module_name,
+                                          const char *module_path,
+                                          char **file_name, Elf **elfp)
+  __nonnull_attribute__ (1, 2, 4, 5);
+
+/* Store an Elf corresponding to MODULE_NAME in the tracker's cache.
+   FILE_NAME and FD values must be provided, similar to the output of
+   a find_elf callback.  Returns TRUE iff the Elf was successfully
+   stored in the cache.  */
+extern bool dwflst_tracker_cache_elf (Dwflst_Process_Tracker *tracker,
+                                     const char *module_name,
+                                     const char *file_name,
+                                     Elf *elf, int fd)
+  __nonnull_attribute__ (1, 2);
+
+/* For implementing a find_elf callback based on the prior two functions.
+   Returns the Dwflst_Process_Tracker corresponding to MOD.  */
+extern Dwflst_Process_Tracker *dwflst_module_gettracker (Dwfl_Module *mod);
+
+/* End all sessions with this tracker. */
 extern void dwflst_tracker_end (Dwflst_Process_Tracker *tracker);
 
 
+/* Adaptation of the dwfl_linux_proc_find_elf callback from libdwfl,
+   except this first attempts to look up a cached Elf* and fd from the
+   Dwfl_Module's Dwflst_Process_Tracker (if any).  If a new Elf* is
+   created, this callback saves it to the tracker's cache.  */
+extern int dwflst_tracker_linux_proc_find_elf (Dwfl_Module *mod, void 
**userdata,
+                                              const char *module_name, 
Dwarf_Addr base,
+                                              char **file_name, Elf **);
+
+
 /* XXX dwflst_perf_sample_getframes to be added in subsequent patch */
 
 /* Returns the linux perf_events register mask describing a set of
diff --git a/libdwfl_stacktrace/libdwfl_stacktraceP.h 
b/libdwfl_stacktrace/libdwfl_stacktraceP.h
index 9313176c..e457d35a 100644
--- a/libdwfl_stacktrace/libdwfl_stacktraceP.h
+++ b/libdwfl_stacktrace/libdwfl_stacktraceP.h
@@ -33,10 +33,32 @@
 
 #include "libdwflP.h"
 
+/* Hash table for Elf *. */
+typedef struct
+{
+  char *module_name; /* dwfltracker_elftab_ent is used iff non-NULL.  */
+  int fd;
+  Elf *elf;
+  dev_t dev;
+  ino_t ino;
+  time_t last_mtime;
+} dwflst_tracker_elf_info;
+#include "dwflst_tracker_elftab.h"
+
 struct Dwflst_Process_Tracker
 {
   const Dwfl_Callbacks *callbacks;
-  /* ... */
+
+  /* Table of cached Elf * including fd, path, fstat info.  */
+  dwflst_tracker_elftab elftab;
+  rwlock_define(, elftab_lock);
 };
 
+
+/* Avoid PLT entries.  */
+INTDECL (dwflst_module_gettracker)
+INTDECL (dwflst_tracker_find_cached_elf)
+INTDECL (dwflst_tracker_cache_elf)
+
+
 #endif  /* libdwfl_stacktraceP.h */
diff --git a/libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c 
b/libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c
new file mode 100644
index 00000000..0974ce68
--- /dev/null
+++ b/libdwfl_stacktrace/libdwfl_stacktrace_next_prime.c
@@ -0,0 +1,6 @@
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#define next_prime attribute_hidden __libdwfl_stacktrace_next_prime
+#include "../lib/next_prime.c"
-- 
2.47.0

Reply via email to