Home | History | Annotate | Download | only in linux-tools-perf
      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 
     16 static char		const *input_name = "-";
     17 static bool		inject_build_ids;
     18 
     19 static int perf_event__repipe_synth(union perf_event *event,
     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 
     39 static int perf_event__repipe(union perf_event *event,
     40 			      struct perf_sample *sample __used,
     41 			      struct perf_session *session)
     42 {
     43 	return perf_event__repipe_synth(event, session);
     44 }
     45 
     46 static int perf_event__repipe_sample(union perf_event *event,
     47 			      struct perf_sample *sample __used,
     48 			      struct perf_evsel *evsel __used,
     49 			      struct perf_session *session)
     50 {
     51 	return perf_event__repipe_synth(event, session);
     52 }
     53 
     54 static int perf_event__repipe_mmap(union perf_event *event,
     55 				   struct perf_sample *sample,
     56 				   struct perf_session *session)
     57 {
     58 	int err;
     59 
     60 	err = perf_event__process_mmap(event, sample, session);
     61 	perf_event__repipe(event, sample, session);
     62 
     63 	return err;
     64 }
     65 
     66 static int perf_event__repipe_task(union perf_event *event,
     67 				   struct perf_sample *sample,
     68 				   struct perf_session *session)
     69 {
     70 	int err;
     71 
     72 	err = perf_event__process_task(event, sample, session);
     73 	perf_event__repipe(event, sample, session);
     74 
     75 	return err;
     76 }
     77 
     78 static int perf_event__repipe_tracing_data(union perf_event *event,
     79 					   struct perf_session *session)
     80 {
     81 	int err;
     82 
     83 	perf_event__repipe_synth(event, session);
     84 	err = perf_event__process_tracing_data(event, session);
     85 
     86 	return err;
     87 }
     88 
     89 static int dso__read_build_id(struct dso *self)
     90 {
     91 	if (self->has_build_id)
     92 		return 0;
     93 
     94 	if (filename__read_build_id(self->long_name, self->build_id,
     95 				    sizeof(self->build_id)) > 0) {
     96 		self->has_build_id = true;
     97 		return 0;
     98 	}
     99 
    100 	return -1;
    101 }
    102 
    103 static int dso__inject_build_id(struct dso *self, struct perf_session *session)
    104 {
    105 	u16 misc = PERF_RECORD_MISC_USER;
    106 	struct machine *machine;
    107 	int err;
    108 
    109 	if (dso__read_build_id(self) < 0) {
    110 		pr_debug("no build_id found for %s\n", self->long_name);
    111 		return -1;
    112 	}
    113 
    114 	machine = perf_session__find_host_machine(session);
    115 	if (machine == NULL) {
    116 		pr_err("Can't find machine for session\n");
    117 		return -1;
    118 	}
    119 
    120 	if (self->kernel)
    121 		misc = PERF_RECORD_MISC_KERNEL;
    122 
    123 	err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
    124 					      machine, session);
    125 	if (err) {
    126 		pr_err("Can't synthesize build_id event for %s\n", self->long_name);
    127 		return -1;
    128 	}
    129 
    130 	return 0;
    131 }
    132 
    133 static int perf_event__inject_buildid(union perf_event *event,
    134 				      struct perf_sample *sample,
    135 				      struct perf_evsel *evsel __used,
    136 				      struct perf_session *session)
    137 {
    138 	struct addr_location al;
    139 	struct thread *thread;
    140 	u8 cpumode;
    141 
    142 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
    143 
    144 	thread = perf_session__findnew(session, event->ip.pid);
    145 	if (thread == NULL) {
    146 		pr_err("problem processing %d event, skipping it.\n",
    147 		       event->header.type);
    148 		goto repipe;
    149 	}
    150 
    151 	thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
    152 			      event->ip.pid, event->ip.ip, &al);
    153 
    154 	if (al.map != NULL) {
    155 		if (!al.map->dso->hit) {
    156 			al.map->dso->hit = 1;
    157 			if (map__load(al.map, NULL) >= 0) {
    158 				dso__inject_build_id(al.map->dso, session);
    159 				/*
    160 				 * If this fails, too bad, let the other side
    161 				 * account this as unresolved.
    162 				 */
    163 			} else
    164 				pr_warning("no symbols found in %s, maybe "
    165 					   "install a debug package?\n",
    166 					   al.map->dso->long_name);
    167 		}
    168 	}
    169 
    170 repipe:
    171 	perf_event__repipe(event, sample, session);
    172 	return 0;
    173 }
    174 
    175 struct perf_event_ops inject_ops = {
    176 	.sample		= perf_event__repipe_sample,
    177 	.mmap		= perf_event__repipe,
    178 	.comm		= perf_event__repipe,
    179 	.fork		= perf_event__repipe,
    180 	.exit		= perf_event__repipe,
    181 	.lost		= perf_event__repipe,
    182 	.read		= perf_event__repipe,
    183 	.throttle	= perf_event__repipe,
    184 	.unthrottle	= perf_event__repipe,
    185 	.attr		= perf_event__repipe_synth,
    186 	.event_type 	= perf_event__repipe_synth,
    187 	.tracing_data 	= perf_event__repipe_synth,
    188 	.build_id 	= perf_event__repipe_synth,
    189 };
    190 
    191 extern volatile int session_done;
    192 
    193 static void sig_handler(int sig __attribute__((__unused__)))
    194 {
    195 	session_done = 1;
    196 }
    197 
    198 static int __cmd_inject(void)
    199 {
    200 	struct perf_session *session;
    201 	int ret = -EINVAL;
    202 
    203 	signal(SIGINT, sig_handler);
    204 
    205 	if (inject_build_ids) {
    206 		inject_ops.sample	= perf_event__inject_buildid;
    207 		inject_ops.mmap		= perf_event__repipe_mmap;
    208 		inject_ops.fork		= perf_event__repipe_task;
    209 		inject_ops.tracing_data	= perf_event__repipe_tracing_data;
    210 	}
    211 
    212 	session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
    213 	if (session == NULL)
    214 		return -ENOMEM;
    215 
    216 	ret = perf_session__process_events(session, &inject_ops);
    217 
    218 	perf_session__delete(session);
    219 
    220 	return ret;
    221 }
    222 
    223 static const char * const report_usage[] = {
    224 	"perf inject [<options>]",
    225 	NULL
    226 };
    227 
    228 static const struct option options[] = {
    229 	OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
    230 		    "Inject build-ids into the output stream"),
    231 	OPT_INCR('v', "verbose", &verbose,
    232 		 "be more verbose (show build ids, etc)"),
    233 	OPT_END()
    234 };
    235 
    236 int cmd_inject(int argc, const char **argv, const char *prefix __used)
    237 {
    238 	argc = parse_options(argc, argv, options, report_usage, 0);
    239 
    240 	/*
    241 	 * Any (unrecognized) arguments left?
    242 	 */
    243 	if (argc)
    244 		usage_with_options(report_usage, options);
    245 
    246 	if (symbol__init() < 0)
    247 		return -1;
    248 
    249 	return __cmd_inject();
    250 }
    251