mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes
@ 2026-06-02 23:56 Arnaldo Carvalho de Melo
  2026-06-02 23:57 ` [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample Arnaldo Carvalho de Melo
                   ` (8 more replies)
  0 siblings, 9 replies; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:56 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo

When perf report, perf sched, or perf timechart skip a malformed or
unprocessable event, the warning message doesn't say where in the
perf.data file the problem occurred.  This makes it hard to
cross-reference with 'perf report -D' output or to locate the
corrupted region with a hex editor.

This series adds a file_offset field to struct perf_sample, set in the
event delivery path (including the deferred callchain path), and
retrofits all skip/stop/error messages to include:

  - The file offset where the event was found
  - The event type name via perf_event__name() with the numeric
    type value in parentheses

For example, instead of:

  problem processing 10 event, skipping it.

a user now sees:

  WARNING: at offset 0x1a3f0: MMAP2 (10) event size 24 too small (min 64), skipping

The peek_event() path, which validates events during initial file
scanning, also gains file offsets in its three warning messages
(misaligned size, unsupported type, undersized event).

Two pre-existing bugs found by sashiko-bot are fixed:

  - builtin-timechart.c cat_backtrace(): use-after-free and
    double-free when an invalid callchain context triggers zfree()
    before fclose() on an open_memstream buffer.  The open_memstream
    contract requires fclose() before the buffer can be freed — see
    open_memstream(3).

  - builtin-sched.c: three BUG_ON(cpu >= MAX_CPUS || cpu < 0)
    that abort perf sched when PERF_SAMPLE_CPU is absent from the
    sample type and the CPU sentinel (u32)-1 is cast to signed -1.
    perf.data is untrusted input — a corrupted or truncated file
    should produce a warning, not an abort.

Arnaldo Carvalho de Melo (8):
  perf sample: Add file_offset field to struct perf_sample
  perf session: Include file offset in event skip/stop messages
  perf sched: Include file offset in event skip messages
  perf timechart: Include file offset in CPU bounds check messages
  perf tools: Include file offset and event type name in skip messages
  perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
  perf sched: Replace BUG_ON on invalid CPU with graceful skip
  perf test: Add file offset diagnostic test for corrupted perf.data

 15 files changed, 261 insertions(+), 101 deletions(-)

Developed with AI assistance (Claude/sashiko), tagged in commits.

Best regards,

- Arnaldo

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:11   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 2/8] perf session: Include file offset in event skip/stop messages Arnaldo Carvalho de Melo
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add a file_offset field to struct perf_sample so that event processing
callbacks can report the byte offset of the problematic event in
perf.data, letting users cross-reference with 'perf report -D' output.

Set sample.file_offset in perf_session__deliver_event(), which is the
common entry point for both file mode (mmap'd offset) and pipe mode
(running byte counter from __perf_session__process_pipe_events).

The assignment is placed after evsel__parse_sample(), which zeroes
the struct via memset.

Preserve file_offset through the deferred callchain delivery path by
storing it in struct deferred_event and restoring it after
evlist__parse_sample() in both evlist__deliver_deferred_callchain()
and session__flush_deferred_samples().

Subsequent patches will use this field in skip/stop warning messages.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/sample.h  | 2 ++
 tools/perf/util/session.c | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h
index e556c9b656ea9cd6..c4eae8b2fd06035a 100644
--- a/tools/perf/util/sample.h
+++ b/tools/perf/util/sample.h
@@ -158,6 +158,8 @@ struct perf_sample {
 	u64 code_page_size;
 	/** @cgroup: The sample event PERF_SAMPLE_CGROUP value. */
 	u64 cgroup;
+	/** @file_offset: Byte offset of this event in the perf.data file. */
+	u64 file_offset;
 	/** @flags: Extra flag data from auxiliary events like intel-pt. */
 	u32 flags;
 	/** @machine_pid: The guest machine pid derived from the sample id. */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e2e821b77766dbfc..7996787d742e32c6 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1824,6 +1824,7 @@ static int evlist__deliver_sample(struct evlist *evlist, const struct perf_tool
 struct deferred_event {
 	struct list_head list;
 	union perf_event *event;
+	u64 file_offset;
 };
 
 /*
@@ -1858,6 +1859,7 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist,
 			perf_sample__exit(&orig_sample);
 			break;
 		}
+		orig_sample.file_offset = de->file_offset;
 
 		if (sample->tid != orig_sample.tid) {
 			perf_sample__exit(&orig_sample);
@@ -1906,6 +1908,7 @@ static int session__flush_deferred_samples(struct perf_session *session,
 			perf_sample__exit(&sample);
 			break;
 		}
+		sample.file_offset = de->file_offset;
 
 		sample.evsel = evlist__id2evsel(evlist, sample.id);
 		ret = evlist__deliver_sample(evlist, tool, de->event,
@@ -1984,6 +1987,7 @@ static int machines__deliver_event(struct machines *machines,
 				return -ENOMEM;
 			}
 			memcpy(de->event, event, sz);
+			de->file_offset = sample->file_offset;
 			list_add_tail(&de->list, &evlist->deferred_samples);
 			return 0;
 		}
@@ -2126,6 +2130,7 @@ static int perf_session__deliver_event(struct perf_session *session,
 		pr_err("Can't parse sample, err = %d\n", ret);
 		goto out;
 	}
+	sample.file_offset = file_offset;
 	/*
 	 * evsel__parse_sample() doesn't populate machine_pid/vcpu,
 	 * which are needed by machines__find_for_cpumode() to
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 2/8] perf session: Include file offset in event skip/stop messages
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
  2026-06-02 23:57 ` [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:12   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 3/8] perf sched: Include file offset in event skip messages Arnaldo Carvalho de Melo
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add 'at offset %#<hex>' to all warning and error messages in session.c
that fire when events are skipped or processing stops due to validation
failures.  This lets users cross-reference with 'perf report -D' output
to inspect the surrounding records and understand the corruption context.

Covers messages in perf_session__process_event() (alignment, min size,
swap failure), perf_session__deliver_event() (no evsel, parse failure,
CPU clamping), machines__deliver_event() (NAMESPACES, TEXT_POKE,
null-terminated string checks for MMAP/MMAP2/COMM/CGROUP/KSYMBOL), and
perf_session__process_user_event() (THREAD_MAP, CPU_MAP, STAT_CONFIG,
BPF_METADATA, HEADER_BUILD_ID).

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/session.c | 112 ++++++++++++++++++++------------------
 1 file changed, 60 insertions(+), 52 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 7996787d742e32c6..e4efb75509278a4e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1931,13 +1931,14 @@ static int session__flush_deferred_samples(struct perf_session *session,
  * read-only (MAP_SHARED + PROT_READ) so we cannot write a
  * null byte in place; skip the event instead.
  */
-static bool perf_event__check_nul(const char *str, const void *end, const char *event_name)
+static bool perf_event__check_nul(const char *str, const void *end,
+				  const char *event_name, u64 file_offset)
 {
 	size_t max_len = (const char *)end - str;
 
 	if (max_len == 0 || strnlen(str, max_len) == max_len) {
-		pr_warning("WARNING: PERF_RECORD_%s: string not null-terminated, skipping event\n",
-			   event_name);
+		pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_%s: string not null-terminated, skipping event\n",
+			   file_offset, event_name);
 		return false;
 	}
 
@@ -1995,7 +1996,7 @@ static int machines__deliver_event(struct machines *machines,
 	case PERF_RECORD_MMAP:
 		if (!perf_event__check_nul(event->mmap.filename,
 					   (void *)event + event->header.size,
-					   "MMAP"))
+					   "MMAP", file_offset))
 			return 0;
 		return tool->mmap(tool, event, sample, machine);
 	case PERF_RECORD_MMAP2:
@@ -2003,13 +2004,13 @@ static int machines__deliver_event(struct machines *machines,
 			++evlist->stats.nr_proc_map_timeout;
 		if (!perf_event__check_nul(event->mmap2.filename,
 					   (void *)event + event->header.size,
-					   "MMAP2"))
+					   "MMAP2", file_offset))
 			return 0;
 		return tool->mmap2(tool, event, sample, machine);
 	case PERF_RECORD_COMM:
 		if (!perf_event__check_nul(event->comm.comm,
 					   (void *)event + event->header.size,
-					   "COMM"))
+					   "COMM", file_offset))
 			return 0;
 		return tool->comm(tool, event, sample, machine);
 	case PERF_RECORD_NAMESPACES: {
@@ -2027,8 +2028,8 @@ static int machines__deliver_event(struct machines *machines,
 		 * cross-endian path.
 		 */
 		if (event->namespaces.nr_namespaces > max_nr) {
-			pr_warning("WARNING: PERF_RECORD_NAMESPACES: nr_namespaces %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
-				   (u64)event->namespaces.nr_namespaces, max_nr);
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_NAMESPACES: nr_namespaces %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
+				   file_offset, (u64)event->namespaces.nr_namespaces, max_nr);
 			return 0;
 		}
 		return tool->namespaces(tool, event, sample, machine);
@@ -2036,7 +2037,7 @@ static int machines__deliver_event(struct machines *machines,
 	case PERF_RECORD_CGROUP:
 		if (!perf_event__check_nul(event->cgroup.path,
 					   (void *)event + event->header.size,
-					   "CGROUP"))
+					   "CGROUP", file_offset))
 			return 0;
 		return tool->cgroup(tool, event, sample, machine);
 	case PERF_RECORD_FORK:
@@ -2078,7 +2079,7 @@ static int machines__deliver_event(struct machines *machines,
 	case PERF_RECORD_KSYMBOL:
 		if (!perf_event__check_nul(event->ksymbol.name,
 					   (void *)event + event->header.size,
-					   "KSYMBOL"))
+					   "KSYMBOL", file_offset))
 			return 0;
 		return tool->ksymbol(tool, event, sample, machine);
 	case PERF_RECORD_BPF_EVENT:
@@ -2090,7 +2091,8 @@ static int machines__deliver_event(struct machines *machines,
 				       event->text_poke.new_len;
 
 		if (event->header.size < text_poke_len) {
-			pr_warning("WARNING: PERF_RECORD_TEXT_POKE: old_len+new_len exceeds event, skipping\n");
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_TEXT_POKE: old_len+new_len exceeds event, skipping\n",
+				   file_offset);
 			return 0;
 		}
 		return tool->text_poke(tool, event, sample, machine);
@@ -2120,14 +2122,17 @@ static int perf_session__deliver_event(struct perf_session *session,
 	perf_sample__init(&sample, /*all=*/false);
 	evsel = evlist__event2evsel(session->evlist, event);
 	if (!evsel) {
-		pr_err("No evsel found for event type %u\n",
+		pr_err("ERROR: at offset %#" PRIx64 ": no evsel found for %s (%u) event\n",
+		       file_offset, perf_event__name(event->header.type),
 		       event->header.type);
 		ret = -EFAULT;
 		goto out;
 	}
 	ret = evsel__parse_sample(evsel, event, &sample);
 	if (ret) {
-		pr_err("Can't parse sample, err = %d\n", ret);
+		pr_err("ERROR: at offset %#" PRIx64 ": can't parse %s (%u) sample, err = %d\n",
+		       file_offset, perf_event__name(event->header.type),
+		       event->header.type, ret);
 		goto out;
 	}
 	sample.file_offset = file_offset;
@@ -2204,8 +2209,8 @@ static int perf_session__deliver_event(struct perf_session *session,
 			 * Downstream array users (timechart, kwork) have
 			 * their own per-callback bounds checks.
 			 */
-			pr_warning_once("WARNING: sample CPU %u >= nr_cpus_avail %u, clamping to 0\n",
-					sample.cpu, nr_cpus_avail);
+			pr_warning_once("WARNING: at offset %#" PRIx64 ": sample CPU %u >= nr_cpus_avail %u, clamping to 0\n",
+					file_offset, sample.cpu, nr_cpus_avail);
 			sample.cpu = 0;
 		}
 	}
@@ -2278,7 +2283,7 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 	case PERF_RECORD_HEADER_BUILD_ID:
 		if (!perf_event__check_nul(event->build_id.filename,
 					   (void *)event + event_size,
-					   "HEADER_BUILD_ID")) {
+					   "HEADER_BUILD_ID", file_offset)) {
 			err = 0;
 			break;
 		}
@@ -2311,8 +2316,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		u64 max_nr;
 
 		if (event_size < sizeof(event->thread_map)) {
-			pr_err("PERF_RECORD_THREAD_MAP: header.size (%u) too small\n",
-			       event_size);
+			pr_err("ERROR: at offset %#" PRIx64 ": PERF_RECORD_THREAD_MAP: header.size (%u) too small\n",
+			       file_offset, event_size);
 			err = -EINVAL;
 			break;
 		}
