[RFC PATCH v1 7/8] perf record: Add --buildid-offset option

Ian Rogers <[email protected]> Fri, 7 Aug 2026 00:18:17 -0700
Newsgroups org.kernel.vger.linux-perf-users,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add the --buildid-offset flag to perf record to natively request
PERF_SAMPLE_BUILD_ID_OFFSET and PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET
from the kernel. This configures the evsel attributes by replacing
the standard IP and CALLCHAIN bits with the build ID offset equivalents.

Signed-off-by: Ian Rogers <[email protected]>
---
 tools/perf/builtin-record.c |  7 +++++++
 tools/perf/util/evsel.c     | 11 +++++++++++
 tools/perf/util/record.h    |  1 +
 3 files changed, 19 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f58d7e3c7879..9ff9cfc06278 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -3608,6 +3608,8 @@ static struct option __record_options[] = {
 		   "file", "vmlinux pathname"),
 	OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
 		    "Record build-id of all DSOs regardless of hits"),
+	OPT_BOOLEAN(0, "buildid-offset", &record.opts.buildid_offset,
+		    "Record build id offset instead of IP"),
 	OPT_BOOLEAN_SET(0, "buildid-mmap", &record.buildid_mmap, &record.buildid_mmap_set,
 			"Record build-id in mmap events and skip build-id processing."),
 	OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename,
@@ -4166,6 +4168,11 @@ int cmd_record(int argc, const char **argv)
 		rec->no_buildid_cache = true;
 	}
 
+	if (rec->opts.buildid_offset) {
+		/* Do not drop mmap events here so we can generate build ids later */
+		/* rec->opts.synth &= ~PERF_SYNTH_MMAP; */
+	}
+
 	if (rec->opts.record_cgroup && !perf_can_record_cgroup()) {
 		pr_err("Kernel has no cgroup sampling support.\n");
 		err = -EINVAL;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d9a07f5825e8..587f0fa41cce 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1744,6 +1744,17 @@ void evsel__config(struct evsel *evsel, const struct record_opts *opts,
 	if (opts->sample_transaction)
 		evsel__set_sample_bit(evsel, TRANSACTION);
 
+	if (opts->buildid_offset) {
+		if (evsel->core.attr.sample_type & PERF_SAMPLE_IP) {
+			evsel__reset_sample_bit(evsel, IP);
+			evsel__set_sample_bit(evsel, BUILD_ID_OFFSET);
+		}
+		if (evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+			evsel__reset_sample_bit(evsel, CALLCHAIN);
+			evsel__set_sample_bit(evsel, CALLCHAIN_BUILD_ID_OFFSET);
+		}
+	}
+
 	if (opts->running_time) {
 		evsel->core.attr.read_format |=
 			PERF_FORMAT_TOTAL_TIME_ENABLED |
diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
index 93627c9a7338..a8cec7db150e 100644
--- a/tools/perf/util/record.h
+++ b/tools/perf/util/record.h
@@ -55,6 +55,7 @@ struct record_opts {
 	bool	      kcore;
 	bool	      text_poke;
 	bool	      build_id;
+	bool	      buildid_offset;
 	unsigned int  freq;
 	unsigned int  mmap_pages;
 	unsigned int  auxtrace_mmap_pages;
-- 
2.55.0.679.g6767b8d81c-goog