aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/pmu.c')
-rw-r--r--tools/perf/util/pmu.c55
1 files changed, 48 insertions, 7 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7bcb8c315615..89c91a1a67e7 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -462,10 +462,6 @@ static struct perf_pmu *pmu_lookup(const char *name)
LIST_HEAD(aliases);
__u32 type;
- /* No support for intel_bts or intel_pt so disallow them */
- if (!strcmp(name, "intel_bts") || !strcmp(name, "intel_pt"))
- return NULL;
-
/*
* The pmu data we store & need consists of the pmu
* type value and format definitions. Load both right
@@ -542,7 +538,7 @@ struct perf_pmu *perf_pmu__find(const char *name)
}
static struct perf_pmu_format *
-pmu_find_format(struct list_head *formats, char *name)
+pmu_find_format(struct list_head *formats, const char *name)
{
struct perf_pmu_format *format;
@@ -553,6 +549,21 @@ pmu_find_format(struct list_head *formats, char *name)
return NULL;
}
+__u64 perf_pmu__format_bits(struct list_head *formats, const char *name)
+{
+ struct perf_pmu_format *format = pmu_find_format(formats, name);
+ __u64 bits = 0;
+ int fbit;
+
+ if (!format)
+ return 0;
+
+ for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
+ bits |= 1ULL << fbit;
+
+ return bits;
+}
+
/*
* Sets value based on the format definition (format parameter)
* and unformated value (value parameter).
@@ -574,6 +585,18 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
}
}
+static __u64 pmu_format_max_value(const unsigned long *format)
+{
+ int w;
+
+ w = bitmap_weight(format, PERF_PMU_FORMAT_BITS);
+ if (!w)
+ return 0;
+ if (w < 64)
+ return (1ULL << w) - 1;
+ return -1;
+}
+
/*
* Term is a string term, and might be a param-term. Try to look up it's value
* in the remaining terms.
@@ -607,7 +630,9 @@ static char *formats_error_string(struct list_head *formats)
{
struct perf_pmu_format *format;
char *err, *str;
- static const char *static_terms = "config,config1,config2,name,period,branch_type\n";
+ static const char *static_terms = "config,config1,config2,name,"
+ "period,freq,branch_type,time,"
+ "call-graph,stack-size\n";
unsigned i = 0;
if (!asprintf(&str, "valid terms:"))
@@ -647,7 +672,7 @@ static int pmu_config_term(struct list_head *formats,
{
struct perf_pmu_format *format;
__u64 *vp;
- __u64 val;
+ __u64 val, max_val;
/*
* If this is a parameter we've already used for parameterized-eval,
@@ -713,6 +738,22 @@ static int pmu_config_term(struct list_head *formats,
} else
return -EINVAL;
+ max_val = pmu_format_max_value(format->bits);
+ if (val > max_val) {
+ if (err) {
+ err->idx = term->err_val;
+ if (asprintf(&err->str,
+ "value too big for format, maximum is %llu",
+ (unsigned long long)max_val) < 0)
+ err->str = strdup("value too big for format");
+ return -EINVAL;
+ }
+ /*
+ * Assume we don't care if !err, in which case the value will be
+ * silently truncated.
+ */
+ }
+
pmu_format_value(format->bits, val, vp, zero);
return 0;
}