@@ -2320,8 +2325,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		max_nr = (event_size - sizeof(event->thread_map)) /
 			 sizeof(event->thread_map.entries[0]);
 		if (event->thread_map.nr > max_nr) {
-			pr_err("PERF_RECORD_THREAD_MAP: nr %" PRIu64 " exceeds max %" PRIu64 "\n",
-			       (u64)event->thread_map.nr, max_nr);
+			pr_err("ERROR: at offset %#" PRIx64 ": PERF_RECORD_THREAD_MAP: nr %" PRIu64 " exceeds max %" PRIu64 "\n",
+			       file_offset, (u64)event->thread_map.nr, max_nr);
 			err = -EINVAL;
 			break;
 		}
@@ -2345,8 +2350,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 				     sizeof(data->cpus_data.cpu[0]);
 
 			if (data->cpus_data.nr > max_nr) {
-				pr_warning("WARNING: PERF_RECORD_CPU_MAP: nr %u exceeds payload (max %u), skipping\n",
-					   data->cpus_data.nr, max_nr);
+				pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP: nr %u exceeds payload (max %u), skipping\n",
+					   file_offset, data->cpus_data.nr, max_nr);
 				err = 0;
 				goto out;
 			}
@@ -2359,8 +2364,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 					     sizeof(data->mask32_data.mask[0]);
 
 				if (data->mask32_data.nr > max_nr) {
-					pr_warning("WARNING: PERF_RECORD_CPU_MAP mask32: nr %u exceeds payload (max %u), skipping\n",
-						   data->mask32_data.nr, max_nr);
+					pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP mask32: nr %u exceeds payload (max %u), skipping\n",
+						   file_offset, data->mask32_data.nr, max_nr);
 					err = 0;
 					goto out;
 				}
@@ -2375,14 +2380,14 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 							     mask64_data.mask)) /
 					 sizeof(data->mask64_data.mask[0]);
 				if (data->mask64_data.nr > max_nr) {
-					pr_warning("WARNING: PERF_RECORD_CPU_MAP mask64: nr %u exceeds payload (max %u), skipping\n",
-						   data->mask64_data.nr, max_nr);
+					pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP mask64: nr %u exceeds payload (max %u), skipping\n",
+						   file_offset, data->mask64_data.nr, max_nr);
 					err = 0;
 					goto out;
 				}
 			} else {
-				pr_warning("WARNING: PERF_RECORD_CPU_MAP: unsupported long_size %u, skipping\n",
-					   data->mask32_data.long_size);
+				pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP: unsupported long_size %u, skipping\n",
+					   file_offset, data->mask32_data.long_size);
 				err = 0;
 				goto out;
 			}
@@ -2404,8 +2409,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		 * cannot clamp nr in place.  Skip the event instead.
 		 */
 		if (event->stat_config.nr > max_nr) {
-			pr_warning("WARNING: PERF_RECORD_STAT_CONFIG: nr %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
-				   (u64)event->stat_config.nr, max_nr);
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_STAT_CONFIG: nr %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
+				   file_offset, (u64)event->stat_config.nr, max_nr);
 			err = 0;
 			goto out;
 		}
@@ -2446,8 +2451,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		u64 nr_entries, max_entries;
 
 		if (event_size < sizeof(event->bpf_metadata)) {
-			pr_warning("WARNING: PERF_RECORD_BPF_METADATA: header.size (%u) too small, skipping\n",
-				   event_size);
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: header.size (%u) too small, skipping\n",
+				   file_offset, event_size);
 			err = 0;
 			break;
 		}
@@ -2458,7 +2463,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		 */
 		if (strnlen(event->bpf_metadata.prog_name,
 			    BPF_PROG_NAME_LEN) == BPF_PROG_NAME_LEN) {
-			pr_warning("WARNING: PERF_RECORD_BPF_METADATA: prog_name not null-terminated, skipping\n");
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: prog_name not null-terminated, skipping\n",
+				   file_offset);
 			err = 0;
 			break;
 		}
@@ -2467,8 +2473,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		max_entries = (event_size - sizeof(event->bpf_metadata)) /
 			      sizeof(event->bpf_metadata.entries[0]);
 		if (nr_entries > max_entries) {
-			pr_warning("WARNING: PERF_RECORD_BPF_METADATA: nr_entries %" PRIu64 " exceeds max %" PRIu64 ", skipping\n",
-				   nr_entries, max_entries);
+			pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: nr_entries %" PRIu64 " exceeds max %" PRIu64 ", skipping\n",
+				   file_offset, nr_entries, max_entries);
 			err = 0;
 			break;
 		}
@@ -2478,7 +2484,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 				    BPF_METADATA_KEY_LEN) == BPF_METADATA_KEY_LEN ||
 			    strnlen(event->bpf_metadata.entries[i].value,
 				    BPF_METADATA_VALUE_LEN) == BPF_METADATA_VALUE_LEN) {
-				pr_warning("WARNING: PERF_RECORD_BPF_METADATA: entry %" PRIu64 " key/value not null-terminated, skipping\n", i);
+				pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: entry %" PRIu64 " key/value not null-terminated, skipping\n",
+					   file_offset, i);
 				err = 0;
 				goto out;
 			}
@@ -2752,22 +2759,22 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
 	    event->header.type != PERF_RECORD_HEADER_TRACING_DATA &&
 	    event->header.type != PERF_RECORD_COMPRESSED &&
 	    event->header.type != PERF_RECORD_HEADER_FEATURE) {
-		pr_warning("WARNING: peek_event: event type %u size %u not aligned to %zu\n",
-			   event->header.type,
-			   event->header.size, sizeof(u64));
+		pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u not aligned to %zu\n",
+			   (u64)file_offset, perf_event__name(event->header.type),
+			   event->header.type, event->header.size, sizeof(u64));
 		return -1;
 	}
 
 	if (event->header.type >= PERF_RECORD_HEADER_MAX) {
-		pr_warning("WARNING: peek_event: unsupported event type %u, skipping\n",
-			   event->header.type);
+		pr_warning("WARNING: at offset %#" PRIx64 ": unsupported event type %u, skipping\n",
+			   (u64)file_offset, event->header.type);
 		return 0;
 	}
 
 	if (perf_event__too_small(event, &min_sz)) {
-		pr_warning("WARNING: peek_event: %s event size %u too small (min %u)\n",
-			   perf_event__name(event->header.type),
-			   event->header.size, min_sz);
+		pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u too small (min %u)\n",
+			   (u64)file_offset, perf_event__name(event->header.type),
+			   event->header.type, event->header.size, min_sz);
 		return -1;
 	}
 
@@ -2883,9 +2890,9 @@ static s64 perf_session__process_event(struct perf_session *session,
 	    event->header.type != PERF_RECORD_HEADER_TRACING_DATA &&
 	    event->header.type != PERF_RECORD_COMPRESSED &&
 	    event->header.type != PERF_RECORD_HEADER_FEATURE) {
-		pr_err("ERROR: %s event size %u is not 8-byte aligned, aborting\n",
-		       perf_event__name(event->header.type),
-		       event->header.size);
+		pr_err("ERROR: at offset %#" PRIx64 ": %s (%u) event size %u is not 8-byte aligned, aborting\n",
+		       file_offset, perf_event__name(event->header.type),
+		       event->header.type, event->header.size);
 		return -EINVAL;
 	}
 
@@ -2905,16 +2912,17 @@ static s64 perf_session__process_event(struct perf_session *session,
 	 * can be safely stepped over without misaligning the stream.
 	 */
 	if (perf_event__too_small(event, &min_sz)) {
-		pr_warning("WARNING: %s event size %u too small (min %u), skipping\n",
-			   perf_event__name(event->header.type),
-			   event->header.size, min_sz);
+		pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u too small (min %u), skipping\n",
+			   file_offset, perf_event__name(event->header.type),
+			   event->header.type, event->header.size, min_sz);
 		return 0;
 	}
 
 	if (session->header.needs_swap &&
 	    event_swap(event, evlist__sample_id_all(evlist))) {
-		pr_warning("WARNING: swap failed for %s event, skipping\n",
-			   perf_event__name(event->header.type));
+		pr_warning("WARNING: at offset %#" PRIx64 ": swap failed for %s (%u) event, skipping\n",
+			   file_offset, perf_event__name(event->header.type),
+			   event->header.type);
 		return 0;
 	}
 
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 3/8] perf sched: Include file offset in event skip messages
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
  2026-06-02 23:57 ` [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample Arnaldo Carvalho de Melo
  2026-06-02 23:57 ` [PATCH 2/8] perf session: Include file offset in event skip/stop messages Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:13   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages Arnaldo Carvalho de Melo
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add the perf.data file offset to the CPU out-of-bounds and
machine__resolve failure messages emitted when samples are skipped in
process_sched_switch_event(), process_sched_runtime_event(), and
timehist_sched_change_event().  Also switch event type from raw integer
to perf_event__name() string for readability.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-sched.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 812a1b0d56d6e5f3..9ec8e049e19b0038 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1792,8 +1792,10 @@ static int process_sched_switch_event(const struct perf_tool *tool,
 	u32 prev_pid = perf_sample__intval(sample, "prev_pid"),
 	    next_pid = perf_sample__intval(sample, "next_pid");
 
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (this_cpu < 0 || this_cpu >= MAX_CPUS) {
-		pr_warning("Out-of-bound sample CPU %d. Skipping sample\n", this_cpu);
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, this_cpu);
 		return 0;
 	}
 
@@ -1819,8 +1821,10 @@ static int process_sched_runtime_event(const struct perf_tool *tool,
 {
 	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
-		pr_warning("Out-of-bound sample CPU %u. Skipping sample\n", sample->cpu);
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %u, skipping sample\n",
+			   sample->file_offset, sample->cpu);
 		return 0;
 	}
 
@@ -2786,15 +2790,18 @@ static int timehist_sched_change_event(const struct perf_tool *tool,
 	int rc = 0;
 	const char state = perf_sample__taskstate(sample, "prev_state");
 
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
-		pr_warning("Out-of-bound sample CPU %d. Skipping sample\n", sample->cpu);
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, sample->cpu);
 		return 0;
 	}
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_err("problem processing %d event. skipping it\n",
-		       event->header.type);
+		pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it\n",
+		       perf_event__name(event->header.type), event->header.type,
+		       sample->file_offset);
 		rc = -1;
 		goto out;
 	}
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (2 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 3/8] perf sched: Include file offset in event skip messages Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:14   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 5/8] perf tools: Include file offset and event type name in skip messages Arnaldo Carvalho de Melo
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add the perf.data file offset to the out-of-bounds CPU debug messages
in process_sample_cpu_idle(), process_sample_cpu_frequency(),
process_sample_sched_wakeup(), and process_sample_sched_switch().

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-timechart.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 630756bebe3242dc..071987241a528ba4 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -605,8 +605,10 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
 	u32 state  = perf_sample__intval(sample, "state");
 	u32 cpu_id = perf_sample__intval(sample, "cpu_id");
 
+	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %u\n",
+			 sample->file_offset, cpu_id);
 		return -1;
 	}
 	if (state == (u32)PWR_EVENT_EXIT)
@@ -624,8 +626,10 @@ process_sample_cpu_frequency(struct timechart *tchart,
 	u32 state  = perf_sample__intval(sample, "state");
 	u32 cpu_id = perf_sample__intval(sample, "cpu_id");
 
+	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %u\n",
+			 sample->file_offset, cpu_id);
 		return -1;
 	}
 	p_state_change(tchart, cpu_id, sample->time, state);
@@ -641,8 +645,10 @@ process_sample_sched_wakeup(struct timechart *tchart,
 	int waker = perf_sample__intval(sample, "common_pid");
 	int wakee = perf_sample__intval(sample, "pid");
 
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
+			 sample->file_offset, sample->cpu);
 		return -1;
 	}
 	sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
@@ -658,8 +664,10 @@ process_sample_sched_switch(struct timechart *tchart,
 	int next_pid   = perf_sample__intval(sample, "next_pid");
 	u64 prev_state = perf_sample__intval(sample, "prev_state");
 
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
+			 sample->file_offset, sample->cpu);
 		return -1;
 	}
 	sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
@@ -676,6 +684,7 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
 	u64 cpu_id = perf_sample__intval(sample, "cpu_id");
 	u64 value  = perf_sample__intval(sample, "value");
 
+	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
 		pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
 		return -1;
