diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2013-10-14 06:43:43 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-10-14 09:29:25 -0400 |
commit | 0544d4225c52ca31ab2a55b22ddce1392d8f45a4 (patch) | |
tree | 6f09d3816bcdf31624d451c00e602a11afaba445 | |
parent | 9a17d7268d71674f0bbff6821f7d8e6dc0ece19a (diff) |
perf symbols: Add ability to find kcore in build-id cache
When no vmlinux is found, tools will use kallsyms and, if possible,
kcore. Add the ability to find kcore in the build-id cache.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1381747424-3557-7-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/symbol.c | 147 |
1 files changed, 103 insertions, 44 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b2f60ddc864f..76a9e933a7a5 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1401,6 +1401,105 @@ out: | |||
1401 | return err; | 1401 | return err; |
1402 | } | 1402 | } |
1403 | 1403 | ||
1404 | static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | ||
1405 | { | ||
1406 | char kallsyms_filename[PATH_MAX]; | ||
1407 | struct dirent *dent; | ||
1408 | int ret = -1; | ||
1409 | DIR *d; | ||
1410 | |||
1411 | d = opendir(dir); | ||
1412 | if (!d) | ||
1413 | return -1; | ||
1414 | |||
1415 | while (1) { | ||
1416 | dent = readdir(d); | ||
1417 | if (!dent) | ||
1418 | break; | ||
1419 | if (dent->d_type != DT_DIR) | ||
1420 | continue; | ||
1421 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | ||
1422 | "%s/%s/kallsyms", dir, dent->d_name); | ||
1423 | if (!validate_kcore_modules(kallsyms_filename, map)) { | ||
1424 | strlcpy(dir, kallsyms_filename, dir_sz); | ||
1425 | ret = 0; | ||
1426 | break; | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | closedir(d); | ||
1431 | |||
1432 | return ret; | ||
1433 | } | ||
1434 | |||
1435 | static char *dso__find_kallsyms(struct dso *dso, struct map *map) | ||
1436 | { | ||
1437 | u8 host_build_id[BUILD_ID_SIZE]; | ||
1438 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
1439 | bool is_host = false; | ||
1440 | char path[PATH_MAX]; | ||
1441 | |||
1442 | if (!dso->has_build_id) { | ||
1443 | /* | ||
1444 | * Last resort, if we don't have a build-id and couldn't find | ||
1445 | * any vmlinux file, try the running kernel kallsyms table. | ||
1446 | */ | ||
1447 | goto proc_kallsyms; | ||
1448 | } | ||
1449 | |||
1450 | if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, | ||
1451 | sizeof(host_build_id)) == 0) | ||
1452 | is_host = dso__build_id_equal(dso, host_build_id); | ||
1453 | |||
1454 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
1455 | |||
1456 | /* Use /proc/kallsyms if possible */ | ||
1457 | if (is_host) { | ||
1458 | DIR *d; | ||
1459 | int fd; | ||
1460 | |||
1461 | /* If no cached kcore go with /proc/kallsyms */ | ||
1462 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", | ||
1463 | buildid_dir, sbuild_id); | ||
1464 | d = opendir(path); | ||
1465 | if (!d) | ||
1466 | goto proc_kallsyms; | ||
1467 | closedir(d); | ||
1468 | |||
1469 | /* | ||
1470 | * Do not check the build-id cache, until we know we cannot use | ||
1471 | * /proc/kcore. | ||
1472 | */ | ||
1473 | fd = open("/proc/kcore", O_RDONLY); | ||
1474 | if (fd != -1) { | ||
1475 | close(fd); | ||
1476 | /* If module maps match go with /proc/kallsyms */ | ||
1477 | if (!validate_kcore_modules("/proc/kallsyms", map)) | ||
1478 | goto proc_kallsyms; | ||
1479 | } | ||
1480 | |||
1481 | /* Find kallsyms in build-id cache with kcore */ | ||
1482 | if (!find_matching_kcore(map, path, sizeof(path))) | ||
1483 | return strdup(path); | ||
1484 | |||
1485 | goto proc_kallsyms; | ||
1486 | } | ||
1487 | |||
1488 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", | ||
1489 | buildid_dir, sbuild_id); | ||
1490 | |||
1491 | if (access(path, F_OK)) { | ||
1492 | pr_err("No kallsyms or vmlinux with build-id %s was found\n", | ||
1493 | sbuild_id); | ||
1494 | return NULL; | ||
1495 | } | ||
1496 | |||
1497 | return strdup(path); | ||
1498 | |||
1499 | proc_kallsyms: | ||
1500 | return strdup("/proc/kallsyms"); | ||
1501 | } | ||
1502 | |||
1404 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 1503 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
1405 | symbol_filter_t filter) | 1504 | symbol_filter_t filter) |
1406 | { | 1505 | { |
@@ -1449,51 +1548,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
1449 | if (symbol_conf.symfs[0] != 0) | 1548 | if (symbol_conf.symfs[0] != 0) |
1450 | return -1; | 1549 | return -1; |
1451 | 1550 | ||
1452 | /* | 1551 | kallsyms_allocated_filename = dso__find_kallsyms(dso, map); |
1453 | * Say the kernel DSO was created when processing the build-id header table, | 1552 | if (!kallsyms_allocated_filename) |
1454 | * we have a build-id, so check if it is the same as the running kernel, | 1553 | return -1; |
1455 | * using it if it is. | ||
1456 | */ | ||
1457 | if (dso->has_build_id) { | ||
1458 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | ||
1459 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
1460 | |||
1461 | if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, | ||
1462 | sizeof(kallsyms_build_id)) == 0) { | ||
1463 | if (dso__build_id_equal(dso, kallsyms_build_id)) { | ||
1464 | kallsyms_filename = "/proc/kallsyms"; | ||
1465 | goto do_kallsyms; | ||
1466 | } | ||
1467 | } | ||
1468 | /* | ||
1469 | * Now look if we have it on the build-id cache in | ||
1470 | * $HOME/.debug/[kernel.kallsyms]. | ||
1471 | */ | ||
1472 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), | ||
1473 | sbuild_id); | ||
1474 | |||
1475 | if (asprintf(&kallsyms_allocated_filename, | ||
1476 | "%s/.debug/[kernel.kallsyms]/%s", | ||
1477 | getenv("HOME"), sbuild_id) == -1) { | ||
1478 | pr_err("Not enough memory for kallsyms file lookup\n"); | ||
1479 | return -1; | ||
1480 | } | ||
1481 | |||
1482 | kallsyms_filename = kallsyms_allocated_filename; | ||
1483 | 1554 | ||
1484 | if (access(kallsyms_filename, F_OK)) { | 1555 | kallsyms_filename = kallsyms_allocated_filename; |
1485 | pr_err("No kallsyms or vmlinux with build-id %s " | ||
1486 | "was found\n", sbuild_id); | ||
1487 | free(kallsyms_allocated_filename); | ||
1488 | return -1; | ||
1489 | } | ||
1490 | } else { | ||
1491 | /* | ||
1492 | * Last resort, if we don't have a build-id and couldn't find | ||
1493 | * any vmlinux file, try the running kernel kallsyms table. | ||
1494 | */ | ||
1495 | kallsyms_filename = "/proc/kallsyms"; | ||
1496 | } | ||
1497 | 1556 | ||
1498 | do_kallsyms: | 1557 | do_kallsyms: |
1499 | err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); | 1558 | err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); |