[RFC PATCH v1 3/8] perf/core: Implement BUILD_ID_OFFSET sample type

Ian Rogers <[email protected]>
Newsgroups org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kernel.vger.linux-perf-users
Message-ID <[email protected]>
Expose stack_map_get_build_id_offset for perf_events to use when generating
these samples, and implement the payload writing in the perf event core.

Signed-off-by: Ian Rogers <[email protected]>
---
 include/linux/bpf.h   | 13 +++++++
 kernel/bpf/stackmap.c |  2 +-
 kernel/events/core.c  | 85 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7719f6528445..fd76900a8e47 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -4209,4 +4209,17 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
 	return 0;
 }
 
+struct bpf_stack_build_id;
+#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PERF_EVENTS)
+void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
+				    u32 trace_nr, bool user, bool may_fault);
+#else
+static inline void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
+						  u32 trace_nr, bool user, bool may_fault)
+{
+	if (id_offs)
+		id_offs->status = 1; /* BPF_STACK_BUILD_ID_EMPTY */
+}
+#endif
+
 #endif /* _LINUX_BPF_H */
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 41fe87d7302f..889ceb7cf29b 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -411,7 +411,7 @@ static void stack_map_get_build_id_offset_sleepable(struct bpf_stack_build_id *i
  *     id_offs[i].build_id is zeroed out and id_offs[i].status is set to
  *     BPF_STACK_BUILD_ID_IP.
  */
-static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
+void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
 					  u32 trace_nr, bool user, bool may_fault)
 {
 	struct mmap_unlock_irq_work *work = NULL;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index ba5bd6a78fe7..97ac70441602 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2048,6 +2048,15 @@ static int __perf_event_read_size(u64 read_format, int nr_siblings)
 	return size + nr * entry;
 }
 
+
+struct perf_sample_build_id_offset {
+	u8	size;
+	u8	res1;
+	u16	res2;
+	u8	build_id[BPF_BUILD_ID_SIZE];
+	u64	offset;
+};
+
 static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
 {
 	struct perf_sample_data *data;
@@ -2086,6 +2095,11 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
 	if (sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)
 		size += sizeof(data->code_page_size);
 
+	if (sample_type & PERF_SAMPLE_BUILD_ID_OFFSET)
+		size += sizeof(struct perf_sample_build_id_offset);
+
+
+
 	event->header_size = size;
 }
 
@@ -8287,6 +8301,62 @@ void perf_output_sample(struct perf_output_handle *handle,
 	if (sample_type & PERF_SAMPLE_READ)
 		perf_output_read(handle, event);
 
+	if (sample_type & PERF_SAMPLE_BUILD_ID_OFFSET) {
+		struct bpf_stack_build_id bpf_bid = { .ip = data->ip };
+		struct perf_sample_build_id_offset bid_offset = { 0 };
+
+		bool is_user = (header->misc & PERF_RECORD_MISC_CPUMODE_MASK) ==
+			       PERF_RECORD_MISC_USER;
+
+		stack_map_get_build_id_offset(
+			&bpf_bid, /*trace_nr=*/1,
+			is_user, /*may_fault=*/false);
+		if (bpf_bid.status == BPF_STACK_BUILD_ID_VALID) {
+			bid_offset.size = BPF_BUILD_ID_SIZE;
+			memcpy(bid_offset.build_id, bpf_bid.build_id,
+				       BPF_BUILD_ID_SIZE);
+			bid_offset.offset = bpf_bid.offset;
+		} else {
+			bid_offset.offset = bpf_bid.ip;
+		}
+		perf_output_put(handle, bid_offset);
+	}
+
+	if (sample_type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) {
+		u64 nr = data->callchain ? data->callchain->nr : 0;
+		struct perf_sample_build_id_offset bid_offset;
+		struct bpf_stack_build_id bpf_bid;
+		u64 i;
+
+		perf_output_put(handle, nr);
+
+		for (i = 0; i < nr; i++) {
+			memset(&bid_offset, /*c=*/0, sizeof(bid_offset));
+			memset(&bpf_bid, /*c=*/0, sizeof(bpf_bid));
+			bpf_bid.ip = data->callchain->ip[i];
+
+			if (data->callchain->ip[i] == PERF_CONTEXT_USER) {
+				bpf_bid.status = BPF_STACK_BUILD_ID_EMPTY;
+			} else {
+				bool is_user = data->callchain->ip[i] < PERF_CONTEXT_MAX;
+
+				stack_map_get_build_id_offset(&bpf_bid, /*trace_nr=*/1,
+					      is_user, /*may_fault=*/false);
+			}
+
+			if (bpf_bid.status == BPF_STACK_BUILD_ID_VALID) {
+				bid_offset.size = BPF_BUILD_ID_SIZE;
+				memcpy(bid_offset.build_id, bpf_bid.build_id,
+			       BPF_BUILD_ID_SIZE);
+				bid_offset.offset = bpf_bid.offset;
+			} else {
+				bid_offset.offset = bpf_bid.ip;
+			}
+			perf_output_put(handle, bid_offset);
+		}
+	}
+
+
 	if (sample_type & PERF_SAMPLE_CALLCHAIN) {
 		int size = 1;
 
@@ -8632,7 +8702,7 @@ void perf_prepare_sample(struct perf_sample_data *data,
 
 	__perf_event_header__init_id(data, event, filtered_sample_type);
 
-	if (filtered_sample_type & PERF_SAMPLE_IP) {
+	if (filtered_sample_type & (PERF_SAMPLE_IP | PERF_SAMPLE_BUILD_ID_OFFSET)) {
 		data->ip = perf_instruction_pointer(event, regs);
 		data->sample_flags |= PERF_SAMPLE_IP;
 	}
@@ -8640,6 +8710,19 @@ void perf_prepare_sample(struct perf_sample_data *data,
 	if (filtered_sample_type & PERF_SAMPLE_CALLCHAIN)
 		perf_sample_save_callchain(data, event, regs);
 
+	if (filtered_sample_type & PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET) {
+		int size = 1;
+
+		if (!data->callchain)
+			data->callchain = perf_callchain(event, regs);
+
+		size += data->callchain->nr *
+			(sizeof(struct perf_sample_build_id_offset) / sizeof(u64));
+		data->dyn_size += size * sizeof(u64);
+		data->sample_flags |= PERF_SAMPLE_CALLCHAIN_BUILD_ID_OFFSET;
+	}
+
+
 	if (filtered_sample_type & PERF_SAMPLE_RAW) {
 		data->raw = NULL;
 		data->dyn_size += sizeof(u64);
-- 
2.55.0.679.g6767b8d81c-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.