]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf tools: Add layout support for --symfs option
authorChangbin Du <changbin.du@huawei.com>
Mon, 9 Mar 2026 17:44:12 +0000 (17:44 +0000)
committerNamhyung Kim <namhyung@kernel.org>
Wed, 11 Mar 2026 06:13:30 +0000 (23:13 -0700)
Add support for parsing an optional layout parameter in the --symfs
command line option. The format is:

  --symfs <directory[,layout]>

Where layout can be:
  - 'hierarchy': matches full path (default)
  - 'flat': only matches base name

When debugging symbol files from a copy of the filesystem (e.g., from a
container or remote machine), the debug files are often stored in a
flat directory structure with only filenames, not the full original
paths. In this case, using 'flat' layout allows perf to find debug
symbols by matching only the filename rather than the full path.

For example, given a binary path like:
  /build/output/lib/foo.so

With 'perf report --symfs /debug/files,flat', perf will look for:
  /debug/files/foo.so

Instead of:
  /debug/files/build/output/lib/foo.so

This is particularly useful when:
- Extracting debug files from containers with different directory layouts
- Working with build systems that flatten directory structures

Signed-off-by: Changbin Du <changbin.du@huawei.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
20 files changed:
tools/perf/Documentation/perf-annotate.txt
tools/perf/Documentation/perf-diff.txt
tools/perf/Documentation/perf-kwork.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-sched.txt
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-timechart.txt
tools/perf/Documentation/tips.txt
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-kwork.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-timechart.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/symbol_conf.h

index 547f1a2680185e3cf288389e0521bd0e44c42034..a688738809c4327df93c6be6eb71f9f60403f995 100644 (file)
@@ -110,8 +110,11 @@ include::itrace.txt[]
        Interleave source code with assembly code. Enabled by default,
        disable with --no-source.
 
---symfs=<directory>::
-        Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 -M::
 --disassembler-style=:: Set disassembler style for objdump.
index 58efab72d2e58e485e34eaeaf9cecfcd757555b7..8e4a3f093135ed42611400f615e3f97868847764 100644 (file)
@@ -81,8 +81,11 @@ OPTIONS
 --force::
         Don't do ownership validation.
 
---symfs=<directory>::
-        Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 -b::
 --baseline-only::
index 21e607669d78a6f252d589be17c5edc484c5ec3a..5c33a1fb2ffe6fda8b21cccc383e9d904e2689a1 100644 (file)
@@ -169,8 +169,11 @@ OPTIONS for 'perf kwork timehist'
 --max-stack::
        Maximum number of functions to display in backtrace, default 5.
 
---symfs=<directory>::
-    Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 --time::
        Only analyze samples within given time window: <start>,<stop>. Times
index 5c43a6edc0e5b7c41bfbeeec400f629a007bfcc2..2e57903254309bcbcf4cd1f427861bdc44b7aaed 100644 (file)
@@ -50,6 +50,12 @@ OPTIONS
 --source=PATH::
        Specify path to kernel source.
 
+--symfs=<directory[,layout]>::
+       Look for files with symbols relative to this directory. The optional
+       layout can be 'hierarchy' (default, matches full path) or 'flat'
+       (only matches base name). This is useful when debug files are stored
+       in a flat directory structure.
+
 -v::
 --verbose::
         Be more verbose (show parsed arguments, etc).
index acef3ff4178eff66e8f876ae16cdac7b1387f07b..802f931ae64db75dcff52ccabdc63cc7f8289132 100644 (file)
@@ -368,8 +368,11 @@ OPTIONS
 --force::
         Don't do ownership validation.
 
---symfs=<directory>::
-        Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 -C::
 --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
index 4d9981609c04973e44bb629e38b6083abc38ca32..a4221398e5e0933e06af43c40a6ce646516495e4 100644 (file)
@@ -437,8 +437,11 @@ OPTIONS for 'perf sched timehist'
     Show all scheduling events followed by a summary by thread with min,
     max, and average run times (in sec) and relative stddev.
 
---symfs=<directory>::
-    Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 -V::
 --cpu-visual::
index ddf92f9c78212974c15d859a6e3e46e8875a8c2b..200ea25891d88d0d4591c06b3e7372f8af84c2df 100644 (file)
@@ -307,8 +307,11 @@ OPTIONS
 --kallsyms=<file>::
         kallsyms pathname
 
---symfs=<directory>::
-        Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 
 -G::
 --hide-call-graph::
index ef2281c56743ea687be19d51c675d8be73b088e5..bacc5df3c400241291c75904c5b60cfe0a065ec2 100644 (file)
@@ -53,8 +53,11 @@ TIMECHART OPTIONS
 -f::
 --force::
        Don't complain, do it.
---symfs=<directory>::
-        Look for files with symbols relative to this directory.
+--symfs=<directory[,layout]>::
+        Look for files with symbols relative to this directory. The optional
+        layout can be 'hierarchy' (default, matches full path) or 'flat'
+        (only matches base name). This is useful when debug files are stored
+        in a flat directory structure.
 -n::
 --proc-num::
         Print task info for at least given number of tasks.
