perf libdw: Fix callchain parent update in ORDER_CALLER mode

Fix the parent srcline lookup in `libdw_a2l_cb()` to target the
correct parent node depending on the callchain order
(ORDER_CALLER/ORDER_CALLEE).

This ensures inline callchains are not corrupted when nest depth > 2.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zecheng Li <zli94@ncsu.edu>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Ian Rogers 2026-05-04 01:12:22 -07:00 committed by Arnaldo Carvalho de Melo
parent 674dea094e
commit 0e18b5bb7c

View File

@ -4,6 +4,7 @@
#include "srcline.h"
#include "symbol.h"
#include "dwarf-aux.h"
#include "callchain.h"
#include <fcntl.h>
#include <unistd.h>
#include <elfutils/libdwfl.h>
@ -80,7 +81,6 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
struct symbol *inline_sym = new_inline_sym(args->dso, args->sym, dwarf_diename(die));
const char *call_fname = die_get_call_file(die);
char *call_srcline = srcline__unknown;
struct inline_list *ilist;
if (!inline_sym)
return -ENOMEM;
@ -89,14 +89,20 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
if (call_fname)
call_srcline = srcline_from_fileline(call_fname, die_get_call_lineno(die));
list_for_each_entry(ilist, &args->node->val, list) {
if (args->leaf_srcline == ilist->srcline)
if (!list_empty(&args->node->val)) {
struct inline_list *parent;
if (callchain_param.order == ORDER_CALLEE)
parent = list_first_entry(&args->node->val, struct inline_list, list);
else
parent = list_last_entry(&args->node->val, struct inline_list, list);
if (args->leaf_srcline == parent->srcline)
args->leaf_srcline_used = false;
else if (ilist->srcline != srcline__unknown)
free(ilist->srcline);
ilist->srcline = call_srcline;
else if (parent->srcline != srcline__unknown)
free(parent->srcline);
parent->srcline = call_srcline;
call_srcline = NULL;
break;
}
if (call_srcline && call_srcline != srcline__unknown)
free(call_srcline);