Re: [PATCH 05/13] libdwfl [5/13]: introduce Dwfl_Process_Tracker

2025-04-05 Thread Serhei Makarov



On Thu, Mar 20, 2025, at 8:01 AM, Mark Wielaard wrote:
> Hi Serhei,
>
> On Sun, 2025-03-16 at 19:14 -0400, Serhei Makarov wrote:
> I am wondering whether this isn't too abstract. libdwfl Dwfl's are
> already super abstract so they can be used for running processes and
> core dump and an offline or running kernel. Which is super powerful,
> but also slightly confusing at times.
>
> Can a Dwfl_Process_Tracker really take any callbacks and any Dwfl? Or
> would it make sense to limit it (as its name already implies) to Dwfls
> that report through dwfl_linux_proc_report with a given pid?
It's important to note that Dwfl_Process_Tracker collects multiple Dwfls that
report about processes with different pid's, for the system-wide profiling use 
case.
That gives a way for these Dwfls to share an Elf data cache,
and query whether a Dwfl for a given pid has already been created.
It looks like I should adjust the comments to make that immediately obvious.
That's ok; for anything in the public headers, a lot of bikeshedding
is appropriate.

I don't see why it's necessarily tied to dwfl_linux_proc_report.
Any method of providing information about a live process would
work, including the profiler doing something custom with
the lower-level dwfl_report_... public functions. That might be
one way for sysprof to handle containers, for example,
without requiring us to reimplement their functionality
for peeking into container filesystems.

{One potentially confusing point about this api IMO comes later
in the patch series, where dwfl_perf_sample_getframes calls
dwfl_attach_state() if the Dwfl is unattached. I'm open to handling
it slightly differently, perhaps by splitting out the attach operation
into a separate function the profiler would need to call first.
I'll reiterate this in the discussion on patch12.}


[RFC v2] sketch of an unwinder cache interface for elfutils libdwfl

2025-04-05 Thread Serhei Makarov
On Tue, Dec 10, 2024, at 4:42 PM, Serhei Makarov wrote:
> This email sketches an 'unwinder cache' interface for libdwfl, derived 
> from recent eu-stacktrace code [1] and based on Christian Hergert's 
> adaptation of eu-stacktrace as sysprof-live-unwinder [2]. The intent is 
> to remove the need for a lot of boilerplate code that would be 
> identical among profiling tools that use libdwfl to unwind perf_events 
> stack samples. But since this becomes a library design, it's in need of 
> feedback and bikeshedding.
In advance of finishing up the Dwfl_Process_Tracker patchset
(initial version currently under review),
wanted to post an update summarizing the current api design.

api summary
===

(1) Create a Dwfl_Process_Tracker that caches data from multiple
Dwfls related to a system-wide profiling session:

typedef struct Dwfl_Process_Tracker Dwfl_Process_Tracker;
Dwfl_Process_Tracker *dwfl_process_tracker_begin (const Dwfl_Callbacks 
*callbacks);
Dwfl *dwfl_begin_with_tracker (Dwfl_Process_Tracker *tracker);
void dwfl_process_tracker_end (Dwfl_Process_Tracker *tracker);

(2) Given a pid, check if a Dwfl has already been created for it and return 
that;
if it hasn't been created, invoke the callback (which is expected to use
dwfl_begin_with_tracker to create an appropriate Dwfl).

Dwfl *dwfl_process_tracker_find_pid (Dwfl_Process_Tracker *tracker,
pid_t pid, Dwfl *(*callback) (Dwfl_Process_Tracker *tracker, pid_t pid, 
void *arg), void *arg);

(3) This is a variant of the dwfl_linux_proc_find_elf callback which first
checks the Dwfl_Process_Tracker associated with the Dwfl,
and reuses any previously-loaded Elf data;
otherwise, it creates a new Elf using dwfl_linux_proc_find_elf.

int dwfl_process_tracker_find_elf (Dwfl_Module *mod, void **userdata,
const char *module_name, Dwarf_Addr base, char **file_name, Elf **)
-> same arguments as dwfl_linux_proc_find_elf

(4) Obtain a perf_events regs_mask suitable for unwinding
on the specified architecture.
Then, use the elfutils unwinder to unwind the stack sample
data returned from perf_events:

uint64_t dwfl_perf_sample_preferred_regs_mask (GElf_Half machine);
int dwfl_perf_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid,
const Dwarf_Word *regs, uint32_t n_regs,
uint64_t perf_regs_mask, uint32_t abi,
int (*callback) (Dwfl_Frame *state, void *arg), void *arg);

NOTE -- based on patch-review feedback, I'm considering to
add another api function that must be called on an unattached
Dwfl prior to using dwfl_perf_sample_getframes:

