Changes for v4: - Separate out libdwfl_stacktrace, as requested.
Changes for v2: - guard the linux/perf_events.h include properly with an #if defined __linux__ * * * Subsequent patches in the series introduce a new library for tracking/caching Elf structs across multiple processes and wrapping the libebl perf register handling (since libebl is a private interface). In this patch, add the library and an interface to access the set of registers that libdwfl needs to allow proper unwinding of stack sample data. (Unwinding with a smaller set of registers can be attempted, but will yield a truncated call chain in most cases.) (Accessing the set of registers feels like an implementation detail, but the profiler invoking perf_event_open and elfutils unwinding code need to agree on the exact set of registers being requested. So it's best for the profiler to ask elfutils for this detail.) * libdwfl_stacktrace/Makefile.am: New file. * libdwfl_stacktrace/libdwfl_stacktrace.h: New file, library for tracking/caching Elf structs and unwinding across multiple processes. * libdwfl_stacktrace/libdwfl_stacktraceP.h: New file. * libdwfl_stacktrace/dwflst_perf_frame.c: New file. (dwflst_perf_sample_preferred_regs_mask): New function. * libdw/libdw.map: Add dwflst_perf_sample_preferred_regs_mask. * NEWS: Add NEWS item about libdwfl_stacktrace. * configure.ac: Add libdwfl_stacktrace/Makefile. * Makefile.am (SUBDIRS): Add libdwfl_stacktrace. * libdw/Makefile.am (libdw_so_LIBS): Add libdwfl_stacktrace. (libdwfl_stacktrace_objects): Add libdwfl_stacktrace.manifest. (libdw_a_LIBADD): Add libdwfl_stacktrace_objects. * config/elfutils.spec.in (%files devel): Add libdwfl_stacktrace.h. --- Makefile.am | 6 +-- NEWS | 6 +++ config/elfutils.spec.in | 1 + configure.ac | 3 ++ libdw/Makefile.am | 7 ++- libdw/libdw.map | 1 + libdwfl_stacktrace/Makefile.am | 63 ++++++++++++++++++++++++ libdwfl_stacktrace/dwflst_perf_frame.c | 63 ++++++++++++++++++++++++ libdwfl_stacktrace/libdwfl_stacktrace.h | 52 +++++++++++++++++++ libdwfl_stacktrace/libdwfl_stacktraceP.h | 36 ++++++++++++++ 10 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 libdwfl_stacktrace/Makefile.am create mode 100644 libdwfl_stacktrace/dwflst_perf_frame.c create mode 100644 libdwfl_stacktrace/libdwfl_stacktrace.h create mode 100644 libdwfl_stacktrace/libdwfl_stacktraceP.h diff --git a/Makefile.am b/Makefile.am index 3a181d75..76e98f60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to create Makefile.in ## Configure input file for elfutils. ## -## Copyright (C) 1996-2006, 2008, 2009, 2015 Red Hat, Inc. +## Copyright (C) 1996-2006, 2008, 2009, 2015, 2025 Red Hat, Inc. ## ## This file is part of elfutils. ## @@ -28,8 +28,8 @@ AM_MAKEFLAGS = --no-print-directory pkginclude_HEADERS = version.h -SUBDIRS = config lib libelf libcpu backends libebl libdwelf libdwfl libdw \ - libasm debuginfod src po doc tests +SUBDIRS = config lib libelf libcpu backends libebl libdwelf libdwfl \ + libdwfl_stacktrace libdw libasm debuginfod src po doc tests EXTRA_DIST = elfutils.spec GPG-KEY NOTES CONTRIBUTING SECURITY \ COPYING COPYING-GPLV2 COPYING-LGPLV3 CONDUCT diff --git a/NEWS b/NEWS index 664c125b..c3c611e3 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,12 @@ debuginfod: Add CORS (webapp access) support to webapi. libdw: Add dwarf_language and dwarf_language_lower_bound functions. +libdwfl_stacktrace: Experimental new library interface for unwinding + stack samples into call chains, and tracking and + caching Elf data for multiple processes, building + on libdwfl. Initially supports perf_events stack + sample data. + Version 0.192 "New rules, faster tools" CONDUCT: A new code of conduct has been adopted. See the diff --git a/config/elfutils.spec.in b/config/elfutils.spec.in index 96934514..37077365 100644 --- a/config/elfutils.spec.in +++ b/config/elfutils.spec.in @@ -300,6 +300,7 @@ fi #%%{_includedir}/elfutils/libasm.h %{_includedir}/elfutils/libdw.h %{_includedir}/elfutils/libdwfl.h +%{_includedir}/elfutils/libdwfl_stacktrace.h %{_includedir}/elfutils/libdwelf.h %{_includedir}/elfutils/version.h #%%{_libdir}/libasm.so diff --git a/configure.ac b/configure.ac index 27488e3f..92108b7f 100644 --- a/configure.ac +++ b/configure.ac @@ -700,6 +700,9 @@ AC_CONFIG_FILES([libdw/Makefile]) dnl Higher-level DWARF support library. AC_CONFIG_FILES([libdwfl/Makefile]) +dnl Higher-level DWARF stacktrace support library +AC_CONFIG_FILES([libdwfl_stacktrace/Makefile]) + dnl CPU handling library. AC_CONFIG_FILES([libcpu/Makefile]) diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 9dadc19b..f024d652 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 2002-2010, 2012, 2014, 2016, 2018 Red Hat, Inc. +## Copyright (C) 2002-2010, 2012, 2014, 2016, 2018, 2025 Red Hat, Inc. ## This file is part of elfutils. ## ## This file is free software; you can redistribute it and/or modify @@ -107,7 +107,7 @@ am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os) libdw_so_LIBS = ../libebl/libebl_pic.a ../backends/libebl_backends_pic.a \ ../libcpu/libcpu_pic.a libdw_pic.a ../libdwelf/libdwelf_pic.a \ - ../libdwfl/libdwfl_pic.a + ../libdwfl/libdwfl_pic.a ../libdwfl_stacktrace/libdwfl_stacktrace_pic.a libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(fts_LIBS) $(obstack_LIBS) $(zip_LIBS) -pthread libdw.so: $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS) @@ -135,6 +135,9 @@ uninstall: uninstall-am libdwfl_objects = $(shell cat ../libdwfl/libdwfl.manifest) libdw_a_LIBADD = $(addprefix ../libdwfl/,$(libdwfl_objects)) +libdwfl_stacktrace_objects = $(shell cat ../libdwfl_stacktrace/libdwfl_stacktrace.manifest) +libdw_a_LIBADD += $(addprefix ../libdwfl_stacktrace/,$(libdwfl_stacktrace_objects)) + libdwelf_objects = $(shell cat ../libdwelf/libdwelf.manifest) libdw_a_LIBADD += $(addprefix ../libdwelf/,$(libdwelf_objects)) diff --git a/libdw/libdw.map b/libdw/libdw.map index e7baf3c4..06dafedb 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -390,4 +390,5 @@ ELFUTILS_0.193 { global: dwarf_language; dwarf_language_lower_bound; + dwflst_perf_sample_preferred_regs_mask; } ELFUTILS_0.192; diff --git a/libdwfl_stacktrace/Makefile.am b/libdwfl_stacktrace/Makefile.am new file mode 100644 index 00000000..6364c292 --- /dev/null +++ b/libdwfl_stacktrace/Makefile.am @@ -0,0 +1,63 @@ +## Makefile.am for libdwfl_stacktrace library subdirectory in elfutils. +## +## Process this file with automake to create Makefile.in +## +## 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/>. +## +include $(top_srcdir)/config/eu.am +AM_CPPFLAGS += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ + -I$(srcdir)/../libdw -I$(srcdir)/../libdwelf -I$(srcdir)/../libdwfl +VERSION = 1 + +noinst_LIBRARIES = libdwfl_stacktrace.a +noinst_LIBRARIES += libdwfl_stacktrace_pic.a + +pkginclude_HEADERS = libdwfl_stacktrace.h + + +libdwfl_stacktrace_a_SOURCES = dwflst_perf_frame.c + +libdwfl_stacktrace = $(libdw) +libdw = ../libdw/libdw.so +libelf = ../libelf/libelf.so +libebl = ../libebl/libebl.a +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 + +EXTRA_libdwfl_stacktrace_a_DEPENDENCIES = libdwfl_stacktrace.manifest + +libdwfl_stacktrace.manifest: $(libdwfl_stacktrace_a_OBJECTS) + $(AM_V_GEN)echo $^ > $@ + +MOSTLYCLEANFILES = $(am_libdwfl_stacktrace_a_OBJECTS) \ + $(am_libdwfl_stacktrace_pic_a_OBJECTS) +CLEANFILES = $(EXTRA_libdwfl_stacktrace_a_DEPENDENCIES) diff --git a/libdwfl_stacktrace/dwflst_perf_frame.c b/libdwfl_stacktrace/dwflst_perf_frame.c new file mode 100644 index 00000000..79e8e482 --- /dev/null +++ b/libdwfl_stacktrace/dwflst_perf_frame.c @@ -0,0 +1,63 @@ +/* Get Dwarf Frame state for perf stack sample data. + 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 + +#if defined(__linux__) +# include <linux/perf_event.h> +#endif + +#include "libdwfl_stacktraceP.h" + +Ebl *default_ebl = NULL; +GElf_Half default_ebl_machine = EM_NONE; + +uint64_t dwflst_perf_sample_preferred_regs_mask (GElf_Half machine) +{ + /* XXX The most likely case is that this will only be called once, + for the current architecture. So we keep one Ebl* around for + answering this query and replace it in the unlikely case of + getting called with different architectures. */ + if (default_ebl != NULL && default_ebl_machine != machine) + { + ebl_closebackend(default_ebl); + default_ebl = NULL; + } + if (default_ebl == NULL) + { + default_ebl = ebl_openbackend_machine(machine); + default_ebl_machine = machine; + } + if (default_ebl != NULL) + return ebl_perf_frame_regs_mask (default_ebl); + return 0; +} + +/* XXX dwflst_perf_sample_getframes to be added in subsequent patch */ diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h b/libdwfl_stacktrace/libdwfl_stacktrace.h new file mode 100644 index 00000000..1edf6887 --- /dev/null +++ b/libdwfl_stacktrace/libdwfl_stacktrace.h @@ -0,0 +1,52 @@ +/* Interfaces for libdwfl_stacktrace. + 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 _LIBDWFL_STACKTRACE_H +#define _LIBDWFL_STACKTRACE_H 1 + +#include "libdwfl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* XXX dwflst_perf_sample_getframes to be added in subsequent patch */ + +/* Returns the linux perf_events register mask describing a set of + registers sufficient for unwinding on MACHINE, or 0 if libdwfl does + not handle perf_events samples for MACHINE. Does not take a Dwfl* + or Elf* since this is meant to allow a profiling tool to configure + perf_events to produce meaningful data for a libdwfl session to be + opened later. */ +uint64_t dwflst_perf_sample_preferred_regs_mask (GElf_Half machine); + +#ifdef __cplusplus +} +#endif + +#endif /* libdwfl_stacktrace.h */ diff --git a/libdwfl_stacktrace/libdwfl_stacktraceP.h b/libdwfl_stacktrace/libdwfl_stacktraceP.h new file mode 100644 index 00000000..fe6945fc --- /dev/null +++ b/libdwfl_stacktrace/libdwfl_stacktraceP.h @@ -0,0 +1,36 @@ +/* Internal definitions for libdwfl_stacktrace. + 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 _LIBDWFL_STACKTRACEP_H +#define _LIBDWFL_STACKTRACEP_H 1 + +#include <libdwfl_stacktrace.h> + +#include "libdwflP.h" + +#endif /* libdwfl_stacktraceP.h */ -- 2.47.0