[PATCH v2 2/8] perf/core: Add BUILD_ID_OFFSET to UAPI
From: Ian Rogers
Date: Fri Oct 02 2026 - 13:44:42 EST
Introduce PERF_SAMPLE_BUILD_ID_OFFSET and
PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
include/uapi/linux/perf_event.h | 34 +++++++++++++++++++++++----
tools/include/uapi/linux/perf_event.h | 34 +++++++++++++++++++++++----
tools/lib/perf/include/perf/event.h | 33 +++++++++++++++++++++++++-
tools/perf/util/session.c | 34 ++++++++++++++++++++++++++-
4 files changed, 125 insertions(+), 10 deletions(-)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 035b4b416ce3..4157aa8a243a 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -165,8 +165,10 @@ enum perf_event_sample_format {
PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22,
PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23,
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
+ PERF_SAMPLE_BUILD_ID_OFFSET = 1U << 25,
+ PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET = 1U << 26,
- PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
+ PERF_SAMPLE_MAX = 1U << 27, /* non-ABI */
};
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
@@ -815,7 +817,8 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_EXACT_IP - PERF_RECORD_SAMPLE of precise events
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT - PERF_RECORD_SWITCH* events
- * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 event
+ * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 and
+ * PERF_RECORD_CALLCHAIN_DEFERRED events
*
*
* PERF_RECORD_MISC_EXACT_IP:
@@ -827,7 +830,7 @@ struct perf_event_mmap_page {
* Indicates that thread was preempted in TASK_RUNNING state.
*
* PERF_RECORD_MISC_MMAP_BUILD_ID:
- * Indicates that mmap2 event carries build ID data.
+ * Indicates that mmap2 or deferred callchain event carries build ID data.
*/
#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
#define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14)
@@ -1054,6 +1057,23 @@ enum perf_event_type {
* { u64 code_page_size;} && PERF_SAMPLE_CODE_PAGE_SIZE
* { u64 size;
* char data[size]; } && PERF_SAMPLE_AUX
+ * { union {
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * };
+ * struct {
+ * u64 zero;
+ * u64 context;
+ * u64 cookie;
+ * u64 ip;
+ * }; && attr.defer_callchain
+ * }; } && PERF_SAMPLE_BUILD_ID_OFFSET
+ * { u64 nr;
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * }[nr]; } && PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET
* };
*/
PERF_RECORD_SAMPLE = 9,
@@ -1260,7 +1280,13 @@ enum perf_event_type {
* struct perf_event_header header;
* u64 cookie;
* u64 nr;
- * u64 ips[nr];
+ * union {
+ * u64 ips[nr];
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * }[nr]; && (header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)
+ * };
* struct sample_id sample_id;
* };
*/
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index 63f8866479a3..56b0cd504a3d 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -165,8 +165,10 @@ enum perf_event_sample_format {
PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22,
PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23,
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
+ PERF_SAMPLE_BUILD_ID_OFFSET = 1U << 25,
+ PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET = 1U << 26,
- PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */
+ PERF_SAMPLE_MAX = 1U << 27, /* non-ABI */
};
#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT)
@@ -840,7 +842,8 @@ struct perf_event_mmap_page {
*
* PERF_RECORD_MISC_EXACT_IP - PERF_RECORD_SAMPLE of precise events
* PERF_RECORD_MISC_SWITCH_OUT_PREEMPT - PERF_RECORD_SWITCH* events
- * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 event
+ * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 and
+ * PERF_RECORD_CALLCHAIN_DEFERRED events
*
*
* PERF_RECORD_MISC_EXACT_IP:
@@ -852,7 +855,7 @@ struct perf_event_mmap_page {
* Indicates that thread was preempted in TASK_RUNNING state.
*
* PERF_RECORD_MISC_MMAP_BUILD_ID:
- * Indicates that mmap2 event carries build ID data.
+ * Indicates that mmap2 or deferred callchain event carries build ID data.
*/
#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
#define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14)
@@ -1095,6 +1098,23 @@ enum perf_event_type {
* { u64 code_page_size;} && PERF_SAMPLE_CODE_PAGE_SIZE
* { u64 size;
* char data[size]; } && PERF_SAMPLE_AUX
+ * { union {
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * };
+ * struct {
+ * u64 zero;
+ * u64 context;
+ * u64 cookie;
+ * u64 ip;
+ * }; && attr.defer_callchain
+ * }; } && PERF_SAMPLE_BUILD_ID_OFFSET
+ * { u64 nr;
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * }[nr]; } && PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET
* };
*/
PERF_RECORD_SAMPLE = 9,
@@ -1301,7 +1321,13 @@ enum perf_event_type {
* struct perf_event_header header;
* u64 cookie;
* u64 nr;
- * u64 ips[nr];
+ * union {
+ * u64 ips[nr];
+ * struct {
+ * struct perf_build_id bid;
+ * u64 offset;
+ * }[nr]; && (header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID)
+ * };
* struct sample_id sample_id;
* };
*/
diff --git a/tools/lib/perf/include/perf/event.h b/tools/lib/perf/include/perf/event.h
index 173eab43c148..3d35a82cccb0 100644
--- a/tools/lib/perf/include/perf/event.h
+++ b/tools/lib/perf/include/perf/event.h
@@ -3,11 +3,24 @@
#define __LIBPERF_EVENT_H
#include <linux/perf_event.h>
+#include <linux/stddef.h>
#include <linux/types.h>
#include <linux/limits.h>
#include <linux/bpf.h>
#include <sys/types.h> /* pid_t */
+#ifndef __DECLARE_FLEX_ARRAY
+#ifdef __cplusplus
+#define __DECLARE_FLEX_ARRAY(T, member) T member[0]
+#else
+#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
+ struct { \
+ struct { } __empty_ ## NAME; \
+ TYPE NAME[]; \
+ }
+#endif
+#endif
+
/*
* Verify the full field fits within the event, not just its start offset.
* Only valid for fixed-size scalar fields — for trailing arrays like
@@ -162,6 +175,21 @@ struct perf_record_switch {
__u32 next_prev_tid;
};
+struct perf_sample_build_id_offset {
+ union {
+ struct perf_build_id bid;
+ struct {
+ __u64 zero;
+ __u64 context;
+ __u64 cookie;
+ };
+ };
+ union {
+ __u64 offset;
+ __u64 ip;
+ };
+};
+
struct perf_record_callchain_deferred {
struct perf_event_header header;
/*
@@ -171,7 +199,10 @@ struct perf_record_callchain_deferred {
*/
__u64 cookie;
__u64 nr;
- __u64 ips[];
+ union {
+ __DECLARE_FLEX_ARRAY(__u64, ips);
+ __DECLARE_FLEX_ARRAY(struct perf_sample_build_id_offset, bids);
+ };
};
struct perf_record_header_attr {
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 7fea9e72726c..5e113070b3c6 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1186,6 +1186,38 @@ static int perf_event__header_feature_swap(union perf_event *event,
return 0;
}
+static int perf_event__callchain_deferred_swap(union perf_event *event,
+ bool sample_id_all)
+{
+ u64 nr, max_nr;
+
+ if (!(event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID))
+ return perf_event__all64_swap(event, sample_id_all);
+
+ if (event->header.size < sizeof(event->callchain_deferred))
+ return -1;
+
+ event->callchain_deferred.cookie = bswap_64(event->callchain_deferred.cookie);
+ event->callchain_deferred.nr = bswap_64(event->callchain_deferred.nr);
+
+ nr = event->callchain_deferred.nr;
+ max_nr = (event->header.size - sizeof(event->callchain_deferred)) /
+ sizeof(event->callchain_deferred.bids[0]);
+ if (nr > max_nr)
+ return -1;
+
+ for (u64 i = 0; i < nr; i++) {
+ struct perf_sample_build_id_offset *bid =
+ &event->callchain_deferred.bids[i];
+
+ bid->offset = bswap_64(bid->offset);
+ }
+
+ if (sample_id_all)
+ swap_sample_id_all(event, &event->callchain_deferred.bids[nr]);
+ return 0;
+}
+
typedef int (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);
@@ -1211,7 +1243,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_BPF_EVENT] = perf_event__bpf_event_swap,
[PERF_RECORD_TEXT_POKE] = perf_event__text_poke_swap,
[PERF_RECORD_AUX_OUTPUT_HW_ID] = perf_event__all64_swap,
- [PERF_RECORD_CALLCHAIN_DEFERRED] = perf_event__all64_swap,
+ [PERF_RECORD_CALLCHAIN_DEFERRED] = perf_event__callchain_deferred_swap,
[PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
[PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
--
2.56.0.rc1.315.gc6ed9934b7-goog