]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf libdw: Fix callchain parent update in ORDER_CALLER mode
authorIan Rogers <irogers@google.com>
Mon, 4 May 2026 08:12:22 +0000 (01:12 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 6 May 2026 00:49:32 +0000 (21:49 -0300)
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>
tools/perf/util/libdw.c

index 216977884103087bb376a998b19af4afafac2753..301642084c6906f92d4ec7fcfc523ae3d3110d71 100644 (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);