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 */ |
