/* Finish a session using libdwfl.
- Copyright (C) 2005, 2008, 2012-2013, 2015 Red Hat, Inc.
+ Copyright (C) 2005, 2008, 2012-2013, 2015, 2025 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
#endif
#include "libdwflP.h"
+#include "libdwfl_stacktraceP.h"
void
dwfl_end (Dwfl *dwfl)
__libdwfl_debuginfod_end (dwfl->debuginfod);
#endif
+ if (dwfl->tracker != NULL)
+ __libdwfl_stacktrace_remove_dwfl_from_tracker (dwfl);
+
if (dwfl->process)
__libdwfl_process_free (dwfl->process);
}
free (dwfl);
}
+INTDEF(dwfl_end)
+
/* Get Dwarf Frame state for target PID or core file.
- Copyright (C) 2013, 2014, 2024 Red Hat, Inc.
+ Copyright (C) 2013, 2014, 2024-2025 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
#include <system.h>
#include "libdwflP.h"
+#include "libdwfl_stacktraceP.h"
/* Set STATE->pc_set from STATE->regs according to the backend. Return true on
success, false on error. */
process->pid = pid;
process->callbacks = thread_callbacks;
process->callbacks_arg = arg;
+
+ if (dwfl->tracker != NULL)
+ __libdwfl_stacktrace_add_dwfl_to_tracker (dwfl);
+
return true;
}
INTDEF(dwfl_attach_state)
/* Avoid PLT entries. */
INTDECL (dwfl_begin)
+INTDECL (dwfl_end)
INTDECL (dwfl_errmsg)
INTDECL (dwfl_errno)
INTDECL (dwfl_addrmodule)
libdwfl_stacktrace_a_SOURCES = dwflst_process_tracker.c \
dwflst_tracker_find_elf.c \
dwflst_tracker_elftab.c \
+ dwflst_tracker_dwfltab.c \
libdwfl_stacktrace_next_prime.c \
dwflst_perf_frame.c
libdwfl_stacktrace_pic_a_SOURCES =
am_libdwfl_stacktrace_pic_a_OBJECTS = $(libdwfl_stacktrace_a_SOURCES:.c=.os)
-noinst_HEADERS = libdwfl_stacktraceP.h dwflst_tracker_elftab.h
+noinst_HEADERS = libdwfl_stacktraceP.h \
+ dwflst_tracker_elftab.h dwflst_tracker_dwfltab.h
EXTRA_libdwfl_stacktrace_a_DEPENDENCIES = libdwfl_stacktrace.manifest
dwflst_tracker_elftab_init (&tracker->elftab, HTAB_DEFAULT_SIZE);
rwlock_init (tracker->elftab_lock);
+ dwflst_tracker_dwfltab_init (&tracker->dwfltab, HTAB_DEFAULT_SIZE);
+ rwlock_init (tracker->dwfltab_lock);
tracker->callbacks = callbacks;
return tracker;
/* TODO: Could also share dwfl->debuginfod, but thread-safely? */
dwfl->tracker = tracker;
+
+ /* XXX: dwfl added to dwfltab when dwfl->process set in dwfl_attach_state. */
+ /* XXX: dwfl removed from dwfltab in dwfl_end() */
+
return dwfl;
}
+
+void
+internal_function
+__libdwfl_stacktrace_add_dwfl_to_tracker (Dwfl *dwfl) {
+ Dwflst_Process_Tracker *tracker = dwfl->tracker;
+ assert (tracker != NULL);
+
+ /* First try to find an existing entry to replace: */
+ dwflst_tracker_dwfl_info *ent = NULL;
+ unsigned long int hval = dwfl->process->pid;
+
+ rwlock_wrlock (tracker->dwfltab_lock);
+ ent = dwflst_tracker_dwfltab_find(&tracker->dwfltab, hval);
+ if (ent != NULL)
+ {
+ /* TODO: This is a bare-minimum solution. Ideally
+ we would clean up the existing ent->dwfl, but
+ this needs to be coordinated with any users of
+ the dwfl library that might still be holding it. */
+ ent->dwfl = dwfl;
+ ent->invalid = false;
+ rwlock_unlock (tracker->dwfltab_lock);
+ return;
+ }
+
+ /* Only otherwise try to insert an entry: */
+ ent = calloc (1, sizeof(dwflst_tracker_dwfl_info));
+ if (ent == NULL)
+ {
+ rwlock_unlock (tracker->dwfltab_lock);
+ __libdwfl_seterrno (DWFL_E_NOMEM);
+ return;
+ }
+ ent->dwfl = dwfl;
+ ent->invalid = false;
+ if (dwflst_tracker_dwfltab_insert(&tracker->dwfltab, hval, ent) != 0)
+ {
+ free(ent);
+ rwlock_unlock (tracker->dwfltab_lock);
+ assert(false); /* Should not occur due to the wrlock on dwfltab. */
+ }
+ rwlock_unlock (tracker->dwfltab_lock);
+}
+
+void
+internal_function
+__libdwfl_stacktrace_remove_dwfl_from_tracker (Dwfl *dwfl) {
+ if (dwfl->tracker == NULL)
+ return;
+ Dwflst_Process_Tracker *tracker = dwfl->tracker;
+ dwflst_tracker_dwfl_info *ent = NULL;
+ if (dwfl->process == NULL)
+ return;
+ unsigned long int hval = dwfl->process->pid;
+
+ rwlock_wrlock (tracker->dwfltab_lock);
+ ent = dwflst_tracker_dwfltab_find(&tracker->dwfltab, hval);
+ if (ent != NULL && ent->dwfl == dwfl)
+ {
+ ent->dwfl = NULL;
+ ent->invalid = true;
+ }
+ rwlock_unlock (tracker->dwfltab_lock);
+}
+
void dwflst_tracker_end (Dwflst_Process_Tracker *tracker)
{
if (tracker == NULL)
return;
+ size_t idx;
+
/* 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++)
+ for (idx = 1; idx <= tracker->elftab.size; idx++)
{
dwflst_tracker_elftab_ent *ent = &tracker->elftab.table[idx];
if (ent->hashval == 0)
}
free (tracker->elftab.table);
- /* TODO: Call dwfl_end for each Dwfl connected to this tracker. */
+ /* XXX Based on lib/dynamicsizehash_concurrent.c free(). */
+ rwlock_fini (tracker->dwfltab_lock);
+ pthread_rwlock_destroy(&tracker->dwfltab.resize_rwl);
+ for (idx = 1; idx <= tracker->dwfltab.size; idx++)
+ {
+ dwflst_tracker_dwfltab_ent *ent = &tracker->dwfltab.table[idx];
+ if (ent->hashval == 0)
+ continue;
+ dwflst_tracker_dwfl_info *t =
+ (dwflst_tracker_dwfl_info *) atomic_load_explicit (&ent->val_ptr,
+ memory_order_relaxed);
+ if (t->dwfl != NULL)
+ INTUSE(dwfl_end) (t->dwfl);
+ free(t);
+ }
+ free (tracker->dwfltab.table);
+
free (tracker);
}
--- /dev/null
+/* Dwflst_Process_Tracker Dwfl 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 <libdwfl_stacktraceP.h>
+
+/* Definitions for the Dwfl table. */
+#define TYPE dwflst_tracker_dwfl_info *
+#define NAME dwflst_tracker_dwfltab
+#define ITERATE 1
+#define COMPARE(a, b) \
+ ((a->invalid && b->invalid) || \
+ (!a->invalid && !b->invalid && \
+ (a)->dwfl->process->pid == (b)->dwfl->process->pid))
+
+#include "../lib/dynamicsizehash_concurrent.c"
--- /dev/null
+/* Dwflst_Process_Tracker Dwfl 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_DWFLTAB_H
+#define DWFLST_TRACKER_DWFLTAB_H 1
+
+/* Definitions for the Dwfl table. */
+#define TYPE dwflst_tracker_dwfl_info *
+#define NAME dwflst_tracker_dwfltab
+#define ITERATE 1
+#define COMPARE(a, b) \
+ ((a->invalid && b->invalid) || \
+ (!a->invalid && !b->invalid && \
+ (a)->dwfl->process->pid == (b)->dwfl->process->pid))
+#include <dynamicsizehash_concurrent.h>
+
+#endif
} dwflst_tracker_elf_info;
#include "dwflst_tracker_elftab.h"
+/* Hash table for Dwfl *. */
+typedef struct
+{
+ Dwfl *dwfl;
+ bool invalid; /* Mark when the dwfl has been removed. */
+} dwflst_tracker_dwfl_info;
+#include "dwflst_tracker_dwfltab.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);
+
+ /* Table of cached Dwfl * including pid. */
+ dwflst_tracker_dwfltab dwfltab;
+ rwlock_define(, dwfltab_lock);
};
+/* Called when dwfl->process->pid becomes known to add the dwfl to its
+ Dwflst_Process_Tracker's dwfltab: */
+extern void __libdwfl_stacktrace_add_dwfl_to_tracker (Dwfl *dwfl)
+ internal_function;
+
+/* Called from dwfl_end() to remove the dwfl from its
+ Dwfl_Process_Tracker's dwfltab: */
+extern void __libdwfl_stacktrace_remove_dwfl_from_tracker (Dwfl *dwfl)
+ internal_function;
+
+
/* Avoid PLT entries. */
INTDECL (dwflst_module_gettracker)
INTDECL (dwflst_tracker_find_cached_elf)