diff options
-rw-r--r-- | tools/perf/util/event.h | 2 | ||||
-rw-r--r-- | tools/perf/util/map.c | 85 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 104 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 10 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 3 |
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); | |||
151 | size_t map__fprintf(struct map *self, FILE *fp); | 151 | size_t map__fprintf(struct map *self, FILE *fp); |
152 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 152 | struct symbol *map__find_symbol(struct map *self, u64 addr, |
153 | symbol_filter_t filter); | 153 | symbol_filter_t filter); |
154 | struct symbol *map__find_symbol_by_name(struct map *self, const char *name, | ||
155 | symbol_filter_t filter); | ||
154 | void map__fixup_start(struct map *self); | 156 | void map__fixup_start(struct map *self); |
155 | void map__fixup_end(struct map *self); | 157 | void 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 | ||
107 | struct symbol *map__find_symbol(struct map *self, u64 addr, | 107 | static 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 | |||
146 | struct 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 | ||
155 | struct 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 | |||
146 | struct map *map__clone(struct map *self) | 167 | struct 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 | ||
31 | static void dsos__add(struct list_head *head, struct dso *dso); | 31 | static void dsos__add(struct list_head *head, struct dso *dso); |
32 | static struct map *map_groups__find_by_name(struct map_groups *self, char *name); | ||
33 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 32 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
34 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); | 33 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); |
35 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 34 | static 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 | ||
53 | bool dso__sorted_by_name(const struct dso *self, enum map_type type) | ||
54 | { | ||
55 | return self->sorted_by_name & (1 << type); | ||
56 | } | ||
57 | |||
54 | static void dso__set_loaded(struct dso *self, enum map_type type) | 58 | static 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 | ||
63 | static void dso__set_sorted_by_name(struct dso *self, enum map_type type) | ||
64 | { | ||
65 | self->sorted_by_name |= (1 << type); | ||
66 | } | ||
67 | |||
59 | static bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 68 | static 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 | ||
261 | struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) | 271 | struct symbol_name_rb_node { |
272 | struct rb_node rb_node; | ||
273 | struct symbol sym; | ||
274 | }; | ||
275 | |||
276 | static 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 | |||
294 | static 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 | |||
304 | static 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 | |||
331 | struct 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 | ||
337 | struct 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 | |||
343 | void 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 | |||
266 | int build_id__sprintf(u8 *self, int len, char *bf) | 350 | int 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 | ||
1229 | static struct map *map_groups__find_by_name(struct map_groups *self, char *name) | 1313 | struct 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 { | |||
52 | struct symbol_conf { | 52 | struct 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 { | |||
74 | struct dso { | 75 | struct 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); | |||
93 | void dso__delete(struct dso *self); | 96 | void dso__delete(struct dso *self); |
94 | 97 | ||
95 | bool dso__loaded(const struct dso *self, enum map_type type); | 98 | bool dso__loaded(const struct dso *self, enum map_type type); |
99 | bool dso__sorted_by_name(const struct dso *self, enum map_type type); | ||
100 | |||
101 | void dso__sort_by_name(struct dso *self, enum map_type type); | ||
96 | 102 | ||
97 | struct dso *dsos__findnew(const char *name); | 103 | struct dso *dsos__findnew(const char *name); |
98 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); | 104 | int 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); | |||
103 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); | 109 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); |
104 | char dso__symtab_origin(const struct dso *self); | 110 | char dso__symtab_origin(const struct dso *self); |
105 | void dso__set_build_id(struct dso *self, void *build_id); | 111 | void dso__set_build_id(struct dso *self, void *build_id); |
112 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | ||
113 | const char *name); | ||
106 | 114 | ||
107 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 115 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
108 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 116 | int 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 | |||
68 | struct 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 */ |