#define _FILE_OFFSET_BITS 64 #include "util.h"#include <sys/types.h>#include <byteswap.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <linux/list.h>#include <linux/kernel.h>#include <linux/bitops.h>#include <sys/utsname.h> #include "evlist.h"#include "evsel.h"#include "header.h"#include "../perf.h"#include "trace-event.h"#include "session.h"#include "symbol.h"#include "debug.h"#include "cpumap.h" static bool no_buildid_cache = false; static int event_count;static struct perf_trace_event_type *events; static u32 header_argc;static const char **header_argv; int perf_header__push_event(u64 id, const char *name){ struct perf_trace_event_type *nevents; if (strlen(name) > MAX_EVENT_NAME) pr_warning("Event %s will be truncated\n", name); nevents = realloc(events, (event_count + 1) * sizeof(*events)); if (nevents == NULL) return -ENOMEM; events = nevents; memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); events[event_count].event_id = id; strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); event_count++; return 0;} char *perf_header__find_event(u64 id){ int i; for (i = 0 ; i < event_count; i++) { if (events[i].event_id == id) return events[i].name; } return NULL;} /* * 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 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(int fd, const void *buf, size_t size){ while (size) { int ret = write(fd, buf, size); if (ret < 0) return -errno; size -= ret; buf += ret; } return 0;} #define NAME_ALIGN 64 static int write_padded(int fd, const void *bf, size_t count, size_t count_aligned){ static const char zero_buf[NAME_ALIGN]; int err = do_write(fd, bf, count); if (!err) err = do_write(fd, zero_buf, count_aligned - count); return err;} static int do_write_string(int fd, const char *str){ u32 len, olen; int ret; olen = strlen(str) + 1; len = ALIGN(olen, NAME_ALIGN); /* write len, incl. \0 */ ret = do_write(fd, &len, sizeof(len)); if (ret < 0) return ret; return write_padded(fd, str, olen, len);} static char *do_read_string(int fd, struct perf_header *ph){ ssize_t sz, ret; u32 len; char *buf; sz = read(fd, &len, sizeof(len)); if (sz < (ssize_t)sizeof(len)) return NULL; if (ph->needs_swap) len = bswap_32(len); buf = malloc(len); if (!buf) return NULL; ret = read(fd, buf, len); if (ret == (ssize_t)len) { /* * strings are padded by zeroes * thus the actual strlen of buf * may be less than len */ return buf; } free(buf); return NULL;} intperf_header__set_cmdline(int argc, const char **argv){ int i; header_argc = (u32)argc; /* do not include NULL termination */ header_argv = calloc(argc, sizeof(char *)); if (!header_argv) return -ENOMEM; /* * must copy argv contents because it gets moved * around during option parsing */ for (i = 0; i < argc ; i++) header_argv[i] = argv[i]; return 0;} #define dsos__for_each_with_build_id(pos, head) \ list_for_each_entry(pos, head, node) \ if (!pos->has_build_id) \ continue; \ else static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, u16 misc, int fd){ struct dso *pos; dsos__for_each_with_build_id(pos, head) { int err; struct build_id_event b; size_t len; if (!pos->hit) continue; len = pos->long_name_len + 1; len = ALIGN(len, NAME_ALIGN); memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); b.pid = pid; b.header.misc = misc; b.header.size = sizeof(b) + len; err = do_write(fd, &b, sizeof(b)); if (err < 0) return err; err = write_padded(fd, pos->long_name, pos->long_name_len + 1, len); if (err < 0) return err; } return 0;} static int machine__write_buildid_table(struct machine *machine, int fd){ int err; u16 kmisc = PERF_RECORD_MISC_KERNEL, umisc = PERF_RECORD_MISC_USER; if (!machine__is_host(machine)) { kmisc = PERF_RECORD_MISC_GUEST_KERNEL; umisc = PERF_RECORD_MISC_GUEST_USER; } err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, kmisc, fd); if (err == 0) err = __dsos__write_buildid_table(&machine->user_dsos, machine->pid, umisc, fd); return err;} static int dsos__write_buildid_table(struct perf_header *header, int fd){ struct perf_session *session = container_of(header, struct perf_session, header); struct rb_node *nd; int err = machine__write_buildid_table(&session->host_machine, fd); if (err) return err; for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); err = machine__write_buildid_table(pos, fd); if (err) break; } return err;} int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms){ const size_t size = PATH_MAX; char *realname, *filename = zalloc(size), *linkname = zalloc(size), *targetname; int len, err = -1; if (is_kallsyms) { if (symbol_conf.kptr_restrict) { pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); return 0; } realname = (char *)name; } else realname = realpath(name, NULL); if (realname == NULL || filename == NULL || linkname == NULL) goto out_free; len = scnprintf(filename, size, "%s%s%s", debugdir, is_kallsyms ? "/" : "", realname); if (mkdir_p(filename, 0755)) goto out_free; snprintf(filename + len, size - len, "/%s", sbuild_id); if (access(filename, F_OK)) { if (is_kallsyms) { if (copyfile("/proc/kallsyms", filename)) goto out_free; } else if (link(realname, filename) && copyfile(name, filename)) goto out_free; } len = scnprintf(linkname, size, "%s/.build-id/%.2s", debugdir, sbuild_id); if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) goto out_free; snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); targetname = filename + strlen(debugdir) - 5; memcpy(targetname, "../..", 5); if (symlink(targetname, linkname) == 0) err = 0;out_free: if (!is_kallsyms) free(realname); free(filename); free(linkname); return err;} static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, const char *name, const char *debugdir, bool is_kallsyms){ char sbuild_id[BUILD_ID_SIZE * 2 + 1]; build_id__sprintf(build_id, build_id_size, sbuild_id); return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);} int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir){ const size_t size = PATH_MAX; char *filename = zalloc(size), *linkname = zalloc(size); int err = -1; if (filename == NULL || linkname == NULL) goto out_free; snprintf(linkname, size, "%s/.build-id/%.2s/%s", debugdir, sbuild_id, sbuild_id + 2); if (access(linkname, F_OK)) goto out_free; if (readlink(linkname, filename, size - 1) < 0) goto out_free; if (unlink(linkname)) goto out_free; /* * Since the link is relative, we must make it absolute: */ snprintf(linkname, size, "%s/.build-id/%.2s/%s", debugdir, sbuild_id, filename); if (unlink(linkname)) goto out_free; err = 0;out_free: free(filename); free(linkname); return err;} static int dso__cache_build_id(struct dso *dso, const char *debugdir){ bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), dso->long_name, debugdir, is_kallsyms);} static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir){ struct dso *pos; int err = 0; dsos__for_each_with_build_id(pos, head) if (dso__cache_build_id(pos, debugdir)) err = -1; return err;} static int machine__cache_build_ids(struct machine *machine, const char *debugdir){ int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); return ret;} static int perf_session__cache_build_ids(struct perf_session *session){ struct rb_node *nd; int ret; char debugdir[PATH_MAX]; snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) return -1; ret = machine__cache_build_ids(&session->host_machine, debugdir); for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__cache_build_ids(pos, debugdir); } return ret ? -1 : 0;} static bool machine__read_build_ids(struct machine *machine, bool with_hits){ bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); return ret;} static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits){ struct rb_node *nd; bool ret = machine__read_build_ids(&session->host_machine, with_hits); for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__read_build_ids(pos, with_hits); } return ret;} static int write_tracing_data(int fd, struct perf_header *h __used, struct perf_evlist *evlist){ return read_tracing_data(fd, &evlist->entries);} static int write_build_id(int fd, struct perf_header *h, struct perf_evlist *evlist __used){ struct perf_session *session; int err; session = container_of(h, struct perf_session, header); if (!perf_session__read_build_ids(session, true)) return -1; err = dsos__write_buildid_table(h, fd); if (err < 0) { pr_debug("failed to write buildid table\n"); return err; } if (!no_buildid_cache) perf_session__cache_build_ids(session); return 0;} static int write_hostname(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used){ struct utsname uts; int ret; ret = uname(&uts); if (ret < 0) return -1; return do_write_string(fd, uts.nodename);} static int write_osrelease(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used){ struct utsname uts; int ret; ret = uname(&uts); if (ret < 0) return -1; return do_write_string(fd, uts.release);} static int write_arch(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used){ struct utsname uts; int ret; Lines 1–500 of 2447. Load more
#define _FILE_OFFSET_BITS 64 #include "util.h" #include <sys/types.h> #include <byteswap.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <linux/list.h> #include <linux/kernel.h> #include <linux/bitops.h> #include <sys/utsname.h> #include "evlist.h" #include "evsel.h" #include "header.h" #include "../perf.h" #include "trace-event.h" #include "session.h" #include "symbol.h" #include "debug.h" #include "cpumap.h" static bool no_buildid_cache = false; static int event_count; static struct perf_trace_event_type *events; static u32 header_argc; static const char **header_argv; int perf_header__push_event(u64 id, const char *name) { struct perf_trace_event_type *nevents; if (strlen(name) > MAX_EVENT_NAME) pr_warning("Event %s will be truncated\n", name); nevents = realloc(events, (event_count + 1) * sizeof(*events)); if (nevents == NULL) return -ENOMEM; events = nevents; memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); events[event_count].event_id = id; strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); event_count++; return 0; } char *perf_header__find_event(u64 id) { int i; for (i = 0 ; i < event_count; i++) { if (events[i].event_id == id) return events[i].name; } return NULL; } /* * 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 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(int fd, const void *buf, size_t size) { while (size) { int ret = write(fd, buf, size); if (ret < 0) return -errno; size -= ret; buf += ret; } return 0; } #define NAME_ALIGN 64 static int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) { static const char zero_buf[NAME_ALIGN]; int err = do_write(fd, bf, count); if (!err) err = do_write(fd, zero_buf, count_aligned - count); return err; } static int do_write_string(int fd, const char *str) { u32 len, olen; int ret; olen = strlen(str) + 1; len = ALIGN(olen, NAME_ALIGN); /* write len, incl. \0 */ ret = do_write(fd, &len, sizeof(len)); if (ret < 0) return ret; return write_padded(fd, str, olen, len); } static char *do_read_string(int fd, struct perf_header *ph) { ssize_t sz, ret; u32 len; char *buf; sz = read(fd, &len, sizeof(len)); if (sz < (ssize_t)sizeof(len)) return NULL; if (ph->needs_swap) len = bswap_32(len); buf = malloc(len); if (!buf) return NULL; ret = read(fd, buf, len); if (ret == (ssize_t)len) { /* * strings are padded by zeroes * thus the actual strlen of buf * may be less than len */ return buf; } free(buf); return NULL; } int perf_header__set_cmdline(int argc, const char **argv) { int i; header_argc = (u32)argc; /* do not include NULL termination */ header_argv = calloc(argc, sizeof(char *)); if (!header_argv) return -ENOMEM; /* * must copy argv contents because it gets moved * around during option parsing */ for (i = 0; i < argc ; i++) header_argv[i] = argv[i]; return 0; } #define dsos__for_each_with_build_id(pos, head) \ list_for_each_entry(pos, head, node) \ if (!pos->has_build_id) \ continue; \ else static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, u16 misc, int fd) { struct dso *pos; dsos__for_each_with_build_id(pos, head) { int err; struct build_id_event b; size_t len; if (!pos->hit) continue; len = pos->long_name_len + 1; len = ALIGN(len, NAME_ALIGN); memset(&b, 0, sizeof(b)); memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); b.pid = pid; b.header.misc = misc; b.header.size = sizeof(b) + len; err = do_write(fd, &b, sizeof(b)); if (err < 0) return err; err = write_padded(fd, pos->long_name, pos->long_name_len + 1, len); if (err < 0) return err; } return 0; } static int machine__write_buildid_table(struct machine *machine, int fd) { int err; u16 kmisc = PERF_RECORD_MISC_KERNEL, umisc = PERF_RECORD_MISC_USER; if (!machine__is_host(machine)) { kmisc = PERF_RECORD_MISC_GUEST_KERNEL; umisc = PERF_RECORD_MISC_GUEST_USER; } err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, kmisc, fd); if (err == 0) err = __dsos__write_buildid_table(&machine->user_dsos, machine->pid, umisc, fd); return err; } static int dsos__write_buildid_table(struct perf_header *header, int fd) { struct perf_session *session = container_of(header, struct perf_session, header); struct rb_node *nd; int err = machine__write_buildid_table(&session->host_machine, fd); if (err) return err; for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); err = machine__write_buildid_table(pos, fd); if (err) break; } return err; } int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms) { const size_t size = PATH_MAX; char *realname, *filename = zalloc(size), *linkname = zalloc(size), *targetname; int len, err = -1; if (is_kallsyms) { if (symbol_conf.kptr_restrict) { pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); return 0; } realname = (char *)name; } else realname = realpath(name, NULL); if (realname == NULL || filename == NULL || linkname == NULL) goto out_free; len = scnprintf(filename, size, "%s%s%s", debugdir, is_kallsyms ? "/" : "", realname); if (mkdir_p(filename, 0755)) goto out_free; snprintf(filename + len, size - len, "/%s", sbuild_id); if (access(filename, F_OK)) { if (is_kallsyms) { if (copyfile("/proc/kallsyms", filename)) goto out_free; } else if (link(realname, filename) && copyfile(name, filename)) goto out_free; } len = scnprintf(linkname, size, "%s/.build-id/%.2s", debugdir, sbuild_id); if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) goto out_free; snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); targetname = filename + strlen(debugdir) - 5; memcpy(targetname, "../..", 5); if (symlink(targetname, linkname) == 0) err = 0; out_free: if (!is_kallsyms) free(realname); free(filename); free(linkname); return err; } static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, const char *name, const char *debugdir, bool is_kallsyms) { char sbuild_id[BUILD_ID_SIZE * 2 + 1]; build_id__sprintf(build_id, build_id_size, sbuild_id); return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); } int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) { const size_t size = PATH_MAX; char *filename = zalloc(size), *linkname = zalloc(size); int err = -1; if (filename == NULL || linkname == NULL) goto out_free; snprintf(linkname, size, "%s/.build-id/%.2s/%s", debugdir, sbuild_id, sbuild_id + 2); if (access(linkname, F_OK)) goto out_free; if (readlink(linkname, filename, size - 1) < 0) goto out_free; if (unlink(linkname)) goto out_free; /* * Since the link is relative, we must make it absolute: */ snprintf(linkname, size, "%s/.build-id/%.2s/%s", debugdir, sbuild_id, filename); if (unlink(linkname)) goto out_free; err = 0; out_free: free(filename); free(linkname); return err; } static int dso__cache_build_id(struct dso *dso, const char *debugdir) { bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), dso->long_name, debugdir, is_kallsyms); } static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) { struct dso *pos; int err = 0; dsos__for_each_with_build_id(pos, head) if (dso__cache_build_id(pos, debugdir)) err = -1; return err; } static int machine__cache_build_ids(struct machine *machine, const char *debugdir) { int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); return ret; } static int perf_session__cache_build_ids(struct perf_session *session) { struct rb_node *nd; int ret; char debugdir[PATH_MAX]; snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) return -1; ret = machine__cache_build_ids(&session->host_machine, debugdir); for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__cache_build_ids(pos, debugdir); } return ret ? -1 : 0; } static bool machine__read_build_ids(struct machine *machine, bool with_hits) { bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); return ret; } static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) { struct rb_node *nd; bool ret = machine__read_build_ids(&session->host_machine, with_hits); for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__read_build_ids(pos, with_hits); } return ret; } static int write_tracing_data(int fd, struct perf_header *h __used, struct perf_evlist *evlist) { return read_tracing_data(fd, &evlist->entries); } static int write_build_id(int fd, struct perf_header *h, struct perf_evlist *evlist __used) { struct perf_session *session; int err; session = container_of(h, struct perf_session, header); if (!perf_session__read_build_ids(session, true)) return -1; err = dsos__write_buildid_table(h, fd); if (err < 0) { pr_debug("failed to write buildid table\n"); return err; } if (!no_buildid_cache) perf_session__cache_build_ids(session); return 0; } static int write_hostname(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used) { struct utsname uts; int ret; ret = uname(&uts); if (ret < 0) return -1; return do_write_string(fd, uts.nodename); } static int write_osrelease(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used) { struct utsname uts; int ret; ret = uname(&uts); if (ret < 0) return -1; return do_write_string(fd, uts.release); } static int write_arch(int fd, struct perf_header *h __used, struct perf_evlist *evlist __used) { struct utsname uts; int ret;