diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/event.h | 6 | ||||
-rw-r--r-- | tools/perf/util/module.c | 545 | ||||
-rw-r--r-- | tools/perf/util/module.h | 53 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 38 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 7 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 447 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 20 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 34 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 4 |
9 files changed, 362 insertions, 792 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 4c69eb553807..a39520e6ae8f 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include "../perf.h" | 4 | #include "../perf.h" |
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include <linux/list.h> | ||
6 | #include <linux/rbtree.h> | 7 | #include <linux/rbtree.h> |
7 | 8 | ||
8 | enum { | 9 | enum { |
@@ -79,7 +80,10 @@ typedef union event_union { | |||
79 | } event_t; | 80 | } event_t; |
80 | 81 | ||
81 | struct map { | 82 | struct map { |
82 | struct rb_node rb_node; | 83 | union { |
84 | struct rb_node rb_node; | ||
85 | struct list_head node; | ||
86 | }; | ||
83 | u64 start; | 87 | u64 start; |
84 | u64 end; | 88 | u64 end; |
85 | u64 pgoff; | 89 | u64 pgoff; |
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c deleted file mode 100644 index 0d8c85defcd2..000000000000 --- a/tools/perf/util/module.c +++ /dev/null | |||
@@ -1,545 +0,0 @@ | |||
1 | #include "util.h" | ||
2 | #include "../perf.h" | ||
3 | #include "string.h" | ||
4 | #include "module.h" | ||
5 | |||
6 | #include <libelf.h> | ||
7 | #include <libgen.h> | ||
8 | #include <gelf.h> | ||
9 | #include <elf.h> | ||
10 | #include <dirent.h> | ||
11 | #include <sys/utsname.h> | ||
12 | |||
13 | static unsigned int crc32(const char *p, unsigned int len) | ||
14 | { | ||
15 | int i; | ||
16 | unsigned int crc = 0; | ||
17 | |||
18 | while (len--) { | ||
19 | crc ^= *p++; | ||
20 | for (i = 0; i < 8; i++) | ||
21 | crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0); | ||
22 | } | ||
23 | return crc; | ||
24 | } | ||
25 | |||
26 | /* module section methods */ | ||
27 | |||
28 | struct sec_dso *sec_dso__new_dso(const char *name) | ||
29 | { | ||
30 | struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1); | ||
31 | |||
32 | if (self != NULL) { | ||
33 | strcpy(self->name, name); | ||
34 | self->secs = RB_ROOT; | ||
35 | self->find_section = sec_dso__find_section; | ||
36 | } | ||
37 | |||
38 | return self; | ||
39 | } | ||
40 | |||
41 | static void sec_dso__delete_section(struct section *self) | ||
42 | { | ||
43 | free(((void *)self)); | ||
44 | } | ||
45 | |||
46 | void sec_dso__delete_sections(struct sec_dso *self) | ||
47 | { | ||
48 | struct section *pos; | ||
49 | struct rb_node *next = rb_first(&self->secs); | ||
50 | |||
51 | while (next) { | ||
52 | pos = rb_entry(next, struct section, rb_node); | ||
53 | next = rb_next(&pos->rb_node); | ||
54 | rb_erase(&pos->rb_node, &self->secs); | ||
55 | sec_dso__delete_section(pos); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | void sec_dso__delete_self(struct sec_dso *self) | ||
60 | { | ||
61 | sec_dso__delete_sections(self); | ||
62 | free(self); | ||
63 | } | ||
64 | |||
65 | static void sec_dso__insert_section(struct sec_dso *self, struct section *sec) | ||
66 | { | ||
67 | struct rb_node **p = &self->secs.rb_node; | ||
68 | struct rb_node *parent = NULL; | ||
69 | const u64 hash = sec->hash; | ||
70 | struct section *s; | ||
71 | |||
72 | while (*p != NULL) { | ||
73 | parent = *p; | ||
74 | s = rb_entry(parent, struct section, rb_node); | ||
75 | if (hash < s->hash) | ||
76 | p = &(*p)->rb_left; | ||
77 | else | ||
78 | p = &(*p)->rb_right; | ||
79 | } | ||
80 | rb_link_node(&sec->rb_node, parent, p); | ||
81 | rb_insert_color(&sec->rb_node, &self->secs); | ||
82 | } | ||
83 | |||
84 | struct section *sec_dso__find_section(struct sec_dso *self, const char *name) | ||
85 | { | ||
86 | struct rb_node *n; | ||
87 | u64 hash; | ||
88 | int len; | ||
89 | |||
90 | if (self == NULL) | ||
91 | return NULL; | ||
92 | |||
93 | len = strlen(name); | ||
94 | hash = crc32(name, len); | ||
95 | |||
96 | n = self->secs.rb_node; | ||
97 | |||
98 | while (n) { | ||
99 | struct section *s = rb_entry(n, struct section, rb_node); | ||
100 | |||
101 | if (hash < s->hash) | ||
102 | n = n->rb_left; | ||
103 | else if (hash > s->hash) | ||
104 | n = n->rb_right; | ||
105 | else { | ||
106 | if (!strcmp(name, s->name)) | ||
107 | return s; | ||
108 | else | ||
109 | n = rb_next(&s->rb_node); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return NULL; | ||
114 | } | ||
115 | |||
116 | static size_t sec_dso__fprintf_section(struct section *self, FILE *fp) | ||
117 | { | ||
118 | return fprintf(fp, "name:%s vma:%llx path:%s\n", | ||
119 | self->name, self->vma, self->path); | ||
120 | } | ||
121 | |||
122 | size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp) | ||
123 | { | ||
124 | size_t ret = fprintf(fp, "dso: %s\n", self->name); | ||
125 | |||
126 | struct rb_node *nd; | ||
127 | for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) { | ||
128 | struct section *pos = rb_entry(nd, struct section, rb_node); | ||
129 | ret += sec_dso__fprintf_section(pos, fp); | ||
130 | } | ||
131 | |||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | static struct section *section__new(const char *name, const char *path) | ||
136 | { | ||
137 | struct section *self = calloc(1, sizeof(*self)); | ||
138 | |||
139 | if (!self) | ||
140 | goto out_failure; | ||
141 | |||
142 | self->name = calloc(1, strlen(name) + 1); | ||
143 | if (!self->name) | ||
144 | goto out_failure; | ||
145 | |||
146 | self->path = calloc(1, strlen(path) + 1); | ||
147 | if (!self->path) | ||
148 | goto out_failure; | ||
149 | |||
150 | strcpy(self->name, name); | ||
151 | strcpy(self->path, path); | ||
152 | self->hash = crc32(self->name, strlen(name)); | ||
153 | |||
154 | return self; | ||
155 | |||
156 | out_failure: | ||
157 | if (self) { | ||
158 | if (self->name) | ||
159 | free(self->name); | ||
160 | if (self->path) | ||
161 | free(self->path); | ||
162 | free(self); | ||
163 | } | ||
164 | |||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | /* module methods */ | ||
169 | |||
170 | struct mod_dso *mod_dso__new_dso(const char *name) | ||
171 | { | ||
172 | struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1); | ||
173 | |||
174 | if (self != NULL) { | ||
175 | strcpy(self->name, name); | ||
176 | self->mods = RB_ROOT; | ||
177 | self->find_module = mod_dso__find_module; | ||
178 | } | ||
179 | |||
180 | return self; | ||
181 | } | ||
182 | |||
183 | static void mod_dso__delete_module(struct module *self) | ||
184 | { | ||
185 | free(((void *)self)); | ||
186 | } | ||
187 | |||
188 | void mod_dso__delete_modules(struct mod_dso *self) | ||
189 | { | ||
190 | struct module *pos; | ||
191 | struct rb_node *next = rb_first(&self->mods); | ||
192 | |||
193 | while (next) { | ||
194 | pos = rb_entry(next, struct module, rb_node); | ||
195 | next = rb_next(&pos->rb_node); | ||
196 | rb_erase(&pos->rb_node, &self->mods); | ||
197 | mod_dso__delete_module(pos); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | void mod_dso__delete_self(struct mod_dso *self) | ||
202 | { | ||
203 | mod_dso__delete_modules(self); | ||
204 | free(self); | ||
205 | } | ||
206 | |||
207 | static void mod_dso__insert_module(struct mod_dso *self, struct module *mod) | ||
208 | { | ||
209 | struct rb_node **p = &self->mods.rb_node; | ||
210 | struct rb_node *parent = NULL; | ||
211 | const u64 hash = mod->hash; | ||
212 | struct module *m; | ||
213 | |||
214 | while (*p != NULL) { | ||
215 | parent = *p; | ||
216 | m = rb_entry(parent, struct module, rb_node); | ||
217 | if (hash < m->hash) | ||
218 | p = &(*p)->rb_left; | ||
219 | else | ||
220 | p = &(*p)->rb_right; | ||
221 | } | ||
222 | rb_link_node(&mod->rb_node, parent, p); | ||
223 | rb_insert_color(&mod->rb_node, &self->mods); | ||
224 | } | ||
225 | |||
226 | struct module *mod_dso__find_module(struct mod_dso *self, const char *name) | ||
227 | { | ||
228 | struct rb_node *n; | ||
229 | u64 hash; | ||
230 | int len; | ||
231 | |||
232 | if (self == NULL) | ||
233 | return NULL; | ||
234 | |||
235 | len = strlen(name); | ||
236 | hash = crc32(name, len); | ||
237 | |||
238 | n = self->mods.rb_node; | ||
239 | |||
240 | while (n) { | ||
241 | struct module *m = rb_entry(n, struct module, rb_node); | ||
242 | |||
243 | if (hash < m->hash) | ||
244 | n = n->rb_left; | ||
245 | else if (hash > m->hash) | ||
246 | n = n->rb_right; | ||
247 | else { | ||
248 | if (!strcmp(name, m->name)) | ||
249 | return m; | ||
250 | else | ||
251 | n = rb_next(&m->rb_node); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | static size_t mod_dso__fprintf_module(struct module *self, FILE *fp) | ||
259 | { | ||
260 | return fprintf(fp, "name:%s path:%s\n", self->name, self->path); | ||
261 | } | ||
262 | |||
263 | size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp) | ||
264 | { | ||
265 | struct rb_node *nd; | ||
266 | size_t ret; | ||
267 | |||
268 | ret = fprintf(fp, "dso: %s\n", self->name); | ||
269 | |||
270 | for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) { | ||
271 | struct module *pos = rb_entry(nd, struct module, rb_node); | ||
272 | |||
273 | ret += mod_dso__fprintf_module(pos, fp); | ||
274 | } | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | static struct module *module__new(const char *name, const char *path) | ||
280 | { | ||
281 | struct module *self = calloc(1, sizeof(*self)); | ||
282 | |||
283 | if (!self) | ||
284 | goto out_failure; | ||
285 | |||
286 | self->name = calloc(1, strlen(name) + 1); | ||
287 | if (!self->name) | ||
288 | goto out_failure; | ||
289 | |||
290 | self->path = calloc(1, strlen(path) + 1); | ||
291 | if (!self->path) | ||
292 | goto out_failure; | ||
293 | |||
294 | strcpy(self->name, name); | ||
295 | strcpy(self->path, path); | ||
296 | self->hash = crc32(self->name, strlen(name)); | ||
297 | |||
298 | return self; | ||
299 | |||
300 | out_failure: | ||
301 | if (self) { | ||
302 | if (self->name) | ||
303 | free(self->name); | ||
304 | if (self->path) | ||
305 | free(self->path); | ||
306 | free(self); | ||
307 | } | ||
308 | |||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | static int mod_dso__load_sections(struct module *mod) | ||
313 | { | ||
314 | int count = 0, path_len; | ||
315 | struct dirent *entry; | ||
316 | char *line = NULL; | ||
317 | char *dir_path; | ||
318 | DIR *dir; | ||
319 | size_t n; | ||
320 | |||
321 | path_len = strlen("/sys/module/"); | ||
322 | path_len += strlen(mod->name); | ||
323 | path_len += strlen("/sections/"); | ||
324 | |||
325 | dir_path = calloc(1, path_len + 1); | ||
326 | if (dir_path == NULL) | ||
327 | goto out_failure; | ||
328 | |||
329 | strcat(dir_path, "/sys/module/"); | ||
330 | strcat(dir_path, mod->name); | ||
331 | strcat(dir_path, "/sections/"); | ||
332 | |||
333 | dir = opendir(dir_path); | ||
334 | if (dir == NULL) | ||
335 | goto out_free; | ||
336 | |||
337 | while ((entry = readdir(dir))) { | ||
338 | struct section *section; | ||
339 | char *path, *vma; | ||
340 | int line_len; | ||
341 | FILE *file; | ||
342 | |||
343 | if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) | ||
344 | continue; | ||
345 | |||
346 | path = calloc(1, path_len + strlen(entry->d_name) + 1); | ||
347 | if (path == NULL) | ||
348 | break; | ||
349 | strcat(path, dir_path); | ||
350 | strcat(path, entry->d_name); | ||
351 | |||
352 | file = fopen(path, "r"); | ||
353 | if (file == NULL) { | ||
354 | free(path); | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | line_len = getline(&line, &n, file); | ||
359 | if (line_len < 0) { | ||
360 | free(path); | ||
361 | fclose(file); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | if (!line) { | ||
366 | free(path); | ||
367 | fclose(file); | ||
368 | break; | ||
369 | } | ||
370 | |||
371 | line[--line_len] = '\0'; /* \n */ | ||
372 | |||
373 | vma = strstr(line, "0x"); | ||
374 | if (!vma) { | ||
375 | free(path); | ||
376 | fclose(file); | ||
377 | break; | ||
378 | } | ||
379 | vma += 2; | ||
380 | |||
381 | section = section__new(entry->d_name, path); | ||
382 | if (!section) { | ||
383 | fprintf(stderr, "load_sections: allocation error\n"); | ||
384 | free(path); | ||
385 | fclose(file); | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | hex2u64(vma, §ion->vma); | ||
390 | sec_dso__insert_section(mod->sections, section); | ||
391 | |||
392 | free(path); | ||
393 | fclose(file); | ||
394 | count++; | ||
395 | } | ||
396 | |||
397 | closedir(dir); | ||
398 | free(line); | ||
399 | free(dir_path); | ||
400 | |||
401 | return count; | ||
402 | |||
403 | out_free: | ||
404 | free(dir_path); | ||
405 | |||
406 | out_failure: | ||
407 | return count; | ||
408 | } | ||
409 | |||
410 | static int mod_dso__load_module_paths(struct mod_dso *self) | ||
411 | { | ||
412 | struct utsname uts; | ||
413 | int count = 0, len, err = -1; | ||
414 | char *line = NULL; | ||
415 | FILE *file; | ||
416 | char *dpath, *dir; | ||
417 | size_t n; | ||
418 | |||
419 | if (uname(&uts) < 0) | ||
420 | return err; | ||
421 | |||
422 | len = strlen("/lib/modules/"); | ||
423 | len += strlen(uts.release); | ||
424 | len += strlen("/modules.dep"); | ||
425 | |||
426 | dpath = calloc(1, len + 1); | ||
427 | if (dpath == NULL) | ||
428 | return err; | ||
429 | |||
430 | strcat(dpath, "/lib/modules/"); | ||
431 | strcat(dpath, uts.release); | ||
432 | strcat(dpath, "/modules.dep"); | ||
433 | |||
434 | file = fopen(dpath, "r"); | ||
435 | if (file == NULL) | ||
436 | goto out_failure; | ||
437 | |||
438 | dir = dirname(dpath); | ||
439 | if (!dir) | ||
440 | goto out_failure; | ||
441 | strcat(dir, "/"); | ||
442 | |||
443 | while (!feof(file)) { | ||
444 | struct module *module; | ||
445 | char *name, *path, *tmp; | ||
446 | FILE *modfile; | ||
447 | int line_len; | ||
448 | |||
449 | line_len = getline(&line, &n, file); | ||
450 | if (line_len < 0) | ||
451 | break; | ||
452 | |||
453 | if (!line) | ||
454 | break; | ||
455 | |||
456 | line[--line_len] = '\0'; /* \n */ | ||
457 | |||
458 | path = strchr(line, ':'); | ||
459 | if (!path) | ||
460 | break; | ||
461 | *path = '\0'; | ||
462 | |||
463 | path = strdup(line); | ||
464 | if (!path) | ||
465 | break; | ||
466 | |||
467 | if (!strstr(path, dir)) { | ||
468 | if (strncmp(path, "kernel/", 7)) | ||
469 | break; | ||
470 | |||
471 | free(path); | ||
472 | path = calloc(1, strlen(dir) + strlen(line) + 1); | ||
473 | if (!path) | ||
474 | break; | ||
475 | strcat(path, dir); | ||
476 | strcat(path, line); | ||
477 | } | ||
478 | |||
479 | modfile = fopen(path, "r"); | ||
480 | if (modfile == NULL) | ||
481 | break; | ||
482 | fclose(modfile); | ||
483 | |||
484 | name = strdup(path); | ||
485 | if (!name) | ||
486 | break; | ||
487 | |||
488 | name = strtok(name, "/"); | ||
489 | tmp = name; | ||
490 | |||
491 | while (tmp) { | ||
492 | tmp = strtok(NULL, "/"); | ||
493 | if (tmp) | ||
494 | name = tmp; | ||
495 | } | ||
496 | |||
497 | name = strsep(&name, "."); | ||
498 | if (!name) | ||
499 | break; | ||
500 | |||
501 | /* Quirk: replace '-' with '_' in all modules */ | ||
502 | for (len = strlen(name); len; len--) { | ||
503 | if (*(name+len) == '-') | ||
504 | *(name+len) = '_'; | ||
505 | } | ||
506 | |||
507 | module = module__new(name, path); | ||
508 | if (!module) | ||
509 | break; | ||
510 | mod_dso__insert_module(self, module); | ||
511 | |||
512 | module->sections = sec_dso__new_dso("sections"); | ||
513 | if (!module->sections) | ||
514 | break; | ||
515 | |||
516 | module->active = mod_dso__load_sections(module); | ||
517 | |||
518 | if (module->active > 0) | ||
519 | count++; | ||
520 | } | ||
521 | |||
522 | if (feof(file)) | ||
523 | err = count; | ||
524 | else | ||
525 | fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n"); | ||
526 | |||
527 | out_failure: | ||
528 | if (dpath) | ||
529 | free(dpath); | ||
530 | if (file) | ||
531 | fclose(file); | ||
532 | if (line) | ||
533 | free(line); | ||
534 | |||
535 | return err; | ||
536 | } | ||
537 | |||
538 | int mod_dso__load_modules(struct mod_dso *dso) | ||
539 | { | ||
540 | int err; | ||
541 | |||
542 | err = mod_dso__load_module_paths(dso); | ||
543 | |||
544 | return err; | ||
545 | } | ||
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h deleted file mode 100644 index 098e0412bc22..000000000000 --- a/tools/perf/util/module.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | #ifndef __PERF_MODULE_ | ||
2 | #define __PERF_MODULE_ 1 | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include "../types.h" | ||
6 | #include <linux/list.h> | ||
7 | #include <linux/rbtree.h> | ||
8 | |||
9 | struct section { | ||
10 | struct rb_node rb_node; | ||
11 | u64 hash; | ||
12 | u64 vma; | ||
13 | char *name; | ||
14 | char *path; | ||
15 | }; | ||
16 | |||
17 | struct sec_dso { | ||
18 | struct list_head node; | ||
19 | struct rb_root secs; | ||
20 | struct section *(*find_section)(struct sec_dso *, const char *name); | ||
21 | char name[0]; | ||
22 | }; | ||
23 | |||
24 | struct module { | ||
25 | struct rb_node rb_node; | ||
26 | u64 hash; | ||
27 | char *name; | ||
28 | char *path; | ||
29 | struct sec_dso *sections; | ||
30 | int active; | ||
31 | }; | ||
32 | |||
33 | struct mod_dso { | ||
34 | struct list_head node; | ||
35 | struct rb_root mods; | ||
36 | struct module *(*find_module)(struct mod_dso *, const char *name); | ||
37 | char name[0]; | ||
38 | }; | ||
39 | |||
40 | struct sec_dso *sec_dso__new_dso(const char *name); | ||
41 | void sec_dso__delete_sections(struct sec_dso *self); | ||
42 | void sec_dso__delete_self(struct sec_dso *self); | ||
43 | size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp); | ||
44 | struct section *sec_dso__find_section(struct sec_dso *self, const char *name); | ||
45 | |||
46 | struct mod_dso *mod_dso__new_dso(const char *name); | ||
47 | void mod_dso__delete_modules(struct mod_dso *self); | ||
48 | void mod_dso__delete_self(struct mod_dso *self); | ||
49 | size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp); | ||
50 | struct module *mod_dso__find_module(struct mod_dso *self, const char *name); | ||
51 | int mod_dso__load_modules(struct mod_dso *dso); | ||
52 | |||
53 | #endif /* __PERF_MODULE_ */ | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 50e75abb1fdd..40c9acd41cad 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -129,20 +129,32 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) | |||
129 | int64_t | 129 | int64_t |
130 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | 130 | sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) |
131 | { | 131 | { |
132 | struct dso *dso_l = left->dso; | 132 | struct dso *dso_l = left->map ? left->map->dso : NULL; |
133 | struct dso *dso_r = right->dso; | 133 | struct dso *dso_r = right->map ? right->map->dso : NULL; |
134 | const char *dso_name_l, *dso_name_r; | ||
134 | 135 | ||
135 | if (!dso_l || !dso_r) | 136 | if (!dso_l || !dso_r) |
136 | return cmp_null(dso_l, dso_r); | 137 | return cmp_null(dso_l, dso_r); |
137 | 138 | ||
138 | return strcmp(dso_l->name, dso_r->name); | 139 | if (verbose) { |
140 | dso_name_l = dso_l->long_name; | ||
141 | dso_name_r = dso_r->long_name; | ||
142 | } else { | ||
143 | dso_name_l = dso_l->short_name; | ||
144 | dso_name_r = dso_r->short_name; | ||
145 | } | ||
146 | |||
147 | return strcmp(dso_name_l, dso_name_r); | ||
139 | } | 148 | } |
140 | 149 | ||
141 | size_t | 150 | size_t |
142 | sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) | 151 | sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) |
143 | { | 152 | { |
144 | if (self->dso) | 153 | if (self->map && self->map->dso) { |
145 | return repsep_fprintf(fp, "%-*s", width, self->dso->name); | 154 | const char *dso_name = !verbose ? self->map->dso->short_name : |
155 | self->map->dso->long_name; | ||
156 | return repsep_fprintf(fp, "%-*s", width, dso_name); | ||
157 | } | ||
146 | 158 | ||
147 | return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); | 159 | return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); |
148 | } | 160 | } |
@@ -169,20 +181,16 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) | |||
169 | { | 181 | { |
170 | size_t ret = 0; | 182 | size_t ret = 0; |
171 | 183 | ||
172 | if (verbose) | 184 | if (verbose) { |
173 | ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, | 185 | char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; |
174 | dso__symtab_origin(self->dso)); | 186 | ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); |
187 | } | ||
175 | 188 | ||
176 | ret += repsep_fprintf(fp, "[%c] ", self->level); | 189 | ret += repsep_fprintf(fp, "[%c] ", self->level); |
177 | if (self->sym) { | 190 | if (self->sym) |
178 | ret += repsep_fprintf(fp, "%s", self->sym->name); | 191 | ret += repsep_fprintf(fp, "%s", self->sym->name); |
179 | 192 | else | |
180 | if (self->sym->module) | ||
181 | ret += repsep_fprintf(fp, "\t[%s]", | ||
182 | self->sym->module->name); | ||
183 | } else { | ||
184 | ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); | 193 | ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); |
185 | } | ||
186 | 194 | ||
187 | return ret; | 195 | return ret; |
188 | } | 196 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 4684fd6d5c4a..13806d782af6 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -42,18 +42,15 @@ extern unsigned int threads__col_width; | |||
42 | 42 | ||
43 | struct hist_entry { | 43 | struct hist_entry { |
44 | struct rb_node rb_node; | 44 | struct rb_node rb_node; |
45 | 45 | u64 count; | |
46 | struct thread *thread; | 46 | struct thread *thread; |
47 | struct map *map; | 47 | struct map *map; |
48 | struct dso *dso; | ||
49 | struct symbol *sym; | 48 | struct symbol *sym; |
50 | struct symbol *parent; | ||
51 | u64 ip; | 49 | u64 ip; |
52 | char level; | 50 | char level; |
51 | struct symbol *parent; | ||
53 | struct callchain_node callchain; | 52 | struct callchain_node callchain; |
54 | struct rb_root sorted_chain; | 53 | struct rb_root sorted_chain; |
55 | |||
56 | u64 count; | ||
57 | }; | 54 | }; |
58 | 55 | ||
59 | /* | 56 | /* |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 559fb06210f5..e88296899470 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -2,12 +2,14 @@ | |||
2 | #include "../perf.h" | 2 | #include "../perf.h" |
3 | #include "string.h" | 3 | #include "string.h" |
4 | #include "symbol.h" | 4 | #include "symbol.h" |
5 | #include "thread.h" | ||
5 | 6 | ||
6 | #include "debug.h" | 7 | #include "debug.h" |
7 | 8 | ||
8 | #include <libelf.h> | 9 | #include <libelf.h> |
9 | #include <gelf.h> | 10 | #include <gelf.h> |
10 | #include <elf.h> | 11 | #include <elf.h> |
12 | #include <sys/utsname.h> | ||
11 | 13 | ||
12 | const char *sym_hist_filter; | 14 | const char *sym_hist_filter; |
13 | 15 | ||
@@ -18,12 +20,15 @@ enum dso_origin { | |||
18 | DSO__ORIG_UBUNTU, | 20 | DSO__ORIG_UBUNTU, |
19 | DSO__ORIG_BUILDID, | 21 | DSO__ORIG_BUILDID, |
20 | DSO__ORIG_DSO, | 22 | DSO__ORIG_DSO, |
23 | DSO__ORIG_KMODULE, | ||
21 | DSO__ORIG_NOT_FOUND, | 24 | DSO__ORIG_NOT_FOUND, |
22 | }; | 25 | }; |
23 | 26 | ||
24 | static struct symbol *symbol__new(u64 start, u64 len, | 27 | static void dsos__add(struct dso *dso); |
25 | const char *name, unsigned int priv_size, | 28 | static struct dso *dsos__find(const char *name); |
26 | u64 obj_start, int v) | 29 | |
30 | static struct symbol *symbol__new(u64 start, u64 len, const char *name, | ||
31 | unsigned int priv_size, int v) | ||
27 | { | 32 | { |
28 | size_t namelen = strlen(name) + 1; | 33 | size_t namelen = strlen(name) + 1; |
29 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); | 34 | struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); |
@@ -32,10 +37,9 @@ static struct symbol *symbol__new(u64 start, u64 len, | |||
32 | return NULL; | 37 | return NULL; |
33 | 38 | ||
34 | if (v >= 2) | 39 | if (v >= 2) |
35 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", | 40 | printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n", |
36 | (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); | 41 | start, (unsigned long)len, name, self->hist); |
37 | 42 | ||
38 | self->obj_start= obj_start; | ||
39 | self->hist = NULL; | 43 | self->hist = NULL; |
40 | self->hist_sum = 0; | 44 | self->hist_sum = 0; |
41 | 45 | ||
@@ -60,12 +64,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size) | |||
60 | 64 | ||
61 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 65 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
62 | { | 66 | { |
63 | if (!self->module) | 67 | return fprintf(fp, " %llx-%llx %s\n", |
64 | return fprintf(fp, " %llx-%llx %s\n", | ||
65 | self->start, self->end, self->name); | 68 | self->start, self->end, self->name); |
66 | else | ||
67 | return fprintf(fp, " %llx-%llx %s \t[%s]\n", | ||
68 | self->start, self->end, self->name, self->module->name); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) | 71 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) |
@@ -74,6 +74,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
74 | 74 | ||
75 | if (self != NULL) { | 75 | if (self != NULL) { |
76 | strcpy(self->name, name); | 76 | strcpy(self->name, name); |
77 | self->long_name = self->name; | ||
78 | self->short_name = self->name; | ||
77 | self->syms = RB_ROOT; | 79 | self->syms = RB_ROOT; |
78 | self->sym_priv_size = sym_priv_size; | 80 | self->sym_priv_size = sym_priv_size; |
79 | self->find_symbol = dso__find_symbol; | 81 | self->find_symbol = dso__find_symbol; |
@@ -100,6 +102,8 @@ static void dso__delete_symbols(struct dso *self) | |||
100 | void dso__delete(struct dso *self) | 102 | void dso__delete(struct dso *self) |
101 | { | 103 | { |
102 | dso__delete_symbols(self); | 104 | dso__delete_symbols(self); |
105 | if (self->long_name != self->name) | ||
106 | free(self->long_name); | ||
103 | free(self); | 107 | free(self); |
104 | } | 108 | } |
105 | 109 | ||
@@ -147,7 +151,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip) | |||
147 | 151 | ||
148 | size_t dso__fprintf(struct dso *self, FILE *fp) | 152 | size_t dso__fprintf(struct dso *self, FILE *fp) |
149 | { | 153 | { |
150 | size_t ret = fprintf(fp, "dso: %s\n", self->name); | 154 | size_t ret = fprintf(fp, "dso: %s\n", self->long_name); |
151 | 155 | ||
152 | struct rb_node *nd; | 156 | struct rb_node *nd; |
153 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { | 157 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { |
@@ -158,7 +162,8 @@ size_t dso__fprintf(struct dso *self, FILE *fp) | |||
158 | return ret; | 162 | return ret; |
159 | } | 163 | } |
160 | 164 | ||
161 | static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) | 165 | static int dso__load_kallsyms(struct dso *self, struct map *map, |
166 | symbol_filter_t filter, int v) | ||
162 | { | 167 | { |
163 | struct rb_node *nd, *prevnd; | 168 | struct rb_node *nd, *prevnd; |
164 | char *line = NULL; | 169 | char *line = NULL; |
@@ -200,12 +205,12 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) | |||
200 | * Well fix up the end later, when we have all sorted. | 205 | * Well fix up the end later, when we have all sorted. |
201 | */ | 206 | */ |
202 | sym = symbol__new(start, 0xdead, line + len + 2, | 207 | sym = symbol__new(start, 0xdead, line + len + 2, |
203 | self->sym_priv_size, 0, v); | 208 | self->sym_priv_size, v); |
204 | 209 | ||
205 | if (sym == NULL) | 210 | if (sym == NULL) |
206 | goto out_delete_line; | 211 | goto out_delete_line; |
207 | 212 | ||
208 | if (filter && filter(self, sym)) | 213 | if (filter && filter(map, sym)) |
209 | symbol__delete(sym, self->sym_priv_size); | 214 | symbol__delete(sym, self->sym_priv_size); |
210 | else { | 215 | else { |
211 | dso__insert_symbol(self, sym); | 216 | dso__insert_symbol(self, sym); |
@@ -241,14 +246,15 @@ out_failure: | |||
241 | return -1; | 246 | return -1; |
242 | } | 247 | } |
243 | 248 | ||
244 | static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) | 249 | static int dso__load_perf_map(struct dso *self, struct map *map, |
250 | symbol_filter_t filter, int v) | ||
245 | { | 251 | { |
246 | char *line = NULL; | 252 | char *line = NULL; |
247 | size_t n; | 253 | size_t n; |
248 | FILE *file; | 254 | FILE *file; |
249 | int nr_syms = 0; | 255 | int nr_syms = 0; |
250 | 256 | ||
251 | file = fopen(self->name, "r"); | 257 | file = fopen(self->long_name, "r"); |
252 | if (file == NULL) | 258 | if (file == NULL) |
253 | goto out_failure; | 259 | goto out_failure; |
254 | 260 | ||
@@ -279,12 +285,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) | |||
279 | continue; | 285 | continue; |
280 | 286 | ||
281 | sym = symbol__new(start, size, line + len, | 287 | sym = symbol__new(start, size, line + len, |
282 | self->sym_priv_size, start, v); | 288 | self->sym_priv_size, v); |
283 | 289 | ||
284 | if (sym == NULL) | 290 | if (sym == NULL) |
285 | goto out_delete_line; | 291 | goto out_delete_line; |
286 | 292 | ||
287 | if (filter && filter(self, sym)) | 293 | if (filter && filter(map, sym)) |
288 | symbol__delete(sym, self->sym_priv_size); | 294 | symbol__delete(sym, self->sym_priv_size); |
289 | else { | 295 | else { |
290 | dso__insert_symbol(self, sym); | 296 | dso__insert_symbol(self, sym); |
@@ -410,7 +416,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
410 | Elf *elf; | 416 | Elf *elf; |
411 | int nr = 0, symidx, fd, err = 0; | 417 | int nr = 0, symidx, fd, err = 0; |
412 | 418 | ||
413 | fd = open(self->name, O_RDONLY); | 419 | fd = open(self->long_name, O_RDONLY); |
414 | if (fd < 0) | 420 | if (fd < 0) |
415 | goto out; | 421 | goto out; |
416 | 422 | ||
@@ -478,7 +484,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
478 | "%s@plt", elf_sym__name(&sym, symstrs)); | 484 | "%s@plt", elf_sym__name(&sym, symstrs)); |
479 | 485 | ||
480 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 486 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
481 | sympltname, self->sym_priv_size, 0, v); | 487 | sympltname, self->sym_priv_size, v); |
482 | if (!f) | 488 | if (!f) |
483 | goto out_elf_end; | 489 | goto out_elf_end; |
484 | 490 | ||
@@ -496,7 +502,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v) | |||
496 | "%s@plt", elf_sym__name(&sym, symstrs)); | 502 | "%s@plt", elf_sym__name(&sym, symstrs)); |
497 | 503 | ||
498 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 504 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
499 | sympltname, self->sym_priv_size, 0, v); | 505 | sympltname, self->sym_priv_size, v); |
500 | if (!f) | 506 | if (!f) |
501 | goto out_elf_end; | 507 | goto out_elf_end; |
502 | 508 | ||
@@ -515,12 +521,13 @@ out_close: | |||
515 | return nr; | 521 | return nr; |
516 | out: | 522 | out: |
517 | fprintf(stderr, "%s: problems reading %s PLT info.\n", | 523 | fprintf(stderr, "%s: problems reading %s PLT info.\n", |
518 | __func__, self->name); | 524 | __func__, self->long_name); |
519 | return 0; | 525 | return 0; |
520 | } | 526 | } |
521 | 527 | ||
522 | static int dso__load_sym(struct dso *self, int fd, const char *name, | 528 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, |
523 | symbol_filter_t filter, int v, struct module *mod) | 529 | int fd, symbol_filter_t filter, int kernel, |
530 | int kmodule, int v) | ||
524 | { | 531 | { |
525 | Elf_Data *symstrs, *secstrs; | 532 | Elf_Data *symstrs, *secstrs; |
526 | uint32_t nr_syms; | 533 | uint32_t nr_syms; |
@@ -532,7 +539,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
532 | GElf_Sym sym; | 539 | GElf_Sym sym; |
533 | Elf_Scn *sec, *sec_strndx; | 540 | Elf_Scn *sec, *sec_strndx; |
534 | Elf *elf; | 541 | Elf *elf; |
535 | int nr = 0, kernel = !strcmp("[kernel]", self->name); | 542 | int nr = 0; |
536 | 543 | ||
537 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | 544 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); |
538 | if (elf == NULL) { | 545 | if (elf == NULL) { |
@@ -589,8 +596,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
589 | struct symbol *f; | 596 | struct symbol *f; |
590 | const char *elf_name; | 597 | const char *elf_name; |
591 | char *demangled; | 598 | char *demangled; |
592 | u64 obj_start; | ||
593 | struct section *section = NULL; | ||
594 | int is_label = elf_sym__is_label(&sym); | 599 | int is_label = elf_sym__is_label(&sym); |
595 | const char *section_name; | 600 | const char *section_name; |
596 | 601 | ||
@@ -607,7 +612,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
607 | continue; | 612 | continue; |
608 | 613 | ||
609 | section_name = elf_sec__name(&shdr, secstrs); | 614 | section_name = elf_sec__name(&shdr, secstrs); |
610 | obj_start = sym.st_value; | ||
611 | 615 | ||
612 | if (self->adjust_symbols) { | 616 | if (self->adjust_symbols) { |
613 | if (v >= 2) | 617 | if (v >= 2) |
@@ -615,18 +619,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
615 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); | 619 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); |
616 | 620 | ||
617 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 621 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
618 | } | 622 | } else if (kmodule) |
619 | 623 | sym.st_value += shdr.sh_offset; | |
620 | if (mod) { | ||
621 | section = mod->sections->find_section(mod->sections, section_name); | ||
622 | if (section) | ||
623 | sym.st_value += section->vma; | ||
624 | else { | ||
625 | fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", | ||
626 | mod->name, section_name); | ||
627 | goto out_elf_end; | ||
628 | } | ||
629 | } | ||
630 | /* | 624 | /* |
631 | * We need to figure out if the object was created from C++ sources | 625 | * We need to figure out if the object was created from C++ sources |
632 | * DWARF DW_compile_unit has this, but we don't always have access | 626 | * DWARF DW_compile_unit has this, but we don't always have access |
@@ -638,15 +632,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
638 | elf_name = demangled; | 632 | elf_name = demangled; |
639 | 633 | ||
640 | f = symbol__new(sym.st_value, sym.st_size, elf_name, | 634 | f = symbol__new(sym.st_value, sym.st_size, elf_name, |
641 | self->sym_priv_size, obj_start, v); | 635 | self->sym_priv_size, v); |
642 | free(demangled); | 636 | free(demangled); |
643 | if (!f) | 637 | if (!f) |
644 | goto out_elf_end; | 638 | goto out_elf_end; |
645 | 639 | ||
646 | if (filter && filter(self, f)) | 640 | if (filter && filter(map, f)) |
647 | symbol__delete(f, self->sym_priv_size); | 641 | symbol__delete(f, self->sym_priv_size); |
648 | else { | 642 | else { |
649 | f->module = mod; | ||
650 | dso__insert_symbol(self, f); | 643 | dso__insert_symbol(self, f); |
651 | nr++; | 644 | nr++; |
652 | } | 645 | } |
@@ -671,7 +664,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
671 | char *build_id = NULL, *bid; | 664 | char *build_id = NULL, *bid; |
672 | unsigned char *raw; | 665 | unsigned char *raw; |
673 | Elf *elf; | 666 | Elf *elf; |
674 | int fd = open(self->name, O_RDONLY); | 667 | int fd = open(self->long_name, O_RDONLY); |
675 | 668 | ||
676 | if (fd < 0) | 669 | if (fd < 0) |
677 | goto out; | 670 | goto out; |
@@ -680,7 +673,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
680 | if (elf == NULL) { | 673 | if (elf == NULL) { |
681 | if (v) | 674 | if (v) |
682 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | 675 | fprintf(stderr, "%s: cannot read %s ELF file.\n", |
683 | __func__, self->name); | 676 | __func__, self->long_name); |
684 | goto out_close; | 677 | goto out_close; |
685 | } | 678 | } |
686 | 679 | ||
@@ -709,7 +702,7 @@ static char *dso__read_build_id(struct dso *self, int v) | |||
709 | bid += 2; | 702 | bid += 2; |
710 | } | 703 | } |
711 | if (v >= 2) | 704 | if (v >= 2) |
712 | printf("%s(%s): %s\n", __func__, self->name, build_id); | 705 | printf("%s(%s): %s\n", __func__, self->long_name, build_id); |
713 | out_elf_end: | 706 | out_elf_end: |
714 | elf_end(elf); | 707 | elf_end(elf); |
715 | out_close: | 708 | out_close: |
@@ -727,6 +720,7 @@ char dso__symtab_origin(const struct dso *self) | |||
727 | [DSO__ORIG_UBUNTU] = 'u', | 720 | [DSO__ORIG_UBUNTU] = 'u', |
728 | [DSO__ORIG_BUILDID] = 'b', | 721 | [DSO__ORIG_BUILDID] = 'b', |
729 | [DSO__ORIG_DSO] = 'd', | 722 | [DSO__ORIG_DSO] = 'd', |
723 | [DSO__ORIG_KMODULE] = 'K', | ||
730 | }; | 724 | }; |
731 | 725 | ||
732 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | 726 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) |
@@ -734,7 +728,7 @@ char dso__symtab_origin(const struct dso *self) | |||
734 | return origin[self->origin]; | 728 | return origin[self->origin]; |
735 | } | 729 | } |
736 | 730 | ||
737 | int dso__load(struct dso *self, symbol_filter_t filter, int v) | 731 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v) |
738 | { | 732 | { |
739 | int size = PATH_MAX; | 733 | int size = PATH_MAX; |
740 | char *name = malloc(size), *build_id = NULL; | 734 | char *name = malloc(size), *build_id = NULL; |
@@ -747,7 +741,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v) | |||
747 | self->adjust_symbols = 0; | 741 | self->adjust_symbols = 0; |
748 | 742 | ||
749 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { | 743 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { |
750 | ret = dso__load_perf_map(self, filter, v); | 744 | ret = dso__load_perf_map(self, map, filter, v); |
751 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : | 745 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : |
752 | DSO__ORIG_NOT_FOUND; | 746 | DSO__ORIG_NOT_FOUND; |
753 | return ret; | 747 | return ret; |
@@ -760,10 +754,12 @@ more: | |||
760 | self->origin++; | 754 | self->origin++; |
761 | switch (self->origin) { | 755 | switch (self->origin) { |
762 | case DSO__ORIG_FEDORA: | 756 | case DSO__ORIG_FEDORA: |
763 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); | 757 | snprintf(name, size, "/usr/lib/debug%s.debug", |
758 | self->long_name); | ||
764 | break; | 759 | break; |
765 | case DSO__ORIG_UBUNTU: | 760 | case DSO__ORIG_UBUNTU: |
766 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 761 | snprintf(name, size, "/usr/lib/debug%s", |
762 | self->long_name); | ||
767 | break; | 763 | break; |
768 | case DSO__ORIG_BUILDID: | 764 | case DSO__ORIG_BUILDID: |
769 | build_id = dso__read_build_id(self, v); | 765 | build_id = dso__read_build_id(self, v); |
@@ -777,7 +773,7 @@ more: | |||
777 | self->origin++; | 773 | self->origin++; |
778 | /* Fall thru */ | 774 | /* Fall thru */ |
779 | case DSO__ORIG_DSO: | 775 | case DSO__ORIG_DSO: |
780 | snprintf(name, size, "%s", self->name); | 776 | snprintf(name, size, "%s", self->long_name); |
781 | break; | 777 | break; |
782 | 778 | ||
783 | default: | 779 | default: |
@@ -787,7 +783,7 @@ more: | |||
787 | fd = open(name, O_RDONLY); | 783 | fd = open(name, O_RDONLY); |
788 | } while (fd < 0); | 784 | } while (fd < 0); |
789 | 785 | ||
790 | ret = dso__load_sym(self, fd, name, filter, v, NULL); | 786 | ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v); |
791 | close(fd); | 787 | close(fd); |
792 | 788 | ||
793 | /* | 789 | /* |
@@ -808,89 +804,247 @@ out: | |||
808 | return ret; | 804 | return ret; |
809 | } | 805 | } |
810 | 806 | ||
811 | static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, | 807 | static struct rb_root kernel_maps; |
812 | symbol_filter_t filter, int v) | 808 | struct map *kernel_map; |
809 | |||
810 | static void kernel_maps__insert(struct map *map) | ||
813 | { | 811 | { |
814 | struct module *mod = mod_dso__find_module(mods, name); | 812 | maps__insert(&kernel_maps, map); |
815 | int err = 0, fd; | 813 | } |
816 | 814 | ||
817 | if (mod == NULL || !mod->active) | 815 | struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) |
818 | return err; | 816 | { |
817 | /* | ||
818 | * We can't have kernel_map in kernel_maps because it spans an address | ||
819 | * space that includes the modules. The right way to fix this is to | ||
820 | * create several maps, so that we don't have overlapping ranges with | ||
821 | * modules. For now lets look first on the kernel dso. | ||
822 | */ | ||
823 | struct map *map = maps__find(&kernel_maps, ip); | ||
824 | struct symbol *sym; | ||
825 | |||
826 | if (map) { | ||
827 | ip = map->map_ip(map, ip); | ||
828 | sym = map->dso->find_symbol(map->dso, ip); | ||
829 | } else { | ||
830 | map = kernel_map; | ||
831 | sym = map->dso->find_symbol(map->dso, ip); | ||
832 | } | ||
819 | 833 | ||
820 | fd = open(mod->path, O_RDONLY); | 834 | if (mapp) |
835 | *mapp = map; | ||
821 | 836 | ||
822 | if (fd < 0) | 837 | return sym; |
838 | } | ||
839 | |||
840 | struct map *kernel_maps__find_by_dso_name(const char *name) | ||
841 | { | ||
842 | struct rb_node *nd; | ||
843 | |||
844 | for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { | ||
845 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
846 | |||
847 | if (map->dso && strcmp(map->dso->name, name) == 0) | ||
848 | return map; | ||
849 | } | ||
850 | |||
851 | return NULL; | ||
852 | } | ||
853 | |||
854 | static int dso__load_module_sym(struct dso *self, struct map *map, | ||
855 | symbol_filter_t filter, int v) | ||
856 | { | ||
857 | int err = 0, fd = open(self->long_name, O_RDONLY); | ||
858 | |||
859 | if (fd < 0) { | ||
860 | if (v) | ||
861 | fprintf(stderr, "%s: cannot open %s\n", | ||
862 | __func__, self->long_name); | ||
823 | return err; | 863 | return err; |
864 | } | ||
824 | 865 | ||
825 | err = dso__load_sym(self, fd, name, filter, v, mod); | 866 | err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v); |
826 | close(fd); | 867 | close(fd); |
827 | 868 | ||
828 | return err; | 869 | return err; |
829 | } | 870 | } |
830 | 871 | ||
831 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) | 872 | static int dsos__load_modules_sym_dir(char *dirname, |
873 | symbol_filter_t filter, int v) | ||
832 | { | 874 | { |
833 | struct mod_dso *mods = mod_dso__new_dso("modules"); | 875 | struct dirent *dent; |
834 | struct module *pos; | 876 | int nr_symbols = 0, err; |
835 | struct rb_node *next; | 877 | DIR *dir = opendir(dirname); |
836 | int err, count = 0; | ||
837 | 878 | ||
838 | err = mod_dso__load_modules(mods); | 879 | if (!dir) { |
880 | if (v) | ||
881 | fprintf(stderr, "%s: cannot open %s dir\n", __func__, | ||
882 | dirname); | ||
883 | return -1; | ||
884 | } | ||
839 | 885 | ||
840 | if (err <= 0) | 886 | while ((dent = readdir(dir)) != NULL) { |
841 | return err; | 887 | char path[PATH_MAX]; |
888 | |||
889 | if (dent->d_type == DT_DIR) { | ||
890 | if (!strcmp(dent->d_name, ".") || | ||
891 | !strcmp(dent->d_name, "..")) | ||
892 | continue; | ||
893 | |||
894 | snprintf(path, sizeof(path), "%s/%s", | ||
895 | dirname, dent->d_name); | ||
896 | err = dsos__load_modules_sym_dir(path, filter, v); | ||
897 | if (err < 0) | ||
898 | goto failure; | ||
899 | } else { | ||
900 | char *dot = strrchr(dent->d_name, '.'), | ||
901 | dso_name[PATH_MAX]; | ||
902 | struct map *map; | ||
903 | struct rb_node *last; | ||
904 | |||
905 | if (dot == NULL || strcmp(dot, ".ko")) | ||
906 | continue; | ||
907 | snprintf(dso_name, sizeof(dso_name), "[%.*s]", | ||
908 | (int)(dot - dent->d_name), dent->d_name); | ||
909 | |||
910 | map = kernel_maps__find_by_dso_name(dso_name); | ||
911 | if (map == NULL) | ||
912 | continue; | ||
913 | |||
914 | snprintf(path, sizeof(path), "%s/%s", | ||
915 | dirname, dent->d_name); | ||
916 | |||
917 | map->dso->long_name = strdup(path); | ||
918 | if (map->dso->long_name == NULL) | ||
919 | goto failure; | ||
920 | |||
921 | err = dso__load_module_sym(map->dso, map, filter, v); | ||
922 | if (err < 0) | ||
923 | goto failure; | ||
924 | last = rb_last(&map->dso->syms); | ||
925 | if (last) { | ||
926 | struct symbol *sym; | ||
927 | sym = rb_entry(last, struct symbol, rb_node); | ||
928 | map->end = map->start + sym->end; | ||
929 | } | ||
930 | } | ||
931 | nr_symbols += err; | ||
932 | } | ||
842 | 933 | ||
843 | /* | 934 | return nr_symbols; |
844 | * Iterate over modules, and load active symbols. | 935 | failure: |
845 | */ | 936 | closedir(dir); |
846 | next = rb_first(&mods->mods); | 937 | return -1; |
847 | while (next) { | 938 | } |
848 | pos = rb_entry(next, struct module, rb_node); | ||
849 | err = dso__load_module(self, mods, pos->name, filter, v); | ||
850 | 939 | ||
851 | if (err < 0) | 940 | static int dsos__load_modules_sym(symbol_filter_t filter, int v) |
852 | break; | 941 | { |
942 | struct utsname uts; | ||
943 | char modules_path[PATH_MAX]; | ||
853 | 944 | ||
854 | next = rb_next(&pos->rb_node); | 945 | if (uname(&uts) < 0) |
855 | count += err; | 946 | return -1; |
856 | } | ||
857 | 947 | ||
858 | if (err < 0) { | 948 | snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", |
859 | mod_dso__delete_modules(mods); | 949 | uts.release); |
860 | mod_dso__delete_self(mods); | ||
861 | return err; | ||
862 | } | ||
863 | 950 | ||
864 | return count; | 951 | return dsos__load_modules_sym_dir(modules_path, filter, v); |
865 | } | 952 | } |
866 | 953 | ||
867 | static inline void dso__fill_symbol_holes(struct dso *self) | 954 | /* |
955 | * Constructor variant for modules (where we know from /proc/modules where | ||
956 | * they are loaded) and for vmlinux, where only after we load all the | ||
957 | * symbols we'll know where it starts and ends. | ||
958 | */ | ||
959 | static struct map *map__new2(u64 start, struct dso *dso) | ||
868 | { | 960 | { |
869 | struct symbol *prev = NULL; | 961 | struct map *self = malloc(sizeof(*self)); |
870 | struct rb_node *nd; | ||
871 | 962 | ||
872 | for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { | 963 | if (self != NULL) { |
873 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | 964 | self->start = start; |
965 | /* | ||
966 | * Will be filled after we load all the symbols | ||
967 | */ | ||
968 | self->end = 0; | ||
969 | |||
970 | self->pgoff = 0; | ||
971 | self->dso = dso; | ||
972 | self->map_ip = map__map_ip; | ||
973 | RB_CLEAR_NODE(&self->rb_node); | ||
974 | } | ||
975 | return self; | ||
976 | } | ||
977 | |||
978 | int dsos__load_modules(unsigned int sym_priv_size, | ||
979 | symbol_filter_t filter, int v) | ||
980 | { | ||
981 | char *line = NULL; | ||
982 | size_t n; | ||
983 | FILE *file = fopen("/proc/modules", "r"); | ||
984 | struct map *map; | ||
874 | 985 | ||
875 | if (prev) { | 986 | if (file == NULL) |
876 | u64 hole = 0; | 987 | return -1; |
877 | int alias = pos->start == prev->start; | ||
878 | 988 | ||
879 | if (!alias) | 989 | while (!feof(file)) { |
880 | hole = prev->start - pos->end - 1; | 990 | char name[PATH_MAX]; |
991 | u64 start; | ||
992 | struct dso *dso; | ||
993 | char *sep; | ||
994 | int line_len; | ||
881 | 995 | ||
882 | if (hole || alias) { | 996 | line_len = getline(&line, &n, file); |
883 | if (alias) | 997 | if (line_len < 0) |
884 | pos->end = prev->end; | 998 | break; |
885 | else if (hole) | 999 | |
886 | pos->end = prev->start - 1; | 1000 | if (!line) |
887 | } | 1001 | goto out_failure; |
1002 | |||
1003 | line[--line_len] = '\0'; /* \n */ | ||
1004 | |||
1005 | sep = strrchr(line, 'x'); | ||
1006 | if (sep == NULL) | ||
1007 | continue; | ||
1008 | |||
1009 | hex2u64(sep + 1, &start); | ||
1010 | |||
1011 | sep = strchr(line, ' '); | ||
1012 | if (sep == NULL) | ||
1013 | continue; | ||
1014 | |||
1015 | *sep = '\0'; | ||
1016 | |||
1017 | snprintf(name, sizeof(name), "[%s]", line); | ||
1018 | dso = dso__new(name, sym_priv_size); | ||
1019 | |||
1020 | if (dso == NULL) | ||
1021 | goto out_delete_line; | ||
1022 | |||
1023 | map = map__new2(start, dso); | ||
1024 | if (map == NULL) { | ||
1025 | dso__delete(dso); | ||
1026 | goto out_delete_line; | ||
888 | } | 1027 | } |
889 | prev = pos; | 1028 | |
1029 | dso->origin = DSO__ORIG_KMODULE; | ||
1030 | kernel_maps__insert(map); | ||
1031 | dsos__add(dso); | ||
890 | } | 1032 | } |
1033 | |||
1034 | free(line); | ||
1035 | fclose(file); | ||
1036 | |||
1037 | v = 1; | ||
1038 | return dsos__load_modules_sym(filter, v); | ||
1039 | |||
1040 | out_delete_line: | ||
1041 | free(line); | ||
1042 | out_failure: | ||
1043 | return -1; | ||
891 | } | 1044 | } |
892 | 1045 | ||
893 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | 1046 | static int dso__load_vmlinux(struct dso *self, struct map *map, |
1047 | const char *vmlinux, | ||
894 | symbol_filter_t filter, int v) | 1048 | symbol_filter_t filter, int v) |
895 | { | 1049 | { |
896 | int err, fd = open(vmlinux, O_RDONLY); | 1050 | int err, fd = open(vmlinux, O_RDONLY); |
@@ -898,28 +1052,36 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | |||
898 | if (fd < 0) | 1052 | if (fd < 0) |
899 | return -1; | 1053 | return -1; |
900 | 1054 | ||
901 | err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); | 1055 | err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v); |
902 | |||
903 | if (err > 0) | ||
904 | dso__fill_symbol_holes(self); | ||
905 | 1056 | ||
906 | close(fd); | 1057 | close(fd); |
907 | 1058 | ||
908 | return err; | 1059 | return err; |
909 | } | 1060 | } |
910 | 1061 | ||
911 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 1062 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, |
912 | symbol_filter_t filter, int v, int use_modules) | 1063 | symbol_filter_t filter, int v, int use_modules) |
913 | { | 1064 | { |
914 | int err = -1; | 1065 | int err = -1; |
1066 | struct dso *dso = dso__new(vmlinux, sym_priv_size); | ||
1067 | |||
1068 | if (dso == NULL) | ||
1069 | return -1; | ||
1070 | |||
1071 | dso->short_name = "[kernel]"; | ||
1072 | kernel_map = map__new2(0, dso); | ||
1073 | if (kernel_map == NULL) | ||
1074 | goto out_delete_dso; | ||
1075 | |||
1076 | kernel_map->map_ip = vdso__map_ip; | ||
915 | 1077 | ||
916 | if (vmlinux) { | 1078 | if (vmlinux) { |
917 | err = dso__load_vmlinux(self, vmlinux, filter, v); | 1079 | err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); |
918 | if (err > 0 && use_modules) { | 1080 | if (err > 0 && use_modules) { |
919 | int syms = dso__load_modules(self, filter, v); | 1081 | int syms = dsos__load_modules(sym_priv_size, filter, v); |
920 | 1082 | ||
921 | if (syms < 0) { | 1083 | if (syms < 0) { |
922 | fprintf(stderr, "dso__load_modules failed!\n"); | 1084 | fprintf(stderr, "dsos__load_modules failed!\n"); |
923 | return syms; | 1085 | return syms; |
924 | } | 1086 | } |
925 | err += syms; | 1087 | err += syms; |
@@ -927,18 +1089,34 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, | |||
927 | } | 1089 | } |
928 | 1090 | ||
929 | if (err <= 0) | 1091 | if (err <= 0) |
930 | err = dso__load_kallsyms(self, filter, v); | 1092 | err = dso__load_kallsyms(dso, kernel_map, filter, v); |
1093 | |||
1094 | if (err > 0) { | ||
1095 | struct rb_node *node = rb_first(&dso->syms); | ||
1096 | struct symbol *sym = rb_entry(node, struct symbol, rb_node); | ||
931 | 1097 | ||
932 | if (err > 0) | 1098 | kernel_map->start = sym->start; |
933 | self->origin = DSO__ORIG_KERNEL; | 1099 | node = rb_last(&dso->syms); |
1100 | sym = rb_entry(node, struct symbol, rb_node); | ||
1101 | kernel_map->end = sym->end; | ||
1102 | |||
1103 | dso->origin = DSO__ORIG_KERNEL; | ||
1104 | /* | ||
1105 | * XXX See kernel_maps__find_symbol comment | ||
1106 | * kernel_maps__insert(kernel_map) | ||
1107 | */ | ||
1108 | dsos__add(dso); | ||
1109 | } | ||
934 | 1110 | ||
935 | return err; | 1111 | return err; |
1112 | |||
1113 | out_delete_dso: | ||
1114 | dso__delete(dso); | ||
1115 | return -1; | ||
936 | } | 1116 | } |
937 | 1117 | ||
938 | LIST_HEAD(dsos); | 1118 | LIST_HEAD(dsos); |
939 | struct dso *kernel_dso; | ||
940 | struct dso *vdso; | 1119 | struct dso *vdso; |
941 | struct dso *hypervisor_dso; | ||
942 | 1120 | ||
943 | const char *vmlinux_name = "vmlinux"; | 1121 | const char *vmlinux_name = "vmlinux"; |
944 | int modules; | 1122 | int modules; |
@@ -970,7 +1148,7 @@ struct dso *dsos__findnew(const char *name) | |||
970 | if (!dso) | 1148 | if (!dso) |
971 | goto out_delete_dso; | 1149 | goto out_delete_dso; |
972 | 1150 | ||
973 | nr = dso__load(dso, NULL, verbose); | 1151 | nr = dso__load(dso, NULL, NULL, verbose); |
974 | if (nr < 0) { | 1152 | if (nr < 0) { |
975 | eprintf("Failed to open: %s\n", name); | 1153 | eprintf("Failed to open: %s\n", name); |
976 | goto out_delete_dso; | 1154 | goto out_delete_dso; |
@@ -995,43 +1173,20 @@ void dsos__fprintf(FILE *fp) | |||
995 | dso__fprintf(pos, fp); | 1173 | dso__fprintf(pos, fp); |
996 | } | 1174 | } |
997 | 1175 | ||
998 | static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) | ||
999 | { | ||
1000 | return dso__find_symbol(dso, ip); | ||
1001 | } | ||
1002 | |||
1003 | int load_kernel(void) | 1176 | int load_kernel(void) |
1004 | { | 1177 | { |
1005 | int err; | 1178 | if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0) |
1006 | |||
1007 | kernel_dso = dso__new("[kernel]", 0); | ||
1008 | if (!kernel_dso) | ||
1009 | return -1; | 1179 | return -1; |
1010 | 1180 | ||
1011 | err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); | ||
1012 | if (err <= 0) { | ||
1013 | dso__delete(kernel_dso); | ||
1014 | kernel_dso = NULL; | ||
1015 | } else | ||
1016 | dsos__add(kernel_dso); | ||
1017 | |||
1018 | vdso = dso__new("[vdso]", 0); | 1181 | vdso = dso__new("[vdso]", 0); |
1019 | if (!vdso) | 1182 | if (!vdso) |
1020 | return -1; | 1183 | return -1; |
1021 | 1184 | ||
1022 | vdso->find_symbol = vdso__find_symbol; | ||
1023 | |||
1024 | dsos__add(vdso); | 1185 | dsos__add(vdso); |
1025 | 1186 | ||
1026 | hypervisor_dso = dso__new("[hypervisor]", 0); | 1187 | return 0; |
1027 | if (!hypervisor_dso) | ||
1028 | return -1; | ||
1029 | dsos__add(hypervisor_dso); | ||
1030 | |||
1031 | return err; | ||
1032 | } | 1188 | } |
1033 | 1189 | ||
1034 | |||
1035 | void symbol__init(void) | 1190 | void symbol__init(void) |
1036 | { | 1191 | { |
1037 | elf_version(EV_CURRENT); | 1192 | elf_version(EV_CURRENT); |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ee164f659ed3..5339fd82ec96 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -5,7 +5,6 @@ | |||
5 | #include "types.h" | 5 | #include "types.h" |
6 | #include <linux/list.h> | 6 | #include <linux/list.h> |
7 | #include <linux/rbtree.h> | 7 | #include <linux/rbtree.h> |
8 | #include "module.h" | ||
9 | #include "event.h" | 8 | #include "event.h" |
10 | 9 | ||
11 | #ifdef HAVE_CPLUS_DEMANGLE | 10 | #ifdef HAVE_CPLUS_DEMANGLE |
@@ -36,10 +35,8 @@ struct symbol { | |||
36 | struct rb_node rb_node; | 35 | struct rb_node rb_node; |
37 | u64 start; | 36 | u64 start; |
38 | u64 end; | 37 | u64 end; |
39 | u64 obj_start; | ||
40 | u64 hist_sum; | 38 | u64 hist_sum; |
41 | u64 *hist; | 39 | u64 *hist; |
42 | struct module *module; | ||
43 | void *priv; | 40 | void *priv; |
44 | char name[0]; | 41 | char name[0]; |
45 | }; | 42 | }; |
@@ -52,12 +49,14 @@ struct dso { | |||
52 | unsigned char adjust_symbols; | 49 | unsigned char adjust_symbols; |
53 | unsigned char slen_calculated; | 50 | unsigned char slen_calculated; |
54 | unsigned char origin; | 51 | unsigned char origin; |
52 | const char *short_name; | ||
53 | char *long_name; | ||
55 | char name[0]; | 54 | char name[0]; |
56 | }; | 55 | }; |
57 | 56 | ||
58 | extern const char *sym_hist_filter; | 57 | extern const char *sym_hist_filter; |
59 | 58 | ||
60 | typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); | 59 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
61 | 60 | ||
62 | struct dso *dso__new(const char *name, unsigned int sym_priv_size); | 61 | struct dso *dso__new(const char *name, unsigned int sym_priv_size); |
63 | void dso__delete(struct dso *self); | 62 | void dso__delete(struct dso *self); |
@@ -69,10 +68,12 @@ static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) | |||
69 | 68 | ||
70 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); | 69 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); |
71 | 70 | ||
72 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 71 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, |
73 | symbol_filter_t filter, int verbose, int modules); | 72 | symbol_filter_t filter, int verbose, int modules); |
74 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); | 73 | int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter, |
75 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose); | 74 | int verbose); |
75 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, | ||
76 | int verbose); | ||
76 | struct dso *dsos__findnew(const char *name); | 77 | struct dso *dsos__findnew(const char *name); |
77 | void dsos__fprintf(FILE *fp); | 78 | void dsos__fprintf(FILE *fp); |
78 | 79 | ||
@@ -84,9 +85,8 @@ int load_kernel(void); | |||
84 | void symbol__init(void); | 85 | void symbol__init(void); |
85 | 86 | ||
86 | extern struct list_head dsos; | 87 | extern struct list_head dsos; |
87 | extern struct dso *kernel_dso; | 88 | extern struct map *kernel_map; |
88 | extern struct dso *vdso; | 89 | extern struct dso *vdso; |
89 | extern struct dso *hypervisor_dso; | ||
90 | extern const char *vmlinux_name; | 90 | extern const char *vmlinux_name; |
91 | extern int modules; | 91 | extern int modules; |
92 | #endif /* __PERF_SYMBOL */ | 92 | #endif /* __PERF_SYMBOL */ |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 9d0945cc66d1..3b56aebb1f4b 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -16,6 +16,7 @@ static struct thread *thread__new(pid_t pid) | |||
16 | if (self->comm) | 16 | if (self->comm) |
17 | snprintf(self->comm, 32, ":%d", self->pid); | 17 | snprintf(self->comm, 32, ":%d", self->pid); |
18 | self->maps = RB_ROOT; | 18 | self->maps = RB_ROOT; |
19 | INIT_LIST_HEAD(&self->removed_maps); | ||
19 | } | 20 | } |
20 | 21 | ||
21 | return self; | 22 | return self; |
@@ -32,13 +33,20 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
32 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 33 | static size_t thread__fprintf(struct thread *self, FILE *fp) |
33 | { | 34 | { |
34 | struct rb_node *nd; | 35 | struct rb_node *nd; |
35 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | 36 | struct map *pos; |
37 | size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", | ||
38 | self->pid, self->comm); | ||
36 | 39 | ||
37 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { | 40 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { |
38 | struct map *pos = rb_entry(nd, struct map, rb_node); | 41 | pos = rb_entry(nd, struct map, rb_node); |
39 | ret += map__fprintf(pos, fp); | 42 | ret += map__fprintf(pos, fp); |
40 | } | 43 | } |
41 | 44 | ||
45 | ret = fprintf(fp, "Removed maps:\n"); | ||
46 | |||
47 | list_for_each_entry(pos, &self->removed_maps, node) | ||
48 | ret += map__fprintf(pos, fp); | ||
49 | |||
42 | return ret; | 50 | return ret; |
43 | } | 51 | } |
44 | 52 | ||
@@ -112,21 +120,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) | |||
112 | map__fprintf(pos, stdout); | 120 | map__fprintf(pos, stdout); |
113 | } | 121 | } |
114 | 122 | ||
115 | if (map->start <= pos->start && map->end > pos->start) | 123 | rb_erase(&pos->rb_node, &self->maps); |
116 | pos->start = map->end; | 124 | /* |
117 | 125 | * We may have references to this map, for instance in some | |
118 | if (map->end >= pos->end && map->start < pos->end) | 126 | * hist_entry instances, so just move them to a separate |
119 | pos->end = map->start; | 127 | * list. |
120 | 128 | */ | |
121 | if (verbose >= 2) { | 129 | list_add_tail(&pos->node, &self->removed_maps); |
122 | printf("after collision:\n"); | ||
123 | map__fprintf(pos, stdout); | ||
124 | } | ||
125 | |||
126 | if (pos->start >= pos->end) { | ||
127 | rb_erase(&pos->rb_node, &self->maps); | ||
128 | free(pos); | ||
129 | } | ||
130 | } | 130 | } |
131 | } | 131 | } |
132 | 132 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index bbb37c1a52ee..845d9b62f96f 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -8,6 +8,7 @@ | |||
8 | struct thread { | 8 | struct thread { |
9 | struct rb_node rb_node; | 9 | struct rb_node rb_node; |
10 | struct rb_root maps; | 10 | struct rb_root maps; |
11 | struct list_head removed_maps; | ||
11 | pid_t pid; | 12 | pid_t pid; |
12 | char shortname[3]; | 13 | char shortname[3]; |
13 | char *comm; | 14 | char *comm; |
@@ -25,6 +26,9 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads); | |||
25 | void maps__insert(struct rb_root *maps, struct map *map); | 26 | void maps__insert(struct rb_root *maps, struct map *map); |
26 | struct map *maps__find(struct rb_root *maps, u64 ip); | 27 | struct map *maps__find(struct rb_root *maps, u64 ip); |
27 | 28 | ||
29 | struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp); | ||
30 | struct map *kernel_maps__find_by_dso_name(const char *name); | ||
31 | |||
28 | static inline struct map *thread__find_map(struct thread *self, u64 ip) | 32 | static inline struct map *thread__find_map(struct thread *self, u64 ip) |
29 | { | 33 | { |
30 | return self ? maps__find(&self->maps, ip) : NULL; | 34 | return self ? maps__find(&self->maps, ip) : NULL; |