All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Matthew Wood" <thepacketgeek@gmail.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v3 2/2] perf unwind: Don't look up symbols when the caller doesn't want them
Date: Fri, 30 Oct 2026 19:51:45 +0000	[thread overview]
Message-ID: <sashiko-outbox-191456@kernel.org> (raw)
In-Reply-To: <20261030193237.1440673-3-thepacketgeek@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] perf unwind: dso__load_symsrc() in entry() runs after libunwind stepping
--

commit a0b5e533925de51fda6cc2ade28ec95e77a4ee79
Author: Matthew Wood <thepacketgeek@gmail.com>

perf unwind: Don't look up symbols when the caller doesn't want them

This commit passes a symbols flag down to the DWARF unwinders (libdw and
libunwind) so callers that only need maps can unwind callchains without
loading and demangling DSO symbol tables. When symbols is false, the
unwinders call dso__load_symsrc() to locate build-ids and separate
debuginfo without loading symbols.

> diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
> index 73d191ce51a55..3c5acc052715a 100644
> --- a/tools/perf/util/unwind-libunwind.c
> +++ b/tools/perf/util/unwind-libunwind.c
> @@ -589,14 +589,26 @@ void unwind__finish_access(struct maps *maps)
>  	libunwind_arch__finish_access(maps);
>  }
>  
> -static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb, void *arg)
> +static int entry(uint64_t ip, struct thread *thread, bool symbols,
> +		 unwind_entry_cb_t cb, void *arg)
>  {
>  	struct unwind_entry e;
>  	struct addr_location al;
>  	int ret;
>  
>  	addr_location__init(&al);
> -	e.ms.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
> +	if (symbols) {
> +		thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
> +	} else {
> +		/*
> +		 * Still find the DSO's separate debuginfo, which loading
> +		 * the symbols would have, for read_unwind_spec_debug_frame().
> +		 */
> +		thread__find_map(thread, PERF_RECORD_MISC_USER, ip, &al);
> +		if (al.map)
> +			dso__load_symsrc(map__dso(al.map));
> +	}
> +	e.ms.sym = al.sym;
>  	e.ip     = ip;
>  	e.ms.map = al.map;
>  	e.ms.thread = thread__get(al.thread);
> @@ -614,7 +626,7 @@ static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb, void
>  int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  			 struct thread *thread,
>  			 struct perf_sample *sample, int max_stack,
> -			 bool best_effort)
> +			 bool symbols, bool best_effort)
>  {
>  	struct unwind_info *ui;
>  	uint64_t first_ip;
> @@ -640,7 +652,7 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  
>  	if (max_stack == 1) {
>  		/* Special case for a single entry. */
> -		ret = entry(first_ip, thread, cb, arg);
> +		ret = entry(first_ip, thread, symbols, cb, arg);
>  		return ret ? (ret == -ENOMEM ? -ENOMEM : 0) : 1;
>  	}
>  
> @@ -662,7 +674,7 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  		int j = callchain_param.order == ORDER_CALLEE ? i : ui->cur_ip - i - 1;
>  
>  		if (ui->ips[j]) {
> -			ret = entry(ui->ips[j], thread, cb, arg);
> +			ret = entry(ui->ips[j], thread, symbols, cb, arg);

[Severity: Medium]
Does calling dso__load_symsrc() inside entry() happen too late for
read_unwind_spec_debug_frame() during unwinding?

In libunwind__get_entries(), all stack stepping runs to completion before
entry() is called on the collected IPs:

tools/perf/util/unwind-libunwind.c:libunwind__get_entries() {
	do {
		ret = libunwind_arch__unwind_step(ui);
		if (ret < 0)
			goto out;

	} while (ret);

	/*
	 * Display what we got based on the order setup.
	 */
	for (i = 0; i < ui->cur_ip; i++) {
		int j = callchain_param.order == ORDER_CALLEE ? i : ui->cur_ip - i - 1;

		if (ui->ips[j]) {
			ret = entry(ui->ips[j], thread, symbols, cb, arg);
			if (ret)
				break;
			entries++;
		}
	}
}

While libunwind_arch__unwind_step() is stepping the stack,
__libunwind__find_proc_info() looks up the map via find_map() (which only
calls thread__find_map()) and then invokes read_unwind_spec_debug_frame():

tools/perf/util/unwind-libunwind.c:__libunwind__find_proc_info() {
	if (ret < 0 && !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) {
		...
		symfile = dso__symsrc_filename(dso) ?: dso__name(dso);
}

Inside read_unwind_spec_debug_frame(), it attempts to open
dso__symsrc_filename(dso):

tools/perf/util/unwind-libunwind.c:read_unwind_spec_debug_frame() {
		if (ofs <= 0) {
			fd = open(dso__symsrc_filename(dso), O_RDONLY);
			if (fd >= 0) {
				ofs = elf_section_offset(fd, ".debug_frame");
				close(fd);
			}
		}
}

When callers pass symbols=false (such as build_id__mark_dso_hit(),
perf_event__inject_buildid(), get_leaf_frame_caller_aarch64(), or
test_dwarf_unwind__thread()), neither dso__load() nor dso__load_symsrc()
has been called before libunwind_arch__unwind_step() runs. As a result,
dso__symsrc_filename(dso) is still NULL when read_unwind_spec_debug_frame()
and __libunwind__find_proc_info() check it, so unwinding fails for frames
that rely on .debug_frame in separate debuginfo discovered by
dso__load_symsrc() (and if libunwind_arch__unwind_step() returns a negative
error, the goto out path skips the entry() loop entirely).

Should dso__load_symsrc(dso) be called in __libunwind__find_proc_info() or
read_unwind_spec_debug_frame() before reading dso__symsrc_filename(dso)
instead of in entry()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261030193237.1440673-1-thepacketgeek@gmail.com?part=2

      reply	other threads:[~2026-10-30 19:51 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-30 19:32 [PATCH v3 0/2] perf unwind: Don't load symbols when the caller doesn't need them Matthew Wood
2026-10-30 19:32 ` [PATCH v3 1/2] perf symbol: Add dso__load_symsrc() Matthew Wood
2026-10-30 19:40   ` sashiko-bot
2026-10-30 19:32 ` [PATCH v3 2/2] perf unwind: Don't look up symbols when the caller doesn't want them Matthew Wood
2026-10-30 19:51   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-191456@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=thepacketgeek@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.