diff options
| author | 2019-08-15 11:10:38 +0200 | |
|---|---|---|
| committer | 2019-08-15 11:10:38 +0200 | |
| commit | 4511708b9a044f2bc83c7c7f7f8a2c45ec488219 (patch) | |
| tree | e892580504b082e9852f5925ba66d1e22910f5e8 /tools/perf/util | |
| parent | Merge tag 'perf-core-for-mingo-5.4-20190729' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (diff) | |
| parent | perf ui: No need to set ui_browser to 1 twice (diff) | |
| download | wireguard-linux-4511708b9a044f2bc83c7c7f7f8a2c45ec488219.tar.xz wireguard-linux-4511708b9a044f2bc83c7c7f7f8a2c45ec488219.zip  | |
Merge tag 'perf-core-for-mingo-5.4-20190814' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo:
Intel PT:
  Adrian Hunter:
  - Add PEBS via Intel PT support, the kernel bits went via PeterZ.
perf record:
  Alexander Shishkin:
  - Add an option to take an AUX snapshot on exit.
  Tan Xiaojun:
  - Support aarch64 random socket_id assignment, just like was fixed for S/390.
tools:
  Andy Shevchenko:
  - Keep list of tools in alphabetical order on 'make -C tools help'.
perf session:
  Arnaldo Carvalho de Melo:
  - Avoid infinite loop when seeing invalid header.size, reported by
    Vince Weaver using a perf.data fuzzer.
Documentation:
  Vince Weaver:
  - Clarify HEADER_SAMPLE_TOPOLOGY format in the perf.data spec.
perf config:
  Arnaldo Carvalho de Melo:
  - Honour $PERF_CONFIG env var to specify alternate .perfconfig.
perf test:
  Arnaldo Carvalho de Melo:
  - Disable ~/.perfconfig to get default output in 'perf trace' tests.
perf top:
  Arnaldo Carvalho de Melo:
  - Set display thread COMM to help with debugging.
  - Collapse and resort evsels in a group, so that we have output
    similar to 'perf report' when using event groups, i.e.
      perf top -e '{cycles,instructions}'
    Will have two columns, and the instructions one will work.
core:
  Igor Lubashev:
  - Detect if libcap development files are available so that we
    can use capabilities to match the checks made by the kernel instead
    of using plain (geteuid() == 0).
Intel:
  Haiyan Song:
  - Add Icelake V1.00 event file.
perf trace:
  Leo Yan:
  - Fix segmentation fault when access syscall info on arm64.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