index 3fee9b2a88ea9420f5643d0fdc241869cad39b7d..ebf12a8c5db5961744c0067ba44a3d461dacdf68 100644 (file)
@@ -11,7 +11,7 @@ Search options using a keyword: perf report -h <keyword>
 Use parent filter to see specific call path: perf report -p <regex>
 List events using substring match: perf list <keyword>
 To see list of saved events and attributes: perf evlist -v
-Use --symfs <dir> if your symbol files are in non-standard locations
+Use --symfs <dir>[,layout] if your symbol files are in non-standard locations.
 To see callchains in a more compact form: perf report -g folded
 To see call chains by final symbol taking CPU time (bottom up) use perf report -G
 Show individual samples with: perf script
index 9c27bb30b70899ee035b88a08c08ab34f7511972..686ad08561d66924e037103ab14e04f59d33e731 100644 (file)
@@ -744,8 +744,7 @@ int cmd_annotate(int argc, const char **argv)
                        &annotate.group_set,
                        "Show event group information together"),
        OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
-       OPT_CALLBACK(0, "symfs", NULL, "directory",
-                    "Look for files with symbols relative to this directory",
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
                     symbol__config_symfs),
        OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
                    "Interleave source code with assembly code (default)"),
index 59bf1f72d12e226ad6a7f458be3310afd98da67b..69069926dd0ba07b0e101eec9eeced900d48d077 100644 (file)
@@ -1280,8 +1280,7 @@ static const struct option options[] = {
        OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
                   "separator for columns, no spaces will be added between "
                   "columns '.' is reserved."),
-       OPT_CALLBACK(0, "symfs", NULL, "directory",
-                    "Look for files with symbols relative to this directory",
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
                     symbol__config_symfs),
        OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
index 7f3068264568ceea64b99de20fa5a305328d67f9..6f94a8f45f605f343e448fc886c287d6bf1aeb6f 100644 (file)
@@ -2423,8 +2423,8 @@ int cmd_kwork(int argc, const char **argv)
                    "Display call chains if present"),
        OPT_UINTEGER(0, "max-stack", &kwork.max_stack,
                   "Maximum number of functions to display backtrace."),
-       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
-                   "Look for files with symbols relative to this directory"),
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
+                    symbol__config_symfs),
        OPT_STRING(0, "time", &kwork.time_str, "str",
                   "Time span for analysis (start,stop)"),
        OPT_STRING('C', "cpu", &kwork.cpu_list, "cpu",
index 1b4ba85ee0190d69231cde7437004b25563ca37e..a67b565278ae95941d717767101cb1d9f75faec1 100644 (file)
@@ -597,8 +597,8 @@ __cmd_probe(int argc, const char **argv)
        OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
                    "Enable kernel symbol demangling"),
        OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
-       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
-                  "Look for files with symbols relative to this directory"),
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
+                    symbol__config_symfs),
        OPT_CALLBACK(0, "target-ns", NULL, "pid",
                     "target pid for namespace contexts", opt_set_target_ns),
        OPT_BOOLEAN(0, "bootconfig", &probe_conf.bootconfig,
index 3b81f4b3dc4903d5759466c331d657c22a7ef8f4..343c0ada5ea1bcc9a921b21983ae70e763c3a057 100644 (file)
@@ -1416,8 +1416,7 @@ int cmd_report(int argc, const char **argv)
                   "columns '.' is reserved."),
        OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
                    "Only display entries resolved to a symbol"),
-       OPT_CALLBACK(0, "symfs", NULL, "directory",
-                    "Look for files with symbols relative to this directory",
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
                     symbol__config_symfs),
        OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
                   "list of cpus to profile"),
index 3f509cfdd58c4ed231111bbb6e3837b515d6c71a..d083e2bb770303a49e4ae0ceb648d9051fe6d027 100644 (file)
@@ -4879,8 +4879,8 @@ int cmd_sched(int argc, const char **argv)
                    "Display call chains if present (default on)"),
        OPT_UINTEGER(0, "max-stack", &sched.max_stack,
                   "Maximum number of functions to display backtrace."),
-       OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
-                   "Look for files with symbols relative to this directory"),
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
+                    symbol__config_symfs),
        OPT_BOOLEAN('s', "summary", &sched.summary_only,
                    "Show only syscall summary with statistics"),
        OPT_BOOLEAN('S', "with-summary", &sched.summary,
index 9f8b0fd27a0a3c790291d41fcfd82548f64b232b..b80c406d1fc1ba256081ffa4a20b7580c80db036 100644 (file)
@@ -4078,8 +4078,7 @@ int cmd_script(int argc, const char **argv)
                   "file", "kallsyms pathname"),
        OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
                    "When printing symbols do not display call chain"),
