[PATCH perf-tools-next v9 3/6] perf symbol: Introduce vmlinux_path__find() helper

From: Aaron Tomlin

Date: Tue Oct 20 2026 - 22:34:55 EST


The vmlinux_path array maintains standard paths used by perf to locate
the kernel image (e.g. "vmlinux", "/boot/vmlinux",
"/lib/modules/%s/build/vmlinux", "/usr/lib/debug/..."). While
vmlinux_path__init() populates these candidates and dso__load_vmlinux_path()
loads symbols into a DSO/map, callers (such as test suites or probing tools)
often need to verify the existence of an accessible vmlinux on disk before
attempting machine setup or test execution.

Introduce vmlinux_path__find() to search through the configured vmlinux_path
entries (or symbol_conf.vmlinux_name if explicitly set) and return the
path to the first readable vmlinux file, or NULL if none is accessible.

Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
---
tools/perf/util/symbol.c | 38 +++++++++++++++++++++++++++++++++++++-
tools/perf/util/symbol.h | 2 ++
2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b61a574ce9a3..fd4a4441718e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2337,6 +2337,9 @@ static int vmlinux_path__init(struct perf_env *env)
const char *kernel_version;
unsigned int i;

+ if (vmlinux_path)
+ return 0;
+
vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
ARRAY_SIZE(vmlinux_paths_upd)));
if (vmlinux_path == NULL)
@@ -2372,6 +2375,38 @@ static int vmlinux_path__init(struct perf_env *env)
return -1;
}

+/**
+ * vmlinux_path__find - Locate the first accessible vmlinux file
+ *
+ * Check symbol_conf.vmlinux_name first if set, then search through the
+ * initialized paths in vmlinux_path.
+ *
+ * Return: A pointer to the path of the first readable vmlinux file, or NULL if
+ * none is accessible.
+ */
+const char *vmlinux_path__find(void)
+{
+ int i;
+
+ if (symbol_conf.vmlinux_name && access(symbol_conf.vmlinux_name, R_OK) == 0)
+ return symbol_conf.vmlinux_name;
+
+ if (symbol__init(NULL) < 0)
+ return NULL;
+
+ if (!vmlinux_path) {
+ if (vmlinux_path__init(NULL) < 0)
+ return NULL;
+ }
+
+ for (i = 0; i < vmlinux_path__nr_entries; ++i) {
+ if (access(vmlinux_path[i], R_OK) == 0)
+ return vmlinux_path[i];
+ }
+
+ return NULL;
+}
+
int setup_list(struct strlist **list, const char *list_str,
const char *list_name)
{
@@ -2598,6 +2633,8 @@ int symbol__init(struct perf_env *env)

void symbol__exit(void)
{
+ vmlinux_path__exit();
+
if (!symbol_conf.initialized)
return;

@@ -2608,7 +2645,6 @@ void symbol__exit(void)
intlist__delete(symbol_conf.tid_list);
intlist__delete(symbol_conf.pid_list);
intlist__delete(symbol_conf.addr_list);
- vmlinux_path__exit();
symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
symbol_conf.bt_stop_list = NULL;
symbol_conf.initialized = false;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index d0bac824c79c..6d1eb08076ab 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -184,6 +184,8 @@ static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
extern int vmlinux_path__nr_entries;
extern char **vmlinux_path;

+const char *vmlinux_path__find(void);
+
static inline void *symbol__priv(struct symbol *sym)
{
return ((void *)sym) - symbol_conf.priv_size;
--
2.55.0