From: Aaron Tomlin <atomlin@atomlin.com>
To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
namhyung@kernel.org
Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com,
jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com,
james.clark@linaro.org, howardchu95@gmail.com,
atomlin@atomlin.com, neelx@suse.com, sean@ashe.io,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] perf trace: Add --bitmask-list option and correct cpumask formatting
Date: Tue, 14 Jul 2026 12:29:47 -0400 [thread overview]
Message-ID: <20260714162947.214270-1-atomlin@atomlin.com> (raw)
Currently, dynamic non-array fields such as 'cpumask_t' are mishandled
in 'perf trace', causing the raw length and offset descriptors to be
interpreted and displayed as a literal integer (e.g., 'cpumask: 524320'
instead of the actual mask data).
This patch corrects the parsing of dynamic fields that do not have the
TEP_FIELD_IS_ARRAY flag set. By doing so, it ensures the pointer to the
raw bits is properly resolved within the payload.
Furthermore, it improves the display formatting for 'cpumask' types:
- By default, the cpumask is now correctly output as a zero-suppressed
hexadecimal string, resolving the aforementioned integer display
anomaly
- A new '--bitmask-list' command-line option has been introduced.
When specified, this delegates formatting to 'bitmap_scnprintf()',
enabling the cpumask to be rendered as a condensed, human-readable
list (e.g., '0,2-5,7')
Fixes: c5e006cdbd27 ("perf trace: Support tracepoint dynamic char arrays")
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
tools/perf/builtin-trace.c | 70 ++++++++++++++++++++++++++++++++------
tools/perf/util/evsel.c | 29 ++++++++++++++++
tools/perf/util/evsel.h | 3 ++
3 files changed, 92 insertions(+), 10 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index ba0f8749fc7d..cd75ac4e5169 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -226,6 +226,7 @@ struct trace {
bool force;
bool vfs_getname;
bool force_btf;
+ bool bitmask_list;
bool summary_bpf;
int trace_pgfaults;
char *perfconfig_events;
@@ -3216,7 +3217,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *
const struct tep_event *tp_format = evsel__tp_format(evsel);
struct tep_format_field *field = tp_format ? tp_format->format.fields : NULL;
struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
- size_t printed = 0, btf_printed;
+ size_t printed = 0, btf_printed, saved_printed;
unsigned long val;
u8 bit = 1;
struct syscall_arg syscall_arg = {
@@ -3238,17 +3239,65 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *
syscall_arg.len = 0;
syscall_arg.fmt = arg;
if (field->flags & TEP_FIELD_IS_ARRAY) {
- int offset = field->offset;
-
- if (field->flags & TEP_FIELD_IS_DYNAMIC) {
- offset = format_field__intval(field, sample, evsel->needs_swap);
- syscall_arg.len = offset >> 16;
- offset &= 0xffff;
- if (tep_field_is_relative(field->flags))
- offset += field->offset + field->size;
+ void *ptr = format_field__get_raw_data(field, sample,
+ evsel->needs_swap,
+ &syscall_arg.len);
+
+ if (!ptr) {
+ pr_err("Problem processing %s field, skipping...\n", field->name);
+ continue;
+ }
+ val = (uintptr_t)ptr;
+ } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) &&
+ strstr(field->type, "cpumask")) {
+ void *ptr = format_field__get_raw_data(field, sample,
+ evsel->needs_swap,
+ &syscall_arg.len);
+
+ if (!ptr) {
+ pr_err("Problem processing %s field, skipping...\n", field->name);
+ continue;
}
+ val = (uintptr_t)ptr;
- val = (uintptr_t)(sample->raw_data + offset);
+ saved_printed = printed;
+
+ printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
+ if (trace->show_arg_names)
+ printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
+
+ if (trace->bitmask_list) {
+ if (syscall_arg.len > 0) {
+ unsigned long *mask = zalloc(BITS_TO_LONGS(syscall_arg.len * 8) * sizeof(unsigned long));
+ if (!mask) {
+ pr_err("Problem processing %s field, skipping...\n", field->name);
+ printed = saved_printed;
+ continue;
+ }
+ memcpy(mask, (void *)val, syscall_arg.len);
+ printed += bitmap_scnprintf(mask, syscall_arg.len * 8,
+ bf + printed, size - printed);
+ free(mask);
+ }
+ } else {
+ unsigned char *b = (unsigned char *)val;
+ int i;
+ bool skip_zero = true;
+
+ printed += scnprintf(bf + printed, size - printed, "0x");
+ /* Print in little-endian order */
+ for (i = syscall_arg.len - 1; i >= 0; i--) {
+ if (skip_zero && b[i] == 0 && i > 0)
+ continue;
+ if (skip_zero) {
+ printed += scnprintf(bf + printed, size - printed, "%x", b[i]);
+ skip_zero = false;
+ } else {
+ printed += scnprintf(bf + printed, size - printed, "%02x", b[i]);
+ }
+ }
+ }
+ continue;
} else
val = format_field__intval(field, sample, evsel->needs_swap);
/*
@@ -5537,6 +5586,7 @@ int cmd_trace(int argc, const char **argv)
"start"),
OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer"
"to customized ones"),
+ OPT_BOOLEAN(0, "bitmask-list", &trace.bitmask_list, "Show bitmask as a human-readable list"),
OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"),
OPT_INTEGER(0, "max-summary", &trace.max_summary,
"Max number of entries in the summary."),
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ea9fa04429f0..0d5eb2cc4ce5 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -3933,6 +3933,35 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name)
return sample->raw_data + offset;
}
+void *format_field__get_raw_data(struct tep_format_field *field, struct
+ perf_sample *sample, bool needs_swap,
+ u16 *len_out)
+{
+ int offset = field->offset;
+ int size = field->size;
+
+ if (field->flags & TEP_FIELD_IS_DYNAMIC) {
+ unsigned int dynamic_data;
+
+ if (out_of_bounds(field, field->offset, 4, sample->raw_size))
+ return NULL;
+
+ dynamic_data = format_field__intval(field, sample, needs_swap);
+
+ offset = dynamic_data & 0xffff;
+ size = (dynamic_data >> 16) & 0xffff;
+
+ if (tep_field_is_relative(field->flags))
+ offset += field->offset + field->size;
+ }
+
+ if (out_of_bounds(field, offset, size, sample->raw_size))
+ return NULL;
+
+ *len_out = size;
+ return sample->raw_data + offset;
+}
+
u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample,
bool needs_swap)
{
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 163fc2b6a7ea..1babfecc5d13 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -400,6 +400,9 @@ static inline char *perf_sample__strval(struct perf_sample *sample, const char *
struct tep_format_field;
+void *format_field__get_raw_data(struct tep_format_field *field,
+ struct perf_sample *sample,
+ bool needs_swap, u16 *len_out);
u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap);
#ifdef HAVE_LIBTRACEEVENT
--
2.54.0
next reply other threads:[~2026-07-14 16:29 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 16:29 Aaron Tomlin [this message]
2026-07-14 16:39 ` [PATCH] perf trace: Add --bitmask-list option and correct cpumask formatting sashiko-bot
2026-07-15 1:22 ` Aaron Tomlin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260714162947.214270-1-atomlin@atomlin.com \
--to=atomlin@atomlin.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=howardchu95@gmail.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=neelx@suse.com \
--cc=peterz@infradead.org \
--cc=sean@ashe.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.