-       OPT_CALLBACK(0, "symfs", NULL, "directory",
-                    "Look for files with symbols relative to this directory",
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
                     symbol__config_symfs),
        OPT_CALLBACK('F', "fields", NULL, "str",
                     "comma separated output fields prepend with 'type:'. "
index f8b49d69e9a52a99b7b7774e39d9697511338903..28f33e39895d362d57683c7d3a86a1a7957f32df 100644 (file)
@@ -1951,8 +1951,7 @@ int cmd_timechart(int argc, const char **argv)
        OPT_CALLBACK('p', "process", NULL, "process",
                      "process selector. Pass a pid or process name.",
                       parse_process),
-       OPT_CALLBACK(0, "symfs", NULL, "directory",
-                    "Look for files with symbols relative to this directory",
+       OPT_CALLBACK(0, "symfs", NULL, "directory[,layout]", SYMFS_HELP,
                     symbol__config_symfs),
        OPT_INTEGER('n', "proc-num", &tchart.proc_num,
                    "min. number of tasks to print"),
index 8662001e1e25b1daec9428a364955385b9004b53..bd811b2b78903a14fdfda8ecd4ece57fbf405ff1 100644 (file)
@@ -66,6 +66,7 @@ struct symbol_conf symbol_conf = {
        .time_quantum           = 100 * NSEC_PER_MSEC, /* 100ms */
        .show_hist_headers      = true,
        .symfs                  = "",
+       .symfs_layout_flat      = false,
        .event_group            = true,
        .inline_name            = true,
        .res_sample             = 0,
@@ -2491,16 +2492,42 @@ int symbol__config_symfs(const struct option *opt __maybe_unused,
                         const char *dir, int unset __maybe_unused)
 {
        char *bf = NULL;
+       char *layout_str;
+       char *dir_copy;
        int ret;
 
-       symbol_conf.symfs = strdup(dir);
-       if (symbol_conf.symfs == NULL)
-               return -ENOMEM;
+       layout_str = strrchr(dir, ',');
+       if (layout_str) {
+               size_t dir_len = layout_str - dir;
+
+               dir_copy = strndup(dir, dir_len);
+               if (dir_copy == NULL)
+                       return -ENOMEM;
+
+               symbol_conf.symfs = dir_copy;
+
+               layout_str++;
+               if (!strcmp(layout_str, "flat"))
+                       symbol_conf.symfs_layout_flat = true;
+               else if (!strcmp(layout_str, "hierarchy"))
+                       symbol_conf.symfs_layout_flat = false;
+               else {
+                       pr_err("Invalid layout: '%s', use 'hierarchy' or 'flat'\n",
+                              layout_str);
+                       free(dir_copy);
+                       return -EINVAL;
+               }
+       } else {
+               symbol_conf.symfs = strdup(dir);
+               if (symbol_conf.symfs == NULL)
+                       return -ENOMEM;
+               symbol_conf.symfs_layout_flat = false;
+       }
 
        /* skip the locally configured cache if a symfs is given, and
         * config buildid dir to symfs/.debug
         */
-       ret = asprintf(&bf, "%s/%s", dir, ".debug");
+       ret = asprintf(&bf, "%s/%s", symbol_conf.symfs, ".debug");
        if (ret < 0)
                return -ENOMEM;
 
index 3fb5d146d9b15bd406a3630ac1eb1966f75d110a..4f1dbd1ebd99506a4412001f7e8d1a416a2f232c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <stdio.h>
+#include <errno.h>
 #include "addr_location.h"
 #include "path.h"
 #include "symbol_conf.h"
@@ -96,6 +97,18 @@ struct intlist;
 
 static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
 {
+       if (symbol_conf.symfs_layout_flat) {
+               char *path_copy = strdup(path);
+               char *base;
+               int ret;
+
+               if (!path_copy)
+                       return -ENOMEM;
+               base = basename(path_copy);
+               ret = path__join(bf, size, symbol_conf.symfs, base);
+               free(path_copy);
+               return ret;
+       }
        return path__join(bf, size, symbol_conf.symfs, path);
 }
 
@@ -169,6 +182,11 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
 size_t symbol__fprintf(struct symbol *sym, FILE *fp);
 bool symbol__restricted_filename(const char *filename,
                                 const char *restricted_filename);
+
+#define SYMFS_HELP "setup root directory which contains debug files:\n" \
+       "\t\t\t\t" "directory:\tLook for files with symbols relative to this directory.\n" \
+       "\t\t\t\t" "layout:   \tLayout of files, 'hierarchy' matches full path (default), 'flat' only matches base name.\n"
+
 int symbol__config_symfs(const struct option *opt __maybe_unused,
                         const char *dir, int unset __maybe_unused);
 
index 71bb17372a6cfea0d650a55a939dd184a17894f6..ac1b444a8fd899560862126569bf634593c93254 100644 (file)
@@ -93,6 +93,7 @@ struct symbol_conf {
                        *tid_list,
                        *addr_list;
        const char      *symfs;
+       bool            symfs_layout_flat;
        int             res_sample;
        int             pad_output_len_dso;
        int             group_sort_idx;