18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/types.h>
38c2ecf20Sopenharmony_ci#include <linux/string.h>
48c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "../../../util/event.h"
78c2ecf20Sopenharmony_ci#include "../../../util/synthetic-events.h"
88c2ecf20Sopenharmony_ci#include "../../../util/machine.h"
98c2ecf20Sopenharmony_ci#include "../../../util/tool.h"
108c2ecf20Sopenharmony_ci#include "../../../util/map.h"
118c2ecf20Sopenharmony_ci#include "../../../util/debug.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#if defined(__x86_64__)
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciint perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
168c2ecf20Sopenharmony_ci				       perf_event__handler_t process,
178c2ecf20Sopenharmony_ci				       struct machine *machine)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	int rc = 0;
208c2ecf20Sopenharmony_ci	struct map *pos;
218c2ecf20Sopenharmony_ci	struct maps *kmaps = &machine->kmaps;
228c2ecf20Sopenharmony_ci	union perf_event *event = zalloc(sizeof(event->mmap) +
238c2ecf20Sopenharmony_ci					 machine->id_hdr_size);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if (!event) {
268c2ecf20Sopenharmony_ci		pr_debug("Not enough memory synthesizing mmap event "
278c2ecf20Sopenharmony_ci			 "for extra kernel maps\n");
288c2ecf20Sopenharmony_ci		return -1;
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	maps__for_each_entry(kmaps, pos) {
328c2ecf20Sopenharmony_ci		struct kmap *kmap;
338c2ecf20Sopenharmony_ci		size_t size;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci		if (!__map__is_extra_kernel_map(pos))
368c2ecf20Sopenharmony_ci			continue;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci		kmap = map__kmap(pos);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci		size = sizeof(event->mmap) - sizeof(event->mmap.filename) +
418c2ecf20Sopenharmony_ci		       PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
428c2ecf20Sopenharmony_ci		       machine->id_hdr_size;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci		memset(event, 0, size);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci		event->mmap.header.type = PERF_RECORD_MMAP;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		/*
498c2ecf20Sopenharmony_ci		 * kernel uses 0 for user space maps, see kernel/perf_event.c
508c2ecf20Sopenharmony_ci		 * __perf_event_mmap
518c2ecf20Sopenharmony_ci		 */
528c2ecf20Sopenharmony_ci		if (machine__is_host(machine))
538c2ecf20Sopenharmony_ci			event->header.misc = PERF_RECORD_MISC_KERNEL;
548c2ecf20Sopenharmony_ci		else
558c2ecf20Sopenharmony_ci			event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		event->mmap.header.size = size;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		event->mmap.start = pos->start;
608c2ecf20Sopenharmony_ci		event->mmap.len   = pos->end - pos->start;
618c2ecf20Sopenharmony_ci		event->mmap.pgoff = pos->pgoff;
628c2ecf20Sopenharmony_ci		event->mmap.pid   = machine->pid;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		strlcpy(event->mmap.filename, kmap->name, PATH_MAX);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		if (perf_tool__process_synth_event(tool, event, machine,
678c2ecf20Sopenharmony_ci						   process) != 0) {
688c2ecf20Sopenharmony_ci			rc = -1;
698c2ecf20Sopenharmony_ci			break;
708c2ecf20Sopenharmony_ci		}
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	free(event);
748c2ecf20Sopenharmony_ci	return rc;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#endif
78