@@ -689,6 +698,7 @@ process_sample_power_end(struct timechart *tchart,
 			 struct perf_sample *sample,
 			 const char *backtrace __maybe_unused)
 {
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
 		pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
 		return -1;
@@ -705,6 +715,7 @@ process_sample_power_frequency(struct timechart *tchart,
 	u64 cpu_id = perf_sample__intval(sample, "cpu_id");
 	u64 value  = perf_sample__intval(sample, "value");
 
+	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
 		pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
 		return -1;
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 5/8] perf tools: Include file offset and event type name in skip messages
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (3 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:14   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain Arnaldo Carvalho de Melo
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add the perf.data file offset and use perf_event__name() instead of raw
event type integers in the 'problem processing event, skipping it'
messages emitted by process_sample_event() callbacks across annotate,
c2c, diff, kmem, kvm, kwork, lock, report, script, and build-id.

This lets users cross-reference skipped events with 'perf report -D'
output.  Also add explicit #include "util/event.h" and <inttypes.h>
where needed to avoid depending on transitive includes.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-annotate.c |  5 +++--
 tools/perf/builtin-c2c.c      |  5 +++--
 tools/perf/builtin-diff.c     |  8 +++++---
 tools/perf/builtin-kmem.c     |  6 ++++--
 tools/perf/builtin-kvm.c      |  9 ++++++---
 tools/perf/builtin-kwork.c    |  4 +++-
 tools/perf/builtin-lock.c     |  6 ++++--
 tools/perf/builtin-report.c   |  9 ++++++---
 tools/perf/builtin-script.c   | 10 ++++++----
 tools/perf/util/build-id.c    |  5 +++--
 10 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5f450c8093c09210..b918f9eed5fd2441 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -288,8 +288,9 @@ static int process_sample_event(const struct perf_tool *tool,
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_warning("problem processing %d event, skipping it.\n",
-			   event->header.type);
+		pr_warning("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			   perf_event__name(event->header.type), event->header.type,
+			   sample->file_offset);
 		ret = -1;
 		goto out_put;
 	}
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 36f38694992386ad..d3503be9350c03bb 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -328,8 +328,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_debug("problem processing %d event, skipping it.\n",
-			 event->header.type);
+		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			 perf_event__name(event->header.type), event->header.type,
+			 sample->file_offset);
 		ret = -1;
 		goto out;
 	}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b4ff863b304ca046..9592f44b6545bab6 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -409,8 +409,9 @@ static int diff__process_sample_event(const struct perf_tool *tool,
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_warning("problem processing %d event, skipping it.\n",
-			   event->header.type);
+		pr_warning("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			   perf_event__name(event->header.type), event->header.type,
+			   sample->file_offset);
 		ret = -1;
 		goto out;
 	}
@@ -436,7 +437,8 @@ static int diff__process_sample_event(const struct perf_tool *tool,
 	case COMPUTE_STREAM:
 		if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
 					 NULL)) {
-			pr_debug("problem adding hist entry, skipping event\n");
+			pr_debug("problem adding hist entry at offset %#" PRIx64 ", skipping event\n",
+				 sample->file_offset);
 			goto out;
 		}
 		break;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 33585e353efe56cc..e1b2f5bc1ba8d887 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -22,6 +22,7 @@
 #include "util/cpumap.h"
 
 #include "util/debug.h"
+#include "util/event.h"
 #include "util/string2.h"
 #include "util/util.h"
 
@@ -987,8 +988,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
 							sample->tid);
 
 	if (thread == NULL) {
-		pr_debug("problem processing %d event, skipping it.\n",
-			 event->header.type);
+		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			 perf_event__name(event->header.type), event->header.type,
+			 sample->file_offset);
 		return -1;
 	}
 
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index dd2ed21596aa59f9..394302ebdb161077 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -22,6 +22,7 @@
 #include "util/synthetic-events.h"
 #include "util/top.h"
 #include "util/data.h"
+#include "util/event.h"
 #include "util/ordered-events.h"
 #include "util/kvm-stat.h"
 #include "util/util.h"
@@ -1141,14 +1142,16 @@ static int process_sample_event(const struct perf_tool *tool,
 		return 0;
 
 	if (machine__resolve(machine, &kvm->al, sample) < 0) {
-		pr_warning("Fail to resolve address location, skip sample.\n");
+		pr_warning("WARNING: at offset %#" PRIx64 ": fail to resolve address location, skipping sample\n",
+			   sample->file_offset);
 		return 0;
 	}
 
 	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
 	if (thread == NULL) {
-		pr_debug("problem processing %d event, skipping it.\n",
-			event->header.type);
+		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			 perf_event__name(event->header.type), event->header.type,
+			 sample->file_offset);
 		return -1;
 	}
 
diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c
index 99dc293a0744726e..110de3507d48160c 100644
--- a/tools/perf/builtin-kwork.c
+++ b/tools/perf/builtin-kwork.c
@@ -9,6 +9,7 @@
 #include "perf.h"
 
 #include "util/data.h"
+#include "util/event.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/header.h"
@@ -897,7 +898,8 @@ static int timehist_exit_event(struct perf_kwork *kwork,
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_debug("Problem processing event, skipping it\n");
+		pr_debug("problem processing event at offset %#" PRIx64 ", skipping it\n",
+			 sample->file_offset);
 		ret = -1;
 		goto out;
 	}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 94a8c35abb0bc991..5841d43be9718414 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -21,6 +21,7 @@
 #include "util/tracepoint.h"
 
 #include "util/debug.h"
+#include "util/event.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/data.h"
@@ -1433,8 +1434,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
 							sample->tid);
 
 	if (thread == NULL) {
-		pr_debug("problem processing %d event, skipping it.\n",
-			event->header.type);
+		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			 perf_event__name(event->header.type), event->header.type,
+			 sample->file_offset);
 		return -1;
 	}
 
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 973d97af85019e6e..cd052aa78132b65f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,6 +27,7 @@
 
 #include "perf.h"
 #include "util/debug.h"
+#include "util/event.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/evswitch.h"
@@ -284,8 +285,9 @@ static int process_sample_event(const struct perf_tool *tool,
 
 	addr_location__init(&al);
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_debug("problem processing %d event, skipping it.\n",
-			 event->header.type);
+		pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+			 perf_event__name(event->header.type), event->header.type,
+			 sample->file_offset);
 		ret = -1;
 		goto out_put;
 	}
@@ -332,7 +334,8 @@ static int process_sample_event(const struct perf_tool *tool,
 
 	ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
 	if (ret < 0)
-		pr_debug("problem adding hist entry, skipping event\n");
+		pr_debug("problem adding hist entry at offset %#" PRIx64 ", skipping event\n",
+			 sample->file_offset);
 out_put:
 	addr_location__exit(&al);
 	return ret;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 5124edf2b7a692b2..f4aa255fc3297f90 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -2693,8 +2693,9 @@ static int process_sample_event(const struct perf_tool *tool,
 		goto out_put;
 
 	if (!al.thread && machine__resolve(machine, &al, sample) < 0) {
-		pr_err("problem processing %d event, skipping it.\n",
-		       event->header.type);
+		pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+		       perf_event__name(event->header.type), event->header.type,
+		       sample->file_offset);
 		ret = -1;
 		goto out_put;
 	}
@@ -2775,8 +2776,9 @@ static int process_deferred_sample_event(const struct perf_tool *tool,
 		goto out_put;
 
 	if (machine__resolve(machine, &al, sample) < 0) {
-		pr_err("problem processing %d event, skipping it.\n",
-		       event->header.type);
+		pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+		       perf_event__name(event->header.type), event->header.type,
+		       sample->file_offset);
 		ret = -1;
 		goto out_put;
 	}
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index af4d874f13810ffe..8c0a9ae932aa5798 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -10,6 +10,7 @@
 #include "util.h" // lsdir(), mkdir_p(), rm_rf()
 #include <dirent.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -62,8 +63,8 @@ int build_id__mark_dso_hit(const struct perf_tool *tool __maybe_unused,
 							sample->tid);
 
 	if (thread == NULL) {
-		pr_err("problem processing %d event, skipping it.\n",
-			event->header.type);
+		pr_err("problem processing %s event at offset %#" PRIx64 ", skipping it.\n",
+		       perf_event__name(event->header.type), sample->file_offset);
 		return -1;
 	}
 
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (4 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 5/8] perf tools: Include file offset and event type name in skip messages Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:16   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip Arnaldo Carvalho de Melo
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, sashiko-bot, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

cat_backtrace() uses open_memstream() to build a backtrace string.
When an invalid callchain context is encountered, zfree(&p) frees
the memstream buffer, then the exit path calls fclose(f), which
flushes to the already-freed buffer — a use-after-free.  The function
then returns a dangling pointer that the caller passes to a handler
and subsequently double-frees.

Fix by replacing the zfree(&p) with a 'corrupted' flag.  At the exit
label, always fclose(f) first (which finalizes the buffer), then
conditionally free it when corrupted.  This ensures the memstream
contract is honored: the buffer remains valid until fclose().

While here, update the machine__resolve failure message to include
file_offset and the event type name, matching the pattern from the
preceding series.  Also update the three legacy power event handlers
under SUPPORT_OLD_POWER_EVENTS to include file_offset in their
out-of-bounds CPU messages for consistency.

Reported-by: sashiko-bot@kernel.org # Running on a local machine
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-timechart.c | 36 ++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 071987241a528ba4..85a9ad0455aecccd 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -489,6 +489,10 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
 	}
 }
 
+/*
+ * Returns a malloc'd backtrace string built via open_memstream, or NULL
+ * on error.  Caller must free() the returned pointer.
+ */
 static char *cat_backtrace(union perf_event *event,
 			   struct perf_sample *sample,
 			   struct machine *machine)
@@ -500,6 +504,7 @@ static char *cat_backtrace(union perf_event *event,
 	u8 cpumode = PERF_RECORD_MISC_USER;
 	struct ip_callchain *chain = sample->callchain;
 	FILE *f = open_memstream(&p, &p_len);
+	bool corrupted = false;
 
 	if (!f) {
 		perror("open_memstream error");
@@ -511,8 +516,9 @@ static char *cat_backtrace(union perf_event *event,
 		goto exit;
 
 	if (machine__resolve(machine, &al, sample) < 0) {
-		fprintf(stderr, "problem processing %d event, skipping it.\n",
-			event->header.type);
+		pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
+		       perf_event__name(event->header.type), event->header.type,
+		       sample->file_offset);
 		goto exit;
 	}
 
@@ -537,14 +543,8 @@ static char *cat_backtrace(union perf_event *event,
 				cpumode = PERF_RECORD_MISC_USER;
 				break;
 			default:
-				pr_debug("invalid callchain context: "
-					 "%"PRId64"\n", (s64) ip);
-
-				/*
-				 * It seems the callchain is corrupted.
-				 * Discard all.
-				 */
-				zfree(&p);
+				pr_debug("invalid callchain context: %" PRId64 "\n", (s64) ip);
+				corrupted = true;
 				goto exit;
 			}
 			continue;
@@ -561,7 +561,14 @@ static char *cat_backtrace(union perf_event *event,
 	}
 exit:
 	addr_location__exit(&al);
+	/*
+	 * fclose() on an open_memstream always sets p to a valid buffer,
+	 * even if nothing was written — see open_memstream(3).  So p is
+	 * never NULL after fclose and we need the flag to discard it.
+	 */
 	fclose(f);
+	if (corrupted)
+		zfree(&p);
 
 	return p;
 }
@@ -686,7 +693,8 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
 
 	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %llu\n",
+			 sample->file_offset, (unsigned long long)cpu_id);
 		return -1;
 	}
 	c_state_start(cpu_id, sample->time, value);
