xref: /linux/tools/perf/util/event.c (revision 9e906a9dead17d81d6c2687f65e159231d0e3286)
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <inttypes.h>
4 #include <linux/compiler.h>
5 #include <linux/kernel.h>
6 #include <linux/types.h>
7 #include <perf/cpumap.h>
8 #include <perf/event.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
14 #include <linux/perf_event.h>
15 #include <linux/zalloc.h>
16 #include "cpumap.h"
17 #include "dso.h"
18 #include "event.h"
19 #include "debug.h"
20 #include "hist.h"
21 #include "machine.h"
22 #include "sort.h"
23 #include "string2.h"
24 #include "strlist.h"
25 #include "thread.h"
26 #include "thread_map.h"
27 #include "time-utils.h"
28 #include <linux/ctype.h>
29 #include "map.h"
30 #include "util/namespaces.h"
31 #include "symbol.h"
32 #include "symbol/kallsyms.h"
33 #include "asm/bug.h"
34 #include "stat.h"
35 #include "session.h"
36 #include "bpf-event.h"
37 #include "print_binary.h"
38 #include "tool.h"
39 #include "util.h"
40 
41 static const char *perf_event__names[] = {
42 	[0]					= "TOTAL",
43 	[PERF_RECORD_MMAP]			= "MMAP",
44 	[PERF_RECORD_MMAP2]			= "MMAP2",
45 	[PERF_RECORD_LOST]			= "LOST",
46 	[PERF_RECORD_COMM]			= "COMM",
47 	[PERF_RECORD_EXIT]			= "EXIT",
48 	[PERF_RECORD_THROTTLE]			= "THROTTLE",
49 	[PERF_RECORD_UNTHROTTLE]		= "UNTHROTTLE",
50 	[PERF_RECORD_FORK]			= "FORK",
51 	[PERF_RECORD_READ]			= "READ",
52 	[PERF_RECORD_SAMPLE]			= "SAMPLE",
53 	[PERF_RECORD_AUX]			= "AUX",
54 	[PERF_RECORD_ITRACE_START]		= "ITRACE_START",
55 	[PERF_RECORD_LOST_SAMPLES]		= "LOST_SAMPLES",
56 	[PERF_RECORD_SWITCH]			= "SWITCH",
57 	[PERF_RECORD_SWITCH_CPU_WIDE]		= "SWITCH_CPU_WIDE",
58 	[PERF_RECORD_NAMESPACES]		= "NAMESPACES",
59 	[PERF_RECORD_KSYMBOL]			= "KSYMBOL",
60 	[PERF_RECORD_BPF_EVENT]			= "BPF_EVENT",
61 	[PERF_RECORD_CGROUP]			= "CGROUP",
62 	[PERF_RECORD_TEXT_POKE]			= "TEXT_POKE",
63 	[PERF_RECORD_AUX_OUTPUT_HW_ID]		= "AUX_OUTPUT_HW_ID",
64 	[PERF_RECORD_CALLCHAIN_DEFERRED]	= "CALLCHAIN_DEFERRED",
65 	[PERF_RECORD_HEADER_ATTR]		= "ATTR",
66 	[PERF_RECORD_HEADER_EVENT_TYPE]		= "EVENT_TYPE",
67 	[PERF_RECORD_HEADER_TRACING_DATA]	= "TRACING_DATA",
68 	[PERF_RECORD_HEADER_BUILD_ID]		= "BUILD_ID",
69 	[PERF_RECORD_FINISHED_ROUND]		= "FINISHED_ROUND",
70 	[PERF_RECORD_ID_INDEX]			= "ID_INDEX",
71 	[PERF_RECORD_AUXTRACE_INFO]		= "AUXTRACE_INFO",
72 	[PERF_RECORD_AUXTRACE]			= "AUXTRACE",
73 	[PERF_RECORD_AUXTRACE_ERROR]		= "AUXTRACE_ERROR",
74 	[PERF_RECORD_THREAD_MAP]		= "THREAD_MAP",
75 	[PERF_RECORD_CPU_MAP]			= "CPU_MAP",
76 	[PERF_RECORD_STAT_CONFIG]		= "STAT_CONFIG",
77 	[PERF_RECORD_STAT]			= "STAT",
78 	[PERF_RECORD_STAT_ROUND]		= "STAT_ROUND",
79 	[PERF_RECORD_EVENT_UPDATE]		= "EVENT_UPDATE",
80 	[PERF_RECORD_TIME_CONV]			= "TIME_CONV",
81 	[PERF_RECORD_HEADER_FEATURE]		= "FEATURE",
82 	[PERF_RECORD_COMPRESSED]		= "COMPRESSED",
83 	[PERF_RECORD_FINISHED_INIT]		= "FINISHED_INIT",
84 	[PERF_RECORD_COMPRESSED2]		= "COMPRESSED2",
85 	[PERF_RECORD_BPF_METADATA]		= "BPF_METADATA",
86 };
87 
perf_event__name(unsigned int id)88 const char *perf_event__name(unsigned int id)
89 {
90 	if (id >= ARRAY_SIZE(perf_event__names))
91 		return "INVALID";
92 	if (!perf_event__names[id])
93 		return "UNKNOWN";
94 	return perf_event__names[id];
95 }
96 
97 struct process_symbol_args {
98 	const char *name;
99 	u64	   start;
100 };
101 
find_func_symbol_cb(void * arg,const char * name,char type,u64 start)102 static int find_func_symbol_cb(void *arg, const char *name, char type,
103 			       u64 start)
104 {
105 	struct process_symbol_args *args = arg;
106 
107 	/*
108 	 * Must be a function or at least an alias, as in PARISC64, where "_text" is
109 	 * an 'A' to the same address as "_stext".
110 	 */
111 	if (!(kallsyms__is_function(type) ||
112 	      type == 'A') || strcmp(name, args->name))
113 		return 0;
114 
115 	args->start = start;
116 	return 1;
117 }
118 
find_any_symbol_cb(void * arg,const char * name,char type __maybe_unused,u64 start)119 static int find_any_symbol_cb(void *arg, const char *name,
120 			      char type __maybe_unused, u64 start)
121 {
122 	struct process_symbol_args *args = arg;
123 
124 	if (strcmp(name, args->name))
125 		return 0;
126 
127 	args->start = start;
128 	return 1;
129 }
130 
kallsyms__get_function_start(const char * kallsyms_filename,const char * symbol_name,u64 * addr)131 int kallsyms__get_function_start(const char *kallsyms_filename,
132 				 const char *symbol_name, u64 *addr)
133 {
134 	struct process_symbol_args args = { .name = symbol_name, };
135 
136 	if (kallsyms__parse(kallsyms_filename, &args, find_func_symbol_cb) <= 0)
137 		return -1;
138 
139 	*addr = args.start;
140 	return 0;
141 }
142 
kallsyms__get_symbol_start(const char * kallsyms_filename,const char * symbol_name,u64 * addr)143 int kallsyms__get_symbol_start(const char *kallsyms_filename,
144 			       const char *symbol_name, u64 *addr)
145 {
146 	struct process_symbol_args args = { .name = symbol_name, };
147 
148 	if (kallsyms__parse(kallsyms_filename, &args, find_any_symbol_cb) <= 0)
149 		return -1;
150 
151 	*addr = args.start;
152 	return 0;
153 }
154 
perf_event__read_stat_config(struct perf_stat_config * config,struct perf_record_stat_config * event)155 void perf_event__read_stat_config(struct perf_stat_config *config,
156 				  struct perf_record_stat_config *event)
157 {
158 	unsigned i;
159 
160 	for (i = 0; i < event->nr; i++) {
161 
162 		switch (event->data[i].tag) {
163 #define CASE(__term, __val)					\
164 		case PERF_STAT_CONFIG_TERM__##__term:		\
165 			config->__val = event->data[i].val;	\
166 			break;
167 
168 		CASE(AGGR_MODE,  aggr_mode)
169 		CASE(SCALE,      scale)
170 		CASE(INTERVAL,   interval)
171 		CASE(AGGR_LEVEL, aggr_level)
172 #undef CASE
173 		default:
174 			pr_warning("unknown stat config term %" PRI_lu64 "\n",
175 				   event->data[i].tag);
176 		}
177 	}
178 }
179 
perf_event__fprintf_comm(union perf_event * event,FILE * fp)180 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
181 {
182 	const char *s;
183 
184 	if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
185 		s = " exec";
186 	else
187 		s = "";
188 
189 	return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
190 }
191 
perf_event__fprintf_namespaces(union perf_event * event,FILE * fp)192 size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
193 {
194 	size_t ret = 0;
195 	struct perf_ns_link_info *ns_link_info;
196 	u32 nr_namespaces, idx;
197 
198 	ns_link_info = event->namespaces.link_info;
199 	nr_namespaces = event->namespaces.nr_namespaces;
200 
201 	ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
202 		       event->namespaces.pid,
203 		       event->namespaces.tid,
204 		       nr_namespaces);
205 
206 	for (idx = 0; idx < nr_namespaces; idx++) {
207 		if (idx && (idx % 4 == 0))
208 			ret += fprintf(fp, "\n\t\t ");
209 
210 		ret  += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
211 				perf_ns__name(idx), (u64)ns_link_info[idx].dev,
212 				(u64)ns_link_info[idx].ino,
213 				((idx + 1) != nr_namespaces) ? ", " : "]\n");
214 	}
215 
216 	return ret;
217 }
218 
perf_event__fprintf_cgroup(union perf_event * event,FILE * fp)219 size_t perf_event__fprintf_cgroup(union perf_event *event, FILE *fp)
220 {
221 	return fprintf(fp, " cgroup: %" PRI_lu64 " %s\n",
222 		       event->cgroup.id, event->cgroup.path);
223 }
224 
perf_event__process_comm(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)225 int perf_event__process_comm(const struct perf_tool *tool __maybe_unused,
226 			     union perf_event *event,
227 			     struct perf_sample *sample,
228 			     struct machine *machine)
229 {
230 	return machine__process_comm_event(machine, event, sample);
231 }
232 
perf_event__process_namespaces(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)233 int perf_event__process_namespaces(const struct perf_tool *tool __maybe_unused,
234 				   union perf_event *event,
235 				   struct perf_sample *sample,
236 				   struct machine *machine)
237 {
238 	return machine__process_namespaces_event(machine, event, sample);
239 }
240 
perf_event__process_cgroup(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)241 int perf_event__process_cgroup(const struct perf_tool *tool __maybe_unused,
242 			       union perf_event *event,
243 			       struct perf_sample *sample,
244 			       struct machine *machine)
245 {
246 	return machine__process_cgroup_event(machine, event, sample);
247 }
248 
perf_event__process_lost(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)249 int perf_event__process_lost(const struct perf_tool *tool __maybe_unused,
250 			     union perf_event *event,
251 			     struct perf_sample *sample,
252 			     struct machine *machine)
253 {
254 	return machine__process_lost_event(machine, event, sample);
255 }
256 
perf_event__process_aux(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)257 int perf_event__process_aux(const struct perf_tool *tool __maybe_unused,
258 			    union perf_event *event,
259 			    struct perf_sample *sample __maybe_unused,
260 			    struct machine *machine)
261 {
262 	return machine__process_aux_event(machine, event);
263 }
264 
perf_event__process_itrace_start(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)265 int perf_event__process_itrace_start(const struct perf_tool *tool __maybe_unused,
266 				     union perf_event *event,
267 				     struct perf_sample *sample __maybe_unused,
268 				     struct machine *machine)
269 {
270 	return machine__process_itrace_start_event(machine, event);
271 }
272 
perf_event__process_aux_output_hw_id(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)273 int perf_event__process_aux_output_hw_id(const struct perf_tool *tool __maybe_unused,
274 					 union perf_event *event,
275 					 struct perf_sample *sample __maybe_unused,
276 					 struct machine *machine)
277 {
278 	return machine__process_aux_output_hw_id_event(machine, event);
279 }
280 
perf_event__process_lost_samples(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)281 int perf_event__process_lost_samples(const struct perf_tool *tool __maybe_unused,
282 				     union perf_event *event,
283 				     struct perf_sample *sample,
284 				     struct machine *machine)
285 {
286 	return machine__process_lost_samples_event(machine, event, sample);
287 }
288 
perf_event__process_switch(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)289 int perf_event__process_switch(const struct perf_tool *tool __maybe_unused,
290 			       union perf_event *event,
291 			       struct perf_sample *sample __maybe_unused,
292 			       struct machine *machine)
293 {
294 	return machine__process_switch_event(machine, event);
295 }
296 
perf_event__process_ksymbol(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)297 int perf_event__process_ksymbol(const struct perf_tool *tool __maybe_unused,
298 				union perf_event *event,
299 				struct perf_sample *sample __maybe_unused,
300 				struct machine *machine)
301 {
302 	return machine__process_ksymbol(machine, event, sample);
303 }
304 
perf_event__process_bpf(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)305 int perf_event__process_bpf(const struct perf_tool *tool __maybe_unused,
306 			    union perf_event *event,
307 			    struct perf_sample *sample,
308 			    struct machine *machine)
309 {
310 	return machine__process_bpf(machine, event, sample);
311 }
312 
perf_event__process_text_poke(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)313 int perf_event__process_text_poke(const struct perf_tool *tool __maybe_unused,
314 				  union perf_event *event,
315 				  struct perf_sample *sample,
316 				  struct machine *machine)
317 {
318 	return machine__process_text_poke(machine, event, sample);
319 }
320 
perf_event__fprintf_mmap(union perf_event * event,FILE * fp)321 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
322 {
323 	return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64 "]: %c %s\n",
324 		       event->mmap.pid, event->mmap.tid, event->mmap.start,
325 		       event->mmap.len, event->mmap.pgoff,
326 		       (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
327 		       event->mmap.filename);
328 }
329 
perf_event__fprintf_mmap2(union perf_event * event,FILE * fp)330 size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
331 {
332 	if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
333 		char sbuild_id[SBUILD_ID_SIZE];
334 		struct build_id bid;
335 
336 		build_id__init(&bid, event->mmap2.build_id,
337 			       event->mmap2.build_id_size);
338 		build_id__snprintf(&bid, sbuild_id, sizeof(sbuild_id));
339 
340 		return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64
341 				   " <%s>]: %c%c%c%c %s\n",
342 			       event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
343 			       event->mmap2.len, event->mmap2.pgoff, sbuild_id,
344 			       (event->mmap2.prot & PROT_READ) ? 'r' : '-',
345 			       (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
346 			       (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
347 			       (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
348 			       event->mmap2.filename);
349 	} else {
350 		return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64
351 				   " %02x:%02x %"PRI_lu64" %"PRI_lu64"]: %c%c%c%c %s\n",
352 			       event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
353 			       event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
354 			       event->mmap2.min, event->mmap2.ino,
355 			       event->mmap2.ino_generation,
356 			       (event->mmap2.prot & PROT_READ) ? 'r' : '-',
357 			       (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
358 			       (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
359 			       (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
360 			       event->mmap2.filename);
361 	}
362 }
363 
perf_event__fprintf_thread_map(union perf_event * event,FILE * fp)364 size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
365 {
366 	struct perf_thread_map *threads = thread_map__new_event(&event->thread_map);
367 	size_t ret;
368 
369 	ret = fprintf(fp, " nr: ");
370 
371 	if (threads)
372 		ret += thread_map__fprintf(threads, fp);
373 	else
374 		ret += fprintf(fp, "failed to get threads from event\n");
375 
376 	perf_thread_map__put(threads);
377 	return ret;
378 }
379 
perf_event__fprintf_cpu_map(union perf_event * event,FILE * fp)380 size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
381 {
382 	struct perf_cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
383 	size_t ret;
384 
385 	ret = fprintf(fp, ": ");
386 
387 	if (cpus)
388 		ret += cpu_map__fprintf(cpus, fp);
389 	else
390 		ret += fprintf(fp, "failed to get cpumap from event\n");
391 
392 	perf_cpu_map__put(cpus);
393 	return ret;
394 }
395 
perf_event__process_mmap(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)396 int perf_event__process_mmap(const struct perf_tool *tool __maybe_unused,
397 			     union perf_event *event,
398 			     struct perf_sample *sample,
399 			     struct machine *machine)
400 {
401 	return machine__process_mmap_event(machine, event, sample);
402 }
403 
perf_event__process_mmap2(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)404 int perf_event__process_mmap2(const struct perf_tool *tool __maybe_unused,
405 			     union perf_event *event,
406 			     struct perf_sample *sample,
407 			     struct machine *machine)
408 {
409 	return machine__process_mmap2_event(machine, event, sample);
410 }
411 
perf_event__fprintf_task(union perf_event * event,FILE * fp)412 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
413 {
414 	return fprintf(fp, "(%d:%d):(%d:%d)\n",
415 		       event->fork.pid, event->fork.tid,
416 		       event->fork.ppid, event->fork.ptid);
417 }
418 
perf_event__process_fork(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)419 int perf_event__process_fork(const struct perf_tool *tool __maybe_unused,
420 			     union perf_event *event,
421 			     struct perf_sample *sample,
422 			     struct machine *machine)
423 {
424 	return machine__process_fork_event(machine, event, sample);
425 }
426 
perf_event__process_exit(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)427 int perf_event__process_exit(const struct perf_tool *tool __maybe_unused,
428 			     union perf_event *event,
429 			     struct perf_sample *sample,
430 			     struct machine *machine)
431 {
432 	return machine__process_exit_event(machine, event, sample);
433 }
434 
perf_event__exit_del_thread(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample __maybe_unused,struct machine * machine)435 int perf_event__exit_del_thread(const struct perf_tool *tool __maybe_unused,
436 				union perf_event *event,
437 				struct perf_sample *sample __maybe_unused,
438 				struct machine *machine)
439 {
440 	struct thread *thread = machine__findnew_thread(machine,
441 							event->fork.pid,
442 							event->fork.tid);
443 
444 	dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
445 		    event->fork.ppid, event->fork.ptid);
446 
447 	if (thread) {
448 		machine__remove_thread(machine, thread);
449 		thread__put(thread);
450 	}
451 
452 	return 0;
453 }
454 
perf_event__fprintf_aux(union perf_event * event,FILE * fp)455 size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp)
456 {
457 	return fprintf(fp, " offset: %#"PRI_lx64" size: %#"PRI_lx64" flags: %#"PRI_lx64" [%s%s%s%s]\n",
458 		       event->aux.aux_offset, event->aux.aux_size,
459 		       event->aux.flags,
460 		       event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "",
461 		       event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : "",
462 		       event->aux.flags & PERF_AUX_FLAG_PARTIAL   ? "P" : "",
463 		       event->aux.flags & PERF_AUX_FLAG_COLLISION ? "C" : "");
464 }
465 
perf_event__fprintf_itrace_start(union perf_event * event,FILE * fp)466 size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp)
467 {
468 	return fprintf(fp, " pid: %u tid: %u\n",
469 		       event->itrace_start.pid, event->itrace_start.tid);
470 }
471 
perf_event__fprintf_aux_output_hw_id(union perf_event * event,FILE * fp)472 size_t perf_event__fprintf_aux_output_hw_id(union perf_event *event, FILE *fp)
473 {
474 	return fprintf(fp, " hw_id: %#"PRI_lx64"\n",
475 		       event->aux_output_hw_id.hw_id);
476 }
477 
perf_event__fprintf_switch(union perf_event * event,FILE * fp)478 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp)
479 {
480 	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
481 	const char *in_out = !out ? "IN         " :
482 		!(event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT) ?
483 				    "OUT        " : "OUT preempt";
484 
485 	if (event->header.type == PERF_RECORD_SWITCH)
486 		return fprintf(fp, " %s\n", in_out);
487 
488 	return fprintf(fp, " %s  %s pid/tid: %5d/%-5d\n",
489 		       in_out, out ? "next" : "prev",
490 		       event->context_switch.next_prev_pid,
491 		       event->context_switch.next_prev_tid);
492 }
493 
perf_event__fprintf_lost(union perf_event * event,FILE * fp)494 static size_t perf_event__fprintf_lost(union perf_event *event, FILE *fp)
495 {
496 	return fprintf(fp, " lost %" PRI_lu64 "\n", event->lost.lost);
497 }
498 
perf_event__fprintf_ksymbol(union perf_event * event,FILE * fp)499 size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp)
500 {
501 	return fprintf(fp, " addr %" PRI_lx64 " len %u type %u flags 0x%x name %s\n",
502 		       event->ksymbol.addr, event->ksymbol.len,
503 		       event->ksymbol.ksym_type,
504 		       event->ksymbol.flags, event->ksymbol.name);
505 }
506 
perf_event__fprintf_bpf(union perf_event * event,FILE * fp)507 size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp)
508 {
509 	return fprintf(fp, " type %u, flags %u, id %u\n",
510 		       event->bpf.type, event->bpf.flags, event->bpf.id);
511 }
512 
perf_event__fprintf_bpf_metadata(union perf_event * event,FILE * fp)513 size_t perf_event__fprintf_bpf_metadata(union perf_event *event, FILE *fp)
514 {
515 	struct perf_record_bpf_metadata *metadata = &event->bpf_metadata;
516 	size_t ret;
517 
518 	ret = fprintf(fp, " prog %s\n", metadata->prog_name);
519 	for (__u32 i = 0; i < metadata->nr_entries; i++) {
520 		ret += fprintf(fp, "  entry %d: %20s = %s\n", i,
521 			       metadata->entries[i].key,
522 			       metadata->entries[i].value);
523 	}
524 	return ret;
525 }
526 
text_poke_printer(enum binary_printer_ops op,unsigned int val,void * extra,FILE * fp)527 static int text_poke_printer(enum binary_printer_ops op, unsigned int val,
528 			     void *extra, FILE *fp)
529 {
530 	bool old = *(bool *)extra;
531 
532 	switch ((int)op) {
533 	case BINARY_PRINT_LINE_BEGIN:
534 		return fprintf(fp, "            %s bytes:", old ? "Old" : "New");
535 	case BINARY_PRINT_NUM_DATA:
536 		return fprintf(fp, " %02x", val);
537 	case BINARY_PRINT_LINE_END:
538 		return fprintf(fp, "\n");
539 	default:
540 		return 0;
541 	}
542 }
543 
perf_event__fprintf_text_poke(union perf_event * event,struct machine * machine,FILE * fp)544 size_t perf_event__fprintf_text_poke(union perf_event *event, struct machine *machine, FILE *fp)
545 {
546 	struct perf_record_text_poke_event *tp = &event->text_poke;
547 	size_t ret;
548 	bool old;
549 
550 	ret = fprintf(fp, " %" PRI_lx64 " ", tp->addr);
551 	if (machine) {
552 		struct addr_location al;
553 
554 		addr_location__init(&al);
555 		al.map = maps__find(machine__kernel_maps(machine), tp->addr);
556 		if (al.map && map__load(al.map) >= 0) {
557 			al.addr = map__map_ip(al.map, tp->addr);
558 			al.sym = map__find_symbol(al.map, al.addr);
559 			if (al.sym)
560 				ret += symbol__fprintf_symname_offs(al.sym, &al, fp);
561 		}
562 		addr_location__exit(&al);
563 	}
564 	ret += fprintf(fp, " old len %u new len %u\n", tp->old_len, tp->new_len);
565 	old = true;
566 	ret += binary__fprintf(tp->bytes, tp->old_len, 16, text_poke_printer,
567 			       &old, fp);
568 	old = false;
569 	ret += binary__fprintf(tp->bytes + tp->old_len, tp->new_len, 16,
570 			       text_poke_printer, &old, fp);
571 	return ret;
572 }
573 
perf_event__fprintf(union perf_event * event,struct machine * machine,FILE * fp)574 size_t perf_event__fprintf(union perf_event *event, struct machine *machine, FILE *fp)
575 {
576 	size_t ret = fprintf(fp, "PERF_RECORD_%s",
577 			     perf_event__name(event->header.type));
578 
579 	switch (event->header.type) {
580 	case PERF_RECORD_COMM:
581 		ret += perf_event__fprintf_comm(event, fp);
582 		break;
583 	case PERF_RECORD_FORK:
584 	case PERF_RECORD_EXIT:
585 		ret += perf_event__fprintf_task(event, fp);
586 		break;
587 	case PERF_RECORD_MMAP:
588 		ret += perf_event__fprintf_mmap(event, fp);
589 		break;
590 	case PERF_RECORD_NAMESPACES:
591 		ret += perf_event__fprintf_namespaces(event, fp);
592 		break;
593 	case PERF_RECORD_CGROUP:
594 		ret += perf_event__fprintf_cgroup(event, fp);
595 		break;
596 	case PERF_RECORD_MMAP2:
597 		ret += perf_event__fprintf_mmap2(event, fp);
598 		break;
599 	case PERF_RECORD_AUX:
600 		ret += perf_event__fprintf_aux(event, fp);
601 		break;
602 	case PERF_RECORD_ITRACE_START:
603 		ret += perf_event__fprintf_itrace_start(event, fp);
604 		break;
605 	case PERF_RECORD_SWITCH:
606 	case PERF_RECORD_SWITCH_CPU_WIDE:
607 		ret += perf_event__fprintf_switch(event, fp);
608 		break;
609 	case PERF_RECORD_LOST:
610 		ret += perf_event__fprintf_lost(event, fp);
611 		break;
612 	case PERF_RECORD_KSYMBOL:
613 		ret += perf_event__fprintf_ksymbol(event, fp);
614 		break;
615 	case PERF_RECORD_BPF_EVENT:
616 		ret += perf_event__fprintf_bpf(event, fp);
617 		break;
618 	case PERF_RECORD_TEXT_POKE:
619 		ret += perf_event__fprintf_text_poke(event, machine, fp);
620 		break;
621 	case PERF_RECORD_AUX_OUTPUT_HW_ID:
622 		ret += perf_event__fprintf_aux_output_hw_id(event, fp);
623 		break;
624 	case PERF_RECORD_BPF_METADATA:
625 		ret += perf_event__fprintf_bpf_metadata(event, fp);
626 		break;
627 	default:
628 		ret += fprintf(fp, "\n");
629 	}
630 
631 	return ret;
632 }
633 
perf_event__process(const struct perf_tool * tool __maybe_unused,union perf_event * event,struct perf_sample * sample,struct machine * machine)634 int perf_event__process(const struct perf_tool *tool __maybe_unused,
635 			union perf_event *event,
636 			struct perf_sample *sample,
637 			struct machine *machine)
638 {
639 	return machine__process_event(machine, event, sample);
640 }
641 
thread__find_map(struct thread * thread,u8 cpumode,u64 addr,struct addr_location * al)642 struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
643 			     struct addr_location *al)
644 {
645 	struct maps *maps = thread__maps(thread);
646 	struct machine *machine = maps__machine(maps);
647 	bool load_map = false;
648 
649 	maps__zput(al->maps);
650 	map__zput(al->map);
651 	thread__zput(al->thread);
652 	al->thread = thread__get(thread);
653 
654 	al->addr = addr;
655 	al->cpumode = cpumode;
656 	al->filtered = 0;
657 
658 	if (machine == NULL)
659 		return NULL;
660 
661 	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
662 		al->level = 'k';
663 		maps = machine__kernel_maps(machine);
664 		load_map = !symbol_conf.lazy_load_kernel_maps;
665 	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
666 		al->level = '.';
667 	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
668 		al->level = 'g';
669 		maps = machine__kernel_maps(machine);
670 		load_map = !symbol_conf.lazy_load_kernel_maps;
671 	} else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
672 		al->level = 'u';
673 	} else {
674 		al->level = 'H';
675 
676 		if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
677 			cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
678 			!perf_guest)
679 			al->filtered |= (1 << HIST_FILTER__GUEST);
680 		if ((cpumode == PERF_RECORD_MISC_USER ||
681 			cpumode == PERF_RECORD_MISC_KERNEL) &&
682 			!perf_host)
683 			al->filtered |= (1 << HIST_FILTER__HOST);
684 
685 		return NULL;
686 	}
687 	al->maps = maps__get(maps);
688 	al->map = maps__find(maps, al->addr);
689 	if (al->map != NULL) {
690 		/*
691 		 * Kernel maps might be changed when loading symbols so loading
692 		 * must be done prior to using kernel maps.
693 		 */
694 		if (load_map)
695 			map__load(al->map);
696 		al->addr = map__map_ip(al->map, al->addr);
697 	}
698 
699 	return al->map;
700 }
701 
702 /*
703  * For branch stacks or branch samples, the sample cpumode might not be correct
704  * because it applies only to the sample 'ip' and not necessary to 'addr' or
705  * branch stack addresses. If possible, use a fallback to deal with those cases.
706  */
thread__find_map_fb(struct thread * thread,u8 cpumode,u64 addr,struct addr_location * al)707 struct map *thread__find_map_fb(struct thread *thread, u8 cpumode, u64 addr,
708 				struct addr_location *al)
709 {
710 	struct map *map = thread__find_map(thread, cpumode, addr, al);
711 	struct machine *machine = maps__machine(thread__maps(thread));
712 	u8 addr_cpumode = machine__addr_cpumode(machine, cpumode, addr);
713 
714 	if (map || addr_cpumode == cpumode)
715 		return map;
716 
717 	return thread__find_map(thread, addr_cpumode, addr, al);
718 }
719 
thread__find_symbol(struct thread * thread,u8 cpumode,u64 addr,struct addr_location * al)720 struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
721 				   u64 addr, struct addr_location *al)
722 {
723 	al->sym = NULL;
724 	if (thread__find_map(thread, cpumode, addr, al))
725 		al->sym = map__find_symbol(al->map, al->addr);
726 	return al->sym;
727 }
728 
thread__find_symbol_fb(struct thread * thread,u8 cpumode,u64 addr,struct addr_location * al)729 struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode,
730 				      u64 addr, struct addr_location *al)
731 {
732 	al->sym = NULL;
733 	if (thread__find_map_fb(thread, cpumode, addr, al))
734 		al->sym = map__find_symbol(al->map, al->addr);
735 	return al->sym;
736 }
737 
check_address_range(struct intlist * addr_list,int addr_range,unsigned long addr)738 static bool check_address_range(struct intlist *addr_list, int addr_range,
739 				unsigned long addr)
740 {
741 	struct int_node *pos;
742 
743 	intlist__for_each_entry(pos, addr_list) {
744 		if (addr >= pos->i && addr < pos->i + addr_range)
745 			return true;
746 	}
747 
748 	return false;
749 }
750 
751 /*
752  * Callers need to drop the reference to al->thread, obtained in
753  * machine__findnew_thread()
754  */
machine__resolve(struct machine * machine,struct addr_location * al,struct perf_sample * sample)755 int machine__resolve(struct machine *machine, struct addr_location *al,
756 		     struct perf_sample *sample)
757 {
758 	struct thread *thread;
759 	struct dso *dso;
760 
761 	if (symbol_conf.guest_code && !machine__is_host(machine))
762 		thread = machine__findnew_guest_code(machine, sample->pid);
763 	else
764 		thread = machine__findnew_thread(machine, sample->pid, sample->tid);
765 	if (thread == NULL)
766 		return -1;
767 
768 	dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread__tid(thread));
769 	thread__find_map(thread, sample->cpumode, sample->ip, al);
770 	dso = al->map ? map__dso(al->map) : NULL;
771 	dump_printf(" ...... dso: %s\n",
772 		dso
773 		? dso__long_name(dso)
774 		: (al->level == 'H' ? "[hypervisor]" : "<not found>"));
775 
776 	if (thread__is_filtered(thread))
777 		al->filtered |= (1 << HIST_FILTER__THREAD);
778 
779 	thread__put(thread);
780 	thread = NULL;
781 
782 	al->sym = NULL;
783 	al->cpu = sample->cpu;
784 	al->socket = -1;
785 	al->srcline = NULL;
786 
787 	if (al->cpu >= 0) {
788 		struct perf_env *env = machine->env;
789 
790 		if (env && env->cpu)
791 			al->socket = env->cpu[al->cpu].socket_id;
792 	}
793 
794 	/* Account for possible out-of-order switch events. */
795 	al->parallelism = max(1, min(machine->parallelism, machine__nr_cpus_avail(machine)));
796 	if (test_bit(al->parallelism, symbol_conf.parallelism_filter))
797 		al->filtered |= (1 << HIST_FILTER__PARALLELISM);
798 	/*
799 	 * Multiply it by some const to avoid precision loss or dealing
800 	 * with floats. The multiplier does not matter otherwise since
801 	 * we only print it as percents.
802 	 */
803 	al->latency = sample->period * 1000 / al->parallelism;
804 
805 	if (al->map) {
806 		if (symbol_conf.dso_list &&
807 		    (!dso || !(strlist__has_entry(symbol_conf.dso_list,
808 						  dso__short_name(dso)) ||
809 			       (dso__short_name(dso) != dso__long_name(dso) &&
810 				strlist__has_entry(symbol_conf.dso_list,
811 						   dso__long_name(dso)))))) {
812 			al->filtered |= (1 << HIST_FILTER__DSO);
813 		}
814 
815 		al->sym = map__find_symbol(al->map, al->addr);
816 	} else if (symbol_conf.dso_list) {
817 		al->filtered |= (1 << HIST_FILTER__DSO);
818 	}
819 
820 	if (symbol_conf.sym_list) {
821 		int ret = 0;
822 		char al_addr_str[32];
823 		size_t sz = sizeof(al_addr_str);
824 
825 		if (al->sym) {
826 			ret = strlist__has_entry(symbol_conf.sym_list,
827 						al->sym->name);
828 		}
829 		if (!ret && al->sym) {
830 			snprintf(al_addr_str, sz, "0x%"PRIx64,
831 				 map__unmap_ip(al->map, al->sym->start));
832 			ret = strlist__has_entry(symbol_conf.sym_list,
833 						al_addr_str);
834 		}
835 		if (!ret && symbol_conf.addr_list && al->map) {
836 			unsigned long addr = map__unmap_ip(al->map, al->addr);
837 
838 			ret = intlist__has_entry(symbol_conf.addr_list, addr);
839 			if (!ret && symbol_conf.addr_range) {
840 				ret = check_address_range(symbol_conf.addr_list,
841 							  symbol_conf.addr_range,
842 							  addr);
843 			}
844 		}
845 
846 		if (!ret)
847 			al->filtered |= (1 << HIST_FILTER__SYMBOL);
848 	}
849 
850 	return 0;
851 }
852 
is_bts_event(struct perf_event_attr * attr)853 bool is_bts_event(struct perf_event_attr *attr)
854 {
855 	return attr->type == PERF_TYPE_HARDWARE &&
856 	       (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
857 	       attr->sample_period == 1;
858 }
859 
sample_addr_correlates_sym(struct perf_event_attr * attr)860 bool sample_addr_correlates_sym(struct perf_event_attr *attr)
861 {
862 	if (attr->type == PERF_TYPE_SOFTWARE &&
863 	    (attr->config == PERF_COUNT_SW_PAGE_FAULTS ||
864 	     attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
865 	     attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))
866 		return true;
867 
868 	if (is_bts_event(attr))
869 		return true;
870 
871 	return false;
872 }
873 
thread__resolve(struct thread * thread,struct addr_location * al,struct perf_sample * sample)874 void thread__resolve(struct thread *thread, struct addr_location *al,
875 		     struct perf_sample *sample)
876 {
877 	thread__find_map_fb(thread, sample->cpumode, sample->addr, al);
878 
879 	al->cpu = sample->cpu;
880 	al->sym = NULL;
881 
882 	if (al->map)
883 		al->sym = map__find_symbol(al->map, al->addr);
884 }
885