diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 116 |
1 files changed, 84 insertions, 32 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8e6627e6b778..381999dd5c1f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -161,7 +161,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp) | |||
161 | self->start, self->end, self->name); | 161 | self->start, self->end, self->name); |
162 | } | 162 | } |
163 | 163 | ||
164 | static void dso__set_long_name(struct dso *self, char *name) | 164 | void dso__set_long_name(struct dso *self, char *name) |
165 | { | 165 | { |
166 | if (name == NULL) | 166 | if (name == NULL) |
167 | return; | 167 | return; |
@@ -176,7 +176,7 @@ static void dso__set_basename(struct dso *self) | |||
176 | 176 | ||
177 | struct dso *dso__new(const char *name) | 177 | struct dso *dso__new(const char *name) |
178 | { | 178 | { |
179 | struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); | 179 | struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1); |
180 | 180 | ||
181 | if (self != NULL) { | 181 | if (self != NULL) { |
182 | int i; | 182 | int i; |
@@ -500,13 +500,17 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
500 | 500 | ||
501 | *module++ = '\0'; | 501 | *module++ = '\0'; |
502 | 502 | ||
503 | if (strcmp(self->name, module)) { | 503 | if (strcmp(curr_map->dso->short_name, module)) { |
504 | curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); | 504 | curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); |
505 | if (curr_map == NULL) { | 505 | if (curr_map == NULL) { |
506 | pr_debug("/proc/{kallsyms,modules} " | 506 | pr_debug("/proc/{kallsyms,modules} " |
507 | "inconsistency!\n"); | 507 | "inconsistency while looking " |
508 | "for \"%s\" module!\n", module); | ||
508 | return -1; | 509 | return -1; |
509 | } | 510 | } |
511 | |||
512 | if (curr_map->dso->loaded) | ||
513 | goto discard_symbol; | ||
510 | } | 514 | } |
511 | /* | 515 | /* |
512 | * So that we look just like we get from .ko files, | 516 | * So that we look just like we get from .ko files, |
@@ -1343,13 +1347,33 @@ struct map *map_groups__find_by_name(struct map_groups *self, | |||
1343 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | 1347 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { |
1344 | struct map *map = rb_entry(nd, struct map, rb_node); | 1348 | struct map *map = rb_entry(nd, struct map, rb_node); |
1345 | 1349 | ||
1346 | if (map->dso && strcmp(map->dso->name, name) == 0) | 1350 | if (map->dso && strcmp(map->dso->short_name, name) == 0) |
1347 | return map; | 1351 | return map; |
1348 | } | 1352 | } |
1349 | 1353 | ||
1350 | return NULL; | 1354 | return NULL; |
1351 | } | 1355 | } |
1352 | 1356 | ||
1357 | static int dso__kernel_module_get_build_id(struct dso *self) | ||
1358 | { | ||
1359 | char filename[PATH_MAX]; | ||
1360 | /* | ||
1361 | * kernel module short names are of the form "[module]" and | ||
1362 | * we need just "module" here. | ||
1363 | */ | ||
1364 | const char *name = self->short_name + 1; | ||
1365 | |||
1366 | snprintf(filename, sizeof(filename), | ||
1367 | "/sys/module/%.*s/notes/.note.gnu.build-id", | ||
1368 | (int)strlen(name - 1), name); | ||
1369 | |||
1370 | if (sysfs__read_build_id(filename, self->build_id, | ||
1371 | sizeof(self->build_id)) == 0) | ||
1372 | self->has_build_id = true; | ||
1373 | |||
1374 | return 0; | ||
1375 | } | ||
1376 | |||
1353 | static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) | 1377 | static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) |
1354 | { | 1378 | { |
1355 | struct dirent *dent; | 1379 | struct dirent *dent; |
@@ -1395,6 +1419,7 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d | |||
1395 | if (long_name == NULL) | 1419 | if (long_name == NULL) |
1396 | goto failure; | 1420 | goto failure; |
1397 | dso__set_long_name(map->dso, long_name); | 1421 | dso__set_long_name(map->dso, long_name); |
1422 | dso__kernel_module_get_build_id(map->dso); | ||
1398 | } | 1423 | } |
1399 | } | 1424 | } |
1400 | 1425 | ||
@@ -1437,6 +1462,24 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | |||
1437 | return self; | 1462 | return self; |
1438 | } | 1463 | } |
1439 | 1464 | ||
1465 | struct map *perf_session__new_module_map(struct perf_session *self, u64 start, | ||
1466 | const char *filename) | ||
1467 | { | ||
1468 | struct map *map; | ||
1469 | struct dso *dso = __dsos__findnew(&dsos__kernel, filename); | ||
1470 | |||
1471 | if (dso == NULL) | ||
1472 | return NULL; | ||
1473 | |||
1474 | map = map__new2(start, dso, MAP__FUNCTION); | ||
1475 | if (map == NULL) | ||
1476 | return NULL; | ||
1477 | |||
1478 | dso->origin = DSO__ORIG_KMODULE; | ||
1479 | map_groups__insert(&self->kmaps, map); | ||
1480 | return map; | ||
1481 | } | ||
1482 | |||
1440 | static int perf_session__create_module_maps(struct perf_session *self) | 1483 | static int perf_session__create_module_maps(struct perf_session *self) |
1441 | { | 1484 | { |
1442 | char *line = NULL; | 1485 | char *line = NULL; |
@@ -1450,7 +1493,6 @@ static int perf_session__create_module_maps(struct perf_session *self) | |||
1450 | while (!feof(file)) { | 1493 | while (!feof(file)) { |
1451 | char name[PATH_MAX]; | 1494 | char name[PATH_MAX]; |
1452 | u64 start; | 1495 | u64 start; |
1453 | struct dso *dso; | ||
1454 | char *sep; | 1496 | char *sep; |
1455 | int line_len; | 1497 | int line_len; |
1456 | 1498 | ||
@@ -1476,26 +1518,10 @@ static int perf_session__create_module_maps(struct perf_session *self) | |||
1476 | *sep = '\0'; | 1518 | *sep = '\0'; |
1477 | 1519 | ||
1478 | snprintf(name, sizeof(name), "[%s]", line); | 1520 | snprintf(name, sizeof(name), "[%s]", line); |
1479 | dso = dso__new(name); | 1521 | map = perf_session__new_module_map(self, start, name); |
1480 | 1522 | if (map == NULL) | |
1481 | if (dso == NULL) | ||
1482 | goto out_delete_line; | ||
1483 | |||
1484 | map = map__new2(start, dso, MAP__FUNCTION); | ||
1485 | if (map == NULL) { | ||
1486 | dso__delete(dso); | ||
1487 | goto out_delete_line; | 1523 | goto out_delete_line; |
1488 | } | 1524 | dso__kernel_module_get_build_id(map->dso); |
1489 | |||
1490 | snprintf(name, sizeof(name), | ||
1491 | "/sys/module/%s/notes/.note.gnu.build-id", line); | ||
1492 | if (sysfs__read_build_id(name, dso->build_id, | ||
1493 | sizeof(dso->build_id)) == 0) | ||
1494 | dso->has_build_id = true; | ||
1495 | |||
1496 | dso->origin = DSO__ORIG_KMODULE; | ||
1497 | map_groups__insert(&self->kmaps, map); | ||
1498 | dsos__add(&dsos__kernel, dso); | ||
1499 | } | 1525 | } |
1500 | 1526 | ||
1501 | free(line); | 1527 | free(line); |
@@ -1573,10 +1599,28 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1573 | } | 1599 | } |
1574 | } | 1600 | } |
1575 | 1601 | ||
1602 | /* | ||
1603 | * Say the kernel DSO was created when processing the build-id header table, | ||
1604 | * we have a build-id, so check if it is the same as the running kernel, | ||
1605 | * using it if it is. | ||
1606 | */ | ||
1607 | if (self->has_build_id) { | ||
1608 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | ||
1609 | |||
1610 | if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, | ||
1611 | sizeof(kallsyms_build_id)) == 0) | ||
1612 | |||
1613 | is_kallsyms = dso__build_id_equal(self, kallsyms_build_id); | ||
1614 | if (is_kallsyms) | ||
1615 | goto do_kallsyms; | ||
1616 | goto do_vmlinux; | ||
1617 | } | ||
1618 | |||
1576 | is_kallsyms = self->long_name[0] == '['; | 1619 | is_kallsyms = self->long_name[0] == '['; |
1577 | if (is_kallsyms) | 1620 | if (is_kallsyms) |
1578 | goto do_kallsyms; | 1621 | goto do_kallsyms; |
1579 | 1622 | ||
1623 | do_vmlinux: | ||
1580 | err = dso__load_vmlinux(self, map, session, self->long_name, filter); | 1624 | err = dso__load_vmlinux(self, map, session, self->long_name, filter); |
1581 | if (err <= 0) { | 1625 | if (err <= 0) { |
1582 | pr_info("The file %s cannot be used, " | 1626 | pr_info("The file %s cannot be used, " |
@@ -1694,16 +1738,12 @@ out_delete_kernel_dso: | |||
1694 | return NULL; | 1738 | return NULL; |
1695 | } | 1739 | } |
1696 | 1740 | ||
1697 | static int map_groups__create_kernel_maps(struct map_groups *self, | 1741 | int __map_groups__create_kernel_maps(struct map_groups *self, |
1698 | struct map *vmlinux_maps[MAP__NR_TYPES], | 1742 | struct map *vmlinux_maps[MAP__NR_TYPES], |
1699 | const char *vmlinux) | 1743 | struct dso *kernel) |
1700 | { | 1744 | { |
1701 | struct dso *kernel = dsos__create_kernel(vmlinux); | ||
1702 | enum map_type type; | 1745 | enum map_type type; |
1703 | 1746 | ||
1704 | if (kernel == NULL) | ||
1705 | return -1; | ||
1706 | |||
1707 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 1747 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
1708 | vmlinux_maps[type] = map__new2(0, kernel, type); | 1748 | vmlinux_maps[type] = map__new2(0, kernel, type); |
1709 | if (vmlinux_maps[type] == NULL) | 1749 | if (vmlinux_maps[type] == NULL) |
@@ -1717,6 +1757,18 @@ static int map_groups__create_kernel_maps(struct map_groups *self, | |||
1717 | return 0; | 1757 | return 0; |
1718 | } | 1758 | } |
1719 | 1759 | ||
1760 | static int map_groups__create_kernel_maps(struct map_groups *self, | ||
1761 | struct map *vmlinux_maps[MAP__NR_TYPES], | ||
1762 | const char *vmlinux) | ||
1763 | { | ||
1764 | struct dso *kernel = dsos__create_kernel(vmlinux); | ||
1765 | |||
1766 | if (kernel == NULL) | ||
1767 | return -1; | ||
1768 | |||
1769 | return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel); | ||
1770 | } | ||
1771 | |||
1720 | static void vmlinux_path__exit(void) | 1772 | static void vmlinux_path__exit(void) |
1721 | { | 1773 | { |
1722 | while (--vmlinux_path__nr_entries >= 0) { | 1774 | while (--vmlinux_path__nr_entries >= 0) { |