Hi Serhei,

On Sun, Mar 16, 2025 at 07:14:11PM -0400, Serhei Makarov wrote:
> Since libebl is a private interface, subsequent patches in the series
> introduce another api wrapping the libebl perf register handling.  In
> this patch, add an interface to access the preferred set of registers
> that libdwfl would like to see to allow proper unwinding of stack
> sample data.
> 
> * libdwfl/libdwfl.h (dwfl_perf_sample_preferred_regs_mask):
>   New function.
> * libdwfl/dwfl_perf_frame.c: New file.
>   (dwfl_perf_sample_preferred_regs_mask): New function.
> * libdw/libdw.map: Add dwfl_perf_sample_preferred_regs_mask.
> * libdwfl/Makefile.am: Add dwfl_perf_frame.c.

I probably need to read the rest of the patch series first. On its own
I am not a fan, it feels very much an implementation detail that
should be abstracted away.

> ---
>  libdw/libdw.map           |  1 +
>  libdwfl/Makefile.am       |  3 +-
>  libdwfl/dwfl_perf_frame.c | 61 +++++++++++++++++++++++++++++++++++++++
>  libdwfl/libdwfl.h         | 10 +++++++
>  4 files changed, 74 insertions(+), 1 deletion(-)
>  create mode 100644 libdwfl/dwfl_perf_frame.c
> 
> diff --git a/libdw/libdw.map b/libdw/libdw.map
> index afbc467f..3218fd9c 100644
> --- a/libdw/libdw.map
> +++ b/libdw/libdw.map
> @@ -389,4 +389,5 @@ ELFUTILS_0.192 {
>  ELFUTILS_0.193 {
>    global:
>      dwfl_set_initial_registers_thread;
> +    dwfl_perf_sample_preferred_regs_mask;
>  } ELFUTILS_0.192;
> diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
> index b30b86f0..37c57bee 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
> @@ -71,6 +71,7 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c 
> dwfl_version.c \
>                   link_map.c core-file.c open.c image-header.c \
>                   dwfl_frame.c frame_unwind.c dwfl_frame_pc.c \
>                   linux-pid-attach.c linux-core-attach.c dwfl_frame_regs.c \
> +                 dwfl_perf_frame.c \
>                   gzip.c debuginfod-client.c
>  
>  if BZLIB
> diff --git a/libdwfl/dwfl_perf_frame.c b/libdwfl/dwfl_perf_frame.c
> new file mode 100644
> index 00000000..87db97bc
> --- /dev/null
> +++ b/libdwfl/dwfl_perf_frame.c
> @@ -0,0 +1,61 @@
> +/* 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
> +
> +#include <linux/perf_event.h>

This should probably be guarded by #ifdef __linux__ or some configure
check? Or... where is this used?

> +#include "libdwflP.h"
> +
> +Ebl *default_ebl = NULL;
> +GElf_Half default_ebl_machine = EM_NONE;

Make these static.

> +uint64_t dwfl_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 dwfl_perf_sample_getframes to be added in subsequent patch */
> diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
> index b3b32d51..29505863 100644
> --- a/libdwfl/libdwfl.h
> +++ b/libdwfl/libdwfl.h
> @@ -825,6 +825,16 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
>                          void *arg)
>    __nonnull_attribute__ (1, 3);
>  
> +/* XXX dwfl_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 dwfl_perf_sample_preferred_regs_mask (GElf_Half machine);
> +
>  /* Return *PC (program counter) for thread-specific frame STATE.
>     Set *ISACTIVATION according to DWARF frame "activation" definition.
>     Typically you need to subtract 1 from *PC if *ACTIVATION is false to 
> safely
> -- 
> 2.47.0
> 

Reply via email to