aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c32
-rw-r--r--tools/perf/util/callchain.h8
-rw-r--r--tools/perf/util/header.c5
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h8
-rw-r--r--tools/perf/util/parse-events.c206
-rw-r--r--tools/perf/util/parse-events.h6
-rw-r--r--tools/perf/util/quote.c2
-rw-r--r--tools/perf/util/string.h3
-rw-r--r--tools/perf/util/strlist.c20
-rw-r--r--tools/perf/util/strlist.h11
-rw-r--r--tools/perf/util/symbol.c281
-rw-r--r--tools/perf/util/symbol.h3
-rw-r--r--tools/perf/util/util.h2
15 files changed, 499 insertions, 91 deletions
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 161d5f413e28..4b50c412b9c5 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -18,6 +18,7 @@
18#define PERFATTRIBUTES_FILE ".perfattributes" 18#define PERFATTRIBUTES_FILE ".perfattributes"
19#define INFOATTRIBUTES_FILE "info/attributes" 19#define INFOATTRIBUTES_FILE "info/attributes"
20#define ATTRIBUTE_MACRO_PREFIX "[attr]" 20#define ATTRIBUTE_MACRO_PREFIX "[attr]"
21#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
21 22
22typedef int (*config_fn_t)(const char *, const char *, void *); 23typedef int (*config_fn_t)(const char *, const char *, void *);
23extern int perf_default_config(const char *, const char *, void *); 24extern int perf_default_config(const char *, const char *, void *);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9d3c8141b8c1..011473411642 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -13,6 +13,7 @@
13#include <stdio.h> 13#include <stdio.h>
14#include <stdbool.h> 14#include <stdbool.h>
15#include <errno.h> 15#include <errno.h>
16#include <math.h>
16 17
17#include "callchain.h" 18#include "callchain.h"
18 19
@@ -26,10 +27,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
26 struct rb_node **p = &root->rb_node; 27 struct rb_node **p = &root->rb_node;
27 struct rb_node *parent = NULL; 28 struct rb_node *parent = NULL;
28 struct callchain_node *rnode; 29 struct callchain_node *rnode;
30 u64 chain_cumul = cumul_hits(chain);
29 31
30 while (*p) { 32 while (*p) {
33 u64 rnode_cumul;
34
31 parent = *p; 35 parent = *p;
32 rnode = rb_entry(parent, struct callchain_node, rb_node); 36 rnode = rb_entry(parent, struct callchain_node, rb_node);
37 rnode_cumul = cumul_hits(rnode);
33 38
34 switch (mode) { 39 switch (mode) {
35 case CHAIN_FLAT: 40 case CHAIN_FLAT:
@@ -40,7 +45,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
40 break; 45 break;
41 case CHAIN_GRAPH_ABS: /* Falldown */ 46 case CHAIN_GRAPH_ABS: /* Falldown */
42 case CHAIN_GRAPH_REL: 47 case CHAIN_GRAPH_REL:
43 if (rnode->cumul_hit < chain->cumul_hit) 48 if (rnode_cumul < chain_cumul)
44 p = &(*p)->rb_left; 49 p = &(*p)->rb_left;
45 else 50 else
46 p = &(*p)->rb_right; 51 p = &(*p)->rb_right;
@@ -87,7 +92,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
87 92
88 chain_for_each_child(child, node) { 93 chain_for_each_child(child, node) {
89 __sort_chain_graph_abs(child, min_hit); 94 __sort_chain_graph_abs(child, min_hit);
90 if (child->cumul_hit >= min_hit) 95 if (cumul_hits(child) >= min_hit)
91 rb_insert_callchain(&node->rb_root, child, 96 rb_insert_callchain(&node->rb_root, child,
92 CHAIN_GRAPH_ABS); 97 CHAIN_GRAPH_ABS);
93 } 98 }
@@ -108,11 +113,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
108 u64 min_hit; 113 u64 min_hit;
109 114
110 node->rb_root = RB_ROOT; 115 node->rb_root = RB_ROOT;
111 min_hit = node->cumul_hit * min_percent / 100.0; 116 min_hit = ceil(node->children_hit * min_percent);
112 117
113 chain_for_each_child(child, node) { 118 chain_for_each_child(child, node) {
114 __sort_chain_graph_rel(child, min_percent); 119 __sort_chain_graph_rel(child, min_percent);
115 if (child->cumul_hit >= min_hit) 120 if (cumul_hits(child) >= min_hit)
116 rb_insert_callchain(&node->rb_root, child, 121 rb_insert_callchain(&node->rb_root, child,
117 CHAIN_GRAPH_REL); 122 CHAIN_GRAPH_REL);
118 } 123 }
@@ -122,7 +127,7 @@ static void
122sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, 127sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
123 u64 min_hit __used, struct callchain_param *param) 128 u64 min_hit __used, struct callchain_param *param)
124{ 129{
125 __sort_chain_graph_rel(chain_root, param->min_percent); 130 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
126 rb_root->rb_node = chain_root->rb_root.rb_node; 131 rb_root->rb_node = chain_root->rb_root.rb_node;
127} 132}
128 133
@@ -211,7 +216,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
211 new = create_child(parent, false); 216 new = create_child(parent, false);
212 fill_node(new, chain, start, syms); 217 fill_node(new, chain, start, syms);
213 218
214 new->cumul_hit = new->hit = 1; 219 new->children_hit = 0;
220 new->hit = 1;
215} 221}
216 222
217/* 223/*
@@ -241,7 +247,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
241 247
242 /* split the hits */ 248 /* split the hits */
243 new->hit = parent->hit; 249 new->hit = parent->hit;
244 new->cumul_hit = parent->cumul_hit; 250 new->children_hit = parent->children_hit;
251 parent->children_hit = cumul_hits(new);
245 new->val_nr = parent->val_nr - idx_local; 252 new->val_nr = parent->val_nr - idx_local;
246 parent->val_nr = idx_local; 253 parent->val_nr = idx_local;
247 254
@@ -249,6 +256,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
249 if (idx_total < chain->nr) { 256 if (idx_total < chain->nr) {
250 parent->hit = 0; 257 parent->hit = 0;
251 add_child(parent, chain, idx_total, syms); 258 add_child(parent, chain, idx_total, syms);
259 parent->children_hit++;
252 } else { 260 } else {
253 parent->hit = 1; 261 parent->hit = 1;
254 } 262 }
@@ -269,13 +277,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
269 unsigned int ret = __append_chain(rnode, chain, start, syms); 277 unsigned int ret = __append_chain(rnode, chain, start, syms);
270 278
271 if (!ret) 279 if (!ret)
272 goto cumul; 280 goto inc_children_hit;
273 } 281 }
274 /* nothing in children, add to the current node */ 282 /* nothing in children, add to the current node */
275 add_child(root, chain, start, syms); 283 add_child(root, chain, start, syms);
276 284
277cumul: 285inc_children_hit:
278 root->cumul_hit++; 286 root->children_hit++;
279} 287}
280 288
281static int 289static int
@@ -317,8 +325,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
317 /* we match 100% of the path, increment the hit */ 325 /* we match 100% of the path, increment the hit */
318 if (i - start == root->val_nr && i == chain->nr) { 326 if (i - start == root->val_nr && i == chain->nr) {
319 root->hit++; 327 root->hit++;
320 root->cumul_hit++;
321
322 return 0; 328 return 0;
323 } 329 }
324 330
@@ -331,5 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
331void append_chain(struct callchain_node *root, struct ip_callchain *chain, 337void append_chain(struct callchain_node *root, struct ip_callchain *chain,
332 struct symbol **syms) 338 struct symbol **syms)
333{ 339{
340 if (!chain->nr)
341 return;
334 __append_chain_children(root, chain, syms, 0); 342 __append_chain_children(root, chain, syms, 0);
335} 343}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 7812122bea1d..a926ae4f5a16 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -7,6 +7,7 @@
7#include "symbol.h" 7#include "symbol.h"
8 8
9enum chain_mode { 9enum chain_mode {
10 CHAIN_NONE,
10 CHAIN_FLAT, 11 CHAIN_FLAT,
11 CHAIN_GRAPH_ABS, 12 CHAIN_GRAPH_ABS,
12 CHAIN_GRAPH_REL 13 CHAIN_GRAPH_REL
@@ -21,7 +22,7 @@ struct callchain_node {
21 struct rb_root rb_root; /* sorted tree of children */ 22 struct rb_root rb_root; /* sorted tree of children */
22 unsigned int val_nr; 23 unsigned int val_nr;
23 u64 hit; 24 u64 hit;
24 u64 cumul_hit; /* hit + hits of children */ 25 u64 children_hit;
25}; 26};
26 27
27struct callchain_param; 28struct callchain_param;
@@ -48,6 +49,11 @@ static inline void callchain_init(struct callchain_node *node)
48 INIT_LIST_HEAD(&node->val); 49 INIT_LIST_HEAD(&node->val);
49} 50}
50 51
52static inline u64 cumul_hits(struct callchain_node *node)
53{
54 return node->hit + node->children_hit;
55}
56
51int register_callchain_param(struct callchain_param *param); 57int register_callchain_param(struct callchain_param *param);
52void append_chain(struct callchain_node *root, struct ip_callchain *chain, 58void append_chain(struct callchain_node *root, struct ip_callchain *chain,
53 struct symbol **syms); 59 struct symbol **syms);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 450384b3bbe5..b92a457ca32e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -185,6 +185,8 @@ static void do_read(int fd, void *buf, size_t size)
185 185
186 if (ret < 0) 186 if (ret < 0)
187 die("failed to read"); 187 die("failed to read");
188 if (ret == 0)
189 die("failed to read: missing data");
188 190
189 size -= ret; 191 size -= ret;
190 buf += ret; 192 buf += ret;
@@ -213,9 +215,10 @@ struct perf_header *perf_header__read(int fd)
213 215
214 for (i = 0; i < nr_attrs; i++) { 216 for (i = 0; i < nr_attrs; i++) {
215 struct perf_header_attr *attr; 217 struct perf_header_attr *attr;
216 off_t tmp = lseek(fd, 0, SEEK_CUR); 218 off_t tmp;
217 219
218 do_read(fd, &f_attr, sizeof(f_attr)); 220 do_read(fd, &f_attr, sizeof(f_attr));
221 tmp = lseek(fd, 0, SEEK_CUR);
219 222
220 attr = perf_header_attr__new(&f_attr.attr); 223 attr = perf_header_attr__new(&f_attr.attr);
221 224
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index b5ef53ad4c7a..bf280449fcfd 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -16,7 +16,7 @@ struct perf_header {
16 int frozen; 16 int frozen;
17 int attrs, size; 17 int attrs, size;
18 struct perf_header_attr **attr; 18 struct perf_header_attr **attr;
19 off_t attr_offset; 19 s64 attr_offset;
20 u64 data_offset; 20 u64 data_offset;
21 u64 data_size; 21 u64 data_size;
22}; 22};
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 99c1b3d1edd9..a6b87390cb52 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -18,4 +18,12 @@
18 (type *)((char *)__mptr - offsetof(type, member)); }) 18 (type *)((char *)__mptr - offsetof(type, member)); })
19#endif 19#endif
20 20
21#ifndef max
22#define max(x, y) ({ \
23 typeof(x) _max1 = (x); \
24 typeof(y) _max2 = (y); \
25 (void) (&_max1 == &_max2); \
26 _max1 > _max2 ? _max1 : _max2; })
27#endif
28
21#endif 29#endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5184959e0615..4858d83b3b67 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8#include "cache.h"
8 9
9extern char *strcasestr(const char *haystack, const char *needle); 10extern char *strcasestr(const char *haystack, const char *needle);
10 11
@@ -19,6 +20,8 @@ struct event_symbol {
19 char *alias; 20 char *alias;
20}; 21};
21 22
23char debugfs_path[MAXPATHLEN];
24
22#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 25#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 26#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24 27
@@ -71,8 +74,8 @@ static char *sw_event_names[] = {
71#define MAX_ALIASES 8 74#define MAX_ALIASES 8
72 75
73static char *hw_cache[][MAX_ALIASES] = { 76static char *hw_cache[][MAX_ALIASES] = {
74 { "L1-d$", "l1-d", "l1d", "L1-data", }, 77 { "L1-dcache", "l1-d", "l1d", "L1-data", },
75 { "L1-i$", "l1-i", "l1i", "L1-instruction", }, 78 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
76 { "LLC", "L2" }, 79 { "LLC", "L2" },
77 { "dTLB", "d-tlb", "Data-TLB", }, 80 { "dTLB", "d-tlb", "Data-TLB", },
78 { "iTLB", "i-tlb", "Instruction-TLB", }, 81 { "iTLB", "i-tlb", "Instruction-TLB", },
@@ -110,6 +113,104 @@ static unsigned long hw_cache_stat[C(MAX)] = {
110 [C(BPU)] = (CACHE_READ), 113 [C(BPU)] = (CACHE_READ),
111}; 114};
112 115
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, "..")))
123
124static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
125{
126 char evt_path[MAXPATHLEN];
127 int fd;
128
129 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
130 sys_dir->d_name, evt_dir->d_name);
131 fd = open(evt_path, O_RDONLY);
132 if (fd < 0)
133 return -EINVAL;
134 close(fd);
135
136 return 0;
137}
138
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147
148#define MAX_EVENT_LENGTH 30
149
150int valid_debugfs_mount(const char *debugfs)
151{
152 struct statfs st_fs;
153
154 if (statfs(debugfs, &st_fs) < 0)
155 return -ENOENT;
156 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
157 return -ENOENT;
158 return 0;
159}
160
161static char *tracepoint_id_to_name(u64 config)
162{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
164 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4];
168 int fd;
169 u64 id;
170 char evt_path[MAXPATHLEN];
171
172 if (valid_debugfs_mount(debugfs_path))
173 return "unkown";
174
175 sys_dir = opendir(debugfs_path);
176 if (!sys_dir)
177 goto cleanup;
178
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
180 evt_dir = opendir(evt_path);
181 if (!evt_dir)
182 goto cleanup;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
184 evt_path, st) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
186 debugfs_path, sys_dirent.d_name,
187 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY);
189 if (fd < 0)
190 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
192 close(fd);
193 continue;
194 }
195 close(fd);
196 id = atoll(id_buf);
197 if (id == config) {
198 closedir(evt_dir);
199 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
201 "%s:%s", sys_dirent.d_name,
202 evt_dirent.d_name);
203 return tracepoint_name;
204 }
205 }
206 closedir(evt_dir);
207 }
208
209cleanup:
210 closedir(sys_dir);
211 return "unkown";
212}
213
113static int is_cache_op_valid(u8 cache_type, u8 cache_op) 214static int is_cache_op_valid(u8 cache_type, u8 cache_op)
114{ 215{
115 if (hw_cache_stat[cache_type] & COP(cache_op)) 216 if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -138,9 +239,15 @@ char *event_name(int counter)
138{ 239{
139 u64 config = attrs[counter].config; 240 u64 config = attrs[counter].config;
140 int type = attrs[counter].type; 241 int type = attrs[counter].type;
242
243 return __event_name(type, config);
244}
245
246char *__event_name(int type, u64 config)
247{
141 static char buf[32]; 248 static char buf[32];
142 249
143 if (attrs[counter].type == PERF_TYPE_RAW) { 250 if (type == PERF_TYPE_RAW) {
144 sprintf(buf, "raw 0x%llx", config); 251 sprintf(buf, "raw 0x%llx", config);
145 return buf; 252 return buf;
146 } 253 }
@@ -177,6 +284,9 @@ char *event_name(int counter)
177 return sw_event_names[config]; 284 return sw_event_names[config];
178 return "unknown-software"; 285 return "unknown-software";
179 286
287 case PERF_TYPE_TRACEPOINT:
288 return tracepoint_id_to_name(config);
289
180 default: 290 default:
181 break; 291 break;
182 } 292 }
@@ -265,6 +375,53 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
265 return 1; 375 return 1;
266} 376}
267 377
378static int parse_tracepoint_event(const char **strp,
379 struct perf_counter_attr *attr)
380{
381 const char *evt_name;
382 char sys_name[MAX_EVENT_LENGTH];
383 char id_buf[4];
384 int fd;
385 unsigned int sys_length, evt_length;
386 u64 id;
387 char evt_path[MAXPATHLEN];
388
389 if (valid_debugfs_mount(debugfs_path))
390 return 0;
391
392 evt_name = strchr(*strp, ':');
393 if (!evt_name)
394 return 0;
395
396 sys_length = evt_name - *strp;
397 if (sys_length >= MAX_EVENT_LENGTH)
398 return 0;
399
400 strncpy(sys_name, *strp, sys_length);
401 sys_name[sys_length] = '\0';
402 evt_name = evt_name + 1;
403 evt_length = strlen(evt_name);
404 if (evt_length >= MAX_EVENT_LENGTH)
405 return 0;
406
407 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
408 sys_name, evt_name);
409 fd = open(evt_path, O_RDONLY);
410 if (fd < 0)
411 return 0;
412
413 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
414 close(fd);
415 return 0;
416 }
417 close(fd);
418 id = atoll(id_buf);
419 attr->config = id;
420 attr->type = PERF_TYPE_TRACEPOINT;
421 *strp = evt_name + evt_length;
422 return 1;
423}
424
268static int check_events(const char *str, unsigned int i) 425static int check_events(const char *str, unsigned int i)
269{ 426{
270 int n; 427 int n;
@@ -374,7 +531,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
374 */ 531 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 532static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{ 533{
377 if (!(parse_raw_event(str, attr) || 534 if (!(parse_tracepoint_event(str, attr) ||
535 parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) || 536 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) || 537 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr))) 538 parse_generic_hw_event(str, attr)))
@@ -423,6 +581,42 @@ static const char * const event_type_descriptors[] = {
423}; 581};
424 582
425/* 583/*
584 * Print the events from <debugfs_mount_point>/tracing/events
585 */
586
587static void print_tracepoint_events(void)
588{
589 DIR *sys_dir, *evt_dir;
590 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
591 struct stat st;
592 char evt_path[MAXPATHLEN];
593
594 if (valid_debugfs_mount(debugfs_path))
595 return;
596
597 sys_dir = opendir(debugfs_path);
598 if (!sys_dir)
599 goto cleanup;
600
601 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
602 evt_dir = opendir(evt_path);
603 if (!evt_dir)
604 goto cleanup;
605 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
606 evt_path, st) {
607 snprintf(evt_path, MAXPATHLEN, "%s:%s",
608 sys_dirent.d_name, evt_dirent.d_name);
609 fprintf(stderr, " %-40s [%s]\n", evt_path,
610 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
611 }
612 closedir(evt_dir);
613 }
614
615cleanup:
616 closedir(sys_dir);
617}
618
619/*
426 * Print the help text for the event symbols: 620 * Print the help text for the event symbols:
427 */ 621 */
428void print_events(void) 622void print_events(void)
@@ -436,7 +630,7 @@ void print_events(void)
436 630
437 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 631 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
438 type = syms->type + 1; 632 type = syms->type + 1;
439 if (type > ARRAY_SIZE(event_type_descriptors)) 633 if (type >= ARRAY_SIZE(event_type_descriptors))
440 type = 0; 634 type = 0;
441 635
442 if (type != prev_type) 636 if (type != prev_type)
@@ -472,5 +666,7 @@ void print_events(void)
472 "rNNN"); 666 "rNNN");
473 fprintf(stderr, "\n"); 667 fprintf(stderr, "\n");
474 668
669 print_tracepoint_events();
670
475 exit(129); 671 exit(129);
476} 672}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..192a962e3a0f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -3,11 +3,14 @@
3 * Parse symbolic events/counts passed in as options: 3 * Parse symbolic events/counts passed in as options:
4 */ 4 */
5 5
6struct option;
7
6extern int nr_counters; 8extern int nr_counters;
7 9
8extern struct perf_counter_attr attrs[MAX_COUNTERS]; 10extern struct perf_counter_attr attrs[MAX_COUNTERS];
9 11
10extern char *event_name(int ctr); 12extern char *event_name(int ctr);
13extern char *__event_name(int type, u64 config);
11 14
12extern int parse_events(const struct option *opt, const char *str, int unset); 15extern int parse_events(const struct option *opt, const char *str, int unset);
13 16
@@ -15,3 +18,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 18
16extern void print_events(void); 19extern void print_events(void);
17 20
21extern char debugfs_path[];
22extern int valid_debugfs_mount(const char *debugfs);
23
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index c6e5dc0dc82f..2726fe40eb5d 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -318,7 +318,7 @@ char *quote_path_relative(const char *in, int len,
318 strbuf_addch(out, '"'); 318 strbuf_addch(out, '"');
319 if (prefix) { 319 if (prefix) {
320 int off = 0; 320 int off = 0;
321 while (prefix[off] && off < len && prefix[off] == in[off]) 321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') { 322 if (prefix[off] == '/') {
323 prefix += off + 1; 323 prefix += off + 1;
324 in += off + 1; 324 in += off + 1;
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 3dca2f654cd0..bf39dfadfd24 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,4 +5,7 @@
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7 7
8#define _STR(x) #x
9#define STR(x) _STR(x)
10
8#endif 11#endif
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 025a78edfffe..7ad38171dc2b 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -64,6 +64,7 @@ int strlist__add(struct strlist *self, const char *new_entry)
64 64
65 rb_link_node(&sn->rb_node, parent, p); 65 rb_link_node(&sn->rb_node, parent, p);
66 rb_insert_color(&sn->rb_node, &self->entries); 66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
67 68
68 return 0; 69 return 0;
69} 70}
@@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
155 struct strlist *self = malloc(sizeof(*self)); 156 struct strlist *self = malloc(sizeof(*self));
156 157
157 if (self != NULL) { 158 if (self != NULL) {
158 self->entries = RB_ROOT; 159 self->entries = RB_ROOT;
159 self->dupstr = dupstr; 160 self->dupstr = dupstr;
161 self->nr_entries = 0;
160 if (slist && strlist__parse_list(self, slist) != 0) 162 if (slist && strlist__parse_list(self, slist) != 0)
161 goto out_error; 163 goto out_error;
162 } 164 }
@@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self)
182 free(self); 184 free(self);
183 } 185 }
184} 186}
187
188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
189{
190 struct rb_node *nd;
191
192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
194
195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 2fdcfee87586..921818e44a54 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -11,7 +11,8 @@ struct str_node {
11 11
12struct strlist { 12struct strlist {
13 struct rb_root entries; 13 struct rb_root entries;
14 bool dupstr; 14 unsigned int nr_entries;
15 bool dupstr;
15}; 16};
16 17
17struct strlist *strlist__new(bool dupstr, const char *slist); 18struct strlist *strlist__new(bool dupstr, const char *slist);
@@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn);
21int strlist__load(struct strlist *self, const char *filename); 22int strlist__load(struct strlist *self, const char *filename);
22int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
23 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
24bool strlist__has_entry(struct strlist *self, const char *entry); 26bool strlist__has_entry(struct strlist *self, const char *entry);
25 27
26static inline bool strlist__empty(const struct strlist *self) 28static inline bool strlist__empty(const struct strlist *self)
27{ 29{
28 return rb_first(&self->entries) == NULL; 30 return self->nr_entries == 0;
31}
32
33static inline unsigned int strlist__nr_entries(const struct strlist *self)
34{
35 return self->nr_entries;
29} 36}
30 37
31int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 4683b67b5ee4..f1dcede14307 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -7,8 +7,33 @@
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9 9
10#ifndef NO_DEMANGLE
11#include <bfd.h>
12#else
13static inline
14char *bfd_demangle(void __used *v, const char __used *c, int __used i)
15{
16 return NULL;
17}
18#endif
19
10const char *sym_hist_filter; 20const char *sym_hist_filter;
11 21
22#ifndef DMGL_PARAMS
23#define DMGL_PARAMS (1 << 0) /* Include function args */
24#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
25#endif
26
27enum dso_origin {
28 DSO__ORIG_KERNEL = 0,
29 DSO__ORIG_JAVA_JIT,
30 DSO__ORIG_FEDORA,
31 DSO__ORIG_UBUNTU,
32 DSO__ORIG_BUILDID,
33 DSO__ORIG_DSO,
34 DSO__ORIG_NOT_FOUND,
35};
36
12static struct symbol *symbol__new(u64 start, u64 len, 37static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 38 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 39 u64 obj_start, int verbose)
@@ -65,6 +90,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
65 self->syms = RB_ROOT; 90 self->syms = RB_ROOT;
66 self->sym_priv_size = sym_priv_size; 91 self->sym_priv_size = sym_priv_size;
67 self->find_symbol = dso__find_symbol; 92 self->find_symbol = dso__find_symbol;
93 self->slen_calculated = 0;
94 self->origin = DSO__ORIG_NOT_FOUND;
68 } 95 }
69 96
70 return self; 97 return self;
@@ -373,36 +400,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
373 idx < nr_entries; \ 400 idx < nr_entries; \
374 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 401 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 402
376static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 403/*
377 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 404 * We need to check if we have a .dynsym, so that we can handle the
378 GElf_Shdr *shdr_dynsym, 405 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
379 size_t dynsym_idx, int verbose) 406 * .dynsym or .symtab).
407 * And always look at the original dso, not at debuginfo packages, that
408 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
409 */
410static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
380{ 411{
381 uint32_t nr_rel_entries, idx; 412 uint32_t nr_rel_entries, idx;
382 GElf_Sym sym; 413 GElf_Sym sym;
383 u64 plt_offset; 414 u64 plt_offset;
384 GElf_Shdr shdr_plt; 415 GElf_Shdr shdr_plt;
385 struct symbol *f; 416 struct symbol *f;
386 GElf_Shdr shdr_rel_plt; 417 GElf_Shdr shdr_rel_plt, shdr_dynsym;
387 Elf_Data *reldata, *syms, *symstrs; 418 Elf_Data *reldata, *syms, *symstrs;
388 Elf_Scn *scn_plt_rel, *scn_symstrs; 419 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
420 size_t dynsym_idx;
421 GElf_Ehdr ehdr;
389 char sympltname[1024]; 422 char sympltname[1024];
390 int nr = 0, symidx; 423 Elf *elf;
424 int nr = 0, symidx, fd, err = 0;
425
426 fd = open(self->name, O_RDONLY);
427 if (fd < 0)
428 goto out;
429
430 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
431 if (elf == NULL)
432 goto out_close;
433
434 if (gelf_getehdr(elf, &ehdr) == NULL)
435 goto out_elf_end;
391 436
392 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 437 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
438 ".dynsym", &dynsym_idx);
439 if (scn_dynsym == NULL)
440 goto out_elf_end;
441
442 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
393 ".rela.plt", NULL); 443 ".rela.plt", NULL);
394 if (scn_plt_rel == NULL) { 444 if (scn_plt_rel == NULL) {
395 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 445 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
396 ".rel.plt", NULL); 446 ".rel.plt", NULL);
397 if (scn_plt_rel == NULL) 447 if (scn_plt_rel == NULL)
398 return 0; 448 goto out_elf_end;
399 } 449 }
400 450
451 err = -1;
452
401 if (shdr_rel_plt.sh_link != dynsym_idx) 453 if (shdr_rel_plt.sh_link != dynsym_idx)
402 return 0; 454 goto out_elf_end;
403 455
404 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 456 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 return 0; 457 goto out_elf_end;
406 458
407 /* 459 /*
408 * Fetch the relocation section to find the indexes to the GOT 460 * Fetch the relocation section to find the indexes to the GOT
@@ -410,19 +462,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
410 */ 462 */
411 reldata = elf_getdata(scn_plt_rel, NULL); 463 reldata = elf_getdata(scn_plt_rel, NULL);
412 if (reldata == NULL) 464 if (reldata == NULL)
413 return -1; 465 goto out_elf_end;
414 466
415 syms = elf_getdata(scn_dynsym, NULL); 467 syms = elf_getdata(scn_dynsym, NULL);
416 if (syms == NULL) 468 if (syms == NULL)
417 return -1; 469 goto out_elf_end;
418 470
419 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 471 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
420 if (scn_symstrs == NULL) 472 if (scn_symstrs == NULL)
421 return -1; 473 goto out_elf_end;
422 474
423 symstrs = elf_getdata(scn_symstrs, NULL); 475 symstrs = elf_getdata(scn_symstrs, NULL);
424 if (symstrs == NULL) 476 if (symstrs == NULL)
425 return -1; 477 goto out_elf_end;
426 478
427 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 479 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 plt_offset = shdr_plt.sh_offset; 480 plt_offset = shdr_plt.sh_offset;
@@ -441,7 +493,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
441 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 493 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 sympltname, self->sym_priv_size, 0, verbose); 494 sympltname, self->sym_priv_size, 0, verbose);
443 if (!f) 495 if (!f)
444 return -1; 496 goto out_elf_end;
445 497
446 dso__insert_symbol(self, f); 498 dso__insert_symbol(self, f);
447 ++nr; 499 ++nr;
@@ -459,19 +511,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
459 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 511 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 sympltname, self->sym_priv_size, 0, verbose); 512 sympltname, self->sym_priv_size, 0, verbose);
461 if (!f) 513 if (!f)
462 return -1; 514 goto out_elf_end;
463 515
464 dso__insert_symbol(self, f); 516 dso__insert_symbol(self, f);
465 ++nr; 517 ++nr;
466 } 518 }
467 } else {
468 /*
469 * TODO: There are still one more shdr_rel_plt.sh_type
470 * I have to investigate, but probably should be ignored.
471 */
472 } 519 }
473 520
474 return nr; 521 err = 0;
522out_elf_end:
523 elf_end(elf);
524out_close:
525 close(fd);
526
527 if (err == 0)
528 return nr;
529out:
530 fprintf(stderr, "%s: problems reading %s PLT info.\n",
531 __func__, self->name);
532 return 0;
475} 533}
476 534
477static int dso__load_sym(struct dso *self, int fd, const char *name, 535static int dso__load_sym(struct dso *self, int fd, const char *name,
@@ -485,10 +543,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
485 GElf_Shdr shdr; 543 GElf_Shdr shdr;
486 Elf_Data *syms; 544 Elf_Data *syms;
487 GElf_Sym sym; 545 GElf_Sym sym;
488 Elf_Scn *sec, *sec_dynsym, *sec_strndx; 546 Elf_Scn *sec, *sec_strndx;
489 Elf *elf; 547 Elf *elf;
490 size_t dynsym_idx; 548 int nr = 0, kernel = !strcmp("[kernel]", self->name);
491 int nr = 0;
492 549
493 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 550 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 if (elf == NULL) { 551 if (elf == NULL) {
@@ -504,32 +561,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
504 goto out_elf_end; 561 goto out_elf_end;
505 } 562 }
506 563
507 /*
508 * We need to check if we have a .dynsym, so that we can handle the
509 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
510 * .dynsym or .symtab)
511 */
512 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
513 ".dynsym", &dynsym_idx);
514 if (sec_dynsym != NULL) {
515 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
516 sec_dynsym, &shdr,
517 dynsym_idx, verbose);
518 if (nr < 0)
519 goto out_elf_end;
520 }
521
522 /*
523 * But if we have a full .symtab (that is a superset of .dynsym) we
524 * should add the symbols not in the .dynsyn
525 */
526 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 564 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 if (sec == NULL) { 565 if (sec == NULL) {
528 if (sec_dynsym == NULL) 566 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
567 if (sec == NULL)
529 goto out_elf_end; 568 goto out_elf_end;
530
531 sec = sec_dynsym;
532 gelf_getshdr(sec, &shdr);
533 } 569 }
534 570
535 syms = elf_getdata(sec, NULL); 571 syms = elf_getdata(sec, NULL);
@@ -549,18 +585,23 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
549 goto out_elf_end; 585 goto out_elf_end;
550 586
551 secstrs = elf_getdata(sec_strndx, NULL); 587 secstrs = elf_getdata(sec_strndx, NULL);
552 if (symstrs == NULL) 588 if (secstrs == NULL)
553 goto out_elf_end; 589 goto out_elf_end;
554 590
555 nr_syms = shdr.sh_size / shdr.sh_entsize; 591 nr_syms = shdr.sh_size / shdr.sh_entsize;
556 592
557 memset(&sym, 0, sizeof(sym)); 593 memset(&sym, 0, sizeof(sym));
558 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 594 if (!kernel) {
595 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 elf_section_by_name(elf, &ehdr, &shdr, 596 elf_section_by_name(elf, &ehdr, &shdr,
560 ".gnu.prelink_undo", 597 ".gnu.prelink_undo",
561 NULL) != NULL); 598 NULL) != NULL);
599 } else self->adjust_symbols = 0;
600
562 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 601 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 struct symbol *f; 602 struct symbol *f;
603 const char *name;
604 char *demangled;
564 u64 obj_start; 605 u64 obj_start;
565 struct section *section = NULL; 606 struct section *section = NULL;
566 int is_label = elf_sym__is_label(&sym); 607 int is_label = elf_sym__is_label(&sym);
@@ -599,10 +640,19 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
599 goto out_elf_end; 640 goto out_elf_end;
600 } 641 }
601 } 642 }
643 /*
644 * We need to figure out if the object was created from C++ sources
645 * DWARF DW_compile_unit has this, but we don't always have access
646 * to it...
647 */
648 name = elf_sym__name(&sym, symstrs);
649 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
650 if (demangled != NULL)
651 name = demangled;
602 652
603 f = symbol__new(sym.st_value, sym.st_size, 653 f = symbol__new(sym.st_value, sym.st_size, name,
604 elf_sym__name(&sym, symstrs),
605 self->sym_priv_size, obj_start, verbose); 654 self->sym_priv_size, obj_start, verbose);
655 free(demangled);
606 if (!f) 656 if (!f)
607 goto out_elf_end; 657 goto out_elf_end;
608 658
@@ -622,11 +672,85 @@ out_close:
622 return err; 672 return err;
623} 673}
624 674
675#define BUILD_ID_SIZE 128
676
677static char *dso__read_build_id(struct dso *self, int verbose)
678{
679 int i;
680 GElf_Ehdr ehdr;
681 GElf_Shdr shdr;
682 Elf_Data *build_id_data;
683 Elf_Scn *sec;
684 char *build_id = NULL, *bid;
685 unsigned char *raw;
686 Elf *elf;
687 int fd = open(self->name, O_RDONLY);
688
689 if (fd < 0)
690 goto out;
691
692 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
693 if (elf == NULL) {
694 if (verbose)
695 fprintf(stderr, "%s: cannot read %s ELF file.\n",
696 __func__, self->name);
697 goto out_close;
698 }
699
700 if (gelf_getehdr(elf, &ehdr) == NULL) {
701 if (verbose)
702 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
703 goto out_elf_end;
704 }
705
706 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
707 if (sec == NULL)
708 goto out_elf_end;
709
710 build_id_data = elf_getdata(sec, NULL);
711 if (build_id_data == NULL)
712 goto out_elf_end;
713 build_id = malloc(BUILD_ID_SIZE);
714 if (build_id == NULL)
715 goto out_elf_end;
716 raw = build_id_data->d_buf + 16;
717 bid = build_id;
718
719 for (i = 0; i < 20; ++i) {
720 sprintf(bid, "%02x", *raw);
721 ++raw;
722 bid += 2;
723 }
724 if (verbose >= 2)
725 printf("%s(%s): %s\n", __func__, self->name, build_id);
726out_elf_end:
727 elf_end(elf);
728out_close:
729 close(fd);
730out:
731 return build_id;
732}
733
734char dso__symtab_origin(const struct dso *self)
735{
736 static const char origin[] = {
737 [DSO__ORIG_KERNEL] = 'k',
738 [DSO__ORIG_JAVA_JIT] = 'j',
739 [DSO__ORIG_FEDORA] = 'f',
740 [DSO__ORIG_UBUNTU] = 'u',
741 [DSO__ORIG_BUILDID] = 'b',
742 [DSO__ORIG_DSO] = 'd',
743 };
744
745 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
746 return '!';
747 return origin[self->origin];
748}
749
625int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 750int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
626{ 751{
627 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 752 int size = PATH_MAX;
628 char *name = malloc(size); 753 char *name = malloc(size), *build_id = NULL;
629 int variant = 0;
630 int ret = -1; 754 int ret = -1;
631 int fd; 755 int fd;
632 756
@@ -635,26 +759,43 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
635 759
636 self->adjust_symbols = 0; 760 self->adjust_symbols = 0;
637 761
638 if (strncmp(self->name, "/tmp/perf-", 10) == 0) 762 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
639 return dso__load_perf_map(self, filter, verbose); 763 ret = dso__load_perf_map(self, filter, verbose);
764 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
765 DSO__ORIG_NOT_FOUND;
766 return ret;
767 }
768
769 self->origin = DSO__ORIG_FEDORA - 1;
640 770
641more: 771more:
642 do { 772 do {
643 switch (variant) { 773 self->origin++;
644 case 0: /* Fedora */ 774 switch (self->origin) {
775 case DSO__ORIG_FEDORA:
645 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 776 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
646 break; 777 break;
647 case 1: /* Ubuntu */ 778 case DSO__ORIG_UBUNTU:
648 snprintf(name, size, "/usr/lib/debug%s", self->name); 779 snprintf(name, size, "/usr/lib/debug%s", self->name);
649 break; 780 break;
650 case 2: /* Sane people */ 781 case DSO__ORIG_BUILDID:
782 build_id = dso__read_build_id(self, verbose);
783 if (build_id != NULL) {
784 snprintf(name, size,
785 "/usr/lib/debug/.build-id/%.2s/%s.debug",
786 build_id, build_id + 2);
787 free(build_id);
788 break;
789 }
790 self->origin++;
791 /* Fall thru */
792 case DSO__ORIG_DSO:
651 snprintf(name, size, "%s", self->name); 793 snprintf(name, size, "%s", self->name);
652 break; 794 break;
653 795
654 default: 796 default:
655 goto out; 797 goto out;
656 } 798 }
657 variant++;
658 799
659 fd = open(name, O_RDONLY); 800 fd = open(name, O_RDONLY);
660 } while (fd < 0); 801 } while (fd < 0);
@@ -668,6 +809,11 @@ more:
668 if (!ret) 809 if (!ret)
669 goto more; 810 goto more;
670 811
812 if (ret > 0) {
813 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
814 if (nr_plt > 0)
815 ret += nr_plt;
816 }
671out: 817out:
672 free(name); 818 free(name);
673 return ret; 819 return ret;
@@ -785,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
785 if (err <= 0) 931 if (err <= 0)
786 err = dso__load_kallsyms(self, filter, verbose); 932 err = dso__load_kallsyms(self, filter, verbose);
787 933
934 if (err > 0)
935 self->origin = DSO__ORIG_KERNEL;
936
788 return err; 937 return err;
789} 938}
790 939
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 7918cffb23cd..1e003ec2f4b1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -25,6 +25,8 @@ struct dso {
25 struct symbol *(*find_symbol)(struct dso *, u64 ip); 25 struct symbol *(*find_symbol)(struct dso *, u64 ip);
26 unsigned int sym_priv_size; 26 unsigned int sym_priv_size;
27 unsigned char adjust_symbols; 27 unsigned char adjust_symbols;
28 unsigned char slen_calculated;
29 unsigned char origin;
28 char name[0]; 30 char name[0];
29}; 31};
30 32
@@ -48,6 +50,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
48int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 50int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
49 51
50size_t dso__fprintf(struct dso *self, FILE *fp); 52size_t dso__fprintf(struct dso *self, FILE *fp);
53char dso__symtab_origin(const struct dso *self);
51 54
52void symbol__init(void); 55void symbol__init(void);
53#endif /* _PERF_SYMBOL_ */ 56#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b4be6071c105..68fe157d72fb 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -50,6 +50,7 @@
50#include <unistd.h> 50#include <unistd.h>
51#include <stdio.h> 51#include <stdio.h>
52#include <sys/stat.h> 52#include <sys/stat.h>
53#include <sys/statfs.h>
53#include <fcntl.h> 54#include <fcntl.h>
54#include <stddef.h> 55#include <stddef.h>
55#include <stdlib.h> 56#include <stdlib.h>
@@ -80,6 +81,7 @@
80#include <netdb.h> 81#include <netdb.h>
81#include <pwd.h> 82#include <pwd.h>
82#include <inttypes.h> 83#include <inttypes.h>
84#include "../../../include/linux/magic.h"
83 85
84#ifndef NO_ICONV 86#ifndef NO_ICONV
85#include <iconv.h> 87#include <iconv.h>