1 // SPDX-License-Identifier: LGPL-2.1 2 #include <string.h> 3 #include "trace/beauty/beauty.h" 4 #include "util/evsel_fprintf.h" 5 #include <linux/perf_event.h> 6 7 #ifndef PERF_FLAG_FD_NO_GROUP 8 # define PERF_FLAG_FD_NO_GROUP (1UL << 0) 9 #endif 10 11 #ifndef PERF_FLAG_FD_OUTPUT 12 # define PERF_FLAG_FD_OUTPUT (1UL << 1) 13 #endif 14 15 #ifndef PERF_FLAG_PID_CGROUP 16 # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ 17 #endif 18 19 #ifndef PERF_FLAG_FD_CLOEXEC 20 # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ 21 #endif 22 23 size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, 24 struct syscall_arg *arg) 25 { 26 bool show_prefix = arg->show_string_prefix; 27 const char *prefix = "PERF_"; 28 int printed = 0, flags = arg->val; 29 30 if (flags == 0) 31 return 0; 32 33 #define P_FLAG(n) \ 34 if (flags & PERF_FLAG_##n) { \ 35 printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ 36 flags &= ~PERF_FLAG_##n; \ 37 } 38 39 P_FLAG(FD_NO_GROUP); 40 P_FLAG(FD_OUTPUT); 41 P_FLAG(PID_CGROUP); 42 P_FLAG(FD_CLOEXEC); 43 #undef P_FLAG 44 45 if (flags) 46 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); 47 48 return printed; 49 } 50 51 52 53 struct attr_fprintf_args { 54 size_t size, printed; 55 char *bf; 56 bool first; 57 }; 58 59 static int attr__fprintf(FILE *fp __maybe_unused, const char *name, const char *val, void *priv) 60 { 61 struct attr_fprintf_args *args = priv; 62 size_t printed = scnprintf(args->bf + args->printed , args->size - args->printed, "%s%s: %s", args->first ? "" : ", ", name, val); 63 64 args->first = false; 65 args->printed += printed; 66 return printed; 67 } 68 69 static size_t perf_event_attr___scnprintf(struct perf_event_attr *attr, char *bf, size_t size, bool show_zeros __maybe_unused) 70 { 71 struct attr_fprintf_args args = { 72 .printed = scnprintf(bf, size, "{ "), 73 .size = size, 74 .first = true, 75 .bf = bf, 76 }; 77 78 perf_event_attr__fprintf(stdout, attr, attr__fprintf, &args); 79 return args.printed + scnprintf(bf + args.printed, size - args.printed, " }"); 80 } 81 82 static size_t syscall_arg__scnprintf_augmented_perf_event_attr(struct syscall_arg *arg, char *bf, size_t size) 83 { 84 struct perf_event_attr *attr = (void *)arg->augmented.args->value; 85 struct perf_event_attr local_attr; 86 87 /* 88 * augmented_raw_syscalls.bpf.c (shipped with perf) copies 89 * PERF_ATTR_SIZE_VER0 bytes when the tracee passes size=0, 90 * but leaves the size field as 0. The payload size is 91 * guaranteed by perf's own BPF program, not externally 92 * controllable. Copy to a local so we can fix up size 93 * without writing to the potentially read-only augmented 94 * args buffer. 95 */ 96 if (!attr->size) { 97 memcpy(&local_attr, attr, PERF_ATTR_SIZE_VER0); 98 memset((void *)&local_attr + PERF_ATTR_SIZE_VER0, 0, 99 sizeof(local_attr) - PERF_ATTR_SIZE_VER0); 100 local_attr.size = PERF_ATTR_SIZE_VER0; 101 attr = &local_attr; 102 } 103 104 return perf_event_attr___scnprintf(attr, bf, size, 105 trace__show_zeros(arg->trace)); 106 } 107 108 size_t syscall_arg__scnprintf_perf_event_attr(char *bf, size_t size, struct syscall_arg *arg) 109 { 110 if (arg->augmented.args) 111 return syscall_arg__scnprintf_augmented_perf_event_attr(arg, bf, size); 112 113 return scnprintf(bf, size, "%#lx", arg->val); 114 } 115