| -rw-r--r-- | tools/perf/util/Build | 2 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/auxtrace.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/auxtrace.h | 5 | ||||
| -rw-r--r-- | tools/perf/util/cap.c | 29 | ||||
| -rw-r--r-- | tools/perf/util/cap.h | 32 | ||||
| -rw-r--r-- | tools/perf/util/cpumap.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 15 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 20 | ||||
| -rw-r--r-- | tools/perf/util/intel-pt.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/machine.c | 3 | ||||
| -rw-r--r-- | tools/perf/util/machine.h | 2 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 8 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.l | 1 | ||||
| -rw-r--r-- | tools/perf/util/python-ext-sources | 1 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 11 | ||||
| -rw-r--r-- | tools/perf/util/setup.py | 2 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 7 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/thread.c | 12 | ||||
| -rw-r--r-- | tools/perf/util/util.c | 9 | 
25 files changed, 197 insertions, 15 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 7abf05131889..7cda749059a9 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -148,6 +148,8 @@ perf-$(CONFIG_ZLIB) += zlib.o  perf-$(CONFIG_LZMA) += lzma.o  perf-$(CONFIG_ZSTD) += zstd.o +perf-$(CONFIG_LIBCAP) += cap.o +  perf-y += demangle-java.o  perf-y += demangle-rust.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 91d4fc3e78cf..e0518dc4c4d2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1122,7 +1122,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)  		goto out;  	(*rawp)[0] = tmp; -	*rawp = skip_spaces(*rawp); +	*rawp = strim(*rawp);  	return 0; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 65728cdeefb6..60428576426e 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -539,9 +539,9 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr)  	return 0;  } -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit)  { -	if (itr && itr->snapshot_finish) +	if (!on_exit && itr && itr->snapshot_finish)  		return itr->snapshot_finish(itr);  	return 0;  } @@ -577,6 +577,16 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,  	if (!str)  		return 0; +	/* PMU-agnostic options */ +	switch (*str) { +	case 'e': +		opts->auxtrace_snapshot_on_exit = true; +		str++; +		break; +	default: +		break; +	} +  	if (itr)  		return itr->parse_snapshot_options(itr, opts, str); @@ -964,6 +974,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,  	synth_opts->transactions = true;  	synth_opts->ptwrites = true;  	synth_opts->pwr_events = true; +	synth_opts->other_events = true;  	synth_opts->errors = true;  	if (no_sample) {  		synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; @@ -1061,6 +1072,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,  		case 'p':  			synth_opts->pwr_events = true;  			break; +		case 'o': +			synth_opts->other_events = true; +			break;  		case 'e':  			synth_opts->errors = true;  			break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 17eb04a1da4d..8e637ac3918e 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -60,6 +60,8 @@ enum itrace_period_type {   * @transactions: whether to synthesize events for transactions   * @ptwrites: whether to synthesize events for ptwrites   * @pwr_events: whether to synthesize power events + * @other_events: whether to synthesize other events recorded due to the use of + *                aux_output   * @errors: whether to synthesize decoder error events   * @dont_decode: whether to skip decoding entirely   * @log: write a decoding log @@ -86,6 +88,7 @@ struct itrace_synth_opts {  	bool			transactions;  	bool			ptwrites;  	bool			pwr_events; +	bool			other_events;  	bool			errors;  	bool			dont_decode;  	bool			log; @@ -499,7 +502,7 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr,  			       size_t priv_size);  void auxtrace_record__free(struct auxtrace_record *itr);  int auxtrace_record__snapshot_start(struct auxtrace_record *itr); -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr); +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit);  int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,  				   struct auxtrace_mmap *mm,  				   unsigned char *data, u64 *head, u64 *old); diff --git a/tools/perf/util/cap.c b/tools/perf/util/cap.c new file mode 100644 index 000000000000..c3ba841bbf37 --- /dev/null +++ b/tools/perf/util/cap.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Capability utilities + */ + +#ifdef HAVE_LIBCAP_SUPPORT + +#include "cap.h" +#include <stdbool.h> +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap) +{ +	cap_flag_value_t val; +	cap_t caps = cap_get_proc(); + +	if (!caps) +		return false; + +	if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0) +		val = CAP_CLEAR; + +	if (cap_free(caps) != 0) +		return false; + +	return val == CAP_SET; +} + +#endif  /* HAVE_LIBCAP_SUPPORT */ diff --git a/tools/perf/util/cap.h b/tools/perf/util/cap.h new file mode 100644 index 000000000000..051dc590ceee --- /dev/null +++ b/tools/perf/util/cap.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_CAP_H +#define __PERF_CAP_H + +#include <stdbool.h> +#include <linux/capability.h> +#include <linux/compiler.h> + +#ifdef HAVE_LIBCAP_SUPPORT + +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap); + +#else + +#include <unistd.h> +#include <sys/types.h> + +static inline bool perf_cap__capable(int cap __maybe_unused) +{ +	return geteuid() == 0; +} + +#endif /* HAVE_LIBCAP_SUPPORT */ + +/* For older systems */ +#ifndef CAP_SYSLOG +#define CAP_SYSLOG	34 +#endif + +#endif /* __PERF_CAP_H */ diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 71d4d7b35a57..beb3525e9e45 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -537,7 +537,10 @@ size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size)  	unsigned char *bitmap;  	int last_cpu = cpu_map__cpu(map, map->nr - 1); -	bitmap = zalloc((last_cpu + 7) / 8); +	if (buf == NULL) +		return 0; + +	bitmap = zalloc(last_cpu / 8 + 1);  	if (bitmap == NULL) {  		buf[0] = '\0';  		return 0; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 70841d115349..0e164e8ae28d 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -851,6 +851,7 @@ void  cpu_map_data__synthesize(struct cpu_map_data *data, struct perf_cpu_map *m  void event_attr_init(struct perf_event_attr *attr);  int perf_event_paranoid(void); +bool perf_event_paranoid_check(int max_level);  extern int sysctl_perf_event_max_stack;  extern int sysctl_perf_event_max_contexts_per_stack; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 64bc32ed6dfa..0a33f7322ecc 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -833,6 +833,9 @@ static void apply_config_terms(struct evsel *evsel,  			break;  		case PERF_EVSEL__CONFIG_TERM_PERCORE:  			break; +		case PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT: +			attr->aux_output = term->val.aux_output ? 1 : 0; +			break;  		default:  			break;  		} @@ -1587,6 +1590,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,  	PRINT_ATTRf(namespaces, p_unsigned);  	PRINT_ATTRf(ksymbol, p_unsigned);  	PRINT_ATTRf(bpf_event, p_unsigned); +	PRINT_ATTRf(aux_output, p_unsigned);  	PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned);  	PRINT_ATTRf(bp_type, p_unsigned); @@ -1734,7 +1738,8 @@ int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus,  	int pid = -1, err;  	enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; -	if (perf_missing_features.write_backward && evsel->core.attr.write_backward) +	if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || +	    (perf_missing_features.aux_output     && evsel->core.attr.aux_output))  		return -EINVAL;  	if (cpus == NULL) { @@ -1908,7 +1913,11 @@ try_fallback:  	 * Must probe features in the order they were added to the  	 * perf_event_attr interface.  	 */ -	if (!perf_missing_features.bpf_event && evsel->core.attr.bpf_event) { +	if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) { +		perf_missing_features.aux_output = true; +		pr_debug2("Kernel has no attr.aux_output support, bailing out\n"); +		goto out_close; +	} else if (!perf_missing_features.bpf_event && evsel->core.attr.bpf_event) {  		perf_missing_features.bpf_event = true;  		pr_debug2("switching off bpf_event\n");  		goto fallback_missing_features; @@ -2922,6 +2931,8 @@ int perf_evsel__open_strerror(struct evsel *evsel, struct target *target,  			return scnprintf(msg, size, "clockid feature not supported.");  		if (perf_missing_features.clockid_wrong)  			return scnprintf(msg, size, "wrong clockid (%d).", clockid); +		if (perf_missing_features.aux_output) +			return scnprintf(msg, size, "The 'aux_output' feature is not supported, update the kernel.");  		break;  	default:  		break; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 3cf35aa782b9..9cd6e3ae479a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -52,6 +52,7 @@ enum term_type {  	PERF_EVSEL__CONFIG_TERM_DRV_CFG,  	PERF_EVSEL__CONFIG_TERM_BRANCH,  	PERF_EVSEL__CONFIG_TERM_PERCORE, +	PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT,  };  struct perf_evsel_config_term { @@ -70,6 +71,7 @@ struct perf_evsel_config_term {  		char	*branch;  		unsigned long max_events;  		bool	percore; +		bool	aux_output;  	} val;  	bool weak;  }; @@ -182,6 +184,7 @@ struct perf_missing_features {  	bool group_read;  	bool ksymbol;  	bool bpf_event; +	bool aux_output;  };  extern struct perf_missing_features perf_missing_features; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b04c2b6b28b3..1f2965a07bef 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2252,8 +2252,10 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)  	/* On s390 the socket_id number is not related to the numbers of cpus.  	 * The socket_id number might be higher than the numbers of cpus.  	 * This depends on the configuration. +	 * AArch64 is the same.  	 */ -	if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4)) +	if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4) +			  || !strncmp(ph->env.arch, "aarch64", 7)))  		do_core_id_test = false;  	for (i = 0; i < (u32)cpu_nr; i++) { diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4297f56b1e05..8efbf58dc3d0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -2436,7 +2436,7 @@ void hists__match(struct hists *leader, struct hists *other)  {  	struct rb_root_cached *root;  	struct rb_node *nd; -	struct hist_entry *pos, *pair; +	struct hist_entry *pos, *pair, *pos_pair, *tmp_pair;  	if (symbol_conf.report_hierarchy) {  		/* hierarchy report always collapses entries */ @@ -2453,8 +2453,24 @@ void hists__match(struct hists *leader, struct hists *other)  		pos  = rb_entry(nd, struct hist_entry, rb_node_in);  		pair = hists__find_entry(other, pos); -		if (pair) +		if (pair && list_empty(&pair->pairs.node)) { +			list_for_each_entry_safe(pos_pair, tmp_pair, &pos->pairs.head, pairs.node) { +				if (pos_pair->hists == other) { +					/* +					 * XXX maybe decayed entries can appear +					 * here?  but then we would have use +					 * after free, as decayed entries are +					 * freed see hists__delete_entry +					 */ +					BUG_ON(!pos_pair->dummy); +					list_del_init(&pos_pair->pairs.node); +					hist_entry__delete(pos_pair); +					break; +				} +			} +  			hist_entry__add_pair(pair, pos); +		}  	}  } diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 4c52204868d8..ea504fa9b623 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -2894,6 +2894,22 @@ static int intel_pt_synth_events(struct intel_pt *pt,  	return 0;  } +static void intel_pt_setup_pebs_events(struct intel_pt *pt) +{ +	struct evsel *evsel; + +	if (!pt->synth_opts.other_events) +		return; + +	evlist__for_each_entry(pt->session->evlist, evsel) { +		if (evsel->core.attr.aux_output && evsel->id) { +			pt->sample_pebs = true; +			pt->pebs_evsel = evsel; +			return; +		} +	} +} +  static struct evsel *intel_pt_find_sched_switch(struct evlist *evlist)  {  	struct evsel *evsel; @@ -3263,6 +3279,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event,  	if (err)  		goto err_delete_thread; +	intel_pt_setup_pebs_events(pt); +  	err = auxtrace_queues__process_index(&pt->queues, session);  	if (err)  		goto err_delete_thread; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index f6ee7fbad3e4..5734460fc89e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1378,6 +1378,7 @@ static int machine__set_modules_path(struct machine *machine)  	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);  }  int __weak arch__fix_module_text_start(u64 *start __maybe_unused, +				u64 *size __maybe_unused,  				const char *name __maybe_unused)  {  	return 0; @@ -1389,7 +1390,7 @@ static int machine__create_module(void *arg, const char *name, u64 start,  	struct machine *machine = arg;  	struct map *map; -	if (arch__fix_module_text_start(&start, name) < 0) +	if (arch__fix_module_text_start(&start, &size, name) < 0)  		return -1;  	map = machine__findnew_module_map(machine, start, name); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index ef803f08ae12..8b9d7157276d 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -222,7 +222,7 @@ struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,  struct map *machine__findnew_module_map(struct machine *machine, u64 start,  					const char *filename); -int arch__fix_module_text_start(u64 *start, const char *name); +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name);  int machine__load_kallsyms(struct machine *machine, const char *filename); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2cfec3b7a982..9101568946d2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -963,6 +963,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {  	[PARSE_EVENTS__TERM_TYPE_NOOVERWRITE]		= "no-overwrite",  	[PARSE_EVENTS__TERM_TYPE_DRV_CFG]		= "driver-config",  	[PARSE_EVENTS__TERM_TYPE_PERCORE]		= "percore", +	[PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT]		= "aux-output",  };  static bool config_term_shrinked; @@ -1083,6 +1084,9 @@ do {									   \  			return -EINVAL;  		}  		break; +	case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: +		CHECK_TYPE_VAL(NUM); +		break;  	default:  		err->str = strdup("unknown term");  		err->idx = term->err_term; @@ -1133,6 +1137,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr,  	case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:  	case PARSE_EVENTS__TERM_TYPE_OVERWRITE:  	case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: +	case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:  		return config_term_common(attr, term, err);  	default:  		if (err) { @@ -1225,6 +1230,9 @@ do {								\  			ADD_CONFIG_TERM(PERCORE, percore,  					term->val.num ? true : false);  			break; +		case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: +			ADD_CONFIG_TERM(AUX_OUTPUT, aux_output, term->val.num ? 1 : 0); +			break;  		default:  			break;  		} diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 48111b8fc232..616ca1eda0eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -76,6 +76,7 @@ enum {  	PARSE_EVENTS__TERM_TYPE_OVERWRITE,  	PARSE_EVENTS__TERM_TYPE_DRV_CFG,  	PARSE_EVENTS__TERM_TYPE_PERCORE, +	PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT,  	__PARSE_EVENTS__TERM_TYPE_NR,  }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index ca6098874fe2..7469497cd28e 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -284,6 +284,7 @@ no-inherit		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }  overwrite		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }  no-overwrite		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); }  percore			{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } +aux-output		{ return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }  ,			{ return ','; }  "/"			{ BEGIN(INITIAL); return '/'; }  {name_minus}		{ return str(yyscanner, PE_NAME); } diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 235bd9803390..c6dd478956f1 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -7,6 +7,7 @@  util/python.c  ../lib/ctype.c +util/cap.c  util/evlist.c  util/evsel.c  util/cpumap.c diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 11e6093c941b..b9fe71d11bf6 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,6 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  #include <errno.h>  #include <inttypes.h> +#include <linux/err.h>  #include <linux/kernel.h>  #include <linux/zalloc.h>  #include <traceevent/event-parse.h> @@ -1955,7 +1956,9 @@ fetch_mmaped_event(struct perf_session *session,  		/* We're not fetching the event so swap back again */  		if (session->header.needs_swap)  			perf_event_header__bswap(&event->header); -		return NULL; +		pr_debug("%s: head=%#" PRIx64 " event->header_size=%#x, mmap_size=%#zx: fuzzed perf.data?\n", +			 __func__, head, event->header.size, mmap_size); +		return ERR_PTR(-EINVAL);  	}  	return event; @@ -1973,6 +1976,9 @@ static int __perf_session__process_decomp_events(struct perf_session *session)  	while (decomp->head < decomp->size && !session_done()) {  		union perf_event *event = fetch_mmaped_event(session, decomp->head, decomp->size, decomp->data); +		if (IS_ERR(event)) +			return PTR_ERR(event); +  		if (!event)  			break; @@ -2072,6 +2078,9 @@ remap:  more:  	event = fetch_mmaped_event(session, head, mmap_size, buf); +	if (IS_ERR(event)) +		return PTR_ERR(event); +  	if (!event) {  		if (mmaps[map_idx]) {  			munmap(mmaps[map_idx], mmap_size); diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index d48f9cd58964..aa344a163eaf 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -59,6 +59,8 @@ ext_sources = list(map(lambda x: '%s/%s' % (src_perf, x) , ext_sources))  extra_libraries = []  if '-DHAVE_LIBNUMA_SUPPORT' in cflags:      extra_libraries = [ 'numa' ] +if '-DHAVE_LIBCAP_SUPPORT' in cflags: +    extra_libraries += [ 'cap' ]  perf = Extension('perf',  		  sources = ext_sources, diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 173f3378aaa0..4efde7879474 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -92,6 +92,11 @@ static int prefix_underscores_count(const char *str)  	return tail - str;  } +void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c) +{ +	p->end = c->start; +} +  const char * __weak arch__normalize_symbol_name(const char *name)  {  	return name; @@ -218,7 +223,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols)  		curr = rb_entry(nd, struct symbol, rb_node);  		if (prev->end == prev->start && prev->end != curr->start) -			prev->end = curr->start; +			arch__symbols__fixup_end(prev, curr);  	}  	/* Last entry */ diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 12755b42ea93..183f630cb5f1 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -288,6 +288,7 @@ const char *arch__normalize_symbol_name(const char *name);  #define SYMBOL_A 0  #define SYMBOL_B 1 +void arch__symbols__fixup_end(struct symbol *p, struct symbol *c);  int arch__compare_symbol_names(const char *namea, const char *nameb);  int arch__compare_symbol_names_n(const char *namea, const char *nameb,  				 unsigned int n); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 873ab505ca80..590793cc5142 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -214,14 +214,24 @@ struct comm *thread__comm(const struct thread *thread)  struct comm *thread__exec_comm(const struct thread *thread)  { -	struct comm *comm, *last = NULL; +	struct comm *comm, *last = NULL, *second_last = NULL;  	list_for_each_entry(comm, &thread->comm_list, list) {  		if (comm->exec)  			return comm; +		second_last = last;  		last = comm;  	} +	/* +	 * 'last' with no start time might be the parent's comm of a synthesized +	 * thread (created by processing a synthesized fork event). For a main +	 * thread, that is very probably wrong. Prefer a later comm to avoid +	 * that case. +	 */ +	if (second_last && !last->start && thread->pid_ == thread->tid) +		return second_last; +  	return last;  } diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 9c3c97697387..6fd130a5d8f2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -16,10 +16,12 @@  #include <string.h>  #include <errno.h>  #include <limits.h> +#include <linux/capability.h>  #include <linux/kernel.h>  #include <linux/log2.h>  #include <linux/time64.h>  #include <unistd.h> +#include "cap.h"  #include "strlist.h"  #include "string2.h" @@ -403,6 +405,13 @@ int perf_event_paranoid(void)  	return value;  } + +bool perf_event_paranoid_check(int max_level) +{ +	return perf_cap__capable(CAP_SYS_ADMIN) || +			perf_event_paranoid() <= max_level; +} +  static int  fetch_ubuntu_kernel_version(unsigned int *puint)  {  | 
