aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-08-04 07:58:28 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-04 07:58:28 -0400
commite16852cfc5580b88cb327413ab8c89375f380592 (patch)
tree67e7d5b84e2602986f2da689625e5a25d7af7bb4 /tools/perf/util
parentbdff78707f3ce47e891f3201c9666122a70556ce (diff)
parent74e7ff8c50b6b022e6ffaa736b16a4dc161d3eaf (diff)
Merge branch 'tracing/fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing into tracing/urgent
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/cache.h1
-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.c182
-rw-r--r--tools/perf/util/parse-events.h5
-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.c145
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/util.h2
11 files changed, 316 insertions, 64 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/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..7bdad8df22a6 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,88 @@ 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
124#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \
125 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
126 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \
127 sys_dirent.d_name, evt_dirent.d_name) && \
128 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
129 (strcmp(evt_dirent.d_name, ".")) && \
130 (strcmp(evt_dirent.d_name, "..")))
131
132#define MAX_EVENT_LENGTH 30
133
134int valid_debugfs_mount(const char *debugfs)
135{
136 struct statfs st_fs;
137
138 if (statfs(debugfs, &st_fs) < 0)
139 return -ENOENT;
140 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
141 return -ENOENT;
142 return 0;
143}
144
145static char *tracepoint_id_to_name(u64 config)
146{
147 static char tracepoint_name[2 * MAX_EVENT_LENGTH];
148 DIR *sys_dir, *evt_dir;
149 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
150 struct stat st;
151 char id_buf[4];
152 int fd;
153 u64 id;
154 char evt_path[MAXPATHLEN];
155
156 if (valid_debugfs_mount(debugfs_path))
157 return "unkown";
158
159 sys_dir = opendir(debugfs_path);
160 if (!sys_dir)
161 goto cleanup;
162
163 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
164 evt_dir = opendir(evt_path);
165 if (!evt_dir)
166 goto cleanup;
167 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
168 evt_path, st) {
169 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id",
170 debugfs_path, sys_dirent.d_name,
171 evt_dirent.d_name);
172 fd = open(evt_path, O_RDONLY);
173 if (fd < 0)
174 continue;
175 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
176 close(fd);
177 continue;
178 }
179 close(fd);
180 id = atoll(id_buf);
181 if (id == config) {
182 closedir(evt_dir);
183 closedir(sys_dir);
184 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH,
185 "%s:%s", sys_dirent.d_name,
186 evt_dirent.d_name);
187 return tracepoint_name;
188 }
189 }
190 closedir(evt_dir);
191 }
192
193cleanup:
194 closedir(sys_dir);
195 return "unkown";
196}
197
113static int is_cache_op_valid(u8 cache_type, u8 cache_op) 198static int is_cache_op_valid(u8 cache_type, u8 cache_op)
114{ 199{
115 if (hw_cache_stat[cache_type] & COP(cache_op)) 200 if (hw_cache_stat[cache_type] & COP(cache_op))
@@ -177,6 +262,9 @@ char *event_name(int counter)
177 return sw_event_names[config]; 262 return sw_event_names[config];
178 return "unknown-software"; 263 return "unknown-software";
179 264
265 case PERF_TYPE_TRACEPOINT:
266 return tracepoint_id_to_name(config);
267
180 default: 268 default:
181 break; 269 break;
182 } 270 }
@@ -265,6 +353,53 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
265 return 1; 353 return 1;
266} 354}
267 355
356static int parse_tracepoint_event(const char **strp,
357 struct perf_counter_attr *attr)
358{
359 const char *evt_name;
360 char sys_name[MAX_EVENT_LENGTH];
361 char id_buf[4];
362 int fd;
363 unsigned int sys_length, evt_length;
364 u64 id;
365 char evt_path[MAXPATHLEN];
366
367 if (valid_debugfs_mount(debugfs_path))
368 return 0;
369
370 evt_name = strchr(*strp, ':');
371 if (!evt_name)
372 return 0;
373
374 sys_length = evt_name - *strp;
375 if (sys_length >= MAX_EVENT_LENGTH)
376 return 0;
377
378 strncpy(sys_name, *strp, sys_length);
379 sys_name[sys_length] = '\0';
380 evt_name = evt_name + 1;
381 evt_length = strlen(evt_name);
382 if (evt_length >= MAX_EVENT_LENGTH)
383 return 0;
384
385 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
386 sys_name, evt_name);
387 fd = open(evt_path, O_RDONLY);
388 if (fd < 0)
389 return 0;
390
391 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
392 close(fd);
393 return 0;
394 }
395 close(fd);
396 id = atoll(id_buf);
397 attr->config = id;
398 attr->type = PERF_TYPE_TRACEPOINT;
399 *strp = evt_name + evt_length;
400 return 1;
401}
402
268static int check_events(const char *str, unsigned int i) 403static int check_events(const char *str, unsigned int i)
269{ 404{
270 int n; 405 int n;
@@ -374,7 +509,8 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
374 */ 509 */
375static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 510static int parse_event_symbols(const char **str, struct perf_counter_attr *attr)
376{ 511{
377 if (!(parse_raw_event(str, attr) || 512 if (!(parse_tracepoint_event(str, attr) ||
513 parse_raw_event(str, attr) ||
378 parse_numeric_event(str, attr) || 514 parse_numeric_event(str, attr) ||
379 parse_symbolic_event(str, attr) || 515 parse_symbolic_event(str, attr) ||
380 parse_generic_hw_event(str, attr))) 516 parse_generic_hw_event(str, attr)))
@@ -423,6 +559,42 @@ static const char * const event_type_descriptors[] = {
423}; 559};
424 560
425/* 561/*
562 * Print the events from <debugfs_mount_point>/tracing/events
563 */
564
565static void print_tracepoint_events(void)
566{
567 DIR *sys_dir, *evt_dir;
568 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
569 struct stat st;
570 char evt_path[MAXPATHLEN];
571
572 if (valid_debugfs_mount(debugfs_path))
573 return;
574
575 sys_dir = opendir(debugfs_path);
576 if (!sys_dir)
577 goto cleanup;
578
579 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) {
580 evt_dir = opendir(evt_path);
581 if (!evt_dir)
582 goto cleanup;
583 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next,
584 evt_path, st) {
585 snprintf(evt_path, MAXPATHLEN, "%s:%s",
586 sys_dirent.d_name, evt_dirent.d_name);
587 fprintf(stderr, " %-40s [%s]\n", evt_path,
588 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
589 }
590 closedir(evt_dir);
591 }
592
593cleanup:
594 closedir(sys_dir);
595}
596
597/*
426 * Print the help text for the event symbols: 598 * Print the help text for the event symbols:
427 */ 599 */
428void print_events(void) 600void print_events(void)
@@ -436,7 +608,7 @@ void print_events(void)
436 608
437 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 609 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
438 type = syms->type + 1; 610 type = syms->type + 1;
439 if (type > ARRAY_SIZE(event_type_descriptors)) 611 if (type >= ARRAY_SIZE(event_type_descriptors))
440 type = 0; 612 type = 0;
441 613
442 if (type != prev_type) 614 if (type != prev_type)
@@ -472,5 +644,7 @@ void print_events(void)
472 "rNNN"); 644 "rNNN");
473 fprintf(stderr, "\n"); 645 fprintf(stderr, "\n");
474 646
647 print_tracepoint_events();
648
475 exit(129); 649 exit(129);
476} 650}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index e3d552908e60..1ea5d09b6eb1 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -3,6 +3,8 @@
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];
@@ -15,3 +17,6 @@ extern int parse_events(const struct option *opt, const char *str, int unset);
15 17
16extern void print_events(void); 18extern void print_events(void);
17 19
20extern char debugfs_path[];
21extern int valid_debugfs_mount(const char *debugfs);
22
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..28106059bf12 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,9 +6,15 @@
6#include <libelf.h> 6#include <libelf.h>
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9#include <bfd.h>
9 10
10const char *sym_hist_filter; 11const char *sym_hist_filter;
11 12
13#ifndef DMGL_PARAMS
14#define DMGL_PARAMS (1 << 0) /* Include function args */
15#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
16#endif
17
12static struct symbol *symbol__new(u64 start, u64 len, 18static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 19 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 20 u64 obj_start, int verbose)
@@ -65,6 +71,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
65 self->syms = RB_ROOT; 71 self->syms = RB_ROOT;
66 self->sym_priv_size = sym_priv_size; 72 self->sym_priv_size = sym_priv_size;
67 self->find_symbol = dso__find_symbol; 73 self->find_symbol = dso__find_symbol;
74 self->slen_calculated = 0;
68 } 75 }
69 76
70 return self; 77 return self;
@@ -373,36 +380,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
373 idx < nr_entries; \ 380 idx < nr_entries; \
374 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 381 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 382
376static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 383/*
377 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 384 * We need to check if we have a .dynsym, so that we can handle the
378 GElf_Shdr *shdr_dynsym, 385 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
379 size_t dynsym_idx, int verbose) 386 * .dynsym or .symtab).
387 * And always look at the original dso, not at debuginfo packages, that
388 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
389 */
390static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
380{ 391{
381 uint32_t nr_rel_entries, idx; 392 uint32_t nr_rel_entries, idx;
382 GElf_Sym sym; 393 GElf_Sym sym;
383 u64 plt_offset; 394 u64 plt_offset;
384 GElf_Shdr shdr_plt; 395 GElf_Shdr shdr_plt;
385 struct symbol *f; 396 struct symbol *f;
386 GElf_Shdr shdr_rel_plt; 397 GElf_Shdr shdr_rel_plt, shdr_dynsym;
387 Elf_Data *reldata, *syms, *symstrs; 398 Elf_Data *reldata, *syms, *symstrs;
388 Elf_Scn *scn_plt_rel, *scn_symstrs; 399 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
400 size_t dynsym_idx;
401 GElf_Ehdr ehdr;
389 char sympltname[1024]; 402 char sympltname[1024];
390 int nr = 0, symidx; 403 Elf *elf;
404 int nr = 0, symidx, fd, err = 0;
405
406 fd = open(self->name, O_RDONLY);
407 if (fd < 0)
408 goto out;
409
410 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
411 if (elf == NULL)
412 goto out_close;
413
414 if (gelf_getehdr(elf, &ehdr) == NULL)
415 goto out_elf_end;
416
417 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
418 ".dynsym", &dynsym_idx);
419 if (scn_dynsym == NULL)
420 goto out_elf_end;
391 421
392 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 422 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
393 ".rela.plt", NULL); 423 ".rela.plt", NULL);
394 if (scn_plt_rel == NULL) { 424 if (scn_plt_rel == NULL) {
395 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 425 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
396 ".rel.plt", NULL); 426 ".rel.plt", NULL);
397 if (scn_plt_rel == NULL) 427 if (scn_plt_rel == NULL)
398 return 0; 428 goto out_elf_end;
399 } 429 }
400 430
431 err = -1;
432
401 if (shdr_rel_plt.sh_link != dynsym_idx) 433 if (shdr_rel_plt.sh_link != dynsym_idx)
402 return 0; 434 goto out_elf_end;
403 435
404 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 436 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 return 0; 437 goto out_elf_end;
406 438
407 /* 439 /*
408 * Fetch the relocation section to find the indexes to the GOT 440 * Fetch the relocation section to find the indexes to the GOT
@@ -410,19 +442,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
410 */ 442 */
411 reldata = elf_getdata(scn_plt_rel, NULL); 443 reldata = elf_getdata(scn_plt_rel, NULL);
412 if (reldata == NULL) 444 if (reldata == NULL)
413 return -1; 445 goto out_elf_end;
414 446
415 syms = elf_getdata(scn_dynsym, NULL); 447 syms = elf_getdata(scn_dynsym, NULL);
416 if (syms == NULL) 448 if (syms == NULL)
417 return -1; 449 goto out_elf_end;
418 450
419 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 451 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
420 if (scn_symstrs == NULL) 452 if (scn_symstrs == NULL)
421 return -1; 453 goto out_elf_end;
422 454
423 symstrs = elf_getdata(scn_symstrs, NULL); 455 symstrs = elf_getdata(scn_symstrs, NULL);
424 if (symstrs == NULL) 456 if (symstrs == NULL)
425 return -1; 457 goto out_elf_end;
426 458
427 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 459 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 plt_offset = shdr_plt.sh_offset; 460 plt_offset = shdr_plt.sh_offset;
@@ -441,7 +473,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
441 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 473 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 sympltname, self->sym_priv_size, 0, verbose); 474 sympltname, self->sym_priv_size, 0, verbose);
443 if (!f) 475 if (!f)
444 return -1; 476 goto out_elf_end;
445 477
446 dso__insert_symbol(self, f); 478 dso__insert_symbol(self, f);
447 ++nr; 479 ++nr;
@@ -459,19 +491,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
459 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 491 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 sympltname, self->sym_priv_size, 0, verbose); 492 sympltname, self->sym_priv_size, 0, verbose);
461 if (!f) 493 if (!f)
462 return -1; 494 goto out_elf_end;
463 495
464 dso__insert_symbol(self, f); 496 dso__insert_symbol(self, f);
465 ++nr; 497 ++nr;
466 } 498 }
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 } 499 }
473 500
474 return nr; 501 err = 0;
502out_elf_end:
503 elf_end(elf);
504out_close:
505 close(fd);
506
507 if (err == 0)
508 return nr;
509out:
510 fprintf(stderr, "%s: problems reading %s PLT info.\n",
511 __func__, self->name);
512 return 0;
475} 513}
476 514
477static int dso__load_sym(struct dso *self, int fd, const char *name, 515static int dso__load_sym(struct dso *self, int fd, const char *name,
@@ -485,10 +523,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
485 GElf_Shdr shdr; 523 GElf_Shdr shdr;
486 Elf_Data *syms; 524 Elf_Data *syms;
487 GElf_Sym sym; 525 GElf_Sym sym;
488 Elf_Scn *sec, *sec_dynsym, *sec_strndx; 526 Elf_Scn *sec, *sec_strndx;
489 Elf *elf; 527 Elf *elf;
490 size_t dynsym_idx; 528 int nr = 0, kernel = !strcmp("[kernel]", self->name);
491 int nr = 0;
492 529
493 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 530 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 if (elf == NULL) { 531 if (elf == NULL) {
@@ -504,32 +541,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
504 goto out_elf_end; 541 goto out_elf_end;
505 } 542 }
506 543
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); 544 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 if (sec == NULL) { 545 if (sec == NULL) {
528 if (sec_dynsym == NULL) 546 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
547 if (sec == NULL)
529 goto out_elf_end; 548 goto out_elf_end;
530
531 sec = sec_dynsym;
532 gelf_getshdr(sec, &shdr);
533 } 549 }
534 550
535 syms = elf_getdata(sec, NULL); 551 syms = elf_getdata(sec, NULL);
@@ -555,12 +571,17 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
555 nr_syms = shdr.sh_size / shdr.sh_entsize; 571 nr_syms = shdr.sh_size / shdr.sh_entsize;
556 572
557 memset(&sym, 0, sizeof(sym)); 573 memset(&sym, 0, sizeof(sym));
558 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 574 if (!kernel) {
575 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 elf_section_by_name(elf, &ehdr, &shdr, 576 elf_section_by_name(elf, &ehdr, &shdr,
560 ".gnu.prelink_undo", 577 ".gnu.prelink_undo",
561 NULL) != NULL); 578 NULL) != NULL);
579 } else self->adjust_symbols = 0;
580
562 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 581 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 struct symbol *f; 582 struct symbol *f;
583 const char *name;
584 char *demangled;
564 u64 obj_start; 585 u64 obj_start;
565 struct section *section = NULL; 586 struct section *section = NULL;
566 int is_label = elf_sym__is_label(&sym); 587 int is_label = elf_sym__is_label(&sym);
@@ -599,10 +620,19 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
599 goto out_elf_end; 620 goto out_elf_end;
600 } 621 }
601 } 622 }
623 /*
624 * We need to figure out if the object was created from C++ sources
625 * DWARF DW_compile_unit has this, but we don't always have access
626 * to it...
627 */
628 name = elf_sym__name(&sym, symstrs);
629 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
630 if (demangled != NULL)
631 name = demangled;
602 632
603 f = symbol__new(sym.st_value, sym.st_size, 633 f = symbol__new(sym.st_value, sym.st_size, name,
604 elf_sym__name(&sym, symstrs),
605 self->sym_priv_size, obj_start, verbose); 634 self->sym_priv_size, obj_start, verbose);
635 free(demangled);
606 if (!f) 636 if (!f)
607 goto out_elf_end; 637 goto out_elf_end;
608 638
@@ -668,6 +698,11 @@ more:
668 if (!ret) 698 if (!ret)
669 goto more; 699 goto more;
670 700
701 if (ret > 0) {
702 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
703 if (nr_plt > 0)
704 ret += nr_plt;
705 }
671out: 706out:
672 free(name); 707 free(name);
673 return ret; 708 return ret;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 7918cffb23cd..2f92b21c712d 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -25,6 +25,7 @@ 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;
28 char name[0]; 29 char name[0];
29}; 30};
30 31
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>