4121 lines · 88.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <errno.h>#include <inttypes.h>#include "string2.h"#include <sys/param.h>#include <sys/types.h>#include <byteswap.h>#include <unistd.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>#include <bpf/libbpf.h>#include <perf/cpumap.h> #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 "vdso.h"#include "strbuf.h"#include "build-id.h"#include "data.h"#include <api/fs/fs.h>#include "asm/bug.h"#include "tool.h"#include "time-utils.h"#include "units.h"#include "util/util.h" // perf_exe()#include "cputopo.h"#include "bpf-event.h"#include "clockid.h" #include <linux/ctype.h>#include <internal/lib.h> /* * 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 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 succeded, -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 succeded, -ERR if failed. */static int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size){	u64 *p = (u64 *) set;	int i, ret; 	ret = do_write(ff, &size, sizeof(size));	if (ret < 0)		return ret; 	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {		ret = do_write(ff, p + i, sizeof(*p));		if (ret < 0)			return ret;	} 	return 0;} /* Return: 0 if succeded, -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 succeded, -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;	return 0;} static int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size){	if (size > (ssize_t)ff->size - ff->offset)		return -1; 	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){	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; 	buf = malloc(len);	if (!buf)		return NULL; 	if (!__do_read(ff, buf, len)) {		/*		 * strings are padded by zeroes		 * thus the actual strlen of buf		 * may be less than len		 */		return buf;	} 	free(buf);	return NULL;} /* Return: 0 if succeded, -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; 	set = bitmap_alloc(size);	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){	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))		return -1; 	return read_tracing_data(ff->fd, &evlist->core.entries);} 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;	}	perf_session__cache_build_ids(session); 	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;	int ret; 	ret = uname(&uts);	if (ret < 0)		return -1; 	return do_write_string(ff, uts.release);} static int write_arch(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.machine);} 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");	if (!file)		return -1; 	while (getline(&buf, &len, file) > 0) {		ret = strncmp(buf, search, strlen(search));		if (!ret)			break;	} 	if (ret) {		ret = -1;		goto done;	} 	s = buf; 	p = strchr(buf, ':');	if (p && *(p+1) == ' ' && *(p+2))		s = p + 2;	p = strchr(s, '\n');	if (p)		*p = '\0'; 	/* squash extra space characters (branding string) */	p = s;	while (*p) {		if (isspace(*p)) {			char *r = p + 1;			char *q = skip_spaces(r);			*p = ' ';			if (q != (p+1))				while ((*r++ = *q++));		}		p++;	}	ret = do_write_string(ff, s);done:	free(buf);	fclose(file);	return ret;} static int write_cpudesc(struct feat_fd *ff,		       struct evlist *evlist __maybe_unused){#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__)#define CPUINFO_PROC	{ "cpu", }#elif defined(__s390__)#define CPUINFO_PROC	{ "vendor_id", }#elif defined(__sh__)#define CPUINFO_PROC	{ "cpu type", }#elif defined(__alpha__) || defined(__mips__)#define CPUINFO_PROC	{ "cpu model", }#elif defined(__arm__)#define CPUINFO_PROC	{ "model name", "Processor", }#elif defined(__arc__)#define CPUINFO_PROC	{ "Processor", }#elif defined(__xtensa__)#define CPUINFO_PROC	{ "core ID", }#else#define CPUINFO_PROC	{ "model name", }#endif	const char *cpuinfo_procs[] = CPUINFO_PROC;#undef CPUINFO_PROC	unsigned int i; 	for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) {		int ret;		ret = __write_cpudesc(ff, cpuinfo_procs[i]);		if (ret >= 0)			return ret;	}	return -1;}  static int write_nrcpus(struct feat_fd *ff,			struct evlist *evlist __maybe_unused){	long nr;	u32 nrc, nra;	int ret; 	nrc = cpu__max_present_cpu(); 	nr = sysconf(_SC_NPROCESSORS_ONLN);	if (nr < 0)		return -1; 	nra = (u32)(nr & UINT_MAX); 	ret = do_write(ff, &nrc, sizeof(nrc));	if (ret < 0)		return ret; 	return do_write(ff, &nra, sizeof(nra));} static int write_event_desc(struct feat_fd *ff,			    struct evlist *evlist){	struct evsel *evsel;	u32 nre, nri, sz;	int ret; 	nre = evlist->core.nr_entries; 	/*	 * write number of events	 */	ret = do_write(ff, &nre, sizeof(nre));	if (ret < 0)		return ret;

Lines 1–500 of 4121.