Re: [PATCH 02/12] perf debuginfo: Fetch debuginfo keyed by build ID using debuginfod

From: Arnaldo Carvalho de Melo

Date: Wed Sep 16 2026 - 16:25:11 EST


On Wed, Sep 16, 2026 at 10:59:31AM -0700, Ian Rogers wrote:
> On Wed, Sep 16, 2026 at 4:48 AM Arnaldo Carvalho de Melo <acme@xxxxxxxxxx> wrote:
> >
> > perf already uses debuginfod to fetch source files when annotating
> > (via probe-finder.c) and 'perf probe' has open_from_debuginfod(),
> > which queries debuginfo keyed by build ID when a module's debuginfo
> > isn't found locally, largely the same thing this adds; eventually
> > that one could be moved over to the new helper. For the analysis
> > tools there was no way to obtain the debuginfo for a DSO in a
> > profile when it isn't available locally under the name the DSO was
> > opened with, for instance the vmlinux for the kernel a profile was
> > recorded on when processing it on another machine, or after the
> > kernel and its debuginfo package got upgraded in between.
> >
> > Add debuginfo__find_build_id(), that uses the debuginfod client to
> > locate a debuginfo file keyed by the build ID, checking its local
> > cache first and then querying the servers in DEBUGINFOD_URLS, and
> > debuginfo__new_build_id(), that opens the DWARF in the file it finds.

> When do we have a build ID but not a DSO? The current intent is that

Trying to parse this: Before we had a PERF_RECORD_MMAP with a dso name
that we, at the end, when enabled, would look for a build-id to add to
the perf.data headers, now we get both in the PERF_RECORD_MMAP3, right?

> dso__debuginfo hide these complexities. We currently don't purge DSOs

>From the cache, right, and that is a problem, we need to do that LRU you
mention, to not have a ever growing cache.

There is a recent patch from someone at Uber about another aspect of
this, the symtabs loaded in memory for resolving symbols are not in any
way constrained, we go on loading, not purging, hope that patch gets
resubmitted addressing the sashiko reviews that were acknowledged.

> and the first call to dso__debuginfo should trigger loading with the
> DSO owning the debuginfo. With this change we now have a duplication
> of DSO's data, keyed by build ID and mapping directly to the
> debuginfo. I can't see a performance or efficiency gain and we could
> potentially implement some kind of LRU mechanism for DSOs, which would
> benefit memory usage for things like perf top.

> > The debuginfod client fails when DEBUGINFOD_URLS isn't set even when
> > what it wants is in its local cache, and the distro setup scripts that
> > populate it from /etc/debuginfod don't reach cron jobs, systemd services
> > and other environments that don't source the profile scripts, so also
> > set it from the .urls files in /etc/debuginfod when not set.

> I found the explanation above hard to follow. Are we setting an
> environment variable because debuginfod isn't respecting its /etc
> setup?

IIRC what I saw was the debuginfod client not finding things in the
cache when that DEBUGINFO_URLS variable wasn't set, so setting it
doesn't mean to ask for downloads necessarily, but to use what is
already cached locally.

> > That has
> > to happen before any thread that can call getenv() is started, as
> > setenv() is not thread safe, and there are getenv()s outside the fetch
> > lock: libdebuginfod reads DEBUGINFOD_URLS in every debuginfod_begin(),
> > which perf also does in build-id.c, probe-event.c and probe-finder.c,
> > so do it from symbol__init(), on the single-threaded setup, and not
> > lazily from the fetch path.
> >
> > Querying servers, possibly third party ones, sends off-box the build
> > IDs of the binaries being analysed and a fetch can take a while, so
> > this is opt-out: on by default, off with --no-debuginfod, with
> > core.debuginfod=false, per tool with report.debuginfod and
> > top.debuginfod, and, since users that set buildid.dir to /dev/null
> > (e.g. Linus) or otherwise turn the local build-id cache off clearly
> > don't want fetched files stored on the box, off too in that case.

> > The opt-outs also cover libdwfl's own debuginfod client, that reads
> > DEBUGINFOD_URLS in every query: when debuginfod is off, be it with
> > --no-debuginfod, core.debuginfod=false or by disabling the build-id
> > cache, the variable is set to the empty string, that the client treats
> > as an opt-out and fails the query without even looking at its cache,
> > instead of being exported from /etc/debuginfod. Tools that manage
> > DEBUGINFOD_URLS themselves, such as 'perf record --debuginfod', keep
> > doing so.

> Libdwfl is part of elfutils and so is debuginfod. Is it possible to
> share clients?

We need to stop using ~/.debug/ and move to have the cache where elfutils
libraries have it.

Transitioning should just use ~/.debug if available but saving copies of
local DSOs like perf does in the elfutils cache directory.

<SNIP>

> > +static bool build_id__equal(const struct build_id *a, const struct build_id *b)
> > +{
> > + return a->size == b->size && memcmp(a->data, b->data, a->size) == 0;
> > +}
>
> This is probably worth moving to the build-id.[ch] file. I see similar
> logic in places like __dso_id__cmp, dso__missing_buildid_cache in
> builitin-buildid-cache.c and sort__dcacheline_cmp. dso__build_id_equal
> has some special backward compatibility checks.

Agreed, will do.

- Arnaldo