// 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. Load more
// 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");