@@ -700,7 +708,8 @@ process_sample_power_end(struct timechart *tchart,
 {
 	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (sample->cpu >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
+			 sample->file_offset, sample->cpu);
 		return -1;
 	}
 	c_state_end(tchart, sample->cpu, sample->time);
@@ -717,7 +726,8 @@ process_sample_power_frequency(struct timechart *tchart,
 
 	/* perf.data is untrusted input — cpu_id may be corrupted */
 	if (cpu_id >= MAX_CPUS) {
-		pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
+		pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %llu\n",
+			 sample->file_offset, (unsigned long long)cpu_id);
 		return -1;
 	}
 	p_state_change(tchart, cpu_id, sample->time, value);
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (5 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:17   ` Ian Rogers
  2026-06-02 23:57 ` [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data Arnaldo Carvalho de Melo
  2026-06-03 15:06 ` [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Ian Rogers
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, sashiko-bot, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

latency_switch_event(), latency_runtime_event(), and map_switch_event()
use BUG_ON(cpu >= MAX_CPUS || cpu < 0) to validate the sample CPU.
When PERF_SAMPLE_CPU is absent from the sample type,
evsel__parse_sample() initializes sample->cpu to (u32)-1.  Casting
this to int yields -1, which triggers the BUG_ON and aborts perf sched.

The central CPU validation in perf_session__deliver_event() intentionally
preserves the (u32)-1 sentinel for downstream tools like perf script
and perf inject, so leaf callbacks must handle it themselves.

Replace the three BUG_ON calls with graceful skips using pr_warning(),
matching the existing pattern in process_sched_switch_event() and
process_sched_runtime_event() earlier in the same file.  Include the
file offset for cross-referencing with perf report -D.

Reported-by: sashiko-bot@kernel.org # Running on a local machine
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-sched.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 9ec8e049e19b0038..81833d169470582b 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1145,7 +1145,12 @@ static int latency_switch_event(struct perf_sched *sched,
 	int cpu = sample->cpu, err = -1;
 	s64 delta;
 
-	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (cpu >= MAX_CPUS || cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, cpu);
+		return 0;
+	}
 
 	timestamp0 = sched->cpu_last_switched[cpu];
 	sched->cpu_last_switched[cpu] = timestamp;
@@ -1215,7 +1220,13 @@ static int latency_runtime_event(struct perf_sched *sched,
 	if (thread == NULL)
 		return -1;
 
-	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (cpu >= MAX_CPUS || cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, cpu);
+		err = 0;
+		goto out_put;
+	}
 	if (!atoms) {
 		if (thread_atoms_insert(sched, thread))
 			goto out_put;
@@ -1640,7 +1651,12 @@ static int map_switch_event(struct perf_sched *sched,  struct perf_sample *sampl
 	const char *str;
 	int ret = -1;
 
-	BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, this_cpu.cpu);
+		return 0;
+	}
 
 	if (this_cpu.cpu > sched->max_cpu.cpu)
 		sched->max_cpu = this_cpu;
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (6 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip Arnaldo Carvalho de Melo
@ 2026-06-02 23:57 ` Arnaldo Carvalho de Melo
  2026-06-03 15:19   ` Ian Rogers
  2026-06-03 15:06 ` [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Ian Rogers
  8 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-02 23:57 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Ingo Molnar, Thomas Gleixner, James Clark, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Clark Williams, linux-kernel, linux-perf-users,
	Arnaldo Carvalho de Melo, Claude Opus 4.6

From: Arnaldo Carvalho de Melo <acme@redhat.com>

Add a shell test that verifies the file_offset diagnostic messages
work correctly when perf encounters corrupted events.

The test corrupts a MMAP2 event's size field in a recorded perf.data
file, then checks that perf report produces warning messages that
include both the file offset (e.g. "at offset 0x2738:") and the
event type name with numeric id (e.g. "MMAP2 (10)").

This exercises the diagnostic improvements from the file_offset
series, which retrofitted all skip/stop/error messages to include
the position and type of the problematic event.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 .../shell/data_file_offset_diagnostics.sh     | 82 +++++++++++++++++++
 1 file changed, 82 insertions(+)
 create mode 100755 tools/perf/tests/shell/data_file_offset_diagnostics.sh

diff --git a/tools/perf/tests/shell/data_file_offset_diagnostics.sh b/tools/perf/tests/shell/data_file_offset_diagnostics.sh
new file mode 100755
index 0000000000000000..031f49480d999d8c
--- /dev/null
+++ b/tools/perf/tests/shell/data_file_offset_diagnostics.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Test that perf report includes file offsets and event type names in diagnostic messages.
+# SPDX-License-Identifier: GPL-2.0
+#
+# The file_offset diagnostic series adds "at offset 0x...: TYPE (N)"
+# to all skip/stop/error messages.  This test corrupts an event's size
+# field in a perf.data file, then verifies the resulting warning
+# includes the file offset and event type.
+
+err=0
+
+cleanup() {
+	[ -n "${perfdata}" ] && rm -f "${perfdata}" "${perfdata}.old"
+	rm -f "${corrupted}" "${stderrfile}"
+	trap - EXIT TERM INT
+}
+trap 'cleanup; exit 1' TERM INT
+trap cleanup EXIT
+
+perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
+corrupted=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
+stderrfile=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
+
+if ! perf record -o "${perfdata}" -- perf test -w noploop 2>/dev/null; then
+	echo "Skip: perf record failed"
+	cleanup
+	exit 2
+fi
+
+# Find the file offset of the first MMAP2 event via perf report -D.
+# Format: "timestamp 0xOFFSET [0xSIZE]: PERF_RECORD_MMAP2 ..."
+mmap2_line=$(perf report -D -i "${perfdata}" 2>/dev/null | grep "PERF_RECORD_MMAP2" | head -1)
+if [ -z "${mmap2_line}" ]; then
+	echo "Skip: no MMAP2 events found in perf.data"
+	cleanup
+	exit 2
+fi
+
+mmap2_offset=$(echo "${mmap2_line}" | awk '{print $2}')
+mmap2_offset_dec=$((mmap2_offset))
+
+# Copy the file and corrupt the MMAP2 event's size field.
+# perf_event_header layout: type(u32) misc(u16) size(u16)
+# Set size to 16 (0x10 0x00 little-endian) — below the MMAP2
+# minimum, which triggers the "event size too small" warning.
+cp "${perfdata}" "${corrupted}"
+printf '\x10\x00' | dd of="${corrupted}" bs=1 seek=$((mmap2_offset_dec + 6)) conv=notrunc 2>/dev/null
+
+perf report -i "${corrupted}" --stdio > /dev/null 2> "${stderrfile}"
+
+# Check that warnings include "at offset 0x..."
+if grep -q "at offset 0x" "${stderrfile}"; then
+	echo "File offset in diagnostics [Success]"
+else
+	echo "File offset in diagnostics [Failed: no 'at offset 0x...' found]"
+	echo "  stderr was:"
+	head -5 "${stderrfile}"
+	err=1
+fi
+
+# Check that the event type name and numeric id appear: "MMAP2 (10)"
+if grep -q "MMAP2 (10)" "${stderrfile}"; then
+	echo "Event type name in diagnostics [Success]"
+else
+	echo "Event type name in diagnostics [Failed: no 'MMAP2 (10)' found]"
+	echo "  stderr was:"
+	head -5 "${stderrfile}"
+	err=1
+fi
+
+# Check that the reported offset matches the actual corruption point
+if grep -q "at offset ${mmap2_offset}:" "${stderrfile}"; then
+	echo "Correct offset reported [Success]"
+else
+	echo "Correct offset reported [Failed: expected offset ${mmap2_offset}]"
+	echo "  stderr was:"
+	head -5 "${stderrfile}"
+	err=1
+fi
+
+cleanup
+exit ${err}
-- 
2.54.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes
  2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
                   ` (7 preceding siblings ...)
  2026-06-02 23:57 ` [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data Arnaldo Carvalho de Melo
@ 2026-06-03 15:06 ` Ian Rogers
  2026-06-03 19:27   ` Arnaldo Carvalho de Melo
  8 siblings, 1 reply; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:06 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> When perf report, perf sched, or perf timechart skip a malformed or
> unprocessable event, the warning message doesn't say where in the
> perf.data file the problem occurred.  This makes it hard to
> cross-reference with 'perf report -D' output or to locate the
> corrupted region with a hex editor.
>
> This series adds a file_offset field to struct perf_sample, set in the
> event delivery path (including the deferred callchain path), and
> retrofits all skip/stop/error messages to include:
>
>   - The file offset where the event was found
>   - The event type name via perf_event__name() with the numeric
>     type value in parentheses
>
> For example, instead of:
>
>   problem processing 10 event, skipping it.
>
> a user now sees:
>
>   WARNING: at offset 0x1a3f0: MMAP2 (10) event size 24 too small (min 64), skipping
>
> The peek_event() path, which validates events during initial file
> scanning, also gains file offsets in its three warning messages
> (misaligned size, unsupported type, undersized event).
>
> Two pre-existing bugs found by sashiko-bot are fixed:
>
>   - builtin-timechart.c cat_backtrace(): use-after-free and
>     double-free when an invalid callchain context triggers zfree()
>     before fclose() on an open_memstream buffer.  The open_memstream
>     contract requires fclose() before the buffer can be freed — see
>     open_memstream(3).

Fwiw, I've also been around the timechart code prompted by AI review
and also trying to clean up tests with address sanitizer:
https://lore.kernel.org/linux-perf-users/agzWqrn6XPEwTAsb@google.com/

Thanks,
Ian

>   - builtin-sched.c: three BUG_ON(cpu >= MAX_CPUS || cpu < 0)
>     that abort perf sched when PERF_SAMPLE_CPU is absent from the
>     sample type and the CPU sentinel (u32)-1 is cast to signed -1.
>     perf.data is untrusted input — a corrupted or truncated file
>     should produce a warning, not an abort.
>
> Arnaldo Carvalho de Melo (8):
>   perf sample: Add file_offset field to struct perf_sample
>   perf session: Include file offset in event skip/stop messages
>   perf sched: Include file offset in event skip messages
>   perf timechart: Include file offset in CPU bounds check messages
>   perf tools: Include file offset and event type name in skip messages
>   perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
>   perf sched: Replace BUG_ON on invalid CPU with graceful skip
>   perf test: Add file offset diagnostic test for corrupted perf.data
>
>  15 files changed, 261 insertions(+), 101 deletions(-)
>
> Developed with AI assistance (Claude/sashiko), tagged in commits.
>
> Best regards,
>
> - Arnaldo

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample
  2026-06-02 23:57 ` [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample Arnaldo Carvalho de Melo
@ 2026-06-03 15:11   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:11 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add a file_offset field to struct perf_sample so that event processing
> callbacks can report the byte offset of the problematic event in
> perf.data, letting users cross-reference with 'perf report -D' output.
>
> Set sample.file_offset in perf_session__deliver_event(), which is the
> common entry point for both file mode (mmap'd offset) and pipe mode
> (running byte counter from __perf_session__process_pipe_events).
>
> The assignment is placed after evsel__parse_sample(), which zeroes
> the struct via memset.
>
> Preserve file_offset through the deferred callchain delivery path by
> storing it in struct deferred_event and restoring it after
> evlist__parse_sample() in both evlist__deliver_deferred_callchain()
> and session__flush_deferred_samples().
>
> Subsequent patches will use this field in skip/stop warning messages.
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/sample.h  | 2 ++
>  tools/perf/util/session.c | 5 +++++
>  2 files changed, 7 insertions(+)
>
> diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h
> index e556c9b656ea9cd6..c4eae8b2fd06035a 100644
> --- a/tools/perf/util/sample.h
> +++ b/tools/perf/util/sample.h
> @@ -158,6 +158,8 @@ struct perf_sample {
>         u64 code_page_size;
>         /** @cgroup: The sample event PERF_SAMPLE_CGROUP value. */
>         u64 cgroup;
> +       /** @file_offset: Byte offset of this event in the perf.data file. */
> +       u64 file_offset;
>         /** @flags: Extra flag data from auxiliary events like intel-pt. */
>         u32 flags;
>         /** @machine_pid: The guest machine pid derived from the sample id. */
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index e2e821b77766dbfc..7996787d742e32c6 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -1824,6 +1824,7 @@ static int evlist__deliver_sample(struct evlist *evlist, const struct perf_tool
>  struct deferred_event {
>         struct list_head list;
>         union perf_event *event;
> +       u64 file_offset;
>  };
>
>  /*
> @@ -1858,6 +1859,7 @@ static int evlist__deliver_deferred_callchain(struct evlist *evlist,
>                         perf_sample__exit(&orig_sample);
>                         break;
>                 }
> +               orig_sample.file_offset = de->file_offset;
>
>                 if (sample->tid != orig_sample.tid) {
>                         perf_sample__exit(&orig_sample);
> @@ -1906,6 +1908,7 @@ static int session__flush_deferred_samples(struct perf_session *session,
>                         perf_sample__exit(&sample);
>                         break;
>                 }
> +               sample.file_offset = de->file_offset;
>
>                 sample.evsel = evlist__id2evsel(evlist, sample.id);
>                 ret = evlist__deliver_sample(evlist, tool, de->event,
> @@ -1984,6 +1987,7 @@ static int machines__deliver_event(struct machines *machines,
>                                 return -ENOMEM;
>                         }
>                         memcpy(de->event, event, sz);
> +                       de->file_offset = sample->file_offset;
>                         list_add_tail(&de->list, &evlist->deferred_samples);
>                         return 0;
>                 }
> @@ -2126,6 +2130,7 @@ static int perf_session__deliver_event(struct perf_session *session,
>                 pr_err("Can't parse sample, err = %d\n", ret);
>                 goto out;
>         }
> +       sample.file_offset = file_offset;
>         /*
>          * evsel__parse_sample() doesn't populate machine_pid/vcpu,
>          * which are needed by machines__find_for_cpumode() to
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/8] perf session: Include file offset in event skip/stop messages
  2026-06-02 23:57 ` [PATCH 2/8] perf session: Include file offset in event skip/stop messages Arnaldo Carvalho de Melo
@ 2026-06-03 15:12   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add 'at offset %#<hex>' to all warning and error messages in session.c
> that fire when events are skipped or processing stops due to validation
> failures.  This lets users cross-reference with 'perf report -D' output
> to inspect the surrounding records and understand the corruption context.
>
> Covers messages in perf_session__process_event() (alignment, min size,
> swap failure), perf_session__deliver_event() (no evsel, parse failure,
> CPU clamping), machines__deliver_event() (NAMESPACES, TEXT_POKE,
> null-terminated string checks for MMAP/MMAP2/COMM/CGROUP/KSYMBOL), and
> perf_session__process_user_event() (THREAD_MAP, CPU_MAP, STAT_CONFIG,
> BPF_METADATA, HEADER_BUILD_ID).
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/util/session.c | 112 ++++++++++++++++++++------------------
>  1 file changed, 60 insertions(+), 52 deletions(-)
>
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index 7996787d742e32c6..e4efb75509278a4e 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -1931,13 +1931,14 @@ static int session__flush_deferred_samples(struct perf_session *session,
>   * read-only (MAP_SHARED + PROT_READ) so we cannot write a
>   * null byte in place; skip the event instead.
>   */
> -static bool perf_event__check_nul(const char *str, const void *end, const char *event_name)
> +static bool perf_event__check_nul(const char *str, const void *end,
> +                                 const char *event_name, u64 file_offset)
>  {
>         size_t max_len = (const char *)end - str;
>
>         if (max_len == 0 || strnlen(str, max_len) == max_len) {
> -               pr_warning("WARNING: PERF_RECORD_%s: string not null-terminated, skipping event\n",
> -                          event_name);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_%s: string not null-terminated, skipping event\n",
> +                          file_offset, event_name);
>                 return false;
>         }
>
> @@ -1995,7 +1996,7 @@ static int machines__deliver_event(struct machines *machines,
>         case PERF_RECORD_MMAP:
>                 if (!perf_event__check_nul(event->mmap.filename,
>                                            (void *)event + event->header.size,
> -                                          "MMAP"))
> +                                          "MMAP", file_offset))
>                         return 0;
>                 return tool->mmap(tool, event, sample, machine);
>         case PERF_RECORD_MMAP2:
> @@ -2003,13 +2004,13 @@ static int machines__deliver_event(struct machines *machines,
>                         ++evlist->stats.nr_proc_map_timeout;
>                 if (!perf_event__check_nul(event->mmap2.filename,
>                                            (void *)event + event->header.size,
> -                                          "MMAP2"))
> +                                          "MMAP2", file_offset))
>                         return 0;
>                 return tool->mmap2(tool, event, sample, machine);
>         case PERF_RECORD_COMM:
>                 if (!perf_event__check_nul(event->comm.comm,
>                                            (void *)event + event->header.size,
> -                                          "COMM"))
> +                                          "COMM", file_offset))
>                         return 0;
>                 return tool->comm(tool, event, sample, machine);
>         case PERF_RECORD_NAMESPACES: {
> @@ -2027,8 +2028,8 @@ static int machines__deliver_event(struct machines *machines,
>                  * cross-endian path.
>                  */
>                 if (event->namespaces.nr_namespaces > max_nr) {
> -                       pr_warning("WARNING: PERF_RECORD_NAMESPACES: nr_namespaces %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
> -                                  (u64)event->namespaces.nr_namespaces, max_nr);
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_NAMESPACES: nr_namespaces %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
> +                                  file_offset, (u64)event->namespaces.nr_namespaces, max_nr);
>                         return 0;
>                 }
>                 return tool->namespaces(tool, event, sample, machine);
> @@ -2036,7 +2037,7 @@ static int machines__deliver_event(struct machines *machines,
>         case PERF_RECORD_CGROUP:
>                 if (!perf_event__check_nul(event->cgroup.path,
>                                            (void *)event + event->header.size,
> -                                          "CGROUP"))
> +                                          "CGROUP", file_offset))
>                         return 0;
>                 return tool->cgroup(tool, event, sample, machine);
>         case PERF_RECORD_FORK:
> @@ -2078,7 +2079,7 @@ static int machines__deliver_event(struct machines *machines,
>         case PERF_RECORD_KSYMBOL:
>                 if (!perf_event__check_nul(event->ksymbol.name,
>                                            (void *)event + event->header.size,
> -                                          "KSYMBOL"))
> +                                          "KSYMBOL", file_offset))
>                         return 0;
>                 return tool->ksymbol(tool, event, sample, machine);
>         case PERF_RECORD_BPF_EVENT:
> @@ -2090,7 +2091,8 @@ static int machines__deliver_event(struct machines *machines,
>                                        event->text_poke.new_len;
>
>                 if (event->header.size < text_poke_len) {
> -                       pr_warning("WARNING: PERF_RECORD_TEXT_POKE: old_len+new_len exceeds event, skipping\n");
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_TEXT_POKE: old_len+new_len exceeds event, skipping\n",
> +                                  file_offset);
>                         return 0;
>                 }
>                 return tool->text_poke(tool, event, sample, machine);
> @@ -2120,14 +2122,17 @@ static int perf_session__deliver_event(struct perf_session *session,
>         perf_sample__init(&sample, /*all=*/false);
>         evsel = evlist__event2evsel(session->evlist, event);
>         if (!evsel) {
> -               pr_err("No evsel found for event type %u\n",
> +               pr_err("ERROR: at offset %#" PRIx64 ": no evsel found for %s (%u) event\n",
> +                      file_offset, perf_event__name(event->header.type),
>                        event->header.type);
>                 ret = -EFAULT;
>                 goto out;
>         }
>         ret = evsel__parse_sample(evsel, event, &sample);
>         if (ret) {
> -               pr_err("Can't parse sample, err = %d\n", ret);
> +               pr_err("ERROR: at offset %#" PRIx64 ": can't parse %s (%u) sample, err = %d\n",
> +                      file_offset, perf_event__name(event->header.type),
> +                      event->header.type, ret);
>                 goto out;
>         }
>         sample.file_offset = file_offset;
> @@ -2204,8 +2209,8 @@ static int perf_session__deliver_event(struct perf_session *session,
>                          * Downstream array users (timechart, kwork) have
>                          * their own per-callback bounds checks.
>                          */
> -                       pr_warning_once("WARNING: sample CPU %u >= nr_cpus_avail %u, clamping to 0\n",
> -                                       sample.cpu, nr_cpus_avail);
> +                       pr_warning_once("WARNING: at offset %#" PRIx64 ": sample CPU %u >= nr_cpus_avail %u, clamping to 0\n",
> +                                       file_offset, sample.cpu, nr_cpus_avail);
>                         sample.cpu = 0;
>                 }
>         }
> @@ -2278,7 +2283,7 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>         case PERF_RECORD_HEADER_BUILD_ID:
>                 if (!perf_event__check_nul(event->build_id.filename,
>                                            (void *)event + event_size,
> -                                          "HEADER_BUILD_ID")) {
> +                                          "HEADER_BUILD_ID", file_offset)) {
>                         err = 0;
>                         break;
>                 }
> @@ -2311,8 +2316,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                 u64 max_nr;
>
>                 if (event_size < sizeof(event->thread_map)) {
> -                       pr_err("PERF_RECORD_THREAD_MAP: header.size (%u) too small\n",
> -                              event_size);
> +                       pr_err("ERROR: at offset %#" PRIx64 ": PERF_RECORD_THREAD_MAP: header.size (%u) too small\n",
> +                              file_offset, event_size);
>                         err = -EINVAL;
>                         break;
>                 }
> @@ -2320,8 +2325,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                 max_nr = (event_size - sizeof(event->thread_map)) /
>                          sizeof(event->thread_map.entries[0]);
>                 if (event->thread_map.nr > max_nr) {
> -                       pr_err("PERF_RECORD_THREAD_MAP: nr %" PRIu64 " exceeds max %" PRIu64 "\n",
> -                              (u64)event->thread_map.nr, max_nr);
> +                       pr_err("ERROR: at offset %#" PRIx64 ": PERF_RECORD_THREAD_MAP: nr %" PRIu64 " exceeds max %" PRIu64 "\n",
> +                              file_offset, (u64)event->thread_map.nr, max_nr);
>                         err = -EINVAL;
>                         break;
>                 }
> @@ -2345,8 +2350,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                                      sizeof(data->cpus_data.cpu[0]);
>
>                         if (data->cpus_data.nr > max_nr) {
> -                               pr_warning("WARNING: PERF_RECORD_CPU_MAP: nr %u exceeds payload (max %u), skipping\n",
> -                                          data->cpus_data.nr, max_nr);
> +                               pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP: nr %u exceeds payload (max %u), skipping\n",
> +                                          file_offset, data->cpus_data.nr, max_nr);
>                                 err = 0;
>                                 goto out;
>                         }
> @@ -2359,8 +2364,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                                              sizeof(data->mask32_data.mask[0]);
>
>                                 if (data->mask32_data.nr > max_nr) {
> -                                       pr_warning("WARNING: PERF_RECORD_CPU_MAP mask32: nr %u exceeds payload (max %u), skipping\n",
> -                                                  data->mask32_data.nr, max_nr);
> +                                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP mask32: nr %u exceeds payload (max %u), skipping\n",
> +                                                  file_offset, data->mask32_data.nr, max_nr);
>                                         err = 0;
>                                         goto out;
>                                 }
> @@ -2375,14 +2380,14 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                                                              mask64_data.mask)) /
>                                          sizeof(data->mask64_data.mask[0]);
>                                 if (data->mask64_data.nr > max_nr) {
> -                                       pr_warning("WARNING: PERF_RECORD_CPU_MAP mask64: nr %u exceeds payload (max %u), skipping\n",
> -                                                  data->mask64_data.nr, max_nr);
> +                                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP mask64: nr %u exceeds payload (max %u), skipping\n",
> +                                                  file_offset, data->mask64_data.nr, max_nr);
>                                         err = 0;
>                                         goto out;
>                                 }
>                         } else {
> -                               pr_warning("WARNING: PERF_RECORD_CPU_MAP: unsupported long_size %u, skipping\n",
> -                                          data->mask32_data.long_size);
> +                               pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_CPU_MAP: unsupported long_size %u, skipping\n",
> +                                          file_offset, data->mask32_data.long_size);
>                                 err = 0;
>                                 goto out;
>                         }
> @@ -2404,8 +2409,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                  * cannot clamp nr in place.  Skip the event instead.
>                  */
>                 if (event->stat_config.nr > max_nr) {
> -                       pr_warning("WARNING: PERF_RECORD_STAT_CONFIG: nr %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
> -                                  (u64)event->stat_config.nr, max_nr);
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_STAT_CONFIG: nr %" PRIu64 " exceeds payload (max %" PRIu64 "), skipping\n",
> +                                  file_offset, (u64)event->stat_config.nr, max_nr);
>                         err = 0;
>                         goto out;
>                 }
> @@ -2446,8 +2451,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                 u64 nr_entries, max_entries;
>
>                 if (event_size < sizeof(event->bpf_metadata)) {
> -                       pr_warning("WARNING: PERF_RECORD_BPF_METADATA: header.size (%u) too small, skipping\n",
> -                                  event_size);
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: header.size (%u) too small, skipping\n",
> +                                  file_offset, event_size);
>                         err = 0;
>                         break;
>                 }
> @@ -2458,7 +2463,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                  */
>                 if (strnlen(event->bpf_metadata.prog_name,
>                             BPF_PROG_NAME_LEN) == BPF_PROG_NAME_LEN) {
> -                       pr_warning("WARNING: PERF_RECORD_BPF_METADATA: prog_name not null-terminated, skipping\n");
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: prog_name not null-terminated, skipping\n",
> +                                  file_offset);
>                         err = 0;
>                         break;
>                 }
> @@ -2467,8 +2473,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                 max_entries = (event_size - sizeof(event->bpf_metadata)) /
>                               sizeof(event->bpf_metadata.entries[0]);
>                 if (nr_entries > max_entries) {
> -                       pr_warning("WARNING: PERF_RECORD_BPF_METADATA: nr_entries %" PRIu64 " exceeds max %" PRIu64 ", skipping\n",
> -                                  nr_entries, max_entries);
> +                       pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: nr_entries %" PRIu64 " exceeds max %" PRIu64 ", skipping\n",
> +                                  file_offset, nr_entries, max_entries);
>                         err = 0;
>                         break;
>                 }
> @@ -2478,7 +2484,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
>                                     BPF_METADATA_KEY_LEN) == BPF_METADATA_KEY_LEN ||
>                             strnlen(event->bpf_metadata.entries[i].value,
>                                     BPF_METADATA_VALUE_LEN) == BPF_METADATA_VALUE_LEN) {
> -                               pr_warning("WARNING: PERF_RECORD_BPF_METADATA: entry %" PRIu64 " key/value not null-terminated, skipping\n", i);
> +                               pr_warning("WARNING: at offset %#" PRIx64 ": PERF_RECORD_BPF_METADATA: entry %" PRIu64 " key/value not null-terminated, skipping\n",
> +                                          file_offset, i);
>                                 err = 0;
>                                 goto out;
>                         }
> @@ -2752,22 +2759,22 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
>             event->header.type != PERF_RECORD_HEADER_TRACING_DATA &&
>             event->header.type != PERF_RECORD_COMPRESSED &&
>             event->header.type != PERF_RECORD_HEADER_FEATURE) {
> -               pr_warning("WARNING: peek_event: event type %u size %u not aligned to %zu\n",
> -                          event->header.type,
> -                          event->header.size, sizeof(u64));
> +               pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u not aligned to %zu\n",
> +                          (u64)file_offset, perf_event__name(event->header.type),
> +                          event->header.type, event->header.size, sizeof(u64));
>                 return -1;
>         }
>
>         if (event->header.type >= PERF_RECORD_HEADER_MAX) {
> -               pr_warning("WARNING: peek_event: unsupported event type %u, skipping\n",
> -                          event->header.type);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": unsupported event type %u, skipping\n",
> +                          (u64)file_offset, event->header.type);
>                 return 0;
>         }
>
>         if (perf_event__too_small(event, &min_sz)) {
> -               pr_warning("WARNING: peek_event: %s event size %u too small (min %u)\n",
> -                          perf_event__name(event->header.type),
> -                          event->header.size, min_sz);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u too small (min %u)\n",
> +                          (u64)file_offset, perf_event__name(event->header.type),
> +                          event->header.type, event->header.size, min_sz);
>                 return -1;
>         }
>
> @@ -2883,9 +2890,9 @@ static s64 perf_session__process_event(struct perf_session *session,
>             event->header.type != PERF_RECORD_HEADER_TRACING_DATA &&
>             event->header.type != PERF_RECORD_COMPRESSED &&
>             event->header.type != PERF_RECORD_HEADER_FEATURE) {
> -               pr_err("ERROR: %s event size %u is not 8-byte aligned, aborting\n",
> -                      perf_event__name(event->header.type),
> -                      event->header.size);
> +               pr_err("ERROR: at offset %#" PRIx64 ": %s (%u) event size %u is not 8-byte aligned, aborting\n",
> +                      file_offset, perf_event__name(event->header.type),
> +                      event->header.type, event->header.size);
>                 return -EINVAL;
>         }
>
> @@ -2905,16 +2912,17 @@ static s64 perf_session__process_event(struct perf_session *session,
>          * can be safely stepped over without misaligning the stream.
>          */
>         if (perf_event__too_small(event, &min_sz)) {
> -               pr_warning("WARNING: %s event size %u too small (min %u), skipping\n",
> -                          perf_event__name(event->header.type),
> -                          event->header.size, min_sz);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": %s (%u) event size %u too small (min %u), skipping\n",
> +                          file_offset, perf_event__name(event->header.type),
> +                          event->header.type, event->header.size, min_sz);
>                 return 0;
>         }
>
>         if (session->header.needs_swap &&
>             event_swap(event, evlist__sample_id_all(evlist))) {
> -               pr_warning("WARNING: swap failed for %s event, skipping\n",
> -                          perf_event__name(event->header.type));
> +               pr_warning("WARNING: at offset %#" PRIx64 ": swap failed for %s (%u) event, skipping\n",
> +                          file_offset, perf_event__name(event->header.type),
> +                          event->header.type);
>                 return 0;
>         }
>
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/8] perf sched: Include file offset in event skip messages
  2026-06-02 23:57 ` [PATCH 3/8] perf sched: Include file offset in event skip messages Arnaldo Carvalho de Melo
@ 2026-06-03 15:13   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add the perf.data file offset to the CPU out-of-bounds and
> machine__resolve failure messages emitted when samples are skipped in
> process_sched_switch_event(), process_sched_runtime_event(), and
> timehist_sched_change_event().  Also switch event type from raw integer
> to perf_event__name() string for readability.
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/builtin-sched.c | 17 ++++++++++++-----
>  1 file changed, 12 insertions(+), 5 deletions(-)
>
> diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
> index 812a1b0d56d6e5f3..9ec8e049e19b0038 100644
> --- a/tools/perf/builtin-sched.c
> +++ b/tools/perf/builtin-sched.c
> @@ -1792,8 +1792,10 @@ static int process_sched_switch_event(const struct perf_tool *tool,
>         u32 prev_pid = perf_sample__intval(sample, "prev_pid"),
>             next_pid = perf_sample__intval(sample, "next_pid");
>
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (this_cpu < 0 || this_cpu >= MAX_CPUS) {
> -               pr_warning("Out-of-bound sample CPU %d. Skipping sample\n", this_cpu);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
> +                          sample->file_offset, this_cpu);
>                 return 0;
>         }
>
> @@ -1819,8 +1821,10 @@ static int process_sched_runtime_event(const struct perf_tool *tool,
>  {
>         struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
>
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
> -               pr_warning("Out-of-bound sample CPU %u. Skipping sample\n", sample->cpu);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %u, skipping sample\n",
> +                          sample->file_offset, sample->cpu);
>                 return 0;
>         }
>
> @@ -2786,15 +2790,18 @@ static int timehist_sched_change_event(const struct perf_tool *tool,
>         int rc = 0;
>         const char state = perf_sample__taskstate(sample, "prev_state");
>
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
> -               pr_warning("Out-of-bound sample CPU %d. Skipping sample\n", sample->cpu);
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
> +                          sample->file_offset, sample->cpu);
>                 return 0;
>         }
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_err("problem processing %d event. skipping it\n",
> -                      event->header.type);
> +               pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it\n",
> +                      perf_event__name(event->header.type), event->header.type,
> +                      sample->file_offset);
>                 rc = -1;
>                 goto out;
>         }
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages
  2026-06-02 23:57 ` [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages Arnaldo Carvalho de Melo
@ 2026-06-03 15:14   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add the perf.data file offset to the out-of-bounds CPU debug messages
> in process_sample_cpu_idle(), process_sample_cpu_frequency(),
> process_sample_sched_wakeup(), and process_sample_sched_switch().
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/builtin-timechart.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
> index 630756bebe3242dc..071987241a528ba4 100644
> --- a/tools/perf/builtin-timechart.c
> +++ b/tools/perf/builtin-timechart.c
> @@ -605,8 +605,10 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
>         u32 state  = perf_sample__intval(sample, "state");
>         u32 cpu_id = perf_sample__intval(sample, "cpu_id");
>
> +       /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %u\n",
> +                        sample->file_offset, cpu_id);
>                 return -1;
>         }
>         if (state == (u32)PWR_EVENT_EXIT)
> @@ -624,8 +626,10 @@ process_sample_cpu_frequency(struct timechart *tchart,
>         u32 state  = perf_sample__intval(sample, "state");
>         u32 cpu_id = perf_sample__intval(sample, "cpu_id");
>
> +       /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %u\n",
> +                        sample->file_offset, cpu_id);
>                 return -1;
>         }
>         p_state_change(tchart, cpu_id, sample->time, state);
> @@ -641,8 +645,10 @@ process_sample_sched_wakeup(struct timechart *tchart,
>         int waker = perf_sample__intval(sample, "common_pid");
>         int wakee = perf_sample__intval(sample, "pid");
>
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
> +                        sample->file_offset, sample->cpu);
>                 return -1;
>         }
>         sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
> @@ -658,8 +664,10 @@ process_sample_sched_switch(struct timechart *tchart,
>         int next_pid   = perf_sample__intval(sample, "next_pid");
>         u64 prev_state = perf_sample__intval(sample, "prev_state");
>
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
> +                        sample->file_offset, sample->cpu);
>                 return -1;
>         }
>         sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
> @@ -676,6 +684,7 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
>         u64 cpu_id = perf_sample__intval(sample, "cpu_id");
>         u64 value  = perf_sample__intval(sample, "value");
>
> +       /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
>                 pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
>                 return -1;
> @@ -689,6 +698,7 @@ process_sample_power_end(struct timechart *tchart,
>                          struct perf_sample *sample,
>                          const char *backtrace __maybe_unused)
>  {
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
>                 pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
>                 return -1;
> @@ -705,6 +715,7 @@ process_sample_power_frequency(struct timechart *tchart,
>         u64 cpu_id = perf_sample__intval(sample, "cpu_id");
>         u64 value  = perf_sample__intval(sample, "value");
>
> +       /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
>                 pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
>                 return -1;
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/8] perf tools: Include file offset and event type name in skip messages
  2026-06-02 23:57 ` [PATCH 5/8] perf tools: Include file offset and event type name in skip messages Arnaldo Carvalho de Melo
@ 2026-06-03 15:14   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:14 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add the perf.data file offset and use perf_event__name() instead of raw
> event type integers in the 'problem processing event, skipping it'
> messages emitted by process_sample_event() callbacks across annotate,
> c2c, diff, kmem, kvm, kwork, lock, report, script, and build-id.
>
> This lets users cross-reference skipped events with 'perf report -D'
> output.  Also add explicit #include "util/event.h" and <inttypes.h>
> where needed to avoid depending on transitive includes.
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/builtin-annotate.c |  5 +++--
>  tools/perf/builtin-c2c.c      |  5 +++--
>  tools/perf/builtin-diff.c     |  8 +++++---
>  tools/perf/builtin-kmem.c     |  6 ++++--
>  tools/perf/builtin-kvm.c      |  9 ++++++---
>  tools/perf/builtin-kwork.c    |  4 +++-
>  tools/perf/builtin-lock.c     |  6 ++++--
>  tools/perf/builtin-report.c   |  9 ++++++---
>  tools/perf/builtin-script.c   | 10 ++++++----
>  tools/perf/util/build-id.c    |  5 +++--
>  10 files changed, 43 insertions(+), 24 deletions(-)
>
> diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
> index 5f450c8093c09210..b918f9eed5fd2441 100644
> --- a/tools/perf/builtin-annotate.c
> +++ b/tools/perf/builtin-annotate.c
> @@ -288,8 +288,9 @@ static int process_sample_event(const struct perf_tool *tool,
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_warning("problem processing %d event, skipping it.\n",
> -                          event->header.type);
> +               pr_warning("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                          perf_event__name(event->header.type), event->header.type,
> +                          sample->file_offset);
>                 ret = -1;
>                 goto out_put;
>         }
> diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
> index 36f38694992386ad..d3503be9350c03bb 100644
> --- a/tools/perf/builtin-c2c.c
> +++ b/tools/perf/builtin-c2c.c
> @@ -328,8 +328,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_debug("problem processing %d event, skipping it.\n",
> -                        event->header.type);
> +               pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                        perf_event__name(event->header.type), event->header.type,
> +                        sample->file_offset);
>                 ret = -1;
>                 goto out;
>         }
> diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
> index b4ff863b304ca046..9592f44b6545bab6 100644
> --- a/tools/perf/builtin-diff.c
> +++ b/tools/perf/builtin-diff.c
> @@ -409,8 +409,9 @@ static int diff__process_sample_event(const struct perf_tool *tool,
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_warning("problem processing %d event, skipping it.\n",
> -                          event->header.type);
> +               pr_warning("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                          perf_event__name(event->header.type), event->header.type,
> +                          sample->file_offset);
>                 ret = -1;
>                 goto out;
>         }
> @@ -436,7 +437,8 @@ static int diff__process_sample_event(const struct perf_tool *tool,
>         case COMPUTE_STREAM:
>                 if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
>                                          NULL)) {
> -                       pr_debug("problem adding hist entry, skipping event\n");
> +                       pr_debug("problem adding hist entry at offset %#" PRIx64 ", skipping event\n",
> +                                sample->file_offset);
>                         goto out;
>                 }
>                 break;
> diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
> index 33585e353efe56cc..e1b2f5bc1ba8d887 100644
> --- a/tools/perf/builtin-kmem.c
> +++ b/tools/perf/builtin-kmem.c
> @@ -22,6 +22,7 @@
>  #include "util/cpumap.h"
>
>  #include "util/debug.h"
> +#include "util/event.h"
>  #include "util/string2.h"
>  #include "util/util.h"
>
> @@ -987,8 +988,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
>                                                         sample->tid);
>
>         if (thread == NULL) {
> -               pr_debug("problem processing %d event, skipping it.\n",
> -                        event->header.type);
> +               pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                        perf_event__name(event->header.type), event->header.type,
> +                        sample->file_offset);
>                 return -1;
>         }
>
> diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> index dd2ed21596aa59f9..394302ebdb161077 100644
> --- a/tools/perf/builtin-kvm.c
> +++ b/tools/perf/builtin-kvm.c
> @@ -22,6 +22,7 @@
>  #include "util/synthetic-events.h"
>  #include "util/top.h"
>  #include "util/data.h"
> +#include "util/event.h"
>  #include "util/ordered-events.h"
>  #include "util/kvm-stat.h"
>  #include "util/util.h"
> @@ -1141,14 +1142,16 @@ static int process_sample_event(const struct perf_tool *tool,
>                 return 0;
>
>         if (machine__resolve(machine, &kvm->al, sample) < 0) {
> -               pr_warning("Fail to resolve address location, skip sample.\n");
> +               pr_warning("WARNING: at offset %#" PRIx64 ": fail to resolve address location, skipping sample\n",
> +                          sample->file_offset);
>                 return 0;
>         }
>
>         thread = machine__findnew_thread(machine, sample->pid, sample->tid);
>         if (thread == NULL) {
> -               pr_debug("problem processing %d event, skipping it.\n",
> -                       event->header.type);
> +               pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                        perf_event__name(event->header.type), event->header.type,
> +                        sample->file_offset);
>                 return -1;
>         }
>
> diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c
> index 99dc293a0744726e..110de3507d48160c 100644
> --- a/tools/perf/builtin-kwork.c
> +++ b/tools/perf/builtin-kwork.c
> @@ -9,6 +9,7 @@
>  #include "perf.h"
>
>  #include "util/data.h"
> +#include "util/event.h"
>  #include "util/evlist.h"
>  #include "util/evsel.h"
>  #include "util/header.h"
> @@ -897,7 +898,8 @@ static int timehist_exit_event(struct perf_kwork *kwork,
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_debug("Problem processing event, skipping it\n");
> +               pr_debug("problem processing event at offset %#" PRIx64 ", skipping it\n",
> +                        sample->file_offset);
>                 ret = -1;
>                 goto out;
>         }
> diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
> index 94a8c35abb0bc991..5841d43be9718414 100644
> --- a/tools/perf/builtin-lock.c
> +++ b/tools/perf/builtin-lock.c
> @@ -21,6 +21,7 @@
>  #include "util/tracepoint.h"
>
>  #include "util/debug.h"
> +#include "util/event.h"
>  #include "util/session.h"
>  #include "util/tool.h"
>  #include "util/data.h"
> @@ -1433,8 +1434,9 @@ static int process_sample_event(const struct perf_tool *tool __maybe_unused,
>                                                         sample->tid);
>
>         if (thread == NULL) {
> -               pr_debug("problem processing %d event, skipping it.\n",
> -                       event->header.type);
> +               pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                        perf_event__name(event->header.type), event->header.type,
> +                        sample->file_offset);
>                 return -1;
>         }
>
> diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> index 973d97af85019e6e..cd052aa78132b65f 100644
> --- a/tools/perf/builtin-report.c
> +++ b/tools/perf/builtin-report.c
> @@ -27,6 +27,7 @@
>
>  #include "perf.h"
>  #include "util/debug.h"
> +#include "util/event.h"
>  #include "util/evlist.h"
>  #include "util/evsel.h"
>  #include "util/evswitch.h"
> @@ -284,8 +285,9 @@ static int process_sample_event(const struct perf_tool *tool,
>
>         addr_location__init(&al);
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_debug("problem processing %d event, skipping it.\n",
> -                        event->header.type);
> +               pr_debug("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                        perf_event__name(event->header.type), event->header.type,
> +                        sample->file_offset);
>                 ret = -1;
>                 goto out_put;
>         }
> @@ -332,7 +334,8 @@ static int process_sample_event(const struct perf_tool *tool,
>
>         ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
>         if (ret < 0)
> -               pr_debug("problem adding hist entry, skipping event\n");
> +               pr_debug("problem adding hist entry at offset %#" PRIx64 ", skipping event\n",
> +                        sample->file_offset);
>  out_put:
>         addr_location__exit(&al);
>         return ret;
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index 5124edf2b7a692b2..f4aa255fc3297f90 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -2693,8 +2693,9 @@ static int process_sample_event(const struct perf_tool *tool,
>                 goto out_put;
>
>         if (!al.thread && machine__resolve(machine, &al, sample) < 0) {
> -               pr_err("problem processing %d event, skipping it.\n",
> -                      event->header.type);
> +               pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                      perf_event__name(event->header.type), event->header.type,
> +                      sample->file_offset);
>                 ret = -1;
>                 goto out_put;
>         }
> @@ -2775,8 +2776,9 @@ static int process_deferred_sample_event(const struct perf_tool *tool,
>                 goto out_put;
>
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               pr_err("problem processing %d event, skipping it.\n",
> -                      event->header.type);
> +               pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                      perf_event__name(event->header.type), event->header.type,
> +                      sample->file_offset);
>                 ret = -1;
>                 goto out_put;
>         }
> diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
> index af4d874f13810ffe..8c0a9ae932aa5798 100644
> --- a/tools/perf/util/build-id.c
> +++ b/tools/perf/util/build-id.c
> @@ -10,6 +10,7 @@
>  #include "util.h" // lsdir(), mkdir_p(), rm_rf()
>  #include <dirent.h>
>  #include <errno.h>
> +#include <inttypes.h>
>  #include <stdio.h>
>  #include <sys/stat.h>
>  #include <sys/types.h>
> @@ -62,8 +63,8 @@ int build_id__mark_dso_hit(const struct perf_tool *tool __maybe_unused,
>                                                         sample->tid);
>
>         if (thread == NULL) {
> -               pr_err("problem processing %d event, skipping it.\n",
> -                       event->header.type);
> +               pr_err("problem processing %s event at offset %#" PRIx64 ", skipping it.\n",
> +                      perf_event__name(event->header.type), sample->file_offset);
>                 return -1;
>         }
>
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
  2026-06-02 23:57 ` [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain Arnaldo Carvalho de Melo
@ 2026-06-03 15:16   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:16 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, sashiko-bot,
	Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> cat_backtrace() uses open_memstream() to build a backtrace string.
> When an invalid callchain context is encountered, zfree(&p) frees
> the memstream buffer, then the exit path calls fclose(f), which
> flushes to the already-freed buffer — a use-after-free.  The function
> then returns a dangling pointer that the caller passes to a handler
> and subsequently double-frees.
>
> Fix by replacing the zfree(&p) with a 'corrupted' flag.  At the exit
> label, always fclose(f) first (which finalizes the buffer), then
> conditionally free it when corrupted.  This ensures the memstream
> contract is honored: the buffer remains valid until fclose().
>
> While here, update the machine__resolve failure message to include
> file_offset and the event type name, matching the pattern from the
> preceding series.  Also update the three legacy power event handlers
> under SUPPORT_OLD_POWER_EVENTS to include file_offset in their
> out-of-bounds CPU messages for consistency.
>
> Reported-by: sashiko-bot@kernel.org # Running on a local machine
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/builtin-timechart.c | 36 ++++++++++++++++++++++------------
>  1 file changed, 23 insertions(+), 13 deletions(-)
>
> diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
> index 071987241a528ba4..85a9ad0455aecccd 100644
> --- a/tools/perf/builtin-timechart.c
> +++ b/tools/perf/builtin-timechart.c
> @@ -489,6 +489,10 @@ static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
>         }
>  }
>
> +/*
> + * Returns a malloc'd backtrace string built via open_memstream, or NULL
> + * on error.  Caller must free() the returned pointer.
> + */
>  static char *cat_backtrace(union perf_event *event,
>                            struct perf_sample *sample,
>                            struct machine *machine)
> @@ -500,6 +504,7 @@ static char *cat_backtrace(union perf_event *event,
>         u8 cpumode = PERF_RECORD_MISC_USER;
>         struct ip_callchain *chain = sample->callchain;
>         FILE *f = open_memstream(&p, &p_len);
> +       bool corrupted = false;
>
>         if (!f) {
>                 perror("open_memstream error");
> @@ -511,8 +516,9 @@ static char *cat_backtrace(union perf_event *event,
>                 goto exit;
>
>         if (machine__resolve(machine, &al, sample) < 0) {
> -               fprintf(stderr, "problem processing %d event, skipping it.\n",
> -                       event->header.type);
> +               pr_err("problem processing %s (%u) event at offset %#" PRIx64 ", skipping it.\n",
> +                      perf_event__name(event->header.type), event->header.type,
> +                      sample->file_offset);
>                 goto exit;
>         }
>
> @@ -537,14 +543,8 @@ static char *cat_backtrace(union perf_event *event,
>                                 cpumode = PERF_RECORD_MISC_USER;
>                                 break;
>                         default:
> -                               pr_debug("invalid callchain context: "
> -                                        "%"PRId64"\n", (s64) ip);
> -
> -                               /*
> -                                * It seems the callchain is corrupted.
> -                                * Discard all.
> -                                */
> -                               zfree(&p);
> +                               pr_debug("invalid callchain context: %" PRId64 "\n", (s64) ip);
> +                               corrupted = true;
>                                 goto exit;
>                         }
>                         continue;
> @@ -561,7 +561,14 @@ static char *cat_backtrace(union perf_event *event,
>         }
>  exit:
>         addr_location__exit(&al);
> +       /*
> +        * fclose() on an open_memstream always sets p to a valid buffer,
> +        * even if nothing was written — see open_memstream(3).  So p is
> +        * never NULL after fclose and we need the flag to discard it.
> +        */
>         fclose(f);
> +       if (corrupted)
> +               zfree(&p);
>
>         return p;
>  }
> @@ -686,7 +693,8 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
>
>         /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %llu\n",
> +                        sample->file_offset, (unsigned long long)cpu_id);
>                 return -1;
>         }
>         c_state_start(cpu_id, sample->time, value);
> @@ -700,7 +708,8 @@ process_sample_power_end(struct timechart *tchart,
>  {
>         /* perf.data is untrusted input — CPU may be absent or corrupted */
>         if (sample->cpu >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu %u\n",
> +                        sample->file_offset, sample->cpu);
>                 return -1;
>         }
>         c_state_end(tchart, sample->cpu, sample->time);
> @@ -717,7 +726,8 @@ process_sample_power_frequency(struct timechart *tchart,
>
>         /* perf.data is untrusted input — cpu_id may be corrupted */
>         if (cpu_id >= MAX_CPUS) {
> -               pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
> +               pr_debug("at offset %#" PRIx64 ": out-of-bounds cpu_id %llu\n",
> +                        sample->file_offset, (unsigned long long)cpu_id);
>                 return -1;
>         }
>         p_state_change(tchart, cpu_id, sample->time, value);
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip
  2026-06-02 23:57 ` [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip Arnaldo Carvalho de Melo
@ 2026-06-03 15:17   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:17 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, sashiko-bot,
	Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> latency_switch_event(), latency_runtime_event(), and map_switch_event()
> use BUG_ON(cpu >= MAX_CPUS || cpu < 0) to validate the sample CPU.
> When PERF_SAMPLE_CPU is absent from the sample type,
> evsel__parse_sample() initializes sample->cpu to (u32)-1.  Casting
> this to int yields -1, which triggers the BUG_ON and aborts perf sched.
>
> The central CPU validation in perf_session__deliver_event() intentionally
> preserves the (u32)-1 sentinel for downstream tools like perf script
> and perf inject, so leaf callbacks must handle it themselves.
>
> Replace the three BUG_ON calls with graceful skips using pr_warning(),
> matching the existing pattern in process_sched_switch_event() and
> process_sched_runtime_event() earlier in the same file.  Include the
> file offset for cross-referencing with perf report -D.
>
> Reported-by: sashiko-bot@kernel.org # Running on a local machine
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  tools/perf/builtin-sched.c | 22 +++++++++++++++++++---
>  1 file changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
> index 9ec8e049e19b0038..81833d169470582b 100644
> --- a/tools/perf/builtin-sched.c
> +++ b/tools/perf/builtin-sched.c
> @@ -1145,7 +1145,12 @@ static int latency_switch_event(struct perf_sched *sched,
>         int cpu = sample->cpu, err = -1;
>         s64 delta;
>
> -       BUG_ON(cpu >= MAX_CPUS || cpu < 0);
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
> +       if (cpu >= MAX_CPUS || cpu < 0) {
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
> +                          sample->file_offset, cpu);
> +               return 0;
> +       }
>
>         timestamp0 = sched->cpu_last_switched[cpu];
>         sched->cpu_last_switched[cpu] = timestamp;
> @@ -1215,7 +1220,13 @@ static int latency_runtime_event(struct perf_sched *sched,
>         if (thread == NULL)
>                 return -1;
>
> -       BUG_ON(cpu >= MAX_CPUS || cpu < 0);
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
> +       if (cpu >= MAX_CPUS || cpu < 0) {
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
> +                          sample->file_offset, cpu);
> +               err = 0;
> +               goto out_put;
> +       }
>         if (!atoms) {
>                 if (thread_atoms_insert(sched, thread))
>                         goto out_put;
> @@ -1640,7 +1651,12 @@ static int map_switch_event(struct perf_sched *sched,  struct perf_sample *sampl
>         const char *str;
>         int ret = -1;
>
> -       BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0);
> +       /* perf.data is untrusted input — CPU may be absent or corrupted */
> +       if (this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0) {
> +               pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
> +                          sample->file_offset, this_cpu.cpu);
> +               return 0;
> +       }
>
>         if (this_cpu.cpu > sched->max_cpu.cpu)
>                 sched->max_cpu = this_cpu;
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data
  2026-06-02 23:57 ` [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data Arnaldo Carvalho de Melo
@ 2026-06-03 15:19   ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 15:19 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users, Arnaldo Carvalho de Melo, Claude Opus 4.6

On Tue, Jun 2, 2026 at 4:58 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
>
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
>
> Add a shell test that verifies the file_offset diagnostic messages
> work correctly when perf encounters corrupted events.
>
> The test corrupts a MMAP2 event's size field in a recorded perf.data
> file, then checks that perf report produces warning messages that
> include both the file offset (e.g. "at offset 0x2738:") and the
> event type name with numeric id (e.g. "MMAP2 (10)").
>
> This exercises the diagnostic improvements from the file_offset
> series, which retrofitted all skip/stop/error messages to include
> the position and type of the problematic event.
>
> Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks,
Ian

> ---
>  .../shell/data_file_offset_diagnostics.sh     | 82 +++++++++++++++++++
>  1 file changed, 82 insertions(+)
>  create mode 100755 tools/perf/tests/shell/data_file_offset_diagnostics.sh
>
> diff --git a/tools/perf/tests/shell/data_file_offset_diagnostics.sh b/tools/perf/tests/shell/data_file_offset_diagnostics.sh
> new file mode 100755
> index 0000000000000000..031f49480d999d8c
> --- /dev/null
> +++ b/tools/perf/tests/shell/data_file_offset_diagnostics.sh
> @@ -0,0 +1,82 @@
> +#!/bin/bash
> +# Test that perf report includes file offsets and event type names in diagnostic messages.
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# The file_offset diagnostic series adds "at offset 0x...: TYPE (N)"
> +# to all skip/stop/error messages.  This test corrupts an event's size
> +# field in a perf.data file, then verifies the resulting warning
> +# includes the file offset and event type.
> +
> +err=0
> +
> +cleanup() {
> +       [ -n "${perfdata}" ] && rm -f "${perfdata}" "${perfdata}.old"
> +       rm -f "${corrupted}" "${stderrfile}"
> +       trap - EXIT TERM INT
> +}
> +trap 'cleanup; exit 1' TERM INT
> +trap cleanup EXIT
> +
> +perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
> +corrupted=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
> +stderrfile=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
> +
> +if ! perf record -o "${perfdata}" -- perf test -w noploop 2>/dev/null; then
> +       echo "Skip: perf record failed"
> +       cleanup
> +       exit 2
> +fi
> +
> +# Find the file offset of the first MMAP2 event via perf report -D.
> +# Format: "timestamp 0xOFFSET [0xSIZE]: PERF_RECORD_MMAP2 ..."
> +mmap2_line=$(perf report -D -i "${perfdata}" 2>/dev/null | grep "PERF_RECORD_MMAP2" | head -1)
> +if [ -z "${mmap2_line}" ]; then
> +       echo "Skip: no MMAP2 events found in perf.data"
> +       cleanup
> +       exit 2
> +fi
> +
> +mmap2_offset=$(echo "${mmap2_line}" | awk '{print $2}')
> +mmap2_offset_dec=$((mmap2_offset))
> +
> +# Copy the file and corrupt the MMAP2 event's size field.
> +# perf_event_header layout: type(u32) misc(u16) size(u16)
> +# Set size to 16 (0x10 0x00 little-endian) — below the MMAP2
> +# minimum, which triggers the "event size too small" warning.
> +cp "${perfdata}" "${corrupted}"
> +printf '\x10\x00' | dd of="${corrupted}" bs=1 seek=$((mmap2_offset_dec + 6)) conv=notrunc 2>/dev/null
> +
> +perf report -i "${corrupted}" --stdio > /dev/null 2> "${stderrfile}"
> +
> +# Check that warnings include "at offset 0x..."
> +if grep -q "at offset 0x" "${stderrfile}"; then
> +       echo "File offset in diagnostics [Success]"
> +else
> +       echo "File offset in diagnostics [Failed: no 'at offset 0x...' found]"
> +       echo "  stderr was:"
> +       head -5 "${stderrfile}"
> +       err=1
> +fi
> +
> +# Check that the event type name and numeric id appear: "MMAP2 (10)"
> +if grep -q "MMAP2 (10)" "${stderrfile}"; then
> +       echo "Event type name in diagnostics [Success]"
> +else
> +       echo "Event type name in diagnostics [Failed: no 'MMAP2 (10)' found]"
> +       echo "  stderr was:"
> +       head -5 "${stderrfile}"
> +       err=1
> +fi
> +
> +# Check that the reported offset matches the actual corruption point
> +if grep -q "at offset ${mmap2_offset}:" "${stderrfile}"; then
> +       echo "Correct offset reported [Success]"
> +else
> +       echo "Correct offset reported [Failed: expected offset ${mmap2_offset}]"
> +       echo "  stderr was:"
> +       head -5 "${stderrfile}"
> +       err=1
> +fi
> +
> +cleanup
> +exit ${err}
> --
> 2.54.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes
  2026-06-03 15:06 ` [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Ian Rogers
@ 2026-06-03 19:27   ` Arnaldo Carvalho de Melo
  2026-06-03 19:44     ` Ian Rogers
  0 siblings, 1 reply; 20+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-06-03 19:27 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users

On Wed, Jun 03, 2026 at 08:06:48AM -0700, Ian Rogers wrote:
> On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> >
> > When perf report, perf sched, or perf timechart skip a malformed or
> > unprocessable event, the warning message doesn't say where in the
> > perf.data file the problem occurred.  This makes it hard to
> > cross-reference with 'perf report -D' output or to locate the
> > corrupted region with a hex editor.
> >
> > This series adds a file_offset field to struct perf_sample, set in the
> > event delivery path (including the deferred callchain path), and
> > retrofits all skip/stop/error messages to include:
> >
> >   - The file offset where the event was found
> >   - The event type name via perf_event__name() with the numeric
> >     type value in parentheses
> >
> > For example, instead of:
> >
> >   problem processing 10 event, skipping it.
> >
> > a user now sees:
> >
> >   WARNING: at offset 0x1a3f0: MMAP2 (10) event size 24 too small (min 64), skipping
> >
> > The peek_event() path, which validates events during initial file
> > scanning, also gains file offsets in its three warning messages
> > (misaligned size, unsupported type, undersized event).
> >
> > Two pre-existing bugs found by sashiko-bot are fixed:
> >
> >   - builtin-timechart.c cat_backtrace(): use-after-free and
> >     double-free when an invalid callchain context triggers zfree()
> >     before fclose() on an open_memstream buffer.  The open_memstream
> >     contract requires fclose() before the buffer can be freed — see
> >     open_memstream(3).
> 
> Fwiw, I've also been around the timechart code prompted by AI review
> and also trying to clean up tests with address sanitizer:
> https://lore.kernel.org/linux-perf-users/agzWqrn6XPEwTAsb@google.com/

Thanks for all the reviews, I'll merge this series since sashiko found
just one endianess issue with the new 'perf test' entry and the other
comments are for pre-existing problems that we've added to TODO lists,
then you can rebase that timechart leaks on top of it, ok?

- Arnaldo
 
> Thanks,
> Ian
> 
> >   - builtin-sched.c: three BUG_ON(cpu >= MAX_CPUS || cpu < 0)
> >     that abort perf sched when PERF_SAMPLE_CPU is absent from the
> >     sample type and the CPU sentinel (u32)-1 is cast to signed -1.
> >     perf.data is untrusted input — a corrupted or truncated file
> >     should produce a warning, not an abort.
> >
> > Arnaldo Carvalho de Melo (8):
> >   perf sample: Add file_offset field to struct perf_sample
> >   perf session: Include file offset in event skip/stop messages
> >   perf sched: Include file offset in event skip messages
> >   perf timechart: Include file offset in CPU bounds check messages
> >   perf tools: Include file offset and event type name in skip messages
> >   perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
> >   perf sched: Replace BUG_ON on invalid CPU with graceful skip
> >   perf test: Add file offset diagnostic test for corrupted perf.data
> >
> >  15 files changed, 261 insertions(+), 101 deletions(-)
> >
> > Developed with AI assistance (Claude/sashiko), tagged in commits.
> >
> > Best regards,
> >
> > - Arnaldo

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes
  2026-06-03 19:27   ` Arnaldo Carvalho de Melo
@ 2026-06-03 19:44     ` Ian Rogers
  0 siblings, 0 replies; 20+ messages in thread
From: Ian Rogers @ 2026-06-03 19:44 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, Ingo Molnar, Thomas Gleixner, James Clark,
	Jiri Olsa, Adrian Hunter, Clark Williams, linux-kernel,
	linux-perf-users

On Wed, Jun 3, 2026 at 12:27 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Wed, Jun 03, 2026 at 08:06:48AM -0700, Ian Rogers wrote:
> > On Tue, Jun 2, 2026 at 4:57 PM Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> > >
> > > When perf report, perf sched, or perf timechart skip a malformed or
> > > unprocessable event, the warning message doesn't say where in the
> > > perf.data file the problem occurred.  This makes it hard to
> > > cross-reference with 'perf report -D' output or to locate the
> > > corrupted region with a hex editor.
> > >
> > > This series adds a file_offset field to struct perf_sample, set in the
> > > event delivery path (including the deferred callchain path), and
> > > retrofits all skip/stop/error messages to include:
> > >
> > >   - The file offset where the event was found
> > >   - The event type name via perf_event__name() with the numeric
> > >     type value in parentheses
> > >
> > > For example, instead of:
> > >
> > >   problem processing 10 event, skipping it.
> > >
> > > a user now sees:
> > >
> > >   WARNING: at offset 0x1a3f0: MMAP2 (10) event size 24 too small (min 64), skipping
> > >
> > > The peek_event() path, which validates events during initial file
> > > scanning, also gains file offsets in its three warning messages
> > > (misaligned size, unsupported type, undersized event).
> > >
> > > Two pre-existing bugs found by sashiko-bot are fixed:
> > >
> > >   - builtin-timechart.c cat_backtrace(): use-after-free and
> > >     double-free when an invalid callchain context triggers zfree()
> > >     before fclose() on an open_memstream buffer.  The open_memstream
> > >     contract requires fclose() before the buffer can be freed — see
> > >     open_memstream(3).
> >
> > Fwiw, I've also been around the timechart code prompted by AI review
> > and also trying to clean up tests with address sanitizer:
> > https://lore.kernel.org/linux-perf-users/agzWqrn6XPEwTAsb@google.com/
>
> Thanks for all the reviews, I'll merge this series since sashiko found
> just one endianess issue with the new 'perf test' entry and the other
> comments are for pre-existing problems that we've added to TODO lists,
> then you can rebase that timechart leaks on top of it, ok?

Sure. I thought we merged the timechart issue fix with this:
https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/commit/tools/perf/builtin-timechart.c?h=perf-tools-next&id=00b36b394c15f625fa166ba3b399cad5bd5065f9
So you may well be fixing other issues I introduced while trying to
implement that fix.

Thanks,
Ian

> - Arnaldo
>
> > Thanks,
> > Ian
> >
> > >   - builtin-sched.c: three BUG_ON(cpu >= MAX_CPUS || cpu < 0)
> > >     that abort perf sched when PERF_SAMPLE_CPU is absent from the
> > >     sample type and the CPU sentinel (u32)-1 is cast to signed -1.
> > >     perf.data is untrusted input — a corrupted or truncated file
> > >     should produce a warning, not an abort.
> > >
> > > Arnaldo Carvalho de Melo (8):
> > >   perf sample: Add file_offset field to struct perf_sample
> > >   perf session: Include file offset in event skip/stop messages
> > >   perf sched: Include file offset in event skip messages
> > >   perf timechart: Include file offset in CPU bounds check messages
> > >   perf tools: Include file offset and event type name in skip messages
> > >   perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain
> > >   perf sched: Replace BUG_ON on invalid CPU with graceful skip
> > >   perf test: Add file offset diagnostic test for corrupted perf.data
> > >
> > >  15 files changed, 261 insertions(+), 101 deletions(-)
> > >
> > > Developed with AI assistance (Claude/sashiko), tagged in commits.
> > >
> > > Best regards,
> > >
> > > - Arnaldo

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-06-03 19:44 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-02 23:56 [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Arnaldo Carvalho de Melo
2026-06-02 23:57 ` [PATCH 1/8] perf sample: Add file_offset field to struct perf_sample Arnaldo Carvalho de Melo
2026-06-03 15:11   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 2/8] perf session: Include file offset in event skip/stop messages Arnaldo Carvalho de Melo
2026-06-03 15:12   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 3/8] perf sched: Include file offset in event skip messages Arnaldo Carvalho de Melo
2026-06-03 15:13   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 4/8] perf timechart: Include file offset in CPU bounds check messages Arnaldo Carvalho de Melo
2026-06-03 15:14   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 5/8] perf tools: Include file offset and event type name in skip messages Arnaldo Carvalho de Melo
2026-06-03 15:14   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 6/8] perf timechart: Fix cat_backtrace() use-after-free on corrupted callchain Arnaldo Carvalho de Melo
2026-06-03 15:16   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 7/8] perf sched: Replace BUG_ON on invalid CPU with graceful skip Arnaldo Carvalho de Melo
2026-06-03 15:17   ` Ian Rogers
2026-06-02 23:57 ` [PATCH 8/8] perf test: Add file offset diagnostic test for corrupted perf.data Arnaldo Carvalho de Melo
2026-06-03 15:19   ` Ian Rogers
2026-06-03 15:06 ` [PATCHES 0/8] perf tools: Diagnostic offsets in skip messages + two hardening fixes Ian Rogers
2026-06-03 19:27   ` Arnaldo Carvalho de Melo
2026-06-03 19:44     ` Ian Rogers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome