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