1/* 2 * builtin-inject.c 3 * 4 * Builtin inject command: Examine the live mode (stdin) event stream 5 * and repipe it to stdout while optionally injecting additional 6 * events into it. 7 */ 8#include "builtin.h" 9 10#include "perf.h" 11#include "util/session.h" 12#include "util/debug.h" 13 14#include "util/parse-options.h" 15 16static char const *input_name = "-"; 17static bool inject_build_ids; 18 19static int event__repipe(event_t *event __used, 20 struct perf_session *session __used) 21{ 22 uint32_t size; 23 void *buf = event; 24 25 size = event->header.size; 26 27 while (size) { 28 int ret = write(STDOUT_FILENO, buf, size); 29 if (ret < 0) 30 return -errno; 31 32 size -= ret; 33 buf += ret; 34 } 35 36 return 0; 37} 38 39static int event__repipe_mmap(event_t *self, struct perf_session *session) 40{ 41 int err; 42 43 err = event__process_mmap(self, session); 44 event__repipe(self, session); 45 46 return err; 47} 48 49static int event__repipe_task(event_t *self, struct perf_session *session) 50{ 51 int err; 52 53 err = event__process_task(self, session); 54 event__repipe(self, session); 55 56 return err; 57} 58 59static int event__repipe_tracing_data(event_t *self, 60 struct perf_session *session) 61{ 62 int err; 63 64 event__repipe(self, session); 65 err = event__process_tracing_data(self, session); 66 67 return err; 68} 69 70static int dso__read_build_id(struct dso *self) 71{ 72 if (self->has_build_id) 73 return 0; 74 75 if (filename__read_build_id(self->long_name, self->build_id, 76 sizeof(self->build_id)) > 0) { 77 self->has_build_id = true; 78 return 0; 79 } 80 81 return -1; 82} 83 84static int dso__inject_build_id(struct dso *self, struct perf_session *session) 85{ 86 u16 misc = PERF_RECORD_MISC_USER; 87 struct machine *machine; 88 int err; 89 90 if (dso__read_build_id(self) < 0) { 91 pr_debug("no build_id found for %s\n", self->long_name); 92 return -1; 93 } 94 95 machine = perf_session__find_host_machine(session); 96 if (machine == NULL) { 97 pr_err("Can't find machine for session\n"); 98 return -1; 99 } 100 101 if (self->kernel) 102 misc = PERF_RECORD_MISC_KERNEL; 103 104 err = event__synthesize_build_id(self, misc, event__repipe, 105 machine, session); 106 if (err) { 107 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 108 return -1; 109 } 110 111 return 0; 112} 113 114static int event__inject_buildid(event_t *event, struct perf_session *session) 115{ 116 struct addr_location al; 117 struct thread *thread; 118 u8 cpumode; 119 120 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 121 122 thread = perf_session__findnew(session, event->ip.pid); 123 if (thread == NULL) { 124 pr_err("problem processing %d event, skipping it.\n", 125 event->header.type); 126 goto repipe; 127 } 128 129 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 130 event->ip.pid, event->ip.ip, &al); 131 132 if (al.map != NULL) { 133 if (!al.map->dso->hit) { 134 al.map->dso->hit = 1; 135 if (map__load(al.map, NULL) >= 0) { 136 dso__inject_build_id(al.map->dso, session); 137 /* 138 * If this fails, too bad, let the other side 139 * account this as unresolved. 140 */ 141 } else 142 pr_warning("no symbols found in %s, maybe " 143 "install a debug package?\n", 144 al.map->dso->long_name); 145 } 146 } 147 148repipe: 149 event__repipe(event, session); 150 return 0; 151} 152 153struct perf_event_ops inject_ops = { 154 .sample = event__repipe, 155 .mmap = event__repipe, 156 .comm = event__repipe, 157 .fork = event__repipe, 158 .exit = event__repipe, 159 .lost = event__repipe, 160 .read = event__repipe, 161 .throttle = event__repipe, 162 .unthrottle = event__repipe, 163 .attr = event__repipe, 164 .event_type = event__repipe, 165 .tracing_data = event__repipe, 166 .build_id = event__repipe, 167}; 168 169extern volatile int session_done; 170 171static void sig_handler(int sig __attribute__((__unused__))) 172{ 173 session_done = 1; 174} 175 176static int __cmd_inject(void) 177{ 178 struct perf_session *session; 179 int ret = -EINVAL; 180 181 signal(SIGINT, sig_handler); 182 183 if (inject_build_ids) { 184 inject_ops.sample = event__inject_buildid; 185 inject_ops.mmap = event__repipe_mmap; 186 inject_ops.fork = event__repipe_task; 187 inject_ops.tracing_data = event__repipe_tracing_data; 188 } 189 190 session = perf_session__new(input_name, O_RDONLY, false, true); 191 if (session == NULL) 192 return -ENOMEM; 193 194 ret = perf_session__process_events(session, &inject_ops); 195 196 perf_session__delete(session); 197 198 return ret; 199} 200 201static const char * const report_usage[] = { 202 "perf inject [<options>]", 203 NULL 204}; 205 206static const struct option options[] = { 207 OPT_BOOLEAN('b', "build-ids", &inject_build_ids, 208 "Inject build-ids into the output stream"), 209 OPT_INCR('v', "verbose", &verbose, 210 "be more verbose (show build ids, etc)"), 211 OPT_END() 212}; 213 214int cmd_inject(int argc, const char **argv, const char *prefix __used) 215{ 216 argc = parse_options(argc, argv, options, report_usage, 0); 217 218 /* 219 * Any (unrecognized) arguments left? 220 */ 221 if (argc) 222 usage_with_options(report_usage, options); 223 224 if (symbol__init() < 0) 225 return -1; 226 227 return __cmd_inject(); 228} 229