int dwfl_sample_attach (Dwfl *dwfl);

Otherwise, the flow with dwfl_perf_sample_getframes() is too confusing;
currently it calls dwfl_attach_state on an unattached Dwfl (with its own
callbacks arg, hidden to the library user), but it can also be called
on a Dwfl that was attached by a previous call to dwfl_perf_sample_getframes().
This 'just works' when used in the profiler code,
but is too fiddly to explain what is and isn't permissible to do.


Re: [PATCH 2/3] src/readelf.c: Support concurrency for -w, --debug-dump

2025-04-05 Thread Frank Ch. Eigler
Hi -

> Due to significant lock contention, running eu-readelf when configured
> with --enable-thread-safety causes a major performance degradation.
> Currently, concurrency may double the runtime of eu-readelf.

> However I think this work should still be merged. --enable-thread-safety
> is still marked as experimental and these patches facilitate testing
> future improvements to lock contention.

Experimental but being enabled in RHEL/Fedora, right?  Have you
considered making this patch set eu-readelf default to traditional
serial mode?  That way, no performance regression for normal users,
but all the code is compiled in for experiments.

- FChE



[PATCH 3/5] doc: Add elf_getbase.3

2025-04-05 Thread Aaron Merey
Signed-off-by: Aaron Merey 
---
 doc/Makefile.am   |  3 ++-
 doc/elf_getbase.3 | 55 +++
 2 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 doc/elf_getbase.3

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 0dec1fc7..56c56b7b 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -60,7 +60,8 @@ notrans_dist_man3_MANS= elf_update.3 \
elf64_checksum.3 \
libelf.3 \
elf_end \
-   elf_fill
+   elf_fill \
+   elf_getbase
 
 # libdebuginfod man pages (also notrans)
 # Note we include them even when not building them because we want
diff --git a/doc/elf_getbase.3 b/doc/elf_getbase.3
new file mode 100644
index ..1934e1ac
--- /dev/null
+++ b/doc/elf_getbase.3
@@ -0,0 +1,55 @@
+.TH ELF_GETBASE 3 2025-03-31 "Libelf" "Libelf Programmer's Manual"
+
+.SH NAME
+elf_getbase \- Retrieve the base offset for an ELF object file.
+
+.SH SYNOPSIS
+.B #include 
+
+.BI "int64_t elf_getbase(Elf *" elf ");"
+
+.SH DESCRIPTION
+.B elf_getbase
+returns the file offset of the first byte of the ELF descriptor
+.IR elf .
+If
+.I elf
+is a member of an archive and has ELF kind
+.BR ELF_K_AR ,
+the base offset is the offset of the ELF object within the archive.
+For other ELF object types the base offset is 0.
+
+.SH PARAMETERS
+.TP
+.I elf
+The ELF descriptor.
+
+.SH RETURN VALUE
+Return the base offset of
+.IR elf .
+If
+.I elf
+is NULL, return -1.
+
+.SH SEE ALSO
+.BR libelf (3),
+.BR elf (5)
+
+.SH ATTRIBUTES
+For an explanation of the terms used in this section, see
+.BR attributes (7).
+
+.TS
+allbox;
+lbx lb lb
+l l l.
+Interface  Attribute   Value
+T{
+.na
+.nh
+.BR elf_getbase ()
+T} Thread safety   MT-Safe
+.TE
+
+.SH REPORTING BUGS
+Report bugs to  or 
https://sourceware.org/bugzilla/.
-- 
2.49.0



Re: [PATCH 1/1] debuginfod: add --http-addr option

2025-04-05 Thread Mark Wielaard
Hi Michael,

On Thu, 2025-03-13 at 12:05 +0100, Michael Trapp wrote:
> Use MHD_OPTION_SOCK_ADDR to bind the http listen socket to a single address.
> The address can be any IPv4 or IPv6 address configured on the system:
> --http-addr=127.0.0.1
> --http-addr=::1
> --http-addr='ANY_ACTIVE_LOCAL_IP_ADDRESS'
> As debuginfod does not include any security features, a listen on the
> localhost address is sufficient for a HTTP/HTTPS reverse-proxy setup.

I like the idea behind this patch. But is the option name clear enough?
Should it maybe be --bind-address= or --listen-address= simply --addr=
like it is --port=?

Or even combine it as --listen=addr:port ?

Does it make sense to allow multiple local addresses to bind to? Like
both 127.0.01 and ::1 ? I guess maybe not because if you are using this
you probably are behind a proxy anyway. So maybe it could simply be --
listen-local and debuginfod figures out whether that is ipv4
(127.0.0.1) and/or ipv6 (::1) ?

I don't know what other programs do, can we follow some semi-standard?

The code itself does look ok, although I think it could be simplified a
little if we go for something like --listen-local only (assuming that
makes sense).

Cheers,

Mark

> ---
>  debuginfod/debuginfod.cxx | 115 ++
>  doc/debuginfod.8  |   5 ++
>  2 files changed, 84 insertions(+), 36 deletions(-)
> 
> diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx
> index 0edd57cb..30916093 100644
> --- a/debuginfod/debuginfod.cxx
> +++ b/debuginfod/debuginfod.cxx
> @@ -81,6 +81,7 @@ extern "C" {
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  
>  /* If fts.h is included before config.h, its indirect inclusions may not
> @@ -481,6 +482,8 @@ static const struct argp_option options[] =
>  #define ARGP_KEY_METADATA_MAXTIME 0x100C
> { "metadata-maxtime", ARGP_KEY_METADATA_MAXTIME, "SECONDS", 0,
>   "Number of seconds to limit metadata query run time, 0=unlimited.", 0 },
> +#define ARGP_KEY_HTTP_ADDR 0x100D
> +   { "http-addr", ARGP_KEY_HTTP_ADDR, "ADDR", 0, "HTTP address to listen 
> on.", 0 },
> { NULL, 0, NULL, 0, NULL, 0 },
>};
>  
> @@ -512,6 +515,8 @@ static volatile sig_atomic_t sigusr1 = 0;
>  static volatile sig_atomic_t forced_groom_count = 0;
>  static volatile sig_atomic_t sigusr2 = 0;
>  static unsigned http_port = 8002;
> +static struct sockaddr_in6 http_sockaddr;
> +static string addr_info = "";
>  static bool webapi_cors = false;
>  static unsigned rescan_s = 300;
>  static unsigned groom_s = 86400;
> @@ -753,6 +758,16 @@ parse_opt (int key, char *arg,
>requires_koji_sigcache_mapping = true;
>break;
>  #endif
> +case ARGP_KEY_HTTP_ADDR:
> +  if (inet_pton(AF_INET, arg, 
> &(((sockaddr_in*)&http_sockaddr)->sin_addr)) == 1)
> +  http_sockaddr.sin6_family = AF_INET;
> +  else
> +  if (inet_pton(AF_INET6, arg, &http_sockaddr.sin6_addr) == 1)
> +  http_sockaddr.sin6_family = AF_INET6;
> +  else
> +  argp_failure(state, 1, EINVAL, "HTTP address");
> +  addr_info = arg;
> +  break;
>// case 'h': argp_state_help (state, stderr, 
> ARGP_HELP_LONG|ARGP_HELP_EXIT_OK);
>  default: return ARGP_ERR_UNKNOWN;
>  }
> @@ -5596,6 +5611,8 @@ main (int argc, char *argv[])
>fdcache_prefetch = 64; // guesstimate storage is this much less costly 
> than re-decompression
>  
>/* Parse and process arguments.  */
> +  memset(&http_sockaddr, 0, sizeof(http_sockaddr));
> +  http_sockaddr.sin6_family = AF_UNSPEC;
>int remaining;
>(void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL);
>if (remaining != argc)
> @@ -5702,50 +5719,75 @@ main (int argc, char *argv[])
>  #endif
>   | MHD_USE_DEBUG); /* report errors to stderr */
>  
> -  // Start httpd server threads.  Use a single dual-homed pool.
> -  MHD_Daemon *d46 = MHD_start_daemon (mhd_flags, http_port,
> -   NULL, NULL, /* default accept policy */
> -   handler_cb, NULL, /* handler callback */
> -   MHD_OPTION_EXTERNAL_LOGGER,
> -   error_cb, NULL,
> -   MHD_OPTION_THREAD_POOL_SIZE,
> -   (int)connection_pool,
> -   MHD_OPTION_END);
> -
> -  MHD_Daemon *d4 = NULL;
> -  if (d46 == NULL)
> +  MHD_Daemon *dsa = NULL,
> +  *d4 = NULL,
> +  *d46 = NULL;
> +
> +  if (http_sockaddr.sin6_family != AF_UNSPEC)
>  {
> -  // Cannot use dual_stack, use ipv4 only
> -  mhd_flags &= ~(MHD_USE_DUAL_STACK);
> -  d4 = MHD_start_daemon (mhd_flags, http_port,
> -  NULL, NULL, /* default accept policy */
> +  if (http_sockaddr.sin6_family == AF_INET)
> + ((sockaddr_in*)&http_sockaddr)->sin_port = htons(http_port);
> +  if (http_sockaddr.sin6_fami