5799 lines · 135.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <errno.h>#include <inttypes.h>#include <limits.h>#include "string2.h"#include <sys/param.h>#include <sys/types.h>#include <byteswap.h>#include <unistd.h>#include <regex.h>#include <stdio.h>#include <stdlib.h>#include <linux/compiler.h>#include <linux/list.h>#include <linux/kernel.h>#include <linux/bitops.h>#include <linux/string.h>#include <linux/stringify.h>#include <linux/zalloc.h>#include <sys/stat.h>#include <sys/utsname.h>#include <linux/time64.h>#include <dirent.h>#ifdef HAVE_LIBBPF_SUPPORT#include <bpf/libbpf.h>#endif#include <perf/cpumap.h>#include <tools/libc_compat.h> // reallocarray #include "dso.h"#include "evlist.h"#include "evsel.h"#include "util/evsel_fprintf.h"#include "header.h"#include "memswap.h"#include "trace-event.h"#include "session.h"#include "symbol.h"#include "debug.h"#include "cpumap.h"#include "pmu.h"#include "pmus.h"#include "vdso.h"#include "strbuf.h"#include "build-id.h"#include "data.h"#include <api/fs/fs.h>#include <api/io_dir.h>#include "asm/bug.h"#include "tool.h"#include "../perf.h"#include "time-utils.h"#include "units.h"#include "util/util.h" // perf_exe()#include "cputopo.h"#include "bpf-event.h"#include "bpf-utils.h"#include "clockid.h"#include "cacheline.h" #include <linux/ctype.h>#include <internal/lib.h> #ifdef HAVE_LIBTRACEEVENT#include <event-parse.h>#endif /* * nr_ids * sizeof(struct perf_sample_id) must not overflow * size_t on 32-bit; the struct is ~104 bytes (32-bit) or * ~184 bytes (64-bit), so 1<<24 (16M) keeps the product * under 2 GB on 32-bit. * * This is a per-attribute cap only — the total across all * attributes is not capped because legitimate high-core-count * workloads (e.g. 5000 tracepoints × 4096 CPUs) can exceed * a single-attribute limit. */#define MAX_IDS_PER_ATTR	(1 << 24)/* * Cap nr_attrs to prevent resource exhaustion from crafted * files.  65536 is well beyond any real workload (perf stat * typically uses < 100 events) but prevents u64-to-int * truncation on the attr count. */#define MAX_NR_ATTRS		(1 << 16)#define MAX_BPF_DATA_LEN	(256 * 1024 * 1024)#define MAX_BPF_PROGS		131072#define MAX_CACHE_ENTRIES	32768#define MAX_GROUP_DESC		32768#define MAX_NUMA_NODES		4096#define MAX_PMU_CAPS		512#define MAX_PMU_MAPPINGS	4096#define MAX_SCHED_DOMAINS	64 /* * magic2 = "PERFILE2" * must be a numerical value to let the endianness * determine the memory layout. That way we are able * to detect endianness when reading the perf.data file * back. * * we check for legacy (PERFFILE) format. */static const char *__perf_magic1 = "PERFFILE";static const u64 __perf_magic2    = 0x32454c4946524550ULL;static const u64 __perf_magic2_sw = 0x50455246494c4532ULL; #define PERF_MAGIC	__perf_magic2#define DNAME_LEN	16 const char perf_version_string[] = PERF_VERSION; struct perf_file_attr {	struct perf_event_attr	attr;	struct perf_file_section	ids;}; void perf_header__set_feat(struct perf_header *header, int feat){	__set_bit(feat, header->adds_features);} void perf_header__clear_feat(struct perf_header *header, int feat){	__clear_bit(feat, header->adds_features);} bool perf_header__has_feat(const struct perf_header *header, int feat){	return test_bit(feat, header->adds_features);} static int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size){	ssize_t ret = writen(ff->fd, buf, size); 	if (ret != (ssize_t)size)		return ret < 0 ? (int)ret : -1;	return 0;} static int __do_write_buf(struct feat_fd *ff,  const void *buf, size_t size){	/* struct perf_event_header::size is u16 */	const size_t max_size = 0xffff - sizeof(struct perf_event_header);	size_t new_size = ff->size;	void *addr; 	if (size + ff->offset > max_size)		return -E2BIG; 	while (size > (new_size - ff->offset))		new_size <<= 1;	new_size = min(max_size, new_size); 	if (ff->size < new_size) {		addr = realloc(ff->buf, new_size);		if (!addr)			return -ENOMEM;		ff->buf = addr;		ff->size = new_size;	} 	memcpy(ff->buf + ff->offset, buf, size);	ff->offset += size; 	return 0;} /* Return: 0 if succeeded, -ERR if failed. */int do_write(struct feat_fd *ff, const void *buf, size_t size){	if (!ff->buf)		return __do_write_fd(ff, buf, size);	return __do_write_buf(ff, buf, size);} /* Return: 0 if succeeded, -ERR if failed. */static int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size){	size_t byte_size = BITS_TO_LONGS(size) * sizeof(unsigned long);	int i, ret; 	ret = do_write(ff, &size, sizeof(size));	if (ret < 0)		return ret; 	/*	 * The on-disk format uses u64 elements, but the in-memory bitmap	 * uses unsigned long, which is only 4 bytes on 32-bit architectures.	 * Copy with bounded size so the last element doesn't read past the	 * bitmap allocation when BITS_TO_LONGS(size) is odd.	 */	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {		u64 val = 0;		size_t off = i * sizeof(val); 		memcpy(&val, (char *)set + off, min(sizeof(val), byte_size - off));		ret = do_write(ff, &val, sizeof(val));		if (ret < 0)			return ret;	} 	return 0;} /* Return: 0 if succeeded, -ERR if failed. */int write_padded(struct feat_fd *ff, const void *bf,		 size_t count, size_t count_aligned){	static const char zero_buf[NAME_ALIGN];	int err = do_write(ff, bf, count); 	if (!err)		err = do_write(ff, zero_buf, count_aligned - count); 	return err;} #define string_size(str)						\	(PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) /* Return: 0 if succeeded, -ERR if failed. */static int do_write_string(struct feat_fd *ff, const char *str){	u32 len, olen;	int ret; 	olen = strlen(str) + 1;	len = PERF_ALIGN(olen, NAME_ALIGN); 	/* write len, incl. \0 */	ret = do_write(ff, &len, sizeof(len));	if (ret < 0)		return ret; 	return write_padded(ff, str, olen, len);} static int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size){	ssize_t ret = readn(ff->fd, addr, size); 	if (ret != size)		return ret < 0 ? (int)ret : -1;	ff->offset += size;	return 0;} static int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size){	memcpy(addr, ff->buf + ff->offset, size);	ff->offset += size; 	return 0;} static int __do_read(struct feat_fd *ff, void *addr, ssize_t size){	/*	 * Reject negative sizes, which on 32-bit can occur when a	 * u32 >= 0x80000000 is passed as ssize_t.  The cast to	 * ssize_t is safe because perf_header__process_sections()	 * validates that each section fits within the file size	 * before any feature callback reaches here, and only	 * feature sections (metadata like build IDs, topology, etc.)	 * use this path — these cannot legitimately approach 2GB.	 */	if (size < 0 || size > (ssize_t)ff->size - ff->offset)		return -1; 	if (!ff->buf)		return __do_read_fd(ff, addr, size);	return __do_read_buf(ff, addr, size);} static int do_read_u32(struct feat_fd *ff, u32 *addr){	int ret; 	ret = __do_read(ff, addr, sizeof(*addr));	if (ret)		return ret; 	if (ff->ph->needs_swap)		*addr = bswap_32(*addr);	return 0;} static int do_read_u64(struct feat_fd *ff, u64 *addr){	int ret; 	ret = __do_read(ff, addr, sizeof(*addr));	if (ret)		return ret; 	if (ff->ph->needs_swap)		*addr = bswap_64(*addr);	return 0;} static char *do_read_string(struct feat_fd *ff){	u32 len;	char *buf; 	if (do_read_u32(ff, &len))		return NULL; 	/* At least the null terminator. */	if (len < 1 || len > ff->size - ff->offset) {		pr_debug("do_read_string: invalid length %u (remaining %zu)\n",			 len, (size_t)(ff->size - ff->offset));		return NULL;	} 	buf = malloc(len);	if (!buf)		return NULL; 	if (!__do_read(ff, buf, len)) {		/*		 * do_write_string() writes len including the null		 * terminator, padded to NAME_ALIGN.  Ensure the		 * string is always null-terminated even if the file		 * data has been tampered with.		 */		buf[len - 1] = '\0';		return buf;	} 	free(buf);	return NULL;} /* Return: 0 if succeeded, -ERR if failed. */static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize){	unsigned long *set;	u64 size, *p;	int i, ret; 	ret = do_read_u64(ff, &size);	if (ret)		return ret; 	/* Bitmap APIs use int for nbits; reject u64 values that truncate. */	if (size > INT_MAX ||	    BITS_TO_U64(size) > (ff->size - ff->offset) / sizeof(u64)) {		pr_debug("do_read_bitmap: size %" PRIu64 " exceeds section bounds\n", size);		return -1;	} 	/*	 * bitmap_zalloc() allocates in unsigned long units, which are only	 * 4 bytes on 32-bit architectures. The read loop below casts the	 * buffer to u64 * and writes 8-byte elements, so allocate in u64	 * units to ensure the buffer is large enough.	 */	set = calloc(BITS_TO_U64(size), sizeof(u64));	if (!set)		return -ENOMEM; 	p = (u64 *) set; 	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {		ret = do_read_u64(ff, p + i);		if (ret < 0) {			free(set);			return ret;		}	} 	*pset  = set;	*psize = size;	return 0;} static int write_tracing_data(struct feat_fd *ff,			      struct evlist *evlist __maybe_unused){	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))		return -1; #ifdef HAVE_LIBTRACEEVENT	return read_tracing_data(ff->fd, &evlist->core.entries);#else	pr_err("ERROR: Trying to write tracing data without libtraceevent support.\n");	return -1;#endif} static int write_build_id(struct feat_fd *ff,			  struct evlist *evlist __maybe_unused){	struct perf_session *session;	int err; 	session = container_of(ff->ph, struct perf_session, header); 	if (!perf_session__read_build_ids(session, true))		return -1; 	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))		return -1; 	err = perf_session__write_buildid_table(session, ff);	if (err < 0) {		pr_debug("failed to write buildid table\n");		return err;	} 	return 0;} static int write_hostname(struct feat_fd *ff,			  struct evlist *evlist __maybe_unused){	struct utsname uts;	int ret; 	ret = uname(&uts);	if (ret < 0)		return -1; 	return do_write_string(ff, uts.nodename);} static int write_osrelease(struct feat_fd *ff,			   struct evlist *evlist __maybe_unused){	struct utsname uts;	const char *release = NULL; 	if (evlist->session)		release = perf_env__os_release(perf_session__env(evlist->session)); 	if (!release) {		int ret = uname(&uts); 		if (ret < 0)			return -1;		release = uts.release;	}	return do_write_string(ff, release);} static int write_arch(struct feat_fd *ff, struct evlist *evlist){	struct utsname uts;	const char *arch = NULL; 	if (evlist->session)		arch = perf_env__arch(perf_session__env(evlist->session)); 	if (!arch) {		int ret = uname(&uts); 		if (ret < 0)			return -1;		arch = uts.machine;	}	return do_write_string(ff, arch);} static int write_e_machine(struct feat_fd *ff, struct evlist *evlist){	/* e_machine expanded from 16 to 32-bits for alignment. */	uint32_t e_flags;	uint32_t e_machine = perf_session__e_machine(evlist->session, &e_flags);	int ret; 	ret = do_write(ff, &e_machine, sizeof(e_machine));	if (ret)		return ret; 	return do_write(ff, &e_flags, sizeof(e_flags));} static int write_version(struct feat_fd *ff,			 struct evlist *evlist __maybe_unused){	return do_write_string(ff, perf_version_string);} static int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc){	FILE *file;	char *buf = NULL;	char *s, *p;	const char *search = cpuinfo_proc;	size_t len = 0;	int ret = -1; 	if (!search)		return -1; 	file = fopen("/proc/cpuinfo", "r");

Lines 1–500 of 5799.