aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c658
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
26static void dso_cache__free(struct rb_root *root);
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 27static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static 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
59static 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
67int 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
77bool dso__loaded(const struct dso *dso, enum map_type type)
78{
79 return dso->loaded & (1 << type);
80}
81
82bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
83{
84 return dso->sorted_by_name & (1 << type);
85}
86
87static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
88{
89 dso->sorted_by_name |= (1 << type);
90}
91
92bool symbol_type__is_a(char symbol_type, enum map_type map_type) 59bool 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
273static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 240size_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
304void dso__set_long_name(struct dso *dso, char *name) 271void 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
312static 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
320static void dso__set_basename(struct dso *dso)
321{
322 dso__set_short_name(dso, basename(dso->long_name));
323}
324
325struct 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
350static 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
363void 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
376void 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
382void symbols__insert(struct rb_root *symbols, struct symbol *sym) 284void 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
507int 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
522size_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
530size_t dso__fprintf_symbols_by_name(struct dso *dso, 409size_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
545size_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
564int kallsyms__parse(const char *filename, void *arg, 424int 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
895bool 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
900bool __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
922char 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
945int 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
1025int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 755int 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
1160static 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
1181static int map_groups__set_modules_path_dir(struct map_groups *mg, 890static 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
1594void dsos__add(struct list_head *head, struct dso *dso)
1595{
1596 list_add_tail(&dso->node, head);
1597}
1598
1599struct 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
1609struct 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
1624size_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
1638size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 1303size_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
1652static 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
1667size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 1317size_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
1687static struct dso*
1688dso__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
1708void 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
1720static struct dso *machine__get_kernel(struct machine *machine) 1337static 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
2068static 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 */
2083int 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
2101char *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
2111int machines__create_guest_kernel_maps(struct rb_root *machines) 1685int 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
2206struct 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
2217static 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
2241int 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
2262static void
2263dso_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
2277static struct dso_cache*
2278dso_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
2301static void
2302dso_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
2326static ssize_t
2327dso_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
2337static ssize_t
2338dso_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
2383static 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
2395ssize_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
2424ssize_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}