diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 658 |
1 files changed, 3 insertions, 655 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e2e8c697cffe..295f8d4feedf 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "build-id.h" | 12 | #include "build-id.h" |
13 | #include "util.h" | 13 | #include "util.h" |
14 | #include "debug.h" | 14 | #include "debug.h" |
15 | #include "machine.h" | ||
15 | #include "symbol.h" | 16 | #include "symbol.h" |
16 | #include "strlist.h" | 17 | #include "strlist.h" |
17 | 18 | ||
@@ -23,7 +24,6 @@ | |||
23 | #define KSYM_NAME_LEN 256 | 24 | #define KSYM_NAME_LEN 256 |
24 | #endif | 25 | #endif |
25 | 26 | ||
26 | static void dso_cache__free(struct rb_root *root); | ||
27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
28 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -56,39 +56,6 @@ static enum dso_binary_type binary_type_symtab[] = { | |||
56 | 56 | ||
57 | #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) | 57 | #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) |
58 | 58 | ||
59 | static enum dso_binary_type binary_type_data[] = { | ||
60 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
61 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
62 | DSO_BINARY_TYPE__NOT_FOUND, | ||
63 | }; | ||
64 | |||
65 | #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data) | ||
66 | |||
67 | int dso__name_len(const struct dso *dso) | ||
68 | { | ||
69 | if (!dso) | ||
70 | return strlen("[unknown]"); | ||
71 | if (verbose) | ||
72 | return dso->long_name_len; | ||
73 | |||
74 | return dso->short_name_len; | ||
75 | } | ||
76 | |||
77 | bool dso__loaded(const struct dso *dso, enum map_type type) | ||
78 | { | ||
79 | return dso->loaded & (1 << type); | ||
80 | } | ||
81 | |||
82 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type) | ||
83 | { | ||
84 | return dso->sorted_by_name & (1 << type); | ||
85 | } | ||
86 | |||
87 | static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | ||
88 | { | ||
89 | dso->sorted_by_name |= (1 << type); | ||
90 | } | ||
91 | |||
92 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 59 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
93 | { | 60 | { |
94 | symbol_type = toupper(symbol_type); | 61 | symbol_type = toupper(symbol_type); |
@@ -270,7 +237,7 @@ void symbol__delete(struct symbol *sym) | |||
270 | free(((void *)sym) - symbol_conf.priv_size); | 237 | free(((void *)sym) - symbol_conf.priv_size); |
271 | } | 238 | } |
272 | 239 | ||
273 | static size_t symbol__fprintf(struct symbol *sym, FILE *fp) | 240 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) |
274 | { | 241 | { |
275 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | 242 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", |
276 | sym->start, sym->end, | 243 | sym->start, sym->end, |
@@ -301,53 +268,7 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | |||
301 | return symbol__fprintf_symname_offs(sym, NULL, fp); | 268 | return symbol__fprintf_symname_offs(sym, NULL, fp); |
302 | } | 269 | } |
303 | 270 | ||
304 | void dso__set_long_name(struct dso *dso, char *name) | 271 | void symbols__delete(struct rb_root *symbols) |
305 | { | ||
306 | if (name == NULL) | ||
307 | return; | ||
308 | dso->long_name = name; | ||
309 | dso->long_name_len = strlen(name); | ||
310 | } | ||
311 | |||
312 | static void dso__set_short_name(struct dso *dso, const char *name) | ||
313 | { | ||
314 | if (name == NULL) | ||
315 | return; | ||
316 | dso->short_name = name; | ||
317 | dso->short_name_len = strlen(name); | ||
318 | } | ||
319 | |||
320 | static void dso__set_basename(struct dso *dso) | ||
321 | { | ||
322 | dso__set_short_name(dso, basename(dso->long_name)); | ||
323 | } | ||
324 | |||
325 | struct dso *dso__new(const char *name) | ||
326 | { | ||
327 | struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); | ||
328 | |||
329 | if (dso != NULL) { | ||
330 | int i; | ||
331 | strcpy(dso->name, name); | ||
332 | dso__set_long_name(dso, dso->name); | ||
333 | dso__set_short_name(dso, dso->name); | ||
334 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
335 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | ||
336 | dso->cache = RB_ROOT; | ||
337 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
338 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
339 | dso->loaded = 0; | ||
340 | dso->sorted_by_name = 0; | ||
341 | dso->has_build_id = 0; | ||
342 | dso->kernel = DSO_TYPE_USER; | ||
343 | dso->needs_swap = DSO_SWAP__UNSET; | ||
344 | INIT_LIST_HEAD(&dso->node); | ||
345 | } | ||
346 | |||
347 | return dso; | ||
348 | } | ||
349 | |||
350 | static void symbols__delete(struct rb_root *symbols) | ||
351 | { | 272 | { |
352 | struct symbol *pos; | 273 | struct symbol *pos; |
353 | struct rb_node *next = rb_first(symbols); | 274 | struct rb_node *next = rb_first(symbols); |
@@ -360,25 +281,6 @@ static void symbols__delete(struct rb_root *symbols) | |||
360 | } | 281 | } |
361 | } | 282 | } |
362 | 283 | ||
363 | void dso__delete(struct dso *dso) | ||
364 | { | ||
365 | int i; | ||
366 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
367 | symbols__delete(&dso->symbols[i]); | ||
368 | if (dso->sname_alloc) | ||
369 | free((char *)dso->short_name); | ||
370 | if (dso->lname_alloc) | ||
371 | free(dso->long_name); | ||
372 | dso_cache__free(&dso->cache); | ||
373 | free(dso); | ||
374 | } | ||
375 | |||
376 | void dso__set_build_id(struct dso *dso, void *build_id) | ||
377 | { | ||
378 | memcpy(dso->build_id, build_id, sizeof(dso->build_id)); | ||
379 | dso->has_build_id = 1; | ||
380 | } | ||
381 | |||
382 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) | 284 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) |
383 | { | 285 | { |
384 | struct rb_node **p = &symbols->rb_node; | 286 | struct rb_node **p = &symbols->rb_node; |
@@ -504,29 +406,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type) | |||
504 | &dso->symbols[type]); | 406 | &dso->symbols[type]); |
505 | } | 407 | } |
506 | 408 | ||
507 | int build_id__sprintf(const u8 *build_id, int len, char *bf) | ||
508 | { | ||
509 | char *bid = bf; | ||
510 | const u8 *raw = build_id; | ||
511 | int i; | ||
512 | |||
513 | for (i = 0; i < len; ++i) { | ||
514 | sprintf(bid, "%02x", *raw); | ||
515 | ++raw; | ||
516 | bid += 2; | ||
517 | } | ||
518 | |||
519 | return raw - build_id; | ||
520 | } | ||
521 | |||
522 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) | ||
523 | { | ||
524 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
525 | |||
526 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
527 | return fprintf(fp, "%s", sbuild_id); | ||
528 | } | ||
529 | |||
530 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | 409 | size_t dso__fprintf_symbols_by_name(struct dso *dso, |
531 | enum map_type type, FILE *fp) | 410 | enum map_type type, FILE *fp) |
532 | { | 411 | { |
@@ -542,25 +421,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
542 | return ret; | 421 | return ret; |
543 | } | 422 | } |
544 | 423 | ||
545 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | ||
546 | { | ||
547 | struct rb_node *nd; | ||
548 | size_t ret = fprintf(fp, "dso: %s (", dso->short_name); | ||
549 | |||
550 | if (dso->short_name != dso->long_name) | ||
551 | ret += fprintf(fp, "%s, ", dso->long_name); | ||
552 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | ||
553 | dso->loaded ? "" : "NOT "); | ||
554 | ret += dso__fprintf_buildid(dso, fp); | ||
555 | ret += fprintf(fp, ")\n"); | ||
556 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { | ||
557 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
558 | ret += symbol__fprintf(pos, fp); | ||
559 | } | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | int kallsyms__parse(const char *filename, void *arg, | 424 | int kallsyms__parse(const char *filename, void *arg, |
565 | int (*process_symbol)(void *arg, const char *name, | 425 | int (*process_symbol)(void *arg, const char *name, |
566 | char type, u64 start)) | 426 | char type, u64 start)) |
@@ -892,136 +752,6 @@ out_failure: | |||
892 | return -1; | 752 | return -1; |
893 | } | 753 | } |
894 | 754 | ||
895 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id) | ||
896 | { | ||
897 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; | ||
898 | } | ||
899 | |||
900 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | ||
901 | { | ||
902 | bool have_build_id = false; | ||
903 | struct dso *pos; | ||
904 | |||
905 | list_for_each_entry(pos, head, node) { | ||
906 | if (with_hits && !pos->hit) | ||
907 | continue; | ||
908 | if (pos->has_build_id) { | ||
909 | have_build_id = true; | ||
910 | continue; | ||
911 | } | ||
912 | if (filename__read_build_id(pos->long_name, pos->build_id, | ||
913 | sizeof(pos->build_id)) > 0) { | ||
914 | have_build_id = true; | ||
915 | pos->has_build_id = true; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | return have_build_id; | ||
920 | } | ||
921 | |||
922 | char dso__symtab_origin(const struct dso *dso) | ||
923 | { | ||
924 | static const char origin[] = { | ||
925 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', | ||
926 | [DSO_BINARY_TYPE__VMLINUX] = 'v', | ||
927 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', | ||
928 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', | ||
929 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', | ||
930 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', | ||
931 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', | ||
932 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', | ||
933 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', | ||
934 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', | ||
935 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', | ||
936 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', | ||
937 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', | ||
938 | }; | ||
939 | |||
940 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) | ||
941 | return '!'; | ||
942 | return origin[dso->symtab_type]; | ||
943 | } | ||
944 | |||
945 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
946 | char *root_dir, char *file, size_t size) | ||
947 | { | ||
948 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
949 | int ret = 0; | ||
950 | |||
951 | switch (type) { | ||
952 | case DSO_BINARY_TYPE__DEBUGLINK: { | ||
953 | char *debuglink; | ||
954 | |||
955 | strncpy(file, dso->long_name, size); | ||
956 | debuglink = file + dso->long_name_len; | ||
957 | while (debuglink != file && *debuglink != '/') | ||
958 | debuglink--; | ||
959 | if (*debuglink == '/') | ||
960 | debuglink++; | ||
961 | filename__read_debuglink(dso->long_name, debuglink, | ||
962 | size - (debuglink - file)); | ||
963 | } | ||
964 | break; | ||
965 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | ||
966 | /* skip the locally configured cache if a symfs is given */ | ||
967 | if (symbol_conf.symfs[0] || | ||
968 | (dso__build_id_filename(dso, file, size) == NULL)) | ||
969 | ret = -1; | ||
970 | break; | ||
971 | |||
972 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | ||
973 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | ||
974 | symbol_conf.symfs, dso->long_name); | ||
975 | break; | ||
976 | |||
977 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | ||
978 | snprintf(file, size, "%s/usr/lib/debug%s", | ||
979 | symbol_conf.symfs, dso->long_name); | ||
980 | break; | ||
981 | |||
982 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | ||
983 | if (!dso->has_build_id) { | ||
984 | ret = -1; | ||
985 | break; | ||
986 | } | ||
987 | |||
988 | build_id__sprintf(dso->build_id, | ||
989 | sizeof(dso->build_id), | ||
990 | build_id_hex); | ||
991 | snprintf(file, size, | ||
992 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
993 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | ||
994 | break; | ||
995 | |||
996 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | ||
997 | snprintf(file, size, "%s%s", | ||
998 | symbol_conf.symfs, dso->long_name); | ||
999 | break; | ||
1000 | |||
1001 | case DSO_BINARY_TYPE__GUEST_KMODULE: | ||
1002 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | ||
1003 | root_dir, dso->long_name); | ||
1004 | break; | ||
1005 | |||
1006 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | ||
1007 | snprintf(file, size, "%s%s", symbol_conf.symfs, | ||
1008 | dso->long_name); | ||
1009 | break; | ||
1010 | |||
1011 | default: | ||
1012 | case DSO_BINARY_TYPE__KALLSYMS: | ||
1013 | case DSO_BINARY_TYPE__VMLINUX: | ||
1014 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | ||
1015 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | ||
1016 | case DSO_BINARY_TYPE__JAVA_JIT: | ||
1017 | case DSO_BINARY_TYPE__NOT_FOUND: | ||
1018 | ret = -1; | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | return ret; | ||
1023 | } | ||
1024 | |||
1025 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | 755 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) |
1026 | { | 756 | { |
1027 | char *name; | 757 | char *name; |
@@ -1157,27 +887,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
1157 | return NULL; | 887 | return NULL; |
1158 | } | 888 | } |
1159 | 889 | ||
1160 | static int dso__kernel_module_get_build_id(struct dso *dso, | ||
1161 | const char *root_dir) | ||
1162 | { | ||
1163 | char filename[PATH_MAX]; | ||
1164 | /* | ||
1165 | * kernel module short names are of the form "[module]" and | ||
1166 | * we need just "module" here. | ||
1167 | */ | ||
1168 | const char *name = dso->short_name + 1; | ||
1169 | |||
1170 | snprintf(filename, sizeof(filename), | ||
1171 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", | ||
1172 | root_dir, (int)strlen(name) - 1, name); | ||
1173 | |||
1174 | if (sysfs__read_build_id(filename, dso->build_id, | ||
1175 | sizeof(dso->build_id)) == 0) | ||
1176 | dso->has_build_id = true; | ||
1177 | |||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | 890 | static int map_groups__set_modules_path_dir(struct map_groups *mg, |
1182 | const char *dir_name) | 891 | const char *dir_name) |
1183 | { | 892 | { |
@@ -1591,50 +1300,6 @@ out_try_fixup: | |||
1591 | return err; | 1300 | return err; |
1592 | } | 1301 | } |
1593 | 1302 | ||
1594 | void dsos__add(struct list_head *head, struct dso *dso) | ||
1595 | { | ||
1596 | list_add_tail(&dso->node, head); | ||
1597 | } | ||
1598 | |||
1599 | struct dso *dsos__find(struct list_head *head, const char *name) | ||
1600 | { | ||
1601 | struct dso *pos; | ||
1602 | |||
1603 | list_for_each_entry(pos, head, node) | ||
1604 | if (strcmp(pos->long_name, name) == 0) | ||
1605 | return pos; | ||
1606 | return NULL; | ||
1607 | } | ||
1608 | |||
1609 | struct dso *__dsos__findnew(struct list_head *head, const char *name) | ||
1610 | { | ||
1611 | struct dso *dso = dsos__find(head, name); | ||
1612 | |||
1613 | if (!dso) { | ||
1614 | dso = dso__new(name); | ||
1615 | if (dso != NULL) { | ||
1616 | dsos__add(head, dso); | ||
1617 | dso__set_basename(dso); | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | return dso; | ||
1622 | } | ||
1623 | |||
1624 | size_t __dsos__fprintf(struct list_head *head, FILE *fp) | ||
1625 | { | ||
1626 | struct dso *pos; | ||
1627 | size_t ret = 0; | ||
1628 | |||
1629 | list_for_each_entry(pos, head, node) { | ||
1630 | int i; | ||
1631 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
1632 | ret += dso__fprintf(pos, i, fp); | ||
1633 | } | ||
1634 | |||
1635 | return ret; | ||
1636 | } | ||
1637 | |||
1638 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | 1303 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) |
1639 | { | 1304 | { |
1640 | struct rb_node *nd; | 1305 | struct rb_node *nd; |
@@ -1649,21 +1314,6 @@ size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | |||
1649 | return ret; | 1314 | return ret; |
1650 | } | 1315 | } |
1651 | 1316 | ||
1652 | static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | ||
1653 | bool with_hits) | ||
1654 | { | ||
1655 | struct dso *pos; | ||
1656 | size_t ret = 0; | ||
1657 | |||
1658 | list_for_each_entry(pos, head, node) { | ||
1659 | if (with_hits && !pos->hit) | ||
1660 | continue; | ||
1661 | ret += dso__fprintf_buildid(pos, fp); | ||
1662 | ret += fprintf(fp, " %s\n", pos->long_name); | ||
1663 | } | ||
1664 | return ret; | ||
1665 | } | ||
1666 | |||
1667 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | 1317 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
1668 | bool with_hits) | 1318 | bool with_hits) |
1669 | { | 1319 | { |
@@ -1684,39 +1334,6 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
1684 | return ret; | 1334 | return ret; |
1685 | } | 1335 | } |
1686 | 1336 | ||
1687 | static struct dso* | ||
1688 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
1689 | const char *short_name, int dso_type) | ||
1690 | { | ||
1691 | /* | ||
1692 | * The kernel dso could be created by build_id processing. | ||
1693 | */ | ||
1694 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); | ||
1695 | |||
1696 | /* | ||
1697 | * We need to run this in all cases, since during the build_id | ||
1698 | * processing we had no idea this was the kernel dso. | ||
1699 | */ | ||
1700 | if (dso != NULL) { | ||
1701 | dso__set_short_name(dso, short_name); | ||
1702 | dso->kernel = dso_type; | ||
1703 | } | ||
1704 | |||
1705 | return dso; | ||
1706 | } | ||
1707 | |||
1708 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | ||
1709 | { | ||
1710 | char path[PATH_MAX]; | ||
1711 | |||
1712 | if (machine__is_default_guest(machine)) | ||
1713 | return; | ||
1714 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); | ||
1715 | if (sysfs__read_build_id(path, dso->build_id, | ||
1716 | sizeof(dso->build_id)) == 0) | ||
1717 | dso->has_build_id = true; | ||
1718 | } | ||
1719 | |||
1720 | static struct dso *machine__get_kernel(struct machine *machine) | 1337 | static struct dso *machine__get_kernel(struct machine *machine) |
1721 | { | 1338 | { |
1722 | const char *vmlinux_name = NULL; | 1339 | const char *vmlinux_name = NULL; |
@@ -2065,49 +1682,6 @@ int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | |||
2065 | return machine__create_kernel_maps(machine); | 1682 | return machine__create_kernel_maps(machine); |
2066 | } | 1683 | } |
2067 | 1684 | ||
2068 | static int hex(char ch) | ||
2069 | { | ||
2070 | if ((ch >= '0') && (ch <= '9')) | ||
2071 | return ch - '0'; | ||
2072 | if ((ch >= 'a') && (ch <= 'f')) | ||
2073 | return ch - 'a' + 10; | ||
2074 | if ((ch >= 'A') && (ch <= 'F')) | ||
2075 | return ch - 'A' + 10; | ||
2076 | return -1; | ||
2077 | } | ||
2078 | |||
2079 | /* | ||
2080 | * While we find nice hex chars, build a long_val. | ||
2081 | * Return number of chars processed. | ||
2082 | */ | ||
2083 | int hex2u64(const char *ptr, u64 *long_val) | ||
2084 | { | ||
2085 | const char *p = ptr; | ||
2086 | *long_val = 0; | ||
2087 | |||
2088 | while (*p) { | ||
2089 | const int hex_val = hex(*p); | ||
2090 | |||
2091 | if (hex_val < 0) | ||
2092 | break; | ||
2093 | |||
2094 | *long_val = (*long_val << 4) | hex_val; | ||
2095 | p++; | ||
2096 | } | ||
2097 | |||
2098 | return p - ptr; | ||
2099 | } | ||
2100 | |||
2101 | char *strxfrchar(char *s, char from, char to) | ||
2102 | { | ||
2103 | char *p = s; | ||
2104 | |||
2105 | while ((p = strchr(p, from)) != NULL) | ||
2106 | *p++ = to; | ||
2107 | |||
2108 | return s; | ||
2109 | } | ||
2110 | |||
2111 | int machines__create_guest_kernel_maps(struct rb_root *machines) | 1685 | int machines__create_guest_kernel_maps(struct rb_root *machines) |
2112 | { | 1686 | { |
2113 | int ret = 0; | 1687 | int ret = 0; |
@@ -2202,229 +1776,3 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | |||
2202 | 1776 | ||
2203 | return ret; | 1777 | return ret; |
2204 | } | 1778 | } |
2205 | |||
2206 | struct map *dso__new_map(const char *name) | ||
2207 | { | ||
2208 | struct map *map = NULL; | ||
2209 | struct dso *dso = dso__new(name); | ||
2210 | |||
2211 | if (dso) | ||
2212 | map = map__new2(0, dso, MAP__FUNCTION); | ||
2213 | |||
2214 | return map; | ||
2215 | } | ||
2216 | |||
2217 | static int open_dso(struct dso *dso, struct machine *machine) | ||
2218 | { | ||
2219 | char *root_dir = (char *) ""; | ||
2220 | char *name; | ||
2221 | int fd; | ||
2222 | |||
2223 | name = malloc(PATH_MAX); | ||
2224 | if (!name) | ||
2225 | return -ENOMEM; | ||
2226 | |||
2227 | if (machine) | ||
2228 | root_dir = machine->root_dir; | ||
2229 | |||
2230 | if (dso__binary_type_file(dso, dso->data_type, | ||
2231 | root_dir, name, PATH_MAX)) { | ||
2232 | free(name); | ||
2233 | return -EINVAL; | ||
2234 | } | ||
2235 | |||
2236 | fd = open(name, O_RDONLY); | ||
2237 | free(name); | ||
2238 | return fd; | ||
2239 | } | ||
2240 | |||
2241 | int dso__data_fd(struct dso *dso, struct machine *machine) | ||
2242 | { | ||
2243 | int i = 0; | ||
2244 | |||
2245 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | ||
2246 | return open_dso(dso, machine); | ||
2247 | |||
2248 | do { | ||
2249 | int fd; | ||
2250 | |||
2251 | dso->data_type = binary_type_data[i++]; | ||
2252 | |||
2253 | fd = open_dso(dso, machine); | ||
2254 | if (fd >= 0) | ||
2255 | return fd; | ||
2256 | |||
2257 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | ||
2258 | |||
2259 | return -EINVAL; | ||
2260 | } | ||
2261 | |||
2262 | static void | ||
2263 | dso_cache__free(struct rb_root *root) | ||
2264 | { | ||
2265 | struct rb_node *next = rb_first(root); | ||
2266 | |||
2267 | while (next) { | ||
2268 | struct dso_cache *cache; | ||
2269 | |||
2270 | cache = rb_entry(next, struct dso_cache, rb_node); | ||
2271 | next = rb_next(&cache->rb_node); | ||
2272 | rb_erase(&cache->rb_node, root); | ||
2273 | free(cache); | ||
2274 | } | ||
2275 | } | ||
2276 | |||
2277 | static struct dso_cache* | ||
2278 | dso_cache__find(struct rb_root *root, u64 offset) | ||
2279 | { | ||
2280 | struct rb_node **p = &root->rb_node; | ||
2281 | struct rb_node *parent = NULL; | ||
2282 | struct dso_cache *cache; | ||
2283 | |||
2284 | while (*p != NULL) { | ||
2285 | u64 end; | ||
2286 | |||
2287 | parent = *p; | ||
2288 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
2289 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
2290 | |||
2291 | if (offset < cache->offset) | ||
2292 | p = &(*p)->rb_left; | ||
2293 | else if (offset >= end) | ||
2294 | p = &(*p)->rb_right; | ||
2295 | else | ||
2296 | return cache; | ||
2297 | } | ||
2298 | return NULL; | ||
2299 | } | ||
2300 | |||
2301 | static void | ||
2302 | dso_cache__insert(struct rb_root *root, struct dso_cache *new) | ||
2303 | { | ||
2304 | struct rb_node **p = &root->rb_node; | ||
2305 | struct rb_node *parent = NULL; | ||
2306 | struct dso_cache *cache; | ||
2307 | u64 offset = new->offset; | ||
2308 | |||
2309 | while (*p != NULL) { | ||
2310 | u64 end; | ||
2311 | |||
2312 | parent = *p; | ||
2313 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
2314 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
2315 | |||
2316 | if (offset < cache->offset) | ||
2317 | p = &(*p)->rb_left; | ||
2318 | else if (offset >= end) | ||
2319 | p = &(*p)->rb_right; | ||
2320 | } | ||
2321 | |||
2322 | rb_link_node(&new->rb_node, parent, p); | ||
2323 | rb_insert_color(&new->rb_node, root); | ||
2324 | } | ||
2325 | |||
2326 | static ssize_t | ||
2327 | dso_cache__memcpy(struct dso_cache *cache, u64 offset, | ||
2328 | u8 *data, u64 size) | ||
2329 | { | ||
2330 | u64 cache_offset = offset - cache->offset; | ||
2331 | u64 cache_size = min(cache->size - cache_offset, size); | ||
2332 | |||
2333 | memcpy(data, cache->data + cache_offset, cache_size); | ||
2334 | return cache_size; | ||
2335 | } | ||
2336 | |||
2337 | static ssize_t | ||
2338 | dso_cache__read(struct dso *dso, struct machine *machine, | ||
2339 | u64 offset, u8 *data, ssize_t size) | ||
2340 | { | ||
2341 | struct dso_cache *cache; | ||
2342 | ssize_t ret; | ||
2343 | int fd; | ||
2344 | |||
2345 | fd = dso__data_fd(dso, machine); | ||
2346 | if (fd < 0) | ||
2347 | return -1; | ||
2348 | |||
2349 | do { | ||
2350 | u64 cache_offset; | ||
2351 | |||
2352 | ret = -ENOMEM; | ||
2353 | |||
2354 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); | ||
2355 | if (!cache) | ||
2356 | break; | ||
2357 | |||
2358 | cache_offset = offset & DSO__DATA_CACHE_MASK; | ||
2359 | ret = -EINVAL; | ||
2360 | |||
2361 | if (-1 == lseek(fd, cache_offset, SEEK_SET)) | ||
2362 | break; | ||
2363 | |||
2364 | ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); | ||
2365 | if (ret <= 0) | ||
2366 | break; | ||
2367 | |||
2368 | cache->offset = cache_offset; | ||
2369 | cache->size = ret; | ||
2370 | dso_cache__insert(&dso->cache, cache); | ||
2371 | |||
2372 | ret = dso_cache__memcpy(cache, offset, data, size); | ||
2373 | |||
2374 | } while (0); | ||
2375 | |||
2376 | if (ret <= 0) | ||
2377 | free(cache); | ||
2378 | |||
2379 | close(fd); | ||
2380 | return ret; | ||
2381 | } | ||
2382 | |||
2383 | static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, | ||
2384 | u64 offset, u8 *data, ssize_t size) | ||
2385 | { | ||
2386 | struct dso_cache *cache; | ||
2387 | |||
2388 | cache = dso_cache__find(&dso->cache, offset); | ||
2389 | if (cache) | ||
2390 | return dso_cache__memcpy(cache, offset, data, size); | ||
2391 | else | ||
2392 | return dso_cache__read(dso, machine, offset, data, size); | ||
2393 | } | ||
2394 | |||
2395 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
2396 | u64 offset, u8 *data, ssize_t size) | ||
2397 | { | ||
2398 | ssize_t r = 0; | ||
2399 | u8 *p = data; | ||
2400 | |||
2401 | do { | ||
2402 | ssize_t ret; | ||
2403 | |||
2404 | ret = dso_cache_read(dso, machine, offset, p, size); | ||
2405 | if (ret < 0) | ||
2406 | return ret; | ||
2407 | |||
2408 | /* Reached EOF, return what we have. */ | ||
2409 | if (!ret) | ||
2410 | break; | ||
2411 | |||
2412 | BUG_ON(ret > size); | ||
2413 | |||
2414 | r += ret; | ||
2415 | p += ret; | ||
2416 | offset += ret; | ||
2417 | size -= ret; | ||
2418 | |||
2419 | } while (size); | ||
2420 | |||
2421 | return r; | ||
2422 | } | ||
2423 | |||
2424 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
2425 | struct machine *machine, u64 addr, | ||
2426 | u8 *data, ssize_t size) | ||
2427 | { | ||
2428 | u64 offset = map->map_ip(map, addr); | ||
2429 | return dso__data_read_offset(dso, machine, offset, data, size); | ||
2430 | } | ||