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