brintos

brintos / linux-shallow public Read only

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