aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-12-11 15:50:22 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-12 01:42:11 -0500
commit79406cd789f745ac6aa9d597895f904a98a14007 (patch)
tree99281664ea6e0fd5bd0a6f762feed4f716b356cd
parent22ccec57f8732de22fd87bce43e8edcb71453c72 (diff)
perf symbols: Allow lookups by symbol name too
Configurable via symbol_conf.sort_by_name, so that the cost of an extra rb_node on all 'struct symbol' instances is not paid by tools that only want to decode addresses. How to use it: symbol_conf.sort_by_name = true; symbol_init(&symbol_conf); struct map *map = map_groups__find_by_name(kmaps, MAP__VARIABLE, "[kernel.kallsyms]"); if (map == NULL) { pr_err("couldn't find map!\n"); kernel_maps__fprintf(stdout); } else { struct symbol *sym = map__find_symbol_by_name(map, sym_filter, NULL); if (sym == NULL) pr_err("couldn't find symbol %s!\n", sym_filter); else pr_info("symbol %s: %#Lx-%#Lx \n", sym_filter, sym->start, sym->end); } Looking over the vmlinux/kallsyms is common enough that I'll add a variable to the upcoming struct perf_session to avoid the need to use map_groups__find_by_name to get the main vmlinux/kallsyms map. The above example looks on the 'variable' symtab, but it is just like that for the functions one. Also the sort operation is done when we first use map__find_symbol_by_name, in a lazy way. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1260564622-12392-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/map.c85
-rw-r--r--tools/perf/util/symbol.c104
-rw-r--r--tools/perf/util/symbol.h10
-rw-r--r--tools/perf/util/thread.h3
5 files changed, 163 insertions, 41 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 56640946b5a9..51a96c2effde 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -151,6 +151,8 @@ int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
152struct symbol *map__find_symbol(struct map *self, u64 addr, 152struct symbol *map__find_symbol(struct map *self, u64 addr,
153 symbol_filter_t filter); 153 symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
155 symbol_filter_t filter);
154void map__fixup_start(struct map *self); 156void map__fixup_start(struct map *self);
155void map__fixup_end(struct map *self); 157void map__fixup_end(struct map *self);
156 158
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 69f94fe9db20..175f1f6b6914 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,45 +104,66 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107struct symbol *map__find_symbol(struct map *self, u64 addr, 107static int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 108{
110 if (!dso__loaded(self->dso, self->type)) { 109 const char *name = self->dso->long_name;
111 int nr = dso__load(self->dso, self, filter); 110 int nr = dso__load(self->dso, self, filter);
112 111
113 if (nr < 0) { 112 if (nr < 0) {
114 if (self->dso->has_build_id) { 113 if (self->dso->has_build_id) {
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 114 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
116 115
117 build_id__sprintf(self->dso->build_id, 116 build_id__sprintf(self->dso->build_id,
118 sizeof(self->dso->build_id), 117 sizeof(self->dso->build_id),
119 sbuild_id); 118 sbuild_id);
120 pr_warning("%s with build id %s not found", 119 pr_warning("%s with build id %s not found",
121 self->dso->long_name, sbuild_id); 120 name, sbuild_id);
122 } else 121 } else
123 pr_warning("Failed to open %s", 122 pr_warning("Failed to open %s", name);
124 self->dso->long_name); 123
125 pr_warning(", continuing without symbols\n"); 124 pr_warning(", continuing without symbols\n");
126 return NULL; 125 return -1;
127 } else if (nr == 0) { 126 } else if (nr == 0) {
128 const char *name = self->dso->long_name; 127 const size_t len = strlen(name);
129 const size_t len = strlen(name); 128 const size_t real_len = len - sizeof(DSO__DELETED);
130 const size_t real_len = len - sizeof(DSO__DELETED); 129
131 130 if (len > sizeof(DSO__DELETED) &&
132 if (len > sizeof(DSO__DELETED) && 131 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 132 pr_warning("%.*s was updated, restart the long "
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n", 133 "running apps that use it!\n",
135 (int)real_len, name); 134 (int)real_len, name);
136 } else { 135 } else {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name); 136 pr_warning("no symbols found in %s, maybe install "
138 } 137 "a debug package?\n", name);
139 return NULL;
140 } 138 }
139
140 return -1;
141 } 141 }
142 142
143 return 0;
144}
145
146struct symbol *map__find_symbol(struct map *self, u64 addr,
147 symbol_filter_t filter)
148{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
150 return NULL;
151
143 return self->dso->find_symbol(self->dso, self->type, addr); 152 return self->dso->find_symbol(self->dso, self->type, addr);
144} 153}
145 154
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
156 symbol_filter_t filter)
157{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
159 return NULL;
160
161 if (!dso__sorted_by_name(self->dso, self->type))
162 dso__sort_by_name(self->dso, self->type);
163
164 return dso__find_symbol_by_name(self->dso, self->type, name);
165}
166
146struct map *map__clone(struct map *self) 167struct map *map__clone(struct map *self)
147{ 168{
148 struct map *map = malloc(sizeof(*self)); 169 struct map *map = malloc(sizeof(*self));
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e63ddb469de7..8134c49deae6 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,7 +29,6 @@ enum dso_origin {
29}; 29};
30 30
31static void dsos__add(struct list_head *head, struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *map_groups__find_by_name(struct map_groups *self, char *name);
33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 33struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 34static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -51,11 +50,21 @@ bool dso__loaded(const struct dso *self, enum map_type type)
51 return self->loaded & (1 << type); 50 return self->loaded & (1 << type);
52} 51}
53 52
53bool dso__sorted_by_name(const struct dso *self, enum map_type type)
54{
55 return self->sorted_by_name & (1 << type);
56}
57
54static void dso__set_loaded(struct dso *self, enum map_type type) 58static void dso__set_loaded(struct dso *self, enum map_type type)
55{ 59{
56 self->loaded |= (1 << type); 60 self->loaded |= (1 << type);
57} 61}
58 62
63static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
64{
65 self->sorted_by_name |= (1 << type);
66}
67
59static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 68static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
60{ 69{
61 switch (map_type) { 70 switch (map_type) {
@@ -176,11 +185,12 @@ struct dso *dso__new(const char *name)
176 dso__set_long_name(self, self->name); 185 dso__set_long_name(self, self->name);
177 self->short_name = self->name; 186 self->short_name = self->name;
178 for (i = 0; i < MAP__NR_TYPES; ++i) 187 for (i = 0; i < MAP__NR_TYPES; ++i)
179 self->symbols[i] = RB_ROOT; 188 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
180 self->find_symbol = dso__find_symbol; 189 self->find_symbol = dso__find_symbol;
181 self->slen_calculated = 0; 190 self->slen_calculated = 0;
182 self->origin = DSO__ORIG_NOT_FOUND; 191 self->origin = DSO__ORIG_NOT_FOUND;
183 self->loaded = 0; 192 self->loaded = 0;
193 self->sorted_by_name = 0;
184 self->has_build_id = 0; 194 self->has_build_id = 0;
185 } 195 }
186 196
@@ -258,11 +268,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
258 return NULL; 268 return NULL;
259} 269}
260 270
261struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 271struct symbol_name_rb_node {
272 struct rb_node rb_node;
273 struct symbol sym;
274};
275
276static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
277{
278 struct rb_node **p = &self->rb_node;
279 struct rb_node *parent = NULL;
280 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
281
282 while (*p != NULL) {
283 parent = *p;
284 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
285 if (strcmp(sym->name, s->sym.name) < 0)
286 p = &(*p)->rb_left;
287 else
288 p = &(*p)->rb_right;
289 }
290 rb_link_node(&symn->rb_node, parent, p);
291 rb_insert_color(&symn->rb_node, self);
292}
293
294static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
295{
296 struct rb_node *nd;
297
298 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
299 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
300 symbols__insert_by_name(self, pos);
301 }
302}
303
304static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
305{
306 struct rb_node *n;
307
308 if (self == NULL)
309 return NULL;
310
311 n = self->rb_node;
312
313 while (n) {
314 struct symbol_name_rb_node *s;
315 int cmp;
316
317 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
318 cmp = strcmp(name, s->sym.name);
319
320 if (cmp < 0)
321 n = n->rb_left;
322 else if (cmp > 0)
323 n = n->rb_right;
324 else
325 return &s->sym;
326 }
327
328 return NULL;
329}
330
331struct symbol *dso__find_symbol(struct dso *self,
332 enum map_type type, u64 addr)
262{ 333{
263 return symbols__find(&self->symbols[type], addr); 334 return symbols__find(&self->symbols[type], addr);
264} 335}
265 336
337struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
338 const char *name)
339{
340 return symbols__find_by_name(&self->symbol_names[type], name);
341}
342
343void dso__sort_by_name(struct dso *self, enum map_type type)
344{
345 dso__set_sorted_by_name(self, type);
346 return symbols__sort_by_name(&self->symbol_names[type],
347 &self->symbols[type]);
348}
349
266int build_id__sprintf(u8 *self, int len, char *bf) 350int build_id__sprintf(u8 *self, int len, char *bf)
267{ 351{
268 char *bid = bf; 352 char *bid = bf;
@@ -397,7 +481,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
397 *module++ = '\0'; 481 *module++ = '\0';
398 482
399 if (strcmp(self->name, module)) { 483 if (strcmp(self->name, module)) {
400 curr_map = map_groups__find_by_name(mg, module); 484 curr_map = map_groups__find_by_name(mg, map->type, module);
401 if (curr_map == NULL) { 485 if (curr_map == NULL) {
402 pr_debug("/proc/{kallsyms,modules} " 486 pr_debug("/proc/{kallsyms,modules} "
403 "inconsistency!\n"); 487 "inconsistency!\n");
@@ -895,7 +979,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
895 snprintf(dso_name, sizeof(dso_name), 979 snprintf(dso_name, sizeof(dso_name),
896 "%s%s", self->short_name, section_name); 980 "%s%s", self->short_name, section_name);
897 981
898 curr_map = map_groups__find_by_name(mg, dso_name); 982 curr_map = map_groups__find_by_name(mg, map->type, dso_name);
899 if (curr_map == NULL) { 983 if (curr_map == NULL) {
900 u64 start = sym.st_value; 984 u64 start = sym.st_value;
901 985
@@ -1226,11 +1310,12 @@ out:
1226 return ret; 1310 return ret;
1227} 1311}
1228 1312
1229static struct map *map_groups__find_by_name(struct map_groups *self, char *name) 1313struct map *map_groups__find_by_name(struct map_groups *self,
1314 enum map_type type, const char *name)
1230{ 1315{
1231 struct rb_node *nd; 1316 struct rb_node *nd;
1232 1317
1233 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1318 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1234 struct map *map = rb_entry(nd, struct map, rb_node); 1319 struct map *map = rb_entry(nd, struct map, rb_node);
1235 1320
1236 if (map->dso && strcmp(map->dso->name, name) == 0) 1321 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1274,7 +1359,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1274 (int)(dot - dent->d_name), dent->d_name); 1359 (int)(dot - dent->d_name), dent->d_name);
1275 1360
1276 strxfrchar(dso_name, '-', '_'); 1361 strxfrchar(dso_name, '-', '_');
1277 map = map_groups__find_by_name(kmaps, dso_name); 1362 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name);
1278 if (map == NULL) 1363 if (map == NULL)
1279 continue; 1364 continue;
1280 1365
@@ -1671,6 +1756,9 @@ int symbol__init(struct symbol_conf *conf)
1671 1756
1672 elf_version(EV_CURRENT); 1757 elf_version(EV_CURRENT);
1673 symbol__priv_size = pconf->priv_size; 1758 symbol__priv_size = pconf->priv_size;
1759 if (pconf->sort_by_name)
1760 symbol__priv_size += (sizeof(struct symbol_name_rb_node) -
1761 sizeof(struct symbol));
1674 map_groups__init(kmaps); 1762 map_groups__init(kmaps);
1675 1763
1676 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1764 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6e1da1ea6311..51c401307bf1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -52,7 +52,8 @@ struct symbol {
52struct symbol_conf { 52struct symbol_conf {
53 unsigned short priv_size; 53 unsigned short priv_size;
54 bool try_vmlinux_path, 54 bool try_vmlinux_path,
55 use_modules; 55 use_modules,
56 sort_by_name;
56 const char *vmlinux_name; 57 const char *vmlinux_name;
57}; 58};
58 59
@@ -74,6 +75,7 @@ struct addr_location {
74struct dso { 75struct dso {
75 struct list_head node; 76 struct list_head node;
76 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES];
77 struct symbol *(*find_symbol)(struct dso *self, 79 struct symbol *(*find_symbol)(struct dso *self,
78 enum map_type type, u64 addr); 80 enum map_type type, u64 addr);
79 u8 adjust_symbols:1; 81 u8 adjust_symbols:1;
@@ -81,6 +83,7 @@ struct dso {
81 u8 has_build_id:1; 83 u8 has_build_id:1;
82 u8 kernel:1; 84 u8 kernel:1;
83 unsigned char origin; 85 unsigned char origin;
86 u8 sorted_by_name;
84 u8 loaded; 87 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE]; 88 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len; 89 u16 long_name_len;
@@ -93,6 +96,9 @@ struct dso *dso__new(const char *name);
93void dso__delete(struct dso *self); 96void dso__delete(struct dso *self);
94 97
95bool dso__loaded(const struct dso *self, enum map_type type); 98bool dso__loaded(const struct dso *self, enum map_type type);
99bool dso__sorted_by_name(const struct dso *self, enum map_type type);
100
101void dso__sort_by_name(struct dso *self, enum map_type type);
96 102
97struct dso *dsos__findnew(const char *name); 103struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 104int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
@@ -103,6 +109,8 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 109size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
104char dso__symtab_origin(const struct dso *self); 110char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id); 111void dso__set_build_id(struct dso *self, void *build_id);
112struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
113 const char *name);
106 114
107int filename__read_build_id(const char *filename, void *bf, size_t size); 115int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size); 116int sysfs__read_build_id(const char *filename, void *bf, size_t size);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index a6333f3716af..1751802a09ba 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -64,4 +64,7 @@ map_groups__find_function(struct map_groups *self, u64 addr,
64{ 64{
65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
66} 66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
67#endif /* __PERF_THREAD_H */ 70#endif /* __PERF_THREAD_H */