* [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers
@ 2026-08-21 20:49 Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses Aaron Tomlin
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-21 20:49 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung
Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
james.clark, howardchu95, atomlin, neelx, chjohnst, sean, steve,
rishil1999, linux-perf-users, linux-kernel
When inspecting kernel execution flows using perf trace (e.g., when
monitoring workqueues, delayed work items, timer callbacks, etc.),
tracepoint payload arguments containing raw kernel virtual addresses are
currently rendered as hexadecimal values (e.g., 0xffffffff81234567).
This requires manual symbol lookups against /proc/kallsyms or vmlinux to
identify the underlying kernel function being executed.
This patch series enhances perf trace by introducing kernel virtual address
and function pointer symbolisation using perf's native symbol engine
(i.e., machine__find_kernel_symbol()).
Before:
workqueue:workqueue_execute_end(work: 0xffffffffab2f1420, function: 0xffffffffa8046b50)
After:
workqueue:workqueue_execute_end(work: 0xffff8ac2c420f270, function: wb_update_bandwidth_workfn)
Patch 1 introduces the syscall_arg__scnprintf_ksym() (SCA_KSYM) beautifier,
which resolves virtual addresses via machine__find_kernel_symbol(),
formatting them as symbol_name+offset (or "NULL", with a graceful
hexadecimal fallback upon lookup failure).
Patch 2 updates event format initialisation in
syscall_arg_fmt__init_array() to automatically assign SCA_KSYM to
tracepoint fields typed as function pointers (such as typedefs ending in
"_func_t" or "_fn", or function prototypes matching "(*)"). It also
registers common function pointer, callback, and callsite field names
(e.g., "action", "call_site", "callback", "caller", "caller_ip",
"callsite", "cb", "fn", "func", "function", "handler", "location") in
syscall_arg_fmts__by_name[], guards SCA_KSYM to pointer fields and
pointer-sized non-array scalars, and removes the legacy
trace__field_is_ip() hex override in trace__fprintf_tp_fields().
Patch 3 extends BTF pretty-printing in trace__btf_scnprintf() with
btf_is_func_ptr() to automatically traverse BTF type hierarchies (including
nested typedefs and qualifiers) and route kernel function pointer arguments
to SCA_KSYM when BTF metadata is available, with negative caching to
prevent redundant BTF scans.
Patch 4 adds an automated regression test script, trace_ksym_beautifier.sh,
under tools/perf/tests/shell/ to verify symbolisation across both default
kallsyms and BTF routing paths.
Changes since v3:
- Added "caller_ip" to syscall_arg_fmts__by_name[] in alphabetical order
to symbolise instruction pointer fields
- Guarded SCA_KSYM auto-assignment in syscall_arg_fmt__init_array() to
only match actual pointer fields or pointer-sized non-array scalars,
allowing unmatched fields to fall through to subsequent type checks
- Fixed btf_struct_scnprintf() to only dump struct data for augmented
input parameters, preventing un-augmented output pointers from dumping
empty "{}" instead of falling back to hexadecimal pointer addresses.
Also ensured btf_dump is properly freed on error exits
- Updated test_ksym_btf() to trace csd:csd_function_entry with --force-btf
instead of call_site, directly verifying function pointer symbolisation
- Link to v3: https://lore.kernel.org/lkml/20260820211100.649142-1-atomlin@atomlin.com/
Changes since v2:
- Populated syscall_arg_fmts__by_name[] with common function pointer,
callback, handler, and callsite field names ("action", "call_site",
"callback", "caller", "callsite", "cb", "fn", "func", "function",
"handler", "location")
- Checked syscall_arg_fmt__find_by_name() prior to generic pointer
fallbacks in syscall_arg_fmt__init_array(), and dropped the inline
64-bit size check to ensure 32-bit and cross-platform compatibility
- Removed legacy trace__field_is_ip() in trace__fprintf_tp_fields() to
allow "call_site" and "caller_ip" to be beautified with SCA_KSYM rather
than being forced to raw hexadecimal
- Simplified btf_is_func_ptr() to remove the internal pointer requirement,
correctly identifying bare prototype typedefs as function pointers
- Prevented pointer enums (e.g., "enum foo *") from being misclassified
and formatted as scalar enum values in
syscall_arg_fmt__cache_btf_type(), trace__btf_scnprintf(), and
syscall_arg__strtoul_btf_type()
- Added negative caching (btf_type_cached) to struct syscall_arg_fmt to
avoid repeated BTF searches on every event for unresolvable or primitive
types
- Widened btf_enum_scnprintf() to accept unsigned long val, eliminating
narrowing truncation of 64-bit values to 32-bit signed integers
- Fixed trace_ksym_beautifier.sh:
- Quoted "$0" to support directory paths containing spaces
- Captured output in memory to eliminate temporary file leaks on early
skip
- Hardened regex validation to require valid C symbol identifiers and
reject raw hexadecimal addresses
- Used '%s' format specifiers in printf to prevent format string
injection
- Link to v2: https://lore.kernel.org/lkml/20260816205921.576365-1-atomlin@atomlin.com/
Changes since v1:
- Fixed reference leak of struct map in syscall_arg__scnprintf_ksym() by
calling map__put() prior to returning Removed unreachable and erroneous
entries ("action", "callsite", "call_site", "fn", "function", "work")
from syscall_arg_fmts__by_name[]
- Restricted name-based SCA_KSYM auto-assignment in
syscall_arg_fmt__init_array() to pointer or 64-bit address fields,
preventing misclassification of non-pointer integer fields
- Updated btf_is_func_ptr() to fully unwrap typedefs and type modifiers
below pointer targets
- Fixed BTF type name matching in syscall_arg_fmt__cache_btf_type() to
handle leading modifiers and strip trailing pointer asterisks before
lookup
- Synchronised arg->val with val in trace__btf_scnprintf() and widened val
to unsigned long, fixing erroneous "NULL" output
- Added shell test script,
tools/perf/tests/shell/trace_ksym_beautifier.sh, to verify kernel symbol
beautification for both default kallsyms and BTF routing
- Link to v1: https://lore.kernel.org/lkml/20260815233651.527936-1-atomlin@atomlin.com/
Aaron Tomlin (4):
perf trace: Introduce kernel symbol beautifier for virtual addresses
perf trace: Auto-assign kernel symbol beautifier to function pointer
fields
perf trace: Enhance BTF type formatting to symbolise kernel function
pointers
perf tests: Add shell test for kernel symbol beautifier
tools/perf/builtin-trace.c | 217 +++++++++++++-----
.../perf/tests/shell/trace_ksym_beautifier.sh | 43 ++++
tools/perf/trace/beauty/beauty.h | 3 +
3 files changed, 202 insertions(+), 61 deletions(-)
create mode 100755 tools/perf/tests/shell/trace_ksym_beautifier.sh
--
2.55.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses
2026-08-21 20:49 [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers Aaron Tomlin
@ 2026-08-21 20:49 ` Aaron Tomlin
2026-08-21 20:56 ` sashiko-bot
2026-08-21 20:49 ` [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields Aaron Tomlin
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-21 20:49 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung
Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
james.clark, howardchu95, atomlin, neelx, chjohnst, sean, steve,
rishil1999, linux-perf-users, linux-kernel
Currently, when 'perf trace' formats tracepoint payloads or system call
arguments containing raw kernel virtual addresses (e.g., a work item
function pointer work_func_t in workqueue:workqueue_execute_start),
it prints them as raw hexadecimal values (e.g., 0xffffffff81234567).
This impairs readability when tracing kernel execution flows.
Introduce a dedicated kernel symbol beautifier,
syscall_arg__scnprintf_ksym (i.e., SCA_KSYM), to resolve kernel
virtual addresses to human-readable symbol names and offsets
(e.g., "flush_to_ldisc").
The beautifier looks up the virtual address in the machine kernel maps via
machine__find_kernel_symbol(). If a valid kernel symbol is found, the
symbol name and offset are printed without requiring --libtraceevent; if
the address is zero, "NULL" is rendered; otherwise, it gracefully falls
back to hexadecimal formatting.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
tools/perf/builtin-trace.c | 29 +++++++++++++++++++++++++++++
tools/perf/trace/beauty/beauty.h | 3 +++
2 files changed, 32 insertions(+)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c3c7f1f85c53..003048946503 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -750,6 +750,35 @@ size_t syscall_arg__scnprintf_ptr(char *bf, size_t size, struct syscall_arg *arg
return syscall_arg__scnprintf_hex(bf, size, arg);
}
+size_t syscall_arg__scnprintf_ksym(char *bf, size_t size, struct syscall_arg *arg)
+{
+ if (arg->val == 0)
+ return scnprintf(bf, size, "NULL");
+
+ if (arg->trace && arg->trace->host) {
+ struct map *map = NULL;
+ struct symbol *sym = machine__find_kernel_symbol(arg->trace->host,
+ arg->val, &map);
+
+ if (sym) {
+ u64 start = map__unmap_ip(map, sym->start);
+ u64 offset = arg->val - start;
+ size_t printed;
+
+ if (offset == 0)
+ printed = scnprintf(bf, size, "%s", sym->name);
+ else
+ printed = scnprintf(bf, size, "%s+0x%" PRIx64,
+ sym->name, offset);
+ map__put(map);
+ return printed;
+ }
+ map__put(map);
+ }
+
+ return syscall_arg__scnprintf_hex(bf, size, arg);
+}
+
size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
{
return scnprintf(bf, size, "%d", arg->val);
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
index 58a3206481ae..0f4801c61a5b 100644
--- a/tools/perf/trace/beauty/beauty.h
+++ b/tools/perf/trace/beauty/beauty.h
@@ -160,6 +160,9 @@ size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg
size_t syscall_arg__scnprintf_ptr(char *bf, size_t size, struct syscall_arg *arg);
#define SCA_PTR syscall_arg__scnprintf_ptr
+size_t syscall_arg__scnprintf_ksym(char *bf, size_t size, struct syscall_arg *arg);
+#define SCA_KSYM syscall_arg__scnprintf_ksym
+
size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg);
#define SCA_INT syscall_arg__scnprintf_int
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields
2026-08-21 20:49 [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses Aaron Tomlin
@ 2026-08-21 20:49 ` Aaron Tomlin
2026-08-21 20:58 ` sashiko-bot
2026-08-21 20:49 ` [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier Aaron Tomlin
3 siblings, 1 reply; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-21 20:49 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung
Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
james.clark, howardchu95, atomlin, neelx, chjohnst, sean, steve,
rishil1999, linux-perf-users, linux-kernel
Tracepoint fields that convey kernel function pointers, callbacks, and
call sites, such as "function", "func", "fn", "callback", "action",
"handler", "caller", "caller_ip", "location", "callsite", and
"call_site" are currently formatted as generic hexadecimal pointers by
default.
Enhance syscall_arg_fmt__init_array() to automatically detect function
pointer fields by type signature (e.g., typedefs ending with "_func_t"
or "_fn", or C function pointer types containing "(*)") and assign
SCA_KSYM as their default beautifier.
Additionally, register common function pointer and callback field names
within the sorted syscall_arg_fmts__by_name lookup table. To prevent
misclassifying dynamic string arrays or non-pointer integers sharing
generic names, guard SCA_KSYM assignment to pointer fields and
pointer-sized non-array scalars. This ensures tracepoint arguments such
as workqueue:workqueue_execute_start.function, csd:csd_function.func,
and xfs:xfs_bunmapi.caller_ip are symbolised automatically without
requiring explicit per-event configuration. For example:
❯ sudo tools/perf/perf trace --event workqueue:workqueue_execute_end --max-events 2 --show-cpu
0.000 [000] kworker/u32:15/236682 workqueue:workqueue_execute_end(work: 0xffffffffab2f1420, function: toggle_allocation_gate)
0.132 [000] kworker/u32:15/236682 workqueue:workqueue_execute_end(work: 0xffff8ac2c1adc010, function: flush_to_ldisc)
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
tools/perf/builtin-trace.c | 88 ++++++++++++++++++++++----------------
1 file changed, 50 insertions(+), 38 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 003048946503..0a12d7b37d8d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -2096,6 +2096,18 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
}
static const struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
+ { .name = "action", .scnprintf = SCA_KSYM, },
+ { .name = "call_site", .scnprintf = SCA_KSYM, },
+ { .name = "callback", .scnprintf = SCA_KSYM, },
+ { .name = "caller", .scnprintf = SCA_KSYM, },
+ { .name = "caller_ip", .scnprintf = SCA_KSYM, },
+ { .name = "callsite", .scnprintf = SCA_KSYM, },
+ { .name = "cb", .scnprintf = SCA_KSYM, },
+ { .name = "fn", .scnprintf = SCA_KSYM, },
+ { .name = "func", .scnprintf = SCA_KSYM, },
+ { .name = "function", .scnprintf = SCA_KSYM, },
+ { .name = "handler", .scnprintf = SCA_KSYM, },
+ { .name = "location", .scnprintf = SCA_KSYM, },
{ .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, },
{ .name = "vector", .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
};
@@ -2198,38 +2210,47 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
strstr(field->name, "path") != NULL)) {
arg->scnprintf = SCA_FILENAME;
- } else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr") ||
- field_has_hex_fmt(field, len))
- arg->scnprintf = SCA_PTR;
- else if (strcmp(field->type, "pid_t") == 0)
- arg->scnprintf = SCA_PID;
- else if (strcmp(field->type, "umode_t") == 0)
- arg->scnprintf = SCA_MODE_T;
- else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
- arg->scnprintf = SCA_CHAR_ARRAY;
- arg->nr_entries = field->arraylen;
- } else if ((strcmp(field->type, "int") == 0 ||
- strcmp(field->type, "unsigned int") == 0 ||
- strcmp(field->type, "long") == 0) &&
- len >= 2 && strcmp(field->name + len - 2, "fd") == 0) {
- /*
- * /sys/kernel/tracing/events/syscalls/sys_enter*
- * grep -E 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
- * 65 int
- * 23 unsigned int
- * 7 unsigned long
- */
- arg->scnprintf = SCA_FD;
- } else if (strstr(field->type, "enum") && use_btf != NULL) {
- *use_btf = true;
- arg->strtoul = STUL_BTF_TYPE;
+ } else if (field->type && (strstr(field->type, "(*)") != NULL ||
+ strstr(field->type, "_func_t") != NULL ||
+ strstr(field->type, "_fn") != NULL)) {
+ arg->scnprintf = SCA_KSYM;
} else {
const struct syscall_arg_fmt *fmt =
syscall_arg_fmt__find_by_name(field->name);
if (fmt) {
- arg->scnprintf = fmt->scnprintf;
- arg->strtoul = fmt->strtoul;
+ if (fmt->scnprintf == SCA_KSYM) {
+ if ((field->flags & TEP_FIELD_IS_POINTER) ||
+ (field->size == sizeof(void *) && !(field->flags & TEP_FIELD_IS_ARRAY))) {
+ arg->scnprintf = fmt->scnprintf;
+ arg->strtoul = fmt->strtoul;
+ }
+ } else {
+ arg->scnprintf = fmt->scnprintf;
+ arg->strtoul = fmt->strtoul;
+ }
+ }
+
+ if (arg->scnprintf == NULL) {
+ if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr") ||
+ field_has_hex_fmt(field, len)) {
+ arg->scnprintf = SCA_PTR;
+ } else if (strcmp(field->type, "pid_t") == 0) {
+ arg->scnprintf = SCA_PID;
+ } else if (strcmp(field->type, "umode_t") == 0) {
+ arg->scnprintf = SCA_MODE_T;
+ } else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
+ arg->scnprintf = SCA_CHAR_ARRAY;
+ arg->nr_entries = field->arraylen;
+ } else if ((strcmp(field->type, "int") == 0 ||
+ strcmp(field->type, "unsigned int") == 0 ||
+ strcmp(field->type, "long") == 0) &&
+ len >= 2 && strcmp(field->name + len - 2, "fd") == 0) {
+ arg->scnprintf = SCA_FD;
+ } else if (strstr(field->type, "enum") && use_btf != NULL) {
+ *use_btf = true;
+ arg->strtoul = STUL_BTF_TYPE;
+ }
}
}
}
@@ -3297,12 +3318,6 @@ static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx)
return b_val;
}
-static bool trace__field_is_ip(const char *name)
-{
- return !strcmp(name, "__probe_ip") ||
- !strcmp(name, "caller_ip") ||
- !strcmp(name, "call_site");
-}
static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample,
struct thread *thread, void *augmented_args, int augmented_args_size)
@@ -3404,14 +3419,11 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *
* Suppress it by default to avoid cluttering the output.
* If verbose mode is enabled, ensure it is formatted as a
* hexadecimal memory address rather than a signed integer.
- *
- * caller_ip and call_site are also expected to be instruction
- * pointers and should always be represented in hexadecimal.
*/
is_probe_ip = evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip");
- if (is_probe_ip || trace__field_is_ip(field->name)) {
- if (is_probe_ip && !verbose)
+ if (is_probe_ip) {
+ if (!verbose)
continue;
printed += scnprintf(bf + printed, size - printed,
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers
2026-08-21 20:49 [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields Aaron Tomlin
@ 2026-08-21 20:49 ` Aaron Tomlin
2026-08-21 21:07 ` sashiko-bot
2026-08-21 20:49 ` [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier Aaron Tomlin
3 siblings, 1 reply; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-21 20:49 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung
Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
james.clark, howardchu95, atomlin, neelx, chjohnst, sean, steve,
rishil1999, linux-perf-users, linux-kernel
When BTF (BPF Type Format) metadata is loaded from vmlinux, 'perf trace'
can inspect the precise C types of tracepoint and system call parameters.
However, function pointer arguments are currently not recognised during
BTF pretty-printing and default to hexadecimal output.
Introduce btf_is_func_ptr() to inspect BTF type hierarchies
(i.e., traversing pointers, typedefs, and type modifiers) to determine
whether a parameter resolves to a function prototype
(BTF_KIND_FUNC_PROTO).
Generalise BTF type caching via syscall_arg_fmt__cache_btf_type() to
handle structs, unions, enums, and function pointers alike. When a field
is identified as a kernel function pointer, trace__btf_scnprintf()
routes its value to syscall_arg__scnprintf_ksym(), enabling automatic
zero-config symbolisation of kernel function pointers whenever BTF is
available.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
tools/perf/builtin-trace.c | 100 ++++++++++++++++++++++++++++---------
1 file changed, 77 insertions(+), 23 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0a12d7b37d8d..9f9494f9d9d8 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -122,6 +122,7 @@ struct syscall_arg_fmt {
#ifdef HAVE_LIBBPF_SUPPORT
const struct btf_type *type;
int type_id; /* used in btf_dump */
+ bool btf_type_cached;
#endif
};
@@ -979,21 +980,61 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
#ifdef HAVE_LIBBPF_SUPPORT
-static void syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
+static bool btf_is_func_ptr(const struct btf *btf, const struct btf_type *type)
{
+ while (type) {
+ if (btf_is_ptr(type) || btf_is_typedef(type) || btf_is_mod(type))
+ type = btf__type_by_id(btf, type->type);
+ else
+ break;
+ }
+ return type && btf_is_func_proto(type);
+}
+
+static void syscall_arg_fmt__cache_btf_type(struct syscall_arg_fmt *arg_fmt,
+ struct btf *btf, const char *type)
+{
+ char name[128];
+ const char *pos;
+ size_t len = 0;
int id;
- type = strstr(type, "enum ");
+ arg_fmt->btf_type_cached = true;
+
if (type == NULL)
return;
- type += 5; // skip "enum " to get the enumeration name
+ /* Pointers to enums are memory addresses, not scalar enums */
+ if (strstr(type, "enum ") && strchr(type, '*'))
+ return;
+
+ if ((pos = strstr(type, "enum ")) != NULL)
+ pos += 5;
+ else if ((pos = strstr(type, "struct ")) != NULL)
+ pos += 7;
+ else if ((pos = strstr(type, "union ")) != NULL)
+ pos += 6;
+ else
+ pos = type;
+
+ while (isspace(*pos))
+ pos++;
+
+ while ((isalnum(pos[len]) || pos[len] == '_') && len < sizeof(name) - 1) {
+ name[len] = pos[len];
+ len++;
+ }
+ name[len] = '\0';
- id = btf__find_by_name(btf, type);
+ if (len == 0)
+ return;
+
+ id = btf__find_by_name(btf, name);
if (id < 0)
return;
arg_fmt->type = btf__type_by_id(btf, id);
+ arg_fmt->type_id = id;
}
static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
@@ -1027,10 +1068,8 @@ static bool syscall_arg__strtoul_btf_type(char *bf, size_t size, struct syscall_
if (btf == NULL)
return false;
- if (arg->fmt->type == NULL) {
- // See if this is an enum
- syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type);
- }
+ if (!arg->fmt->btf_type_cached)
+ syscall_arg_fmt__cache_btf_type(arg->fmt, btf, type);
// Now let's see if we have a BTF type resolved
bt = arg->fmt->type;
@@ -1038,19 +1077,22 @@ static bool syscall_arg__strtoul_btf_type(char *bf, size_t size, struct syscall_
return false;
// If it is an enum:
- if (btf_is_enum(arg->fmt->type))
+ if (btf_is_enum(arg->fmt->type)) {
+ if (type && strchr(type, '*'))
+ return false;
return syscall_arg__strtoul_btf_enum(bf, size, arg, val);
+ }
return false;
}
-static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
+static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, unsigned long val)
{
struct btf_enum *be = btf_enum(type);
const unsigned int nr_entries = btf_vlen(type);
for (unsigned int i = 0; i < nr_entries; ++i, ++be) {
- if (be->val == val) {
+ if ((unsigned long)(__u32)be->val == val || (unsigned long)be->val == val) {
return scnprintf(bf, size, "%s",
btf__name_by_offset(btf, be->name_off));
}
@@ -1077,14 +1119,19 @@ static size_t btf_struct_scnprintf(const struct btf_type *type, struct btf *btf,
.bf = bf,
.size = size,
};
- struct augmented_arg *augmented_arg = arg->augmented.args;
+ struct augmented_arg *augmented_arg;
int type_id = arg->fmt->type_id, consumed;
struct btf_dump *btf_dump;
LIBBPF_OPTS(btf_dump_opts, dump_opts);
LIBBPF_OPTS(btf_dump_type_data_opts, dump_data_opts);
- if (arg == NULL || arg->augmented.args == NULL)
+ if (arg == NULL || arg->augmented.args == NULL || arg->augmented.size <= 0 ||
+ arg->fmt == NULL || !arg->fmt->from_user)
+ return 0;
+
+ augmented_arg = arg->augmented.args;
+ if (augmented_arg->size <= 0)
return 0;
dump_data_opts.compact = true;
@@ -1095,8 +1142,10 @@ static size_t btf_struct_scnprintf(const struct btf_type *type, struct btf *btf,
return 0;
/* pretty print the struct data here */
- if (btf_dump__dump_type_data(btf_dump, type_id, arg->augmented.args->value, type->size, &dump_data_opts) == 0)
+ if (btf_dump__dump_type_data(btf_dump, type_id, augmented_arg->value, type->size, &dump_data_opts) == 0) {
+ btf_dump__free(btf_dump);
return 0;
+ }
consumed = sizeof(*augmented_arg) + augmented_arg->size;
arg->augmented.args = ((void *)arg->augmented.args) + consumed;
@@ -1108,33 +1157,37 @@ static size_t btf_struct_scnprintf(const struct btf_type *type, struct btf *btf,
}
static size_t trace__btf_scnprintf(struct trace *trace, struct syscall_arg *arg, char *bf,
- size_t size, int val, char *type)
+ size_t size, unsigned long val, char *type)
{
struct syscall_arg_fmt *arg_fmt = arg->fmt;
if (trace->btf == NULL)
return 0;
- if (arg_fmt->type == NULL) {
- // Check if this is an enum and if we have the BTF type for it.
- syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type);
- }
+ if (!arg_fmt->btf_type_cached)
+ syscall_arg_fmt__cache_btf_type(arg_fmt, trace->btf, type);
// Did we manage to find a BTF type for the syscall/tracepoint argument?
if (arg_fmt->type == NULL)
return 0;
- if (btf_is_enum(arg_fmt->type))
+ if (btf_is_enum(arg_fmt->type)) {
+ if (type && strchr(type, '*'))
+ return 0;
return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
- else if (btf_is_struct(arg_fmt->type) || btf_is_union(arg_fmt->type))
+ } else if (btf_is_struct(arg_fmt->type) || btf_is_union(arg_fmt->type))
return btf_struct_scnprintf(arg_fmt->type, trace->btf, bf, size, arg);
+ else if (btf_is_func_ptr(trace->btf, arg_fmt->type)) {
+ arg->val = val;
+ return syscall_arg__scnprintf_ksym(bf, size, arg);
+ }
return 0;
}
#else // HAVE_LIBBPF_SUPPORT
static size_t trace__btf_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg *arg __maybe_unused,
- char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
+ char *bf __maybe_unused, size_t size __maybe_unused, unsigned long val __maybe_unused,
char *type __maybe_unused)
{
return 0;
@@ -2579,7 +2632,8 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
default_scnprintf = sc->arg_fmt[arg.idx].scnprintf;
- if (trace->force_btf || default_scnprintf == NULL || default_scnprintf == SCA_PTR) {
+ if (trace->force_btf || default_scnprintf == NULL ||
+ default_scnprintf == SCA_PTR || default_scnprintf == SCA_KSYM) {
btf_printed = trace__btf_scnprintf(trace, &arg, bf + printed,
size - printed, val, field->type);
if (btf_printed) {
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier
2026-08-21 20:49 [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers Aaron Tomlin
` (2 preceding siblings ...)
2026-08-21 20:49 ` [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers Aaron Tomlin
@ 2026-08-21 20:49 ` Aaron Tomlin
2026-08-21 21:01 ` sashiko-bot
3 siblings, 1 reply; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-21 20:49 UTC (permalink / raw)
To: peterz, mingo, acme, namhyung
Cc: mark.rutland, alexander.shishkin, jolsa, irogers, adrian.hunter,
james.clark, howardchu95, atomlin, neelx, chjohnst, sean, steve,
rishil1999, linux-perf-users, linux-kernel
Add a dedicated shell test script, trace_ksym_beautifier.sh, to verify
that 'perf trace' properly symbolises kernel virtual addresses and
function pointers using both the default kallsyms beautifier (SCA_KSYM)
and BTF type routing i.e., --force-btf.
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
.../perf/tests/shell/trace_ksym_beautifier.sh | 43 +++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100755 tools/perf/tests/shell/trace_ksym_beautifier.sh
diff --git a/tools/perf/tests/shell/trace_ksym_beautifier.sh b/tools/perf/tests/shell/trace_ksym_beautifier.sh
new file mode 100755
index 000000000000..c030b03e2b66
--- /dev/null
+++ b/tools/perf/tests/shell/trace_ksym_beautifier.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# perf trace kernel symbol beautifier tests
+# SPDX-License-Identifier: GPL-2.0
+
+err=0
+
+# shellcheck source=lib/probe.sh
+. "$(dirname "$0")"/lib/probe.sh
+skip_if_no_perf_trace || exit 2
+[ "$(id -u)" = 0 ] || exit 2
+
+test_ksym_kallsyms() {
+ echo "Testing perf trace kernel symbol beautifier (default kallsyms)"
+ output="$(perf trace -e kmem:kmalloc --max-events=1 2>&1)"
+ if ! echo "$output" | grep -q -E "call_site: [a-zA-Z_][a-zA-Z0-9_]*" || echo "$output" | grep -q -E "call_site: 0x[0-9a-fA-F]+"
+ then
+ printf "Default kallsyms function symbolization failed, output:\n%s\n" "$output"
+ err=1
+ fi
+}
+
+test_ksym_btf() {
+ echo "Testing perf trace kernel symbol beautifier (BTF)"
+ if [ ! -f /sys/kernel/btf/vmlinux ]; then
+ echo "Skipping BTF test due to missing vmlinux BTF"
+ return
+ fi
+
+ output="$(perf trace -e csd:csd_function_entry --force-btf --max-events=1 2>&1)"
+ if ! echo "$output" | grep -q -E "func: [a-zA-Z_][a-zA-Z0-9_]*" || echo "$output" | grep -q -E "func: 0x[0-9a-fA-F]+"
+ then
+ printf "BTF function symbolization failed, output:\n%s\n" "$output"
+ err=1
+ fi
+}
+
+test_ksym_kallsyms
+
+if [ $err = 0 ]; then
+ test_ksym_btf
+fi
+
+exit $err
--
2.55.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses
2026-08-21 20:49 ` [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses Aaron Tomlin
@ 2026-08-21 20:56 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-21 20:56 UTC (permalink / raw)
To: Aaron Tomlin; +Cc: linux-perf-users
> Currently, when 'perf trace' formats tracepoint payloads or system call
> arguments containing raw kernel virtual addresses (e.g., a work item
> function pointer work_func_t in workqueue:workqueue_execute_start),
> it prints them as raw hexadecimal values (e.g., 0xffffffff81234567).
> This impairs readability when tracing kernel execution flows.
>
> Introduce a dedicated kernel symbol beautifier,
> syscall_arg__scnprintf_ksym (i.e., SCA_KSYM), to resolve kernel
> virtual addresses to human-readable symbol names and offsets
> (e.g., "flush_to_ldisc").
>
> The beautifier looks up the virtual address in the machine kernel maps via
> machine__find_kernel_symbol(). If a valid kernel symbol is found, the
> symbol name and offset are printed without requiring --libtraceevent; if
> the address is zero, "NULL" is rendered; otherwise, it gracefully falls
> back to hexadecimal formatting.
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260821204930.679027-1-atomlin@atomlin.com?part=1
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields
2026-08-21 20:49 ` [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields Aaron Tomlin
@ 2026-08-21 20:58 ` sashiko-bot
2026-08-22 20:17 ` Aaron Tomlin
0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-08-21 20:58 UTC (permalink / raw)
To: Aaron Tomlin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Using the host's `sizeof(void *)` to validate tracepoint field sizes breaks cross-architecture analysis.
- [Medium] The type-based heuristic for function pointers assigns `SCA_KSYM` without array safety guards, which can lead to misinterpretation of data and leaking of perf's internal heap addresses.
--
--- Patch [2]: [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields ---
commit 5464cb16d3d8a0ba80bef02f5451353ddbb24637
Author: Aaron Tomlin <atomlin@atomlin.com>
perf trace: Auto-assign kernel symbol beautifier to function pointer fields
This commit enhances perf trace to automatically assign the SCA_KSYM
beautifier to tracepoint fields conveying function pointers. It uses
heuristics based on both type signatures and field names to detect these
pointers.
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index 0030489465032..0a12d7b37d8d4 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
[ ... ]
> @@ -2198,38 +2210,47 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
> strstr(field->name, "path") != NULL)) {
> arg->scnprintf = SCA_FILENAME;
[ ... ]
> + } else if (field->type && (strstr(field->type, "(*)") != NULL ||
> + strstr(field->type, "_func_t") != NULL ||
> + strstr(field->type, "_fn") != NULL)) {
> + arg->scnprintf = SCA_KSYM;
[Severity: Medium]
Will this unconditionally assign SCA_KSYM for matching types without checking
if the field is an array?
If this encounters a tracepoint with an array field whose type matches
the heuristic (like an array of function pointer typedefs),
trace__fprintf_tp_fields() will assign a pointer to the tool's raw heap buffer
to the value.
Since SCA_KSYM is applied without an array guard, it might attempt to resolve
this user-space heap pointer as a kernel symbol, leaking the tool's memory
address in hex instead of printing the trace data.
Could we add a check for !(field->flags & TEP_FIELD_IS_ARRAY) here as well?
> } else {
> const struct syscall_arg_fmt *fmt =
> syscall_arg_fmt__find_by_name(field->name);
>
> if (fmt) {
> - arg->scnprintf = fmt->scnprintf;
> - arg->strtoul = fmt->strtoul;
> + if (fmt->scnprintf == SCA_KSYM) {
> + if ((field->flags & TEP_FIELD_IS_POINTER) ||
> + (field->size == sizeof(void *) && !(field->flags & TEP_FIELD_IS_ARRAY))) {
[Severity: Medium]
Does using sizeof(void *) here break cross-architecture analysis?
When using perf trace on a 64-bit host to process a 32-bit perf.data file for
events that use unsigned long for instruction pointer fields (like caller_ip in
XFS tracepoints), field->size in the trace will be 4.
This fails the sizeof(void *) check, which evaluates to 8 on the 64-bit host,
preventing the expected symbol resolution.
Can we rely on the trace data's pointer size instead of the host's, or use a
different heuristic?
> + arg->scnprintf = fmt->scnprintf;
> + arg->strtoul = fmt->strtoul;
> + }
> + } else {
> + arg->scnprintf = fmt->scnprintf;
> + arg->strtoul = fmt->strtoul;
> + }
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260821204930.679027-1-atomlin@atomlin.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier
2026-08-21 20:49 ` [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier Aaron Tomlin
@ 2026-08-21 21:01 ` sashiko-bot
2026-08-22 20:47 ` Aaron Tomlin
0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-08-21 21:01 UTC (permalink / raw)
To: Aaron Tomlin; +Cc: linux-perf-users
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The test script erroneously fails on uniprocessor (UP) kernels due to a missing SMP-only tracepoint.
- [Medium] The test script can hang the test suite indefinitely on quiescent systems due to unbounded system-wide waits.
--
--- Patch [4]: [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier ---
commit c9c4a1b0dcd918dc4702b41032200c74d4363a15
Author: Aaron Tomlin <atomlin@atomlin.com>
perf tests: Add shell test for kernel symbol beautifier
This commit adds a dedicated shell test script to verify that perf trace
properly symbolises kernel virtual addresses and function pointers using
both the default kallsyms beautifier and BTF type routing.
> diff --git a/tools/perf/tests/shell/trace_ksym_beautifier.sh b/tools/perf/tests/shell/trace_ksym_beautifier.sh
> new file mode 100755
> index 0000000000000..c030b03e2b662
> --- /dev/null
> +++ b/tools/perf/tests/shell/trace_ksym_beautifier.sh
> @@ -0,0 +1,43 @@
[ ... ]
> +test_ksym_kallsyms() {
> + echo "Testing perf trace kernel symbol beautifier (default kallsyms)"
> + output="$(perf trace -e kmem:kmalloc --max-events=1 2>&1)"
[Severity: Medium]
Could this wait indefinitely on a completely quiescent system?
Because it waits system-wide for the kmem:kmalloc event without a timeout or
a deterministic workload to trigger it, it might stall the test suite if the
event takes too long to fire.
> + if ! echo "$output" | grep -q -E "call_site: [a-zA-Z_][a-zA-Z0-9_]*" || echo "$output" | grep -q -E "call_site: 0x[0-9a-fA-F]+"
> + then
> + printf "Default kallsyms function symbolization failed, output:\n%s\n" "$output"
> + err=1
> + fi
> +}
> +
> +test_ksym_btf() {
> + echo "Testing perf trace kernel symbol beautifier (BTF)"
> + if [ ! -f /sys/kernel/btf/vmlinux ]; then
> + echo "Skipping BTF test due to missing vmlinux BTF"
> + return
> + fi
> +
> + output="$(perf trace -e csd:csd_function_entry --force-btf --max-events=1 2>&1)"
[Severity: Medium]
Will this test fail erroneously on uniprocessor (UP) kernels?
The csd:csd_function_entry tracepoint is defined in kernel/smp.c, which is
only available when CONFIG_SMP is enabled. On a UP kernel, perf trace will
fail with an unknown tracepoint error, which the script would parse as a
symbolization failure.
[Severity: Medium]
Additionally, can this cause an indefinite hang on idle SMP systems?
The csd:csd_function_entry event relies on SMP cross-calls (IPIs). On an idle
or isolated test VM, this event might not occur organically for extended
periods, potentially causing perf trace to block forever without a timeout or
a triggering workload.
> + if ! echo "$output" | grep -q -E "func: [a-zA-Z_][a-zA-Z0-9_]*" || echo "$output" | grep -q -E "func: 0x[0-9a-fA-F]+"
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260821204930.679027-1-atomlin@atomlin.com?part=4
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers
2026-08-21 20:49 ` [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers Aaron Tomlin
@ 2026-08-21 21:07 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-21 21:07 UTC (permalink / raw)
To: Aaron Tomlin; +Cc: linux-perf-users
> When BTF (BPF Type Format) metadata is loaded from vmlinux, 'perf trace'
> can inspect the precise C types of tracepoint and system call parameters.
> However, function pointer arguments are currently not recognised during
> BTF pretty-printing and default to hexadecimal output.
>
> Introduce btf_is_func_ptr() to inspect BTF type hierarchies
> (i.e., traversing pointers, typedefs, and type modifiers) to determine
> whether a parameter resolves to a function prototype
> (BTF_KIND_FUNC_PROTO).
>
> Generalise BTF type caching via syscall_arg_fmt__cache_btf_type() to
> handle structs, unions, enums, and function pointers alike. When a field
> is identified as a kernel function pointer, trace__btf_scnprintf()
> routes its value to syscall_arg__scnprintf_ksym(), enabling automatic
> zero-config symbolisation of kernel function pointers whenever BTF is
> available.
>
> Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260821204930.679027-1-atomlin@atomlin.com?part=3
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields
2026-08-21 20:58 ` sashiko-bot
@ 2026-08-22 20:17 ` Aaron Tomlin
0 siblings, 0 replies; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-22 20:17 UTC (permalink / raw)
To: sashiko-reviews, namhyung, irogers, acme; +Cc: linux-perf-users
On Fri, Aug 21, 2026 at 08:58:14PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> perf trace: Auto-assign kernel symbol beautifier to function pointer fields
>
> This commit enhances perf trace to automatically assign the SCA_KSYM
> beautifier to tracepoint fields conveying function pointers. It uses
> heuristics based on both type signatures and field names to detect these
> pointers.
>
> > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > index 0030489465032..0a12d7b37d8d4 100644
> > --- a/tools/perf/builtin-trace.c
> > +++ b/tools/perf/builtin-trace.c
> [ ... ]
> > @@ -2198,38 +2210,47 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> > ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
> > strstr(field->name, "path") != NULL)) {
> > arg->scnprintf = SCA_FILENAME;
> [ ... ]
> > + } else if (field->type && (strstr(field->type, "(*)") != NULL ||
> > + strstr(field->type, "_func_t") != NULL ||
> > + strstr(field->type, "_fn") != NULL)) {
> > + arg->scnprintf = SCA_KSYM;
>
> [Severity: Medium]
> Will this unconditionally assign SCA_KSYM for matching types without checking
> if the field is an array?
>
> If this encounters a tracepoint with an array field whose type matches
> the heuristic (like an array of function pointer typedefs),
> trace__fprintf_tp_fields() will assign a pointer to the tool's raw heap buffer
> to the value.
>
> Since SCA_KSYM is applied without an array guard, it might attempt to resolve
> this user-space heap pointer as a kernel symbol, leaking the tool's memory
> address in hex instead of printing the trace data.
>
> Could we add a check for !(field->flags & TEP_FIELD_IS_ARRAY) here as well?
At the time of writing, a search across all tracepoint definitions in
include/trace/events/ shows that existing tracepoints only use __array()
for byte buffers, UUIDs, filesystem block arrays (e.g., nid_t nid[3]), or
CPU masks. However, this could change.
The type-based heuristic in the 'else if' branch needs this check.
For SCA_KSYM, syscall_arg__scnprintf_ksym() expects arg->val to be an
actual kernel virtual address and passes it to
machine__find_kernel_symbol().
>
> > } else {
> > const struct syscall_arg_fmt *fmt =
> > syscall_arg_fmt__find_by_name(field->name);
> >
> > if (fmt) {
> > - arg->scnprintf = fmt->scnprintf;
> > - arg->strtoul = fmt->strtoul;
> > + if (fmt->scnprintf == SCA_KSYM) {
> > + if ((field->flags & TEP_FIELD_IS_POINTER) ||
> > + (field->size == sizeof(void *) && !(field->flags & TEP_FIELD_IS_ARRAY))) {
>
> [Severity: Medium]
> Does using sizeof(void *) here break cross-architecture analysis?
>
> When using perf trace on a 64-bit host to process a 32-bit perf.data file for
> events that use unsigned long for instruction pointer fields (like caller_ip in
> XFS tracepoints), field->size in the trace will be 4.
>
> This fails the sizeof(void *) check, which evaluates to 8 on the 64-bit host,
> preventing the expected symbol resolution.
>
> Can we rely on the trace data's pointer size instead of the host's, or use a
> different heuristic?
>
> > + arg->scnprintf = fmt->scnprintf;
> > + arg->strtoul = fmt->strtoul;
> > + }
> > + } else {
> > + arg->scnprintf = fmt->scnprintf;
> > + arg->strtoul = fmt->strtoul;
> > + }
> > + }
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260821204930.679027-1-atomlin@atomlin.com?part=2
Indeed. Perhaps we could use tep_get_long_size(), which retrieves the
target's recorded long size; which matches field->size. Therefore,
caller_ip is correctly recognised as an instruction pointer scalar and
symbolised with SCA_KSYM.
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier
2026-08-21 21:01 ` sashiko-bot
@ 2026-08-22 20:47 ` Aaron Tomlin
0 siblings, 0 replies; 11+ messages in thread
From: Aaron Tomlin @ 2026-08-22 20:47 UTC (permalink / raw)
To: sashiko-reviews, namhyung, acme, irogers; +Cc: linux-perf-users
On Fri, Aug 21, 2026 at 09:01:55PM +0000, sashiko-bot@kernel.org wrote:
> --- Patch [4]: [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier ---
> commit c9c4a1b0dcd918dc4702b41032200c74d4363a15
> Author: Aaron Tomlin <atomlin@atomlin.com>
>
> perf tests: Add shell test for kernel symbol beautifier
>
> This commit adds a dedicated shell test script to verify that perf trace
> properly symbolises kernel virtual addresses and function pointers using
> both the default kallsyms beautifier and BTF type routing.
>
> > diff --git a/tools/perf/tests/shell/trace_ksym_beautifier.sh b/tools/perf/tests/shell/trace_ksym_beautifier.sh
> > new file mode 100755
> > index 0000000000000..c030b03e2b662
> > --- /dev/null
> > +++ b/tools/perf/tests/shell/trace_ksym_beautifier.sh
> > @@ -0,0 +1,43 @@
> [ ... ]
> > +test_ksym_kallsyms() {
> > + echo "Testing perf trace kernel symbol beautifier (default kallsyms)"
> > + output="$(perf trace -e kmem:kmalloc --max-events=1 2>&1)"
>
> [Severity: Medium]
> Could this wait indefinitely on a completely quiescent system?
>
> Because it waits system-wide for the kmem:kmalloc event without a timeout
> or a deterministic workload to trigger it, it might stall the test suite
> if the event takes too long to fire.
Fair. I will propose: 'perf trace -e kmem:kmalloc --max-events=1 -- true 2>&1'.
> > +test_ksym_btf() {
> > + echo "Testing perf trace kernel symbol beautifier (BTF)"
> > + if [ ! -f /sys/kernel/btf/vmlinux ]; then
> > + echo "Skipping BTF test due to missing vmlinux BTF"
> > + return
> > + fi
> > +
> > + output="$(perf trace -e csd:csd_function_entry --force-btf --max-events=1 2>&1)"
>
> [Severity: Medium]
> Will this test fail erroneously on uniprocessor (UP) kernels?
>
> The csd:csd_function_entry tracepoint is defined in kernel/smp.c, which is
> only available when CONFIG_SMP is enabled. On a UP kernel, perf trace will
> fail with an unknown tracepoint error, which the script would parse as a
> symbolization failure.
>
> [Severity: Medium]
> Additionally, can this cause an indefinite hang on idle SMP systems?
>
> The csd:csd_function_entry event relies on SMP cross-calls (IPIs). On an
> idle or isolated test VM, this event might not occur organically for
> extended periods, potentially causing perf trace to block forever without
> a timeout or a triggering workload.
Acknowledged. Instead: 'perf trace -e timer:hrtimer_start --force-btf --max-events=1 -- sleep 0.01 2>&1'
Kind regards,
--
Aaron Tomlin
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-08-22 20:47 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 20:49 [PATCH perf-tools-next v4 0/4] perf trace: Symbolise kernel virtual addresses and function pointers Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 1/4] perf trace: Introduce kernel symbol beautifier for virtual addresses Aaron Tomlin
2026-08-21 20:56 ` sashiko-bot
2026-08-21 20:49 ` [PATCH perf-tools-next v4 2/4] perf trace: Auto-assign kernel symbol beautifier to function pointer fields Aaron Tomlin
2026-08-21 20:58 ` sashiko-bot
2026-08-22 20:17 ` Aaron Tomlin
2026-08-21 20:49 ` [PATCH perf-tools-next v4 3/4] perf trace: Enhance BTF type formatting to symbolise kernel function pointers Aaron Tomlin
2026-08-21 21:07 ` sashiko-bot
2026-08-21 20:49 ` [PATCH perf-tools-next v4 4/4] perf tests: Add shell test for kernel symbol beautifier Aaron Tomlin
2026-08-21 21:01 ` sashiko-bot
2026-08-22 20:47 ` Aaron Tomlin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox