Changes for v4:

- Separate out libdwfl_stacktrace, as requested.

* * *

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.
---
 libdw/libdw.map                             |  4 ++
 libdwfl/libdwflP.h                          |  4 ++
 libdwfl_stacktrace/Makefile.am              |  3 +-
 libdwfl_stacktrace/dwflst_process_tracker.c | 66 +++++++++++++++++++++
 libdwfl_stacktrace/libdwfl_stacktrace.h     | 20 +++++++
 libdwfl_stacktrace/libdwfl_stacktraceP.h    |  6 ++
 6 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 libdwfl_stacktrace/dwflst_process_tracker.c

diff --git a/libdw/libdw.map b/libdw/libdw.map
index 4f3fe6ba..fb69a62a 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -396,4 +396,8 @@ ELFUTILS_0.193 {
 ELFUTILS_0.193_EXPERIMENTAL {
   global:
     dwflst_perf_sample_preferred_regs_mask;
+    dwflst_perf_sample_preferred_regs_mask;
+    dwflst_tracker_begin;
+    dwflst_tracker_dwfl_begin;
+    dwflst_tracker_end;
 };
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 2b7eb8da..57305f81 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -111,9 +111,13 @@ struct Dwfl_User_Core
   int fd;                       /* close if >= 0.  */
 };
 
+/* forward decl from ../libdwfl_stacktrace/ */
+typedef struct Dwflst_Process_Tracker Dwflst_Process_Tracker;
+
 struct Dwfl
 {
   const Dwfl_Callbacks *callbacks;
+  Dwflst_Process_Tracker *tracker;
 #ifdef ENABLE_LIBDEBUGINFOD
   debuginfod_client *debuginfod;
 #endif
diff --git a/libdwfl_stacktrace/Makefile.am b/libdwfl_stacktrace/Makefile.am
index 6364c292..d57431c0 100644
--- a/libdwfl_stacktrace/Makefile.am
+++ b/libdwfl_stacktrace/Makefile.am
@@ -40,7 +40,8 @@ noinst_LIBRARIES += libdwfl_stacktrace_pic.a
 pkginclude_HEADERS = libdwfl_stacktrace.h
 
 
-libdwfl_stacktrace_a_SOURCES = dwflst_perf_frame.c
+libdwfl_stacktrace_a_SOURCES = dwflst_process_tracker.c \
+                              dwflst_perf_frame.c
 
 libdwfl_stacktrace = $(libdw)
 libdw = ../libdw/libdw.so
diff --git a/libdwfl_stacktrace/dwflst_process_tracker.c 
b/libdwfl_stacktrace/dwflst_process_tracker.c
new file mode 100644
index 00000000..057c9f7a
--- /dev/null
+++ b/libdwfl_stacktrace/dwflst_process_tracker.c
@@ -0,0 +1,66 @@
+/* Track multiple Dwfl structs for multiple processes.
+   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 "libdwfl_stacktraceP.h"
+
+Dwflst_Process_Tracker *dwflst_tracker_begin (const Dwfl_Callbacks *callbacks)
+{
+  Dwflst_Process_Tracker *tracker = calloc (1, sizeof *tracker);
+  if (tracker == NULL)
+    {
+      __libdwfl_seterrno (DWFL_E_NOMEM);
+      return tracker;
+    }
+
+  tracker->callbacks = callbacks;
+  return tracker;
+}
+
+Dwfl *dwflst_tracker_dwfl_begin (Dwflst_Process_Tracker *tracker)
+{
+  Dwfl *dwfl = INTUSE(dwfl_begin) (tracker->callbacks);
+  if (dwfl == NULL)
+    return dwfl;
+
+  /* TODO: Could also share dwfl->debuginfod, but thread-safely? */
+  dwfl->tracker = tracker;
+  return dwfl;
+}
+
+void dwflst_tracker_end (Dwflst_Process_Tracker *tracker)
+{
+  if (tracker == NULL)
+    return;
+
+  /* TODO: Call dwfl_end for each Dwfl connected to this tracker. */
+  free (tracker);
+}
diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h 
b/libdwfl_stacktrace/libdwfl_stacktrace.h
index 564f504a..f3a82d18 100644
--- a/libdwfl_stacktrace/libdwfl_stacktrace.h
+++ b/libdwfl_stacktrace/libdwfl_stacktrace.h
@@ -41,6 +41,26 @@
 extern "C" {
 #endif
 
+/* Keeps track of and caches Elf structs across multiple libdwfl
+   sessions corresponding to different processes.  */
+typedef struct Dwflst_Process_Tracker Dwflst_Process_Tracker;
+
+
+/* Initialize a new tracker for multiple libdwfl sessions.  Since Elf
+   data will shared between the libdwfl sessions, each Dwfl must use
+   the same Dwfl_Callbacks CALLBACKS provided when the tracker is
+   created.  */
+extern Dwflst_Process_Tracker *dwflst_tracker_begin (const Dwfl_Callbacks 
*callbacks)
+  __nonnull_attribute__ (1);
+
+/* Create a new Dwfl linked to this tracker.  */
+extern Dwfl *dwflst_tracker_dwfl_begin (Dwflst_Process_Tracker *tracker)
+  __nonnull_attribute__ (1);
+
+/* End all sessions with this tracker.  */
+extern void dwflst_tracker_end (Dwflst_Process_Tracker *tracker);
+
+
 /* 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 fe6945fc..9313176c 100644
--- a/libdwfl_stacktrace/libdwfl_stacktraceP.h
+++ b/libdwfl_stacktrace/libdwfl_stacktraceP.h
@@ -33,4 +33,10 @@
 
 #include "libdwflP.h"
 
+struct Dwflst_Process_Tracker
+{
+  const Dwfl_Callbacks *callbacks;
+  /* ... */
+};
+
 #endif  /* libdwfl_stacktraceP.h */
-- 
2.47.0

Reply via email to