summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c20
-rw-r--r--tools/perf/util/color.c126
-rw-r--r--tools/perf/util/color.h2
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h1
-rw-r--r--tools/perf/util/evlist.c27
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c4
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.c48
-rw-r--r--tools/perf/util/hist.h11
-rw-r--r--tools/perf/util/map.h16
-rw-r--r--tools/perf/util/parse-events.c27
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/parse-events.y26
-rw-r--r--tools/perf/util/parse-options.c2
-rw-r--r--tools/perf/util/pmu.c102
-rw-r--r--tools/perf/util/probe-event.c34
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/session.c8
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c37
-rw-r--r--tools/perf/util/symbol-elf.c13
-rw-r--r--tools/perf/util/symbol.c33
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/unwind-libunwind.c31
28 files changed, 314 insertions, 275 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 79999ceaf2b..61bf9128e1f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -177,14 +177,17 @@ static int lock__parse(struct ins_operands *ops)
goto out_free_ops;
ops->locked.ins = ins__find(name);
+ free(name);
+
if (ops->locked.ins == NULL)
goto out_free_ops;
if (!ops->locked.ins->ops)
return 0;
- if (ops->locked.ins->ops->parse)
- ops->locked.ins->ops->parse(ops->locked.ops);
+ if (ops->locked.ins->ops->parse &&
+ ops->locked.ins->ops->parse(ops->locked.ops) < 0)
+ goto out_free_ops;
return 0;
@@ -208,6 +211,13 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
static void lock__delete(struct ins_operands *ops)
{
+ struct ins *ins = ops->locked.ins;
+
+ if (ins && ins->ops->free)
+ ins->ops->free(ops->locked.ops);
+ else
+ ins__delete(ops->locked.ops);
+
zfree(&ops->locked.ops);
zfree(&ops->target.raw);
zfree(&ops->target.name);
@@ -229,7 +239,7 @@ static int mov__parse(struct ins_operands *ops)
*s = '\0';
ops->source.raw = strdup(ops->raw);
*s = ',';
-
+
if (ops->source.raw == NULL)
return -1;
@@ -531,8 +541,8 @@ static void disasm_line__init_ins(struct disasm_line *dl)
if (!dl->ins->ops)
return;
- if (dl->ins->ops->parse)
- dl->ins->ops->parse(&dl->ops);
+ if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0)
+ dl->ins = NULL;
}
static int disasm_line__parse(char *line, char **namep, char **rawp)
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index f4654183d39..55355b3d4f8 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -5,132 +5,6 @@
int perf_use_color_default = -1;
-static int parse_color(const char *name, int len)
-{
- static const char * const color_names[] = {
- "normal", "black", "red", "green", "yellow",
- "blue", "magenta", "cyan", "white"
- };
- char *end;
- int i;
-
- for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
- const char *str = color_names[i];
- if (!strncasecmp(name, str, len) && !str[len])
- return i - 1;
- }
- i = strtol(name, &end, 10);
- if (end - name == len && i >= -1 && i <= 255)
- return i;
- return -2;
-}
-
-static int parse_attr(const char *name, int len)
-{
- static const int attr_values[] = { 1, 2, 4, 5, 7 };
- static const char * const attr_names[] = {
- "bold", "dim", "ul", "blink", "reverse"
- };
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
- const char *str = attr_names[i];
- if (!strncasecmp(name, str, len) && !str[len])
- return attr_values[i];
- }
- return -1;
-}
-
-void color_parse(const char *value, const char *var, char *dst)
-{
- color_parse_mem(value, strlen(value), var, dst);
-}
-
-void color_parse_mem(const char *value, int value_len, const char *var,
- char *dst)
-{
- const char *ptr = value;
- int len = value_len;
- int attr = -1;
- int fg = -2;
- int bg = -2;
-
- if (!strncasecmp(value, "reset", len)) {
- strcpy(dst, PERF_COLOR_RESET);
- return;
- }
-
- /* [fg [bg]] [attr] */
- while (len > 0) {
- const char *word = ptr;
- int val, wordlen = 0;
-
- while (len > 0 && !isspace(word[wordlen])) {
- wordlen++;
- len--;
- }
-
- ptr = word + wordlen;
- while (len > 0 && isspace(*ptr)) {
- ptr++;
- len--;
- }
-
- val = parse_color(word, wordlen);
- if (val >= -1) {
- if (fg == -2) {
- fg = val;
- continue;
- }
- if (bg == -2) {
- bg = val;
- continue;
- }
- goto bad;
- }
- val = parse_attr(word, wordlen);
- if (val < 0 || attr != -1)
- goto bad;
- attr = val;
- }
-
- if (attr >= 0 || fg >= 0 || bg >= 0) {
- int sep = 0;
-
- *dst++ = '\033';
- *dst++ = '[';
- if (attr >= 0) {
- *dst++ = '0' + attr;
- sep++;
- }
- if (fg >= 0) {
- if (sep++)
- *dst++ = ';';
- if (fg < 8) {
- *dst++ = '3';
- *dst++ = '0' + fg;
- } else {
- dst += sprintf(dst, "38;5;%d", fg);
- }
- }
- if (bg >= 0) {
- if (sep++)
- *dst++ = ';';
- if (bg < 8) {
- *dst++ = '4';
- *dst++ = '0' + bg;
- } else {
- dst += sprintf(dst, "48;5;%d", bg);
- }
- }
- *dst++ = 'm';
- }
- *dst = 0;
- return;
-bad:
- die("bad color value '%.*s' for variable '%s'", value_len, value, var);
-}
-
int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
{
if (value) {
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 0a594b8a0c2..38146f922c5 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -30,8 +30,6 @@ extern int perf_use_color_default;
int perf_color_default_config(const char *var, const char *value, void *cb);
int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
-void color_parse(const char *value, const char *var, char *dst);
-void color_parse_mem(const char *value, int len, const char *var, char *dst);
int color_vsnprintf(char *bf, size_t size, const char *color,
const char *fmt, va_list args);
int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 45be944d450..c2f7d3b9096 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -532,12 +532,8 @@ dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
break;
cache_offset = offset & DSO__DATA_CACHE_MASK;
- ret = -EINVAL;
- if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET))
- break;
-
- ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
+ ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset);
if (ret <= 0)
break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 3782c82c6e4..ced92841ff9 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -139,6 +139,7 @@ struct dso {
u32 status_seen;
size_t file_size;
struct list_head open_entry;
+ u64 frame_offset;
} data;
union { /* Tool specific area */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index cbab1fb77b1..28b8ce86bf1 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1436,33 +1436,6 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
return printed + fprintf(fp, "\n");
}
-int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
- int err, char *buf, size_t size)
-{
- char sbuf[128];
-
- switch (err) {
- case ENOENT:
- scnprintf(buf, size, "%s",
- "Error:\tUnable to find debugfs\n"
- "Hint:\tWas your kernel was compiled with debugfs support?\n"
- "Hint:\tIs the debugfs filesystem mounted?\n"
- "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
- break;
- case EACCES:
- scnprintf(buf, size,
- "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
- "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
- debugfs_mountpoint, debugfs_mountpoint);
- break;
- default:
- scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
- break;
- }
-
- return 0;
-}
-
int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
int err, char *buf, size_t size)
{
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0ba93f67ab9..c94a9e03ecf 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -183,7 +183,6 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
-int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1e90c8557ed..ea51a90e20a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -709,6 +709,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
if (opts->sample_weight)
perf_evsel__set_sample_bit(evsel, WEIGHT);
+ attr->task = track;
attr->mmap = track;
attr->mmap2 = track && !perf_missing_features.mmap2;
attr->comm = track;
@@ -797,6 +798,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
{
+ if (ncpus == 0 || nthreads == 0)
+ return 0;
+
if (evsel->system_wide)
nthreads = 1;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b20e40c7446..1f407f7352a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2237,6 +2237,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
* - unique number to identify actual perf.data files
* - encode endianness of file
*/
+ ph->version = PERF_HEADER_VERSION_2;
/* check magic number with one endianness */
if (magic == __perf_magic2)
@@ -2247,7 +2248,6 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
return -1;
ph->needs_swap = true;
- ph->version = PERF_HEADER_VERSION_2;
return 0;
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 182395546dd..70b48a65064 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -241,6 +241,20 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
return he->stat.period == 0;
}
+static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
+{
+ rb_erase(&he->rb_node, &hists->entries);
+
+ if (sort__need_collapse)
+ rb_erase(&he->rb_node_in, &hists->entries_collapsed);
+
+ --hists->nr_entries;
+ if (!he->filtered)
+ --hists->nr_non_filtered_entries;
+
+ hist_entry__delete(he);
+}
+
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
struct rb_node *next = rb_first(&hists->entries);
@@ -258,16 +272,7 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
(zap_kernel && n->level != '.') ||
hists__decay_entry(hists, n)) &&
!n->used) {
- rb_erase(&n->rb_node, &hists->entries);
-
- if (sort__need_collapse)
- rb_erase(&n->rb_node_in, &hists->entries_collapsed);
-
- --hists->nr_entries;
- if (!n->filtered)
- --hists->nr_non_filtered_entries;
-
- hist_entry__free(n);
+ hists__delete_entry(hists, n);
}
}
}
@@ -281,16 +286,7 @@ void hists__delete_entries(struct hists *hists)
n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
- rb_erase(&n->rb_node, &hists->entries);
-
- if (sort__need_collapse)
- rb_erase(&n->rb_node_in, &hists->entries_collapsed);
-
- --hists->nr_entries;
- if (!n->filtered)
- --hists->nr_non_filtered_entries;
-
- hist_entry__free(n);
+ hists__delete_entry(hists, n);
}
}
@@ -433,6 +429,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
if (!he)
return NULL;
+ hists->nr_entries++;
+
rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, hists->entries_in);
out:
@@ -915,7 +913,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
if (perf_hpp__should_skip(fmt))
continue;
- cmp = fmt->cmp(left, right);
+ cmp = fmt->cmp(fmt, left, right);
if (cmp)
break;
}
@@ -933,7 +931,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
if (perf_hpp__should_skip(fmt))
continue;
- cmp = fmt->collapse(left, right);
+ cmp = fmt->collapse(fmt, left, right);
if (cmp)
break;
}
@@ -941,7 +939,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
return cmp;
}
-void hist_entry__free(struct hist_entry *he)
+void hist_entry__delete(struct hist_entry *he)
{
zfree(&he->branch_info);
zfree(&he->mem_info);
@@ -981,7 +979,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
iter->callchain,
he->callchain);
}
- hist_entry__free(he);
+ hist_entry__delete(he);
return false;
}
@@ -1063,7 +1061,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
if (perf_hpp__should_skip(fmt))
continue;
- cmp = fmt->sort(a, b);
+ cmp = fmt->sort(fmt, a, b);
if (cmp)
break;
}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 46bd50344f8..2b690d02890 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -119,7 +119,7 @@ int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
int hist_entry__transaction_len(void);
int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
struct hists *hists);
-void hist_entry__free(struct hist_entry *);
+void hist_entry__delete(struct hist_entry *he);
void hists__output_resort(struct hists *hists, struct ui_progress *prog);
void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
@@ -195,9 +195,12 @@ struct perf_hpp_fmt {
struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
- int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
- int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
- int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
+ int64_t (*cmp)(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b);
+ int64_t (*collapse)(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b);
+ int64_t (*sort)(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b);
struct list_head list;
struct list_head sort_list;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 6951a9d4233..0e42438b1e5 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -116,6 +116,22 @@ struct thread;
#define map__for_each_symbol(map, pos, n) \
dso__for_each_symbol(map->dso, pos, n, map->type)
+/* map__for_each_symbol_with_name - iterate over the symbols in the given map
+ * that have the given name
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @sym_name: the symbol name
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @filter: to use when loading the DSO
+ */
+#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \
+ for (pos = map__find_symbol_by_name(map, sym_name, filter); \
+ pos && strcmp(pos->name, sym_name) == 0; \
+ pos = symbol__next_by_name(pos))
+
+#define map__for_each_symbol_by_name(map, sym_name, pos) \
+ __map__for_each_symbol_by_name(map, sym_name, (pos), NULL)
+
typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 77b43fe43d5..7f8ec6ce282 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -526,7 +526,7 @@ do { \
}
int parse_events_add_breakpoint(struct list_head *list, int *idx,
- void *ptr, char *type)
+ void *ptr, char *type, u64 len)
{
struct perf_event_attr attr;
@@ -536,14 +536,15 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
if (parse_breakpoint_type(type, &attr))
return -EINVAL;
- /*
- * We should find a nice way to override the access length
- * Provide some defaults for now
- */
- if (attr.bp_type == HW_BREAKPOINT_X)
- attr.bp_len = sizeof(long);
- else
- attr.bp_len = HW_BREAKPOINT_LEN_4;
+ /* Provide some defaults if len is not specified */
+ if (!len) {
+ if (attr.bp_type == HW_BREAKPOINT_X)
+ len = sizeof(long);
+ else
+ len = HW_BREAKPOINT_LEN_4;
+ }
+
+ attr.bp_len = len;
attr.type = PERF_TYPE_BREAKPOINT;
attr.sample_period = 1;
@@ -1121,7 +1122,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
return;
for_each_subsystem(sys_dir, sys_dirent, sys_next) {
- if (subsys_glob != NULL &&
+ if (subsys_glob != NULL &&
!strglobmatch(sys_dirent.d_name, subsys_glob))
continue;
@@ -1132,7 +1133,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
continue;
for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
- if (event_glob != NULL &&
+ if (event_glob != NULL &&
!strglobmatch(evt_dirent.d_name, event_glob))
continue;
@@ -1305,7 +1306,7 @@ static void print_symbol_events(const char *event_glob, unsigned type,
for (i = 0; i < max; i++, syms++) {
- if (event_glob != NULL &&
+ if (event_glob != NULL &&
!(strglobmatch(syms->symbol, event_glob) ||
(syms->alias && strglobmatch(syms->alias, event_glob))))
continue;
@@ -1366,7 +1367,7 @@ void print_events(const char *event_glob, bool name_only)
printf("\n");
printf(" %-50s [%s]\n",
- "mem:<addr>[:access]",
+ "mem:<addr>[/len][:access]",
event_type_descriptors[PERF_TYPE_BREAKPOINT]);
printf("\n");
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index db2cf78ff0f..ff6e1fa4111 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -71,6 +71,7 @@ struct parse_events_term {
int type_val;
int type_term;
struct list_head list;
+ bool used;
};
struct parse_events_evlist {
@@ -104,7 +105,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2);
int parse_events_add_breakpoint(struct list_head *list, int *idx,
- void *ptr, char *type);
+ void *ptr, char *type, u64 len);
int parse_events_add_pmu(struct list_head *list, int *idx,
char *pmu , struct list_head *head_config);
enum perf_pmu_event_symbol_type
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 906630bbf8e..94eacb6c1ef 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -159,6 +159,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE
<mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
: { return ':'; }
+"/" { return '/'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 93c4c9fbc92..72def077dbb 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -326,6 +326,28 @@ PE_NAME_CACHE_TYPE
}
event_legacy_mem:
+PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
+{
+ struct parse_events_evlist *data = _data;
+ struct list_head *list;
+
+ ALLOC_LIST(list);
+ ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
+ (void *) $2, $6, $4));
+ $$ = list;
+}
+|
+PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
+{
+ struct parse_events_evlist *data = _data;
+ struct list_head *list;
+
+ ALLOC_LIST(list);
+ ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
+ (void *) $2, NULL, $4));
+ $$ = list;
+}
+|
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
struct parse_events_evlist *data = _data;
@@ -333,7 +355,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
- (void *) $2, $4));
+ (void *) $2, $4, 0));
$$ = list;
}
|
@@ -344,7 +366,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
- (void *) $2, NULL));
+ (void *) $2, NULL, 0));
$$ = list;
}
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index f62dee7bd92..4a015f77e2b 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -46,7 +46,7 @@ static int get_value(struct parse_opt_ctx_t *p,
return opterror(opt, "is not usable", flags);
if (opt->flags & PARSE_OPT_EXCLUSIVE) {
- if (p->excl_opt) {
+ if (p->excl_opt && p->excl_opt != opt) {
char msg[128];
if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 5c9c4947cfb..48411674da0 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -551,31 +551,68 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
}
/*
+ * Term is a string term, and might be a param-term. Try to look up it's value
+ * in the remaining terms.
+ * - We have a term like "base-or-format-term=param-term",
+ * - We need to find the value supplied for "param-term" (with param-term named
+ * in a config string) later on in the term list.
+ */
+static int pmu_resolve_param_term(struct parse_events_term *term,
+ struct list_head *head_terms,
+ __u64 *value)
+{
+ struct parse_events_term *t;
+
+ list_for_each_entry(t, head_terms, list) {
+ if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
+ if (!strcmp(t->config, term->config)) {
+ t->used = true;
+ *value = t->val.num;
+ return 0;
+ }
+ }
+ }
+
+ if (verbose)
+ printf("Required parameter '%s' not specified\n", term->config);
+
+ return -1;
+}
+
+/*
* Setup one of config[12] attr members based on the
* user input data - term parameter.
*/
static int pmu_config_term(struct list_head *formats,
struct perf_event_attr *attr,
struct parse_events_term *term,
+ struct list_head *head_terms,
bool zero)
{
struct perf_pmu_format *format;
__u64 *vp;
+ __u64 val;
+
+ /*
+ * If this is a parameter we've already used for parameterized-eval,
+ * skip it in normal eval.
+ */
+ if (term->used)
+ return 0;
/*
- * Support only for hardcoded and numnerial terms.
* Hardcoded terms should be already in, so nothing
* to be done for them.
*/
if (parse_events__is_hardcoded_term(term))
return 0;
- if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
- return -EINVAL;
-
format = pmu_find_format(formats, term->config);
- if (!format)
+ if (!format) {
+ if (verbose)
+ printf("Invalid event/parameter '%s'\n", term->config);
return -EINVAL;
+ }
switch (format->value) {
case PERF_PMU_FORMAT_VALUE_CONFIG:
@@ -592,11 +629,25 @@ static int pmu_config_term(struct list_head *formats,
}
/*
- * XXX If we ever decide to go with string values for
- * non-hardcoded terms, here's the place to translate
- * them into value.
+ * Either directly use a numeric term, or try to translate string terms
+ * using event parameters.
*/
- pmu_format_value(format->bits, term->val.num, vp, zero);
+ if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
+ val = term->val.num;
+ else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
+ if (strcmp(term->val.str, "?")) {
+ if (verbose)
+ pr_info("Invalid sysfs entry %s=%s\n",
+ term->config, term->val.str);
+ return -EINVAL;
+ }
+
+ if (pmu_resolve_param_term(term, head_terms, &val))
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ pmu_format_value(format->bits, val, vp, zero);
return 0;
}
@@ -607,9 +658,10 @@ int perf_pmu__config_terms(struct list_head *formats,
{
struct parse_events_term *term;
- list_for_each_entry(term, head_terms, list)
- if (pmu_config_term(formats, attr, term, zero))
+ list_for_each_entry(term, head_terms, list) {
+ if (pmu_config_term(formats, attr, term, head_terms, zero))
return -EINVAL;
+ }
return 0;
}
@@ -767,10 +819,36 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
set_bit(b, bits);
}
+static int sub_non_neg(int a, int b)
+{
+ if (b > a)
+ return 0;
+ return a - b;
+}
+
static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
struct perf_pmu_alias *alias)
{
- snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
+ struct parse_events_term *term;
+ int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
+
+ list_for_each_entry(term, &alias->terms, list) {
+ if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
+ used += snprintf(buf + used, sub_non_neg(len, used),
+ ",%s=%s", term->config,
+ term->val.str);
+ }
+
+ if (sub_non_neg(len, used) > 0) {
+ buf[used] = '/';
+ used++;
+ }
+ if (sub_non_neg(len, used) > 0) {
+ buf[used] = '\0';
+ used++;
+ } else
+ buf[len - 1] = '\0';
+
return buf;
}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 94a717bf007..919937eb0be 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -446,7 +446,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
}
for (i = 0; i < ntevs; i++) {
- if (tevs[i].point.address) {
+ if (tevs[i].point.address && !tevs[i].point.retprobe) {
tmp = strdup(reloc_sym->name);
if (!tmp)
return -ENOMEM;
@@ -2193,18 +2193,17 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
return ret;
}
-static char *looking_function_name;
-static int num_matched_functions;
-
-static int probe_function_filter(struct map *map __maybe_unused,
- struct symbol *sym)
+static int find_probe_functions(struct map *map, char *name)
{
- if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
- strcmp(looking_function_name, sym->name) == 0) {
- num_matched_functions++;
- return 0;
+ int found = 0;
+ struct symbol *sym;
+
+ map__for_each_symbol_by_name(map, name, sym) {
+ if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL)
+ found++;
}
- return 1;
+
+ return found;
}
#define strdup_or_goto(str, label) \
@@ -2222,10 +2221,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
struct kmap *kmap = NULL;
struct ref_reloc_sym *reloc_sym = NULL;
struct symbol *sym;
- struct rb_node *nd;
struct probe_trace_event *tev;
struct perf_probe_point *pp = &pev->point;
struct probe_trace_point *tp;
+ int num_matched_functions;
int ret, i;
/* Init maps of given executable or kernel */
@@ -2242,10 +2241,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
* Load matched symbols: Since the different local symbols may have
* same name but different addresses, this lists all the symbols.
*/
- num_matched_functions = 0;
- looking_function_name = pp->function;
- ret = map__load(map, probe_function_filter);
- if (ret || num_matched_functions == 0) {
+ num_matched_functions = find_probe_functions(map, pp->function);
+ if (num_matched_functions == 0) {
pr_err("Failed to find symbol %s in %s\n", pp->function,
target ? : "kernel");
ret = -ENOENT;
@@ -2257,7 +2254,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
goto out;
}
- if (!pev->uprobes) {
+ if (!pev->uprobes && !pp->retprobe) {
kmap = map__kmap(map);
reloc_sym = kmap->ref_reloc_sym;
if (!reloc_sym) {
@@ -2275,7 +2272,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
}
ret = 0;
- map__for_each_symbol(map, sym, nd) {
+
+ map__for_each_symbol_by_name(map, pp->function, sym) {
tev = (*tevs) + ret;
tp = &tev->point;
if (ret == num_matched_functions) {
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 3dda85ca50c..d906d0ad5d4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -768,7 +768,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
Py_DECREF(file);
goto free_list;
}
-
+
Py_DECREF(file);
}
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index d808a328f4d..0c815a40a6e 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -89,7 +89,7 @@ static void handler_call_die(const char *handler_name)
/*
* Insert val into into the dictionary and decrement the reference counter.
- * This is necessary for dictionaries since PyDict_SetItemString() does not
+ * This is necessary for dictionaries since PyDict_SetItemString() does not
* steal a reference, as opposed to PyTuple_SetItem().
*/
static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5f0e05a76c0..0baf75f12b7 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -274,7 +274,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
if (tool->id_index == NULL)
tool->id_index = process_id_index_stub;
}
-
+
static void swap_sample_id_all(union perf_event *event, void *data)
{
void *end = (void *) event + event->header.size;
@@ -1251,9 +1251,9 @@ fetch_mmaped_event(struct perf_session *session,
#define NUM_MMAPS 128
#endif
-int __perf_session__process_events(struct perf_session *session,
- u64 data_offset, u64 data_size,
- u64 file_size, struct perf_tool *tool)
+static int __perf_session__process_events(struct perf_session *session,
+ u64 data_offset, u64 data_size,
+ u64 file_size, struct perf_tool *tool)
{
int fd = perf_data_file__fd(session->file);
u64 head, page_offset, file_offset, file_pos, size;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index dc26ebf60fe..6d663dc7640 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -49,9 +49,6 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
union perf_event **event_ptr,
struct perf_sample *sample);
-int __perf_session__process_events(struct perf_session *session,
- u64 data_offset, u64 data_size, u64 size,
- struct perf_tool *tool);
int perf_session__process_events(struct perf_session *session,
struct perf_tool *tool);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 9139dda9f9a..7a39c1ed8d3 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1304,6 +1304,37 @@ static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
}
+static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct hpp_sort_entry *hse;
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ return hse->se->se_cmp(a, b);
+}
+
+static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct hpp_sort_entry *hse;
+ int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
+ return collapse_fn(a, b);
+}
+
+static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct hpp_sort_entry *hse;
+ int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
+ return sort_fn(a, b);
+}
+
static struct hpp_sort_entry *
__sort_dimension__alloc_hpp(struct sort_dimension *sd)
{
@@ -1322,9 +1353,9 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
hse->hpp.entry = __sort__hpp_entry;
hse->hpp.color = NULL;
- hse->hpp.cmp = sd->entry->se_cmp;
- hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
- hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
+ hse->hpp.cmp = __sort__hpp_cmp;
+ hse->hpp.collapse = __sort__hpp_collapse;
+ hse->hpp.sort = __sort__hpp_sort;
INIT_LIST_HEAD(&hse->hpp.list);
INIT_LIST_HEAD(&hse->hpp.sort_list);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 06fcd1bf98b..b24f9d8727a 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -574,13 +574,16 @@ static int decompress_kmodule(struct dso *dso, const char *name,
const char *ext = strrchr(name, '.');
char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
- if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
- type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
- type != dso->symtab_type)
+ if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+ type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
+ type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
return -1;
- if (!ext || !is_supported_compression(ext + 1))
- return -1;
+ if (!ext || !is_supported_compression(ext + 1)) {
+ ext = strrchr(dso->name, '.');
+ if (!ext || !is_supported_compression(ext + 1))
+ return -1;
+ }
fd = mkstemp(tmpbuf);
if (fd < 0)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c24c5b83156..a69066865a5 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -396,6 +396,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
const char *name)
{
struct rb_node *n;
+ struct symbol_name_rb_node *s;
if (symbols == NULL)
return NULL;
@@ -403,7 +404,6 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
n = symbols->rb_node;
while (n) {
- struct symbol_name_rb_node *s;
int cmp;
s = rb_entry(n, struct symbol_name_rb_node, rb_node);
@@ -414,10 +414,24 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
else if (cmp > 0)
n = n->rb_right;
else
- return &s->sym;
+ break;
}
- return NULL;
+ if (n == NULL)
+ return NULL;
+
+ /* return first symbol that has same name (if any) */
+ for (n = rb_prev(n); n; n = rb_prev(n)) {
+ struct symbol_name_rb_node *tmp;
+
+ tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
+ if (strcmp(tmp->sym.name, s->sym.name))
+ break;
+
+ s = tmp;
+ }
+
+ return &s->sym;
}
struct symbol *dso__find_symbol(struct dso *dso,
@@ -436,6 +450,17 @@ struct symbol *dso__next_symbol(struct symbol *sym)
return symbols__next(sym);
}
+struct symbol *symbol__next_by_name(struct symbol *sym)
+{
+ struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
+ struct rb_node *n = rb_next(&s->rb_node);
+
+ return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
+}
+
+ /*
+ * Teturns first symbol that matched with @name.
+ */
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
const char *name)
{
@@ -660,7 +685,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
struct machine *machine = kmaps->machine;
struct map *curr_map = map;
struct symbol *pos;
- int count = 0, moved = 0;
+ int count = 0, moved = 0;
struct rb_root *root = &dso->symbols[map->type];
struct rb_node *next = rb_first(root);
int kernel_range = 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9d602e9c6f5..1650dcb3a67 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -231,6 +231,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
u64 addr);
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
const char *name);
+struct symbol *symbol__next_by_name(struct symbol *sym);
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
struct symbol *dso__next_symbol(struct symbol *sym);
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 6edf535f65c..e3c40a520a2 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -266,14 +266,17 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
u64 *fde_count)
{
int ret = -EINVAL, fd;
- u64 offset;
+ u64 offset = dso->data.frame_offset;
- fd = dso__data_fd(dso, machine);
- if (fd < 0)
- return -EINVAL;
+ if (offset == 0) {
+ fd = dso__data_fd(dso, machine);
+ if (fd < 0)
+ return -EINVAL;
- /* Check the .eh_frame section for unwinding info */
- offset = elf_section_offset(fd, ".eh_frame_hdr");
+ /* Check the .eh_frame section for unwinding info */
+ offset = elf_section_offset(fd, ".eh_frame_hdr");
+ dso->data.frame_offset = offset;
+ }
if (offset)
ret = unwind_spec_ehframe(dso, machine, offset,
@@ -287,14 +290,20 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
static int read_unwind_spec_debug_frame(struct dso *dso,
struct machine *machine, u64 *offset)
{
- int fd = dso__data_fd(dso, machine);
+ int fd;
+ u64 ofs = dso->data.frame_offset;
- if (fd < 0)
- return -EINVAL;
+ if (ofs == 0) {
+ fd = dso__data_fd(dso, machine);
+ if (fd < 0)
+ return -EINVAL;
- /* Check the .debug_frame section for unwinding info */
- *offset = elf_section_offset(fd, ".debug_frame");
+ /* Check the .debug_frame section for unwinding info */
+ ofs = elf_section_offset(fd, ".debug_frame");
+ dso->data.frame_offset = ofs;
+ }
+ *offset = ofs;
if (*offset)
return 0;