diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 13:28:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 13:28:49 -0400 |
commit | 7e92daaefa68e5ef1e1732e45231e73adbb724e7 (patch) | |
tree | 8e7f8ac9d82654df4c65939c6682f95510e22977 /tools/perf/util/symbol.c | |
parent | 7a68294278ae714ce2632a54f0f46916dca64f56 (diff) | |
parent | 1d787d37c8ff6612b8151c6dff15bfa7347bcbdf (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf update from Ingo Molnar:
"Lots of changes in this cycle as well, with hundreds of commits from
over 30 contributors. Most of the activity was on the tooling side.
Higher level changes:
- New 'perf kvm' analysis tool, from Xiao Guangrong.
- New 'perf trace' system-wide tracing tool
- uprobes fixes + cleanups from Oleg Nesterov.
- Lots of patches to make perf build on Android out of box, from
Irina Tirdea
- Extend ftrace function tracing utility to be more dynamic for its
users. It allows for data passing to the callback functions, as
well as reading regs as if a breakpoint were to trigger at function
entry.
The main goal of this patch series was to allow kprobes to use
ftrace as an optimized probe point when a probe is placed on an
ftrace nop. With lots of help from Masami Hiramatsu, and going
through lots of iterations, we finally came up with a good
solution.
- Add cpumask for uncore pmu, use it in 'stat', from Yan, Zheng.
- Various tracing updates from Steve Rostedt
- Clean up and improve 'perf sched' performance by elliminating lots
of needless calls to libtraceevent.
- Event group parsing support, from Jiri Olsa
- UI/gtk refactorings and improvements from Namhyung Kim
- Add support for non-tracepoint events in perf script python, from
Feng Tang
- Add --symbols to 'script', similar to the one in 'report', from
Feng Tang.
Infrastructure enhancements and fixes:
- Convert the trace builtins to use the growing evsel/evlist
tracepoint infrastructure, removing several open coded constructs
like switch like series of strcmp to dispatch events, etc.
Basically what had already been showcased in 'perf sched'.
- Add evsel constructor for tracepoints, that uses libtraceevent just
to parse the /format events file, use it in a new 'perf test' to
make sure the libtraceevent format parsing regressions can be more
readily caught.
- Some strange errors were happening in some builds, but not on the
next, reported by several people, problem was some parser related
files, generated during the build, didn't had proper make deps, fix
from Eric Sandeen.
- Introduce struct and cache information about the environment where
a perf.data file was captured, from Namhyung Kim.
- Fix handling of unresolved samples when --symbols is used in
'report', from Feng Tang.
- Add union member access support to 'probe', from Hyeoncheol Lee.
- Fixups to die() removal, from Namhyung Kim.
- Render fixes for the TUI, from Namhyung Kim.
- Don't enable annotation in non symbolic view, from Namhyung Kim.
- Fix pipe mode in 'report', from Namhyung Kim.
- Move related stats code from stat to util/, will be used by the
'stat' kvm tool, from Xiao Guangrong.
- Remove die()/exit() calls from several tools.
- Resolve vdso callchains, from Jiri Olsa
- Don't pass const char pointers to basename, so that we can
unconditionally use libgen.h and thus avoid ifdef BIONIC lines,
from David Ahern
- Refactor hist formatting so that it can be reused with the GTK
browser, From Namhyung Kim
- Fix build for another rbtree.c change, from Adrian Hunter.
- Make 'perf diff' command work with evsel hists, from Jiri Olsa.
- Use the only field_sep var that is set up: symbol_conf.field_sep,
fix from Jiri Olsa.
- .gitignore compiled python binaries, from Namhyung Kim.
- Get rid of die() in more libtraceevent places, from Namhyung Kim.
- Rename libtraceevent 'private' struct member to 'priv' so that it
works in C++, from Steven Rostedt
- Remove lots of exit()/die() calls from tools so that the main perf
exit routine can take place, from David Ahern
- Fix x86 build on x86-64, from David Ahern.
- {int,str,rb}list fixes from Suzuki K Poulose
- perf.data header fixes from Namhyung Kim
- Allow user to indicate objdump path, needed in cross environments,
from Maciek Borzecki
- Fix hardware cache event name generation, fix from Jiri Olsa
- Add round trip test for sw, hw and cache event names, catching the
problem Jiri fixed, after Jiri's patch, the test passes
successfully.
- Clean target should do clean for lib/traceevent too, fix from David
Ahern
- Check the right variable for allocation failure, fix from Namhyung
Kim
- Set up evsel->tp_format regardless of evsel->name being set
already, fix from Namhyung Kim
- Oprofile fixes from Robert Richter.
- Remove perf_event_attr needless version inflation, from Jiri Olsa
- Introduce libtraceevent strerror like error reporting facility,
from Namhyung Kim
- Add pmu mappings to perf.data header and use event names from cmd
line, from Robert Richter
- Fix include order for bison/flex-generated C files, from Ben
Hutchings
- Build fixes and documentation corrections from David Ahern
- Assorted cleanups from Robert Richter
- Let O= makes handle relative paths, from Steven Rostedt
- perf script python fixes, from Feng Tang.
- Initial bash completion support, from Frederic Weisbecker
- Allow building without libelf, from Namhyung Kim.
- Support DWARF CFI based unwind to have callchains when %bp based
unwinding is not possible, from Jiri Olsa.
- Symbol resolution fixes, while fixing support PPC64 files with an
.opt ELF section was the end goal, several fixes for code that
handles all architectures and cleanups are included, from Cody
Schafer.
- Assorted fixes for Documentation and build in 32 bit, from Robert
Richter
- Cache the libtraceevent event_format associated to each evsel
early, so that we avoid relookups, i.e. calling pevent_find_event
repeatedly when processing tracepoint events.
[ This is to reduce the surface contact with libtraceevents and
make clear what is that the perf tools needs from that lib: so
far parsing the common and per event fields. ]
- Don't stop the build if the audit libraries are not installed, fix
from Namhyung Kim.
- Fix bfd.h/libbfd detection with recent binutils, from Markus
Trippelsdorf.
- Improve warning message when libunwind devel packages not present,
from Jiri Olsa"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (282 commits)
perf trace: Add aliases for some syscalls
perf probe: Print an enum type variable in "enum variable-name" format when showing accessible variables
perf tools: Check libaudit availability for perf-trace builtin
perf hists: Add missing period_* fields when collapsing a hist entry
perf trace: New tool
perf evsel: Export the event_format constructor
perf evsel: Introduce rawptr() method
perf tools: Use perf_evsel__newtp in the event parser
perf evsel: The tracepoint constructor should store sys:name
perf evlist: Introduce set_filter() method
perf evlist: Renane set_filters method to apply_filters
perf test: Add test to check we correctly parse and match syscall open parms
perf evsel: Handle endianity in intval method
perf evsel: Know if byte swap is needed
perf tools: Allow handling a NULL cpu_map as meaning "all cpus"
perf evsel: Improve tracepoint constructor setup
tools lib traceevent: Fix error path on pevent_parse_event
perf test: Fix build failure
trace: Move trace event enable from fs_initcall to core_initcall
tracing: Add an option for disabling markers
...
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 942 |
1 files changed, 91 insertions, 851 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8b63b678e127..e2e8c697cffe 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -15,8 +15,6 @@ | |||
15 | #include "symbol.h" | 15 | #include "symbol.h" |
16 | #include "strlist.h" | 16 | #include "strlist.h" |
17 | 17 | ||
18 | #include <libelf.h> | ||
19 | #include <gelf.h> | ||
20 | #include <elf.h> | 18 | #include <elf.h> |
21 | #include <limits.h> | 19 | #include <limits.h> |
22 | #include <sys/utsname.h> | 20 | #include <sys/utsname.h> |
@@ -25,15 +23,7 @@ | |||
25 | #define KSYM_NAME_LEN 256 | 23 | #define KSYM_NAME_LEN 256 |
26 | #endif | 24 | #endif |
27 | 25 | ||
28 | #ifndef NT_GNU_BUILD_ID | ||
29 | #define NT_GNU_BUILD_ID 3 | ||
30 | #endif | ||
31 | |||
32 | static void dso_cache__free(struct rb_root *root); | 26 | static void dso_cache__free(struct rb_root *root); |
33 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | ||
34 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); | ||
35 | static void dsos__add(struct list_head *head, struct dso *dso); | ||
36 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | ||
37 | 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, |
38 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
39 | 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, |
@@ -170,7 +160,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | |||
170 | return SYMBOL_B; | 160 | return SYMBOL_B; |
171 | } | 161 | } |
172 | 162 | ||
173 | static void symbols__fixup_duplicate(struct rb_root *symbols) | 163 | void symbols__fixup_duplicate(struct rb_root *symbols) |
174 | { | 164 | { |
175 | struct rb_node *nd; | 165 | struct rb_node *nd; |
176 | struct symbol *curr, *next; | 166 | struct symbol *curr, *next; |
@@ -199,7 +189,7 @@ again: | |||
199 | } | 189 | } |
200 | } | 190 | } |
201 | 191 | ||
202 | static void symbols__fixup_end(struct rb_root *symbols) | 192 | void symbols__fixup_end(struct rb_root *symbols) |
203 | { | 193 | { |
204 | struct rb_node *nd, *prevnd = rb_first(symbols); | 194 | struct rb_node *nd, *prevnd = rb_first(symbols); |
205 | struct symbol *curr, *prev; | 195 | struct symbol *curr, *prev; |
@@ -222,7 +212,7 @@ static void symbols__fixup_end(struct rb_root *symbols) | |||
222 | curr->end = roundup(curr->start, 4096); | 212 | curr->end = roundup(curr->start, 4096); |
223 | } | 213 | } |
224 | 214 | ||
225 | static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) | 215 | void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) |
226 | { | 216 | { |
227 | struct map *prev, *curr; | 217 | struct map *prev, *curr; |
228 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); | 218 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); |
@@ -252,8 +242,7 @@ static void map_groups__fixup_end(struct map_groups *mg) | |||
252 | __map_groups__fixup_end(mg, i); | 242 | __map_groups__fixup_end(mg, i); |
253 | } | 243 | } |
254 | 244 | ||
255 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, | 245 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) |
256 | const char *name) | ||
257 | { | 246 | { |
258 | size_t namelen = strlen(name) + 1; | 247 | size_t namelen = strlen(name) + 1; |
259 | struct symbol *sym = calloc(1, (symbol_conf.priv_size + | 248 | struct symbol *sym = calloc(1, (symbol_conf.priv_size + |
@@ -390,7 +379,7 @@ void dso__set_build_id(struct dso *dso, void *build_id) | |||
390 | dso->has_build_id = 1; | 379 | dso->has_build_id = 1; |
391 | } | 380 | } |
392 | 381 | ||
393 | static void symbols__insert(struct rb_root *symbols, struct symbol *sym) | 382 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) |
394 | { | 383 | { |
395 | struct rb_node **p = &symbols->rb_node; | 384 | struct rb_node **p = &symbols->rb_node; |
396 | struct rb_node *parent = NULL; | 385 | struct rb_node *parent = NULL; |
@@ -574,7 +563,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
574 | 563 | ||
575 | int kallsyms__parse(const char *filename, void *arg, | 564 | int kallsyms__parse(const char *filename, void *arg, |
576 | int (*process_symbol)(void *arg, const char *name, | 565 | int (*process_symbol)(void *arg, const char *name, |
577 | char type, u64 start, u64 end)) | 566 | char type, u64 start)) |
578 | { | 567 | { |
579 | char *line = NULL; | 568 | char *line = NULL; |
580 | size_t n; | 569 | size_t n; |
@@ -614,13 +603,8 @@ int kallsyms__parse(const char *filename, void *arg, | |||
614 | break; | 603 | break; |
615 | } | 604 | } |
616 | 605 | ||
617 | /* | ||
618 | * module symbols are not sorted so we add all | ||
619 | * symbols with zero length and rely on | ||
620 | * symbols__fixup_end() to fix it up. | ||
621 | */ | ||
622 | err = process_symbol(arg, symbol_name, | 606 | err = process_symbol(arg, symbol_name, |
623 | symbol_type, start, start); | 607 | symbol_type, start); |
624 | if (err) | 608 | if (err) |
625 | break; | 609 | break; |
626 | } | 610 | } |
@@ -647,7 +631,7 @@ static u8 kallsyms2elf_type(char type) | |||
647 | } | 631 | } |
648 | 632 | ||
649 | static int map__process_kallsym_symbol(void *arg, const char *name, | 633 | static int map__process_kallsym_symbol(void *arg, const char *name, |
650 | char type, u64 start, u64 end) | 634 | char type, u64 start) |
651 | { | 635 | { |
652 | struct symbol *sym; | 636 | struct symbol *sym; |
653 | struct process_kallsyms_args *a = arg; | 637 | struct process_kallsyms_args *a = arg; |
@@ -656,8 +640,12 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
656 | if (!symbol_type__is_a(type, a->map->type)) | 640 | if (!symbol_type__is_a(type, a->map->type)) |
657 | return 0; | 641 | return 0; |
658 | 642 | ||
659 | sym = symbol__new(start, end - start + 1, | 643 | /* |
660 | kallsyms2elf_type(type), name); | 644 | * module symbols are not sorted so we add all |
645 | * symbols, setting length to 0, and rely on | ||
646 | * symbols__fixup_end() to fix it up. | ||
647 | */ | ||
648 | sym = symbol__new(start, 0, kallsyms2elf_type(type), name); | ||
661 | if (sym == NULL) | 649 | if (sym == NULL) |
662 | return -ENOMEM; | 650 | return -ENOMEM; |
663 | /* | 651 | /* |
@@ -904,556 +892,7 @@ out_failure: | |||
904 | return -1; | 892 | return -1; |
905 | } | 893 | } |
906 | 894 | ||
907 | /** | 895 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id) |
908 | * elf_symtab__for_each_symbol - iterate thru all the symbols | ||
909 | * | ||
910 | * @syms: struct elf_symtab instance to iterate | ||
911 | * @idx: uint32_t idx | ||
912 | * @sym: GElf_Sym iterator | ||
913 | */ | ||
914 | #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ | ||
915 | for (idx = 0, gelf_getsym(syms, idx, &sym);\ | ||
916 | idx < nr_syms; \ | ||
917 | idx++, gelf_getsym(syms, idx, &sym)) | ||
918 | |||
919 | static inline uint8_t elf_sym__type(const GElf_Sym *sym) | ||
920 | { | ||
921 | return GELF_ST_TYPE(sym->st_info); | ||
922 | } | ||
923 | |||
924 | static inline int elf_sym__is_function(const GElf_Sym *sym) | ||
925 | { | ||
926 | return elf_sym__type(sym) == STT_FUNC && | ||
927 | sym->st_name != 0 && | ||
928 | sym->st_shndx != SHN_UNDEF; | ||
929 | } | ||
930 | |||
931 | static inline bool elf_sym__is_object(const GElf_Sym *sym) | ||
932 | { | ||
933 | return elf_sym__type(sym) == STT_OBJECT && | ||
934 | sym->st_name != 0 && | ||
935 | sym->st_shndx != SHN_UNDEF; | ||
936 | } | ||
937 | |||
938 | static inline int elf_sym__is_label(const GElf_Sym *sym) | ||
939 | { | ||
940 | return elf_sym__type(sym) == STT_NOTYPE && | ||
941 | sym->st_name != 0 && | ||
942 | sym->st_shndx != SHN_UNDEF && | ||
943 | sym->st_shndx != SHN_ABS; | ||
944 | } | ||
945 | |||
946 | static inline const char *elf_sec__name(const GElf_Shdr *shdr, | ||
947 | const Elf_Data *secstrs) | ||
948 | { | ||
949 | return secstrs->d_buf + shdr->sh_name; | ||
950 | } | ||
951 | |||
952 | static inline int elf_sec__is_text(const GElf_Shdr *shdr, | ||
953 | const Elf_Data *secstrs) | ||
954 | { | ||
955 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | ||
956 | } | ||
957 | |||
958 | static inline bool elf_sec__is_data(const GElf_Shdr *shdr, | ||
959 | const Elf_Data *secstrs) | ||
960 | { | ||
961 | return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; | ||
962 | } | ||
963 | |||
964 | static inline const char *elf_sym__name(const GElf_Sym *sym, | ||
965 | const Elf_Data *symstrs) | ||
966 | { | ||
967 | return symstrs->d_buf + sym->st_name; | ||
968 | } | ||
969 | |||
970 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
971 | GElf_Shdr *shp, const char *name, | ||
972 | size_t *idx) | ||
973 | { | ||
974 | Elf_Scn *sec = NULL; | ||
975 | size_t cnt = 1; | ||
976 | |||
977 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
978 | char *str; | ||
979 | |||
980 | gelf_getshdr(sec, shp); | ||
981 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
982 | if (!strcmp(name, str)) { | ||
983 | if (idx) | ||
984 | *idx = cnt; | ||
985 | break; | ||
986 | } | ||
987 | ++cnt; | ||
988 | } | ||
989 | |||
990 | return sec; | ||
991 | } | ||
992 | |||
993 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ | ||
994 | for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ | ||
995 | idx < nr_entries; \ | ||
996 | ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) | ||
997 | |||
998 | #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ | ||
999 | for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ | ||
1000 | idx < nr_entries; \ | ||
1001 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | ||
1002 | |||
1003 | /* | ||
1004 | * We need to check if we have a .dynsym, so that we can handle the | ||
1005 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it | ||
1006 | * .dynsym or .symtab). | ||
1007 | * And always look at the original dso, not at debuginfo packages, that | ||
1008 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | ||
1009 | */ | ||
1010 | static int | ||
1011 | dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, | ||
1012 | symbol_filter_t filter) | ||
1013 | { | ||
1014 | uint32_t nr_rel_entries, idx; | ||
1015 | GElf_Sym sym; | ||
1016 | u64 plt_offset; | ||
1017 | GElf_Shdr shdr_plt; | ||
1018 | struct symbol *f; | ||
1019 | GElf_Shdr shdr_rel_plt, shdr_dynsym; | ||
1020 | Elf_Data *reldata, *syms, *symstrs; | ||
1021 | Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; | ||
1022 | size_t dynsym_idx; | ||
1023 | GElf_Ehdr ehdr; | ||
1024 | char sympltname[1024]; | ||
1025 | Elf *elf; | ||
1026 | int nr = 0, symidx, fd, err = 0; | ||
1027 | |||
1028 | fd = open(name, O_RDONLY); | ||
1029 | if (fd < 0) | ||
1030 | goto out; | ||
1031 | |||
1032 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1033 | if (elf == NULL) | ||
1034 | goto out_close; | ||
1035 | |||
1036 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
1037 | goto out_elf_end; | ||
1038 | |||
1039 | scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, | ||
1040 | ".dynsym", &dynsym_idx); | ||
1041 | if (scn_dynsym == NULL) | ||
1042 | goto out_elf_end; | ||
1043 | |||
1044 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
1045 | ".rela.plt", NULL); | ||
1046 | if (scn_plt_rel == NULL) { | ||
1047 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
1048 | ".rel.plt", NULL); | ||
1049 | if (scn_plt_rel == NULL) | ||
1050 | goto out_elf_end; | ||
1051 | } | ||
1052 | |||
1053 | err = -1; | ||
1054 | |||
1055 | if (shdr_rel_plt.sh_link != dynsym_idx) | ||
1056 | goto out_elf_end; | ||
1057 | |||
1058 | if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) | ||
1059 | goto out_elf_end; | ||
1060 | |||
1061 | /* | ||
1062 | * Fetch the relocation section to find the idxes to the GOT | ||
1063 | * and the symbols in the .dynsym they refer to. | ||
1064 | */ | ||
1065 | reldata = elf_getdata(scn_plt_rel, NULL); | ||
1066 | if (reldata == NULL) | ||
1067 | goto out_elf_end; | ||
1068 | |||
1069 | syms = elf_getdata(scn_dynsym, NULL); | ||
1070 | if (syms == NULL) | ||
1071 | goto out_elf_end; | ||
1072 | |||
1073 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); | ||
1074 | if (scn_symstrs == NULL) | ||
1075 | goto out_elf_end; | ||
1076 | |||
1077 | symstrs = elf_getdata(scn_symstrs, NULL); | ||
1078 | if (symstrs == NULL) | ||
1079 | goto out_elf_end; | ||
1080 | |||
1081 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; | ||
1082 | plt_offset = shdr_plt.sh_offset; | ||
1083 | |||
1084 | if (shdr_rel_plt.sh_type == SHT_RELA) { | ||
1085 | GElf_Rela pos_mem, *pos; | ||
1086 | |||
1087 | elf_section__for_each_rela(reldata, pos, pos_mem, idx, | ||
1088 | nr_rel_entries) { | ||
1089 | symidx = GELF_R_SYM(pos->r_info); | ||
1090 | plt_offset += shdr_plt.sh_entsize; | ||
1091 | gelf_getsym(syms, symidx, &sym); | ||
1092 | snprintf(sympltname, sizeof(sympltname), | ||
1093 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
1094 | |||
1095 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
1096 | STB_GLOBAL, sympltname); | ||
1097 | if (!f) | ||
1098 | goto out_elf_end; | ||
1099 | |||
1100 | if (filter && filter(map, f)) | ||
1101 | symbol__delete(f); | ||
1102 | else { | ||
1103 | symbols__insert(&dso->symbols[map->type], f); | ||
1104 | ++nr; | ||
1105 | } | ||
1106 | } | ||
1107 | } else if (shdr_rel_plt.sh_type == SHT_REL) { | ||
1108 | GElf_Rel pos_mem, *pos; | ||
1109 | elf_section__for_each_rel(reldata, pos, pos_mem, idx, | ||
1110 | nr_rel_entries) { | ||
1111 | symidx = GELF_R_SYM(pos->r_info); | ||
1112 | plt_offset += shdr_plt.sh_entsize; | ||
1113 | gelf_getsym(syms, symidx, &sym); | ||
1114 | snprintf(sympltname, sizeof(sympltname), | ||
1115 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
1116 | |||
1117 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
1118 | STB_GLOBAL, sympltname); | ||
1119 | if (!f) | ||
1120 | goto out_elf_end; | ||
1121 | |||
1122 | if (filter && filter(map, f)) | ||
1123 | symbol__delete(f); | ||
1124 | else { | ||
1125 | symbols__insert(&dso->symbols[map->type], f); | ||
1126 | ++nr; | ||
1127 | } | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | err = 0; | ||
1132 | out_elf_end: | ||
1133 | elf_end(elf); | ||
1134 | out_close: | ||
1135 | close(fd); | ||
1136 | |||
1137 | if (err == 0) | ||
1138 | return nr; | ||
1139 | out: | ||
1140 | pr_debug("%s: problems reading %s PLT info.\n", | ||
1141 | __func__, dso->long_name); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) | ||
1146 | { | ||
1147 | switch (type) { | ||
1148 | case MAP__FUNCTION: | ||
1149 | return elf_sym__is_function(sym); | ||
1150 | case MAP__VARIABLE: | ||
1151 | return elf_sym__is_object(sym); | ||
1152 | default: | ||
1153 | return false; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, | ||
1158 | enum map_type type) | ||
1159 | { | ||
1160 | switch (type) { | ||
1161 | case MAP__FUNCTION: | ||
1162 | return elf_sec__is_text(shdr, secstrs); | ||
1163 | case MAP__VARIABLE: | ||
1164 | return elf_sec__is_data(shdr, secstrs); | ||
1165 | default: | ||
1166 | return false; | ||
1167 | } | ||
1168 | } | ||
1169 | |||
1170 | static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | ||
1171 | { | ||
1172 | Elf_Scn *sec = NULL; | ||
1173 | GElf_Shdr shdr; | ||
1174 | size_t cnt = 1; | ||
1175 | |||
1176 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
1177 | gelf_getshdr(sec, &shdr); | ||
1178 | |||
1179 | if ((addr >= shdr.sh_addr) && | ||
1180 | (addr < (shdr.sh_addr + shdr.sh_size))) | ||
1181 | return cnt; | ||
1182 | |||
1183 | ++cnt; | ||
1184 | } | ||
1185 | |||
1186 | return -1; | ||
1187 | } | ||
1188 | |||
1189 | static int dso__swap_init(struct dso *dso, unsigned char eidata) | ||
1190 | { | ||
1191 | static unsigned int const endian = 1; | ||
1192 | |||
1193 | dso->needs_swap = DSO_SWAP__NO; | ||
1194 | |||
1195 | switch (eidata) { | ||
1196 | case ELFDATA2LSB: | ||
1197 | /* We are big endian, DSO is little endian. */ | ||
1198 | if (*(unsigned char const *)&endian != 1) | ||
1199 | dso->needs_swap = DSO_SWAP__YES; | ||
1200 | break; | ||
1201 | |||
1202 | case ELFDATA2MSB: | ||
1203 | /* We are little endian, DSO is big endian. */ | ||
1204 | if (*(unsigned char const *)&endian != 0) | ||
1205 | dso->needs_swap = DSO_SWAP__YES; | ||
1206 | break; | ||
1207 | |||
1208 | default: | ||
1209 | pr_err("unrecognized DSO data encoding %d\n", eidata); | ||
1210 | return -EINVAL; | ||
1211 | } | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | |||
1216 | static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | ||
1217 | int fd, symbol_filter_t filter, int kmodule, | ||
1218 | int want_symtab) | ||
1219 | { | ||
1220 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; | ||
1221 | struct map *curr_map = map; | ||
1222 | struct dso *curr_dso = dso; | ||
1223 | Elf_Data *symstrs, *secstrs; | ||
1224 | uint32_t nr_syms; | ||
1225 | int err = -1; | ||
1226 | uint32_t idx; | ||
1227 | GElf_Ehdr ehdr; | ||
1228 | GElf_Shdr shdr, opdshdr; | ||
1229 | Elf_Data *syms, *opddata = NULL; | ||
1230 | GElf_Sym sym; | ||
1231 | Elf_Scn *sec, *sec_strndx, *opdsec; | ||
1232 | Elf *elf; | ||
1233 | int nr = 0; | ||
1234 | size_t opdidx = 0; | ||
1235 | |||
1236 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1237 | if (elf == NULL) { | ||
1238 | pr_debug("%s: cannot read %s ELF file.\n", __func__, name); | ||
1239 | goto out_close; | ||
1240 | } | ||
1241 | |||
1242 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1243 | pr_debug("%s: cannot get elf header.\n", __func__); | ||
1244 | goto out_elf_end; | ||
1245 | } | ||
1246 | |||
1247 | if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) | ||
1248 | goto out_elf_end; | ||
1249 | |||
1250 | /* Always reject images with a mismatched build-id: */ | ||
1251 | if (dso->has_build_id) { | ||
1252 | u8 build_id[BUILD_ID_SIZE]; | ||
1253 | |||
1254 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) | ||
1255 | goto out_elf_end; | ||
1256 | |||
1257 | if (!dso__build_id_equal(dso, build_id)) | ||
1258 | goto out_elf_end; | ||
1259 | } | ||
1260 | |||
1261 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | ||
1262 | if (sec == NULL) { | ||
1263 | if (want_symtab) | ||
1264 | goto out_elf_end; | ||
1265 | |||
1266 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); | ||
1267 | if (sec == NULL) | ||
1268 | goto out_elf_end; | ||
1269 | } | ||
1270 | |||
1271 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | ||
1272 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1273 | opdsec = NULL; | ||
1274 | if (opdsec) | ||
1275 | opddata = elf_rawdata(opdsec, NULL); | ||
1276 | |||
1277 | syms = elf_getdata(sec, NULL); | ||
1278 | if (syms == NULL) | ||
1279 | goto out_elf_end; | ||
1280 | |||
1281 | sec = elf_getscn(elf, shdr.sh_link); | ||
1282 | if (sec == NULL) | ||
1283 | goto out_elf_end; | ||
1284 | |||
1285 | symstrs = elf_getdata(sec, NULL); | ||
1286 | if (symstrs == NULL) | ||
1287 | goto out_elf_end; | ||
1288 | |||
1289 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | ||
1290 | if (sec_strndx == NULL) | ||
1291 | goto out_elf_end; | ||
1292 | |||
1293 | secstrs = elf_getdata(sec_strndx, NULL); | ||
1294 | if (secstrs == NULL) | ||
1295 | goto out_elf_end; | ||
1296 | |||
1297 | nr_syms = shdr.sh_size / shdr.sh_entsize; | ||
1298 | |||
1299 | memset(&sym, 0, sizeof(sym)); | ||
1300 | if (dso->kernel == DSO_TYPE_USER) { | ||
1301 | dso->adjust_symbols = (ehdr.e_type == ET_EXEC || | ||
1302 | elf_section_by_name(elf, &ehdr, &shdr, | ||
1303 | ".gnu.prelink_undo", | ||
1304 | NULL) != NULL); | ||
1305 | } else { | ||
1306 | dso->adjust_symbols = 0; | ||
1307 | } | ||
1308 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { | ||
1309 | struct symbol *f; | ||
1310 | const char *elf_name = elf_sym__name(&sym, symstrs); | ||
1311 | char *demangled = NULL; | ||
1312 | int is_label = elf_sym__is_label(&sym); | ||
1313 | const char *section_name; | ||
1314 | |||
1315 | if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && | ||
1316 | strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) | ||
1317 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | ||
1318 | |||
1319 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | ||
1320 | continue; | ||
1321 | |||
1322 | /* Reject ARM ELF "mapping symbols": these aren't unique and | ||
1323 | * don't identify functions, so will confuse the profile | ||
1324 | * output: */ | ||
1325 | if (ehdr.e_machine == EM_ARM) { | ||
1326 | if (!strcmp(elf_name, "$a") || | ||
1327 | !strcmp(elf_name, "$d") || | ||
1328 | !strcmp(elf_name, "$t")) | ||
1329 | continue; | ||
1330 | } | ||
1331 | |||
1332 | if (opdsec && sym.st_shndx == opdidx) { | ||
1333 | u32 offset = sym.st_value - opdshdr.sh_addr; | ||
1334 | u64 *opd = opddata->d_buf + offset; | ||
1335 | sym.st_value = DSO__SWAP(dso, u64, *opd); | ||
1336 | sym.st_shndx = elf_addr_to_index(elf, sym.st_value); | ||
1337 | } | ||
1338 | |||
1339 | sec = elf_getscn(elf, sym.st_shndx); | ||
1340 | if (!sec) | ||
1341 | goto out_elf_end; | ||
1342 | |||
1343 | gelf_getshdr(sec, &shdr); | ||
1344 | |||
1345 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) | ||
1346 | continue; | ||
1347 | |||
1348 | section_name = elf_sec__name(&shdr, secstrs); | ||
1349 | |||
1350 | /* On ARM, symbols for thumb functions have 1 added to | ||
1351 | * the symbol address as a flag - remove it */ | ||
1352 | if ((ehdr.e_machine == EM_ARM) && | ||
1353 | (map->type == MAP__FUNCTION) && | ||
1354 | (sym.st_value & 1)) | ||
1355 | --sym.st_value; | ||
1356 | |||
1357 | if (dso->kernel != DSO_TYPE_USER || kmodule) { | ||
1358 | char dso_name[PATH_MAX]; | ||
1359 | |||
1360 | if (strcmp(section_name, | ||
1361 | (curr_dso->short_name + | ||
1362 | dso->short_name_len)) == 0) | ||
1363 | goto new_symbol; | ||
1364 | |||
1365 | if (strcmp(section_name, ".text") == 0) { | ||
1366 | curr_map = map; | ||
1367 | curr_dso = dso; | ||
1368 | goto new_symbol; | ||
1369 | } | ||
1370 | |||
1371 | snprintf(dso_name, sizeof(dso_name), | ||
1372 | "%s%s", dso->short_name, section_name); | ||
1373 | |||
1374 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); | ||
1375 | if (curr_map == NULL) { | ||
1376 | u64 start = sym.st_value; | ||
1377 | |||
1378 | if (kmodule) | ||
1379 | start += map->start + shdr.sh_offset; | ||
1380 | |||
1381 | curr_dso = dso__new(dso_name); | ||
1382 | if (curr_dso == NULL) | ||
1383 | goto out_elf_end; | ||
1384 | curr_dso->kernel = dso->kernel; | ||
1385 | curr_dso->long_name = dso->long_name; | ||
1386 | curr_dso->long_name_len = dso->long_name_len; | ||
1387 | curr_map = map__new2(start, curr_dso, | ||
1388 | map->type); | ||
1389 | if (curr_map == NULL) { | ||
1390 | dso__delete(curr_dso); | ||
1391 | goto out_elf_end; | ||
1392 | } | ||
1393 | curr_map->map_ip = identity__map_ip; | ||
1394 | curr_map->unmap_ip = identity__map_ip; | ||
1395 | curr_dso->symtab_type = dso->symtab_type; | ||
1396 | map_groups__insert(kmap->kmaps, curr_map); | ||
1397 | dsos__add(&dso->node, curr_dso); | ||
1398 | dso__set_loaded(curr_dso, map->type); | ||
1399 | } else | ||
1400 | curr_dso = curr_map->dso; | ||
1401 | |||
1402 | goto new_symbol; | ||
1403 | } | ||
1404 | |||
1405 | if (curr_dso->adjust_symbols) { | ||
1406 | pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " | ||
1407 | "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, | ||
1408 | (u64)sym.st_value, (u64)shdr.sh_addr, | ||
1409 | (u64)shdr.sh_offset); | ||
1410 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | ||
1411 | } | ||
1412 | /* | ||
1413 | * We need to figure out if the object was created from C++ sources | ||
1414 | * DWARF DW_compile_unit has this, but we don't always have access | ||
1415 | * to it... | ||
1416 | */ | ||
1417 | demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); | ||
1418 | if (demangled != NULL) | ||
1419 | elf_name = demangled; | ||
1420 | new_symbol: | ||
1421 | f = symbol__new(sym.st_value, sym.st_size, | ||
1422 | GELF_ST_BIND(sym.st_info), elf_name); | ||
1423 | free(demangled); | ||
1424 | if (!f) | ||
1425 | goto out_elf_end; | ||
1426 | |||
1427 | if (filter && filter(curr_map, f)) | ||
1428 | symbol__delete(f); | ||
1429 | else { | ||
1430 | symbols__insert(&curr_dso->symbols[curr_map->type], f); | ||
1431 | nr++; | ||
1432 | } | ||
1433 | } | ||
1434 | |||
1435 | /* | ||
1436 | * For misannotated, zeroed, ASM function sizes. | ||
1437 | */ | ||
1438 | if (nr > 0) { | ||
1439 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1440 | symbols__fixup_end(&dso->symbols[map->type]); | ||
1441 | if (kmap) { | ||
1442 | /* | ||
1443 | * We need to fixup this here too because we create new | ||
1444 | * maps here, for things like vsyscall sections. | ||
1445 | */ | ||
1446 | __map_groups__fixup_end(kmap->kmaps, map->type); | ||
1447 | } | ||
1448 | } | ||
1449 | err = nr; | ||
1450 | out_elf_end: | ||
1451 | elf_end(elf); | ||
1452 | out_close: | ||
1453 | return err; | ||
1454 | } | ||
1455 | |||
1456 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) | ||
1457 | { | 896 | { |
1458 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; | 897 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; |
1459 | } | 898 | } |
@@ -1480,216 +919,11 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
1480 | return have_build_id; | 919 | return have_build_id; |
1481 | } | 920 | } |
1482 | 921 | ||
1483 | /* | ||
1484 | * Align offset to 4 bytes as needed for note name and descriptor data. | ||
1485 | */ | ||
1486 | #define NOTE_ALIGN(n) (((n) + 3) & -4U) | ||
1487 | |||
1488 | static int elf_read_build_id(Elf *elf, void *bf, size_t size) | ||
1489 | { | ||
1490 | int err = -1; | ||
1491 | GElf_Ehdr ehdr; | ||
1492 | GElf_Shdr shdr; | ||
1493 | Elf_Data *data; | ||
1494 | Elf_Scn *sec; | ||
1495 | Elf_Kind ek; | ||
1496 | void *ptr; | ||
1497 | |||
1498 | if (size < BUILD_ID_SIZE) | ||
1499 | goto out; | ||
1500 | |||
1501 | ek = elf_kind(elf); | ||
1502 | if (ek != ELF_K_ELF) | ||
1503 | goto out; | ||
1504 | |||
1505 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1506 | pr_err("%s: cannot get elf header.\n", __func__); | ||
1507 | goto out; | ||
1508 | } | ||
1509 | |||
1510 | /* | ||
1511 | * Check following sections for notes: | ||
1512 | * '.note.gnu.build-id' | ||
1513 | * '.notes' | ||
1514 | * '.note' (VDSO specific) | ||
1515 | */ | ||
1516 | do { | ||
1517 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1518 | ".note.gnu.build-id", NULL); | ||
1519 | if (sec) | ||
1520 | break; | ||
1521 | |||
1522 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1523 | ".notes", NULL); | ||
1524 | if (sec) | ||
1525 | break; | ||
1526 | |||
1527 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1528 | ".note", NULL); | ||
1529 | if (sec) | ||
1530 | break; | ||
1531 | |||
1532 | return err; | ||
1533 | |||
1534 | } while (0); | ||
1535 | |||
1536 | data = elf_getdata(sec, NULL); | ||
1537 | if (data == NULL) | ||
1538 | goto out; | ||
1539 | |||
1540 | ptr = data->d_buf; | ||
1541 | while (ptr < (data->d_buf + data->d_size)) { | ||
1542 | GElf_Nhdr *nhdr = ptr; | ||
1543 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), | ||
1544 | descsz = NOTE_ALIGN(nhdr->n_descsz); | ||
1545 | const char *name; | ||
1546 | |||
1547 | ptr += sizeof(*nhdr); | ||
1548 | name = ptr; | ||
1549 | ptr += namesz; | ||
1550 | if (nhdr->n_type == NT_GNU_BUILD_ID && | ||
1551 | nhdr->n_namesz == sizeof("GNU")) { | ||
1552 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | ||
1553 | size_t sz = min(size, descsz); | ||
1554 | memcpy(bf, ptr, sz); | ||
1555 | memset(bf + sz, 0, size - sz); | ||
1556 | err = descsz; | ||
1557 | break; | ||
1558 | } | ||
1559 | } | ||
1560 | ptr += descsz; | ||
1561 | } | ||
1562 | |||
1563 | out: | ||
1564 | return err; | ||
1565 | } | ||
1566 | |||
1567 | int filename__read_build_id(const char *filename, void *bf, size_t size) | ||
1568 | { | ||
1569 | int fd, err = -1; | ||
1570 | Elf *elf; | ||
1571 | |||
1572 | if (size < BUILD_ID_SIZE) | ||
1573 | goto out; | ||
1574 | |||
1575 | fd = open(filename, O_RDONLY); | ||
1576 | if (fd < 0) | ||
1577 | goto out; | ||
1578 | |||
1579 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1580 | if (elf == NULL) { | ||
1581 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1582 | goto out_close; | ||
1583 | } | ||
1584 | |||
1585 | err = elf_read_build_id(elf, bf, size); | ||
1586 | |||
1587 | elf_end(elf); | ||
1588 | out_close: | ||
1589 | close(fd); | ||
1590 | out: | ||
1591 | return err; | ||
1592 | } | ||
1593 | |||
1594 | int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | ||
1595 | { | ||
1596 | int fd, err = -1; | ||
1597 | |||
1598 | if (size < BUILD_ID_SIZE) | ||
1599 | goto out; | ||
1600 | |||
1601 | fd = open(filename, O_RDONLY); | ||
1602 | if (fd < 0) | ||
1603 | goto out; | ||
1604 | |||
1605 | while (1) { | ||
1606 | char bf[BUFSIZ]; | ||
1607 | GElf_Nhdr nhdr; | ||
1608 | size_t namesz, descsz; | ||
1609 | |||
1610 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | ||
1611 | break; | ||
1612 | |||
1613 | namesz = NOTE_ALIGN(nhdr.n_namesz); | ||
1614 | descsz = NOTE_ALIGN(nhdr.n_descsz); | ||
1615 | if (nhdr.n_type == NT_GNU_BUILD_ID && | ||
1616 | nhdr.n_namesz == sizeof("GNU")) { | ||
1617 | if (read(fd, bf, namesz) != (ssize_t)namesz) | ||
1618 | break; | ||
1619 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | ||
1620 | size_t sz = min(descsz, size); | ||
1621 | if (read(fd, build_id, sz) == (ssize_t)sz) { | ||
1622 | memset(build_id + sz, 0, size - sz); | ||
1623 | err = 0; | ||
1624 | break; | ||
1625 | } | ||
1626 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) | ||
1627 | break; | ||
1628 | } else { | ||
1629 | int n = namesz + descsz; | ||
1630 | if (read(fd, bf, n) != n) | ||
1631 | break; | ||
1632 | } | ||
1633 | } | ||
1634 | close(fd); | ||
1635 | out: | ||
1636 | return err; | ||
1637 | } | ||
1638 | |||
1639 | static int filename__read_debuglink(const char *filename, | ||
1640 | char *debuglink, size_t size) | ||
1641 | { | ||
1642 | int fd, err = -1; | ||
1643 | Elf *elf; | ||
1644 | GElf_Ehdr ehdr; | ||
1645 | GElf_Shdr shdr; | ||
1646 | Elf_Data *data; | ||
1647 | Elf_Scn *sec; | ||
1648 | Elf_Kind ek; | ||
1649 | |||
1650 | fd = open(filename, O_RDONLY); | ||
1651 | if (fd < 0) | ||
1652 | goto out; | ||
1653 | |||
1654 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1655 | if (elf == NULL) { | ||
1656 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1657 | goto out_close; | ||
1658 | } | ||
1659 | |||
1660 | ek = elf_kind(elf); | ||
1661 | if (ek != ELF_K_ELF) | ||
1662 | goto out_close; | ||
1663 | |||
1664 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1665 | pr_err("%s: cannot get elf header.\n", __func__); | ||
1666 | goto out_close; | ||
1667 | } | ||
1668 | |||
1669 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1670 | ".gnu_debuglink", NULL); | ||
1671 | if (sec == NULL) | ||
1672 | goto out_close; | ||
1673 | |||
1674 | data = elf_getdata(sec, NULL); | ||
1675 | if (data == NULL) | ||
1676 | goto out_close; | ||
1677 | |||
1678 | /* the start of this section is a zero-terminated string */ | ||
1679 | strncpy(debuglink, data->d_buf, size); | ||
1680 | |||
1681 | elf_end(elf); | ||
1682 | |||
1683 | out_close: | ||
1684 | close(fd); | ||
1685 | out: | ||
1686 | return err; | ||
1687 | } | ||
1688 | |||
1689 | char dso__symtab_origin(const struct dso *dso) | 922 | char dso__symtab_origin(const struct dso *dso) |
1690 | { | 923 | { |
1691 | static const char origin[] = { | 924 | static const char origin[] = { |
1692 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', | 925 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', |
926 | [DSO_BINARY_TYPE__VMLINUX] = 'v', | ||
1693 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', | 927 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', |
1694 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', | 928 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', |
1695 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', | 929 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', |
@@ -1700,6 +934,7 @@ char dso__symtab_origin(const struct dso *dso) | |||
1700 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', | 934 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', |
1701 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', | 935 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', |
1702 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', | 936 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', |
937 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', | ||
1703 | }; | 938 | }; |
1704 | 939 | ||
1705 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) | 940 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) |
@@ -1775,7 +1010,9 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
1775 | 1010 | ||
1776 | default: | 1011 | default: |
1777 | case DSO_BINARY_TYPE__KALLSYMS: | 1012 | case DSO_BINARY_TYPE__KALLSYMS: |
1013 | case DSO_BINARY_TYPE__VMLINUX: | ||
1778 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | 1014 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: |
1015 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | ||
1779 | case DSO_BINARY_TYPE__JAVA_JIT: | 1016 | case DSO_BINARY_TYPE__JAVA_JIT: |
1780 | case DSO_BINARY_TYPE__NOT_FOUND: | 1017 | case DSO_BINARY_TYPE__NOT_FOUND: |
1781 | ret = -1; | 1018 | ret = -1; |
@@ -1789,11 +1026,12 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1789 | { | 1026 | { |
1790 | char *name; | 1027 | char *name; |
1791 | int ret = -1; | 1028 | int ret = -1; |
1792 | int fd; | ||
1793 | u_int i; | 1029 | u_int i; |
1794 | struct machine *machine; | 1030 | struct machine *machine; |
1795 | char *root_dir = (char *) ""; | 1031 | char *root_dir = (char *) ""; |
1796 | int want_symtab; | 1032 | int ss_pos = 0; |
1033 | struct symsrc ss_[2]; | ||
1034 | struct symsrc *syms_ss = NULL, *runtime_ss = NULL; | ||
1797 | 1035 | ||
1798 | dso__set_loaded(dso, map->type); | 1036 | dso__set_loaded(dso, map->type); |
1799 | 1037 | ||
@@ -1835,54 +1073,69 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1835 | root_dir = machine->root_dir; | 1073 | root_dir = machine->root_dir; |
1836 | 1074 | ||
1837 | /* Iterate over candidate debug images. | 1075 | /* Iterate over candidate debug images. |
1838 | * On the first pass, only load images if they have a full symtab. | 1076 | * Keep track of "interesting" ones (those which have a symtab, dynsym, |
1839 | * Failing that, do a second pass where we accept .dynsym also | 1077 | * and/or opd section) for processing. |
1840 | */ | 1078 | */ |
1841 | want_symtab = 1; | ||
1842 | restart: | ||
1843 | for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { | 1079 | for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { |
1080 | struct symsrc *ss = &ss_[ss_pos]; | ||
1081 | bool next_slot = false; | ||
1844 | 1082 | ||
1845 | dso->symtab_type = binary_type_symtab[i]; | 1083 | enum dso_binary_type symtab_type = binary_type_symtab[i]; |
1846 | 1084 | ||
1847 | if (dso__binary_type_file(dso, dso->symtab_type, | 1085 | if (dso__binary_type_file(dso, symtab_type, |
1848 | root_dir, name, PATH_MAX)) | 1086 | root_dir, name, PATH_MAX)) |
1849 | continue; | 1087 | continue; |
1850 | 1088 | ||
1851 | /* Name is now the name of the next image to try */ | 1089 | /* Name is now the name of the next image to try */ |
1852 | fd = open(name, O_RDONLY); | 1090 | if (symsrc__init(ss, dso, name, symtab_type) < 0) |
1853 | if (fd < 0) | ||
1854 | continue; | 1091 | continue; |
1855 | 1092 | ||
1856 | ret = dso__load_sym(dso, map, name, fd, filter, 0, | 1093 | if (!syms_ss && symsrc__has_symtab(ss)) { |
1857 | want_symtab); | 1094 | syms_ss = ss; |
1858 | close(fd); | 1095 | next_slot = true; |
1096 | } | ||
1859 | 1097 | ||
1860 | /* | 1098 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { |
1861 | * Some people seem to have debuginfo files _WITHOUT_ debug | 1099 | runtime_ss = ss; |
1862 | * info!?!? | 1100 | next_slot = true; |
1863 | */ | 1101 | } |
1864 | if (!ret) | ||
1865 | continue; | ||
1866 | 1102 | ||
1867 | if (ret > 0) { | 1103 | if (next_slot) { |
1868 | int nr_plt; | 1104 | ss_pos++; |
1869 | 1105 | ||
1870 | nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter); | 1106 | if (syms_ss && runtime_ss) |
1871 | if (nr_plt > 0) | 1107 | break; |
1872 | ret += nr_plt; | ||
1873 | break; | ||
1874 | } | 1108 | } |
1109 | |||
1875 | } | 1110 | } |
1876 | 1111 | ||
1877 | /* | 1112 | if (!runtime_ss && !syms_ss) |
1878 | * If we wanted a full symtab but no image had one, | 1113 | goto out_free; |
1879 | * relax our requirements and repeat the search. | 1114 | |
1880 | */ | 1115 | if (runtime_ss && !syms_ss) { |
1881 | if (ret <= 0 && want_symtab) { | 1116 | syms_ss = runtime_ss; |
1882 | want_symtab = 0; | 1117 | } |
1883 | goto restart; | 1118 | |
1119 | /* We'll have to hope for the best */ | ||
1120 | if (!runtime_ss && syms_ss) | ||
1121 | runtime_ss = syms_ss; | ||
1122 | |||
1123 | if (syms_ss) | ||
1124 | ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); | ||
1125 | else | ||
1126 | ret = -1; | ||
1127 | |||
1128 | if (ret > 0) { | ||
1129 | int nr_plt; | ||
1130 | |||
1131 | nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); | ||
1132 | if (nr_plt > 0) | ||
1133 | ret += nr_plt; | ||
1884 | } | 1134 | } |
1885 | 1135 | ||
1136 | for (; ss_pos > 0; ss_pos--) | ||
1137 | symsrc__destroy(&ss_[ss_pos - 1]); | ||
1138 | out_free: | ||
1886 | free(name); | 1139 | free(name); |
1887 | if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) | 1140 | if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) |
1888 | return 0; | 1141 | return 0; |
@@ -2030,25 +1283,6 @@ static int machine__set_modules_path(struct machine *machine) | |||
2030 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | 1283 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); |
2031 | } | 1284 | } |
2032 | 1285 | ||
2033 | /* | ||
2034 | * Constructor variant for modules (where we know from /proc/modules where | ||
2035 | * they are loaded) and for vmlinux, where only after we load all the | ||
2036 | * symbols we'll know where it starts and ends. | ||
2037 | */ | ||
2038 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | ||
2039 | { | ||
2040 | struct map *map = calloc(1, (sizeof(*map) + | ||
2041 | (dso->kernel ? sizeof(struct kmap) : 0))); | ||
2042 | if (map != NULL) { | ||
2043 | /* | ||
2044 | * ->end will be filled after we load all the symbols | ||
2045 | */ | ||
2046 | map__init(map, type, start, 0, 0, dso); | ||
2047 | } | ||
2048 | |||
2049 | return map; | ||
2050 | } | ||
2051 | |||
2052 | struct map *machine__new_module(struct machine *machine, u64 start, | 1286 | struct map *machine__new_module(struct machine *machine, u64 start, |
2053 | const char *filename) | 1287 | const char *filename) |
2054 | { | 1288 | { |
@@ -2141,22 +1375,30 @@ out_failure: | |||
2141 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 1375 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
2142 | const char *vmlinux, symbol_filter_t filter) | 1376 | const char *vmlinux, symbol_filter_t filter) |
2143 | { | 1377 | { |
2144 | int err = -1, fd; | 1378 | int err = -1; |
1379 | struct symsrc ss; | ||
2145 | char symfs_vmlinux[PATH_MAX]; | 1380 | char symfs_vmlinux[PATH_MAX]; |
1381 | enum dso_binary_type symtab_type; | ||
2146 | 1382 | ||
2147 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", | 1383 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", |
2148 | symbol_conf.symfs, vmlinux); | 1384 | symbol_conf.symfs, vmlinux); |
2149 | fd = open(symfs_vmlinux, O_RDONLY); | 1385 | |
2150 | if (fd < 0) | 1386 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1387 | symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | ||
1388 | else | ||
1389 | symtab_type = DSO_BINARY_TYPE__VMLINUX; | ||
1390 | |||
1391 | if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) | ||
2151 | return -1; | 1392 | return -1; |
2152 | 1393 | ||
2153 | dso__set_long_name(dso, (char *)vmlinux); | 1394 | err = dso__load_sym(dso, map, &ss, &ss, filter, 0); |
2154 | dso__set_loaded(dso, map->type); | 1395 | symsrc__destroy(&ss); |
2155 | err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); | ||
2156 | close(fd); | ||
2157 | 1396 | ||
2158 | if (err > 0) | 1397 | if (err > 0) { |
1398 | dso__set_long_name(dso, (char *)vmlinux); | ||
1399 | dso__set_loaded(dso, map->type); | ||
2159 | pr_debug("Using %s for symbols\n", symfs_vmlinux); | 1400 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1401 | } | ||
2160 | 1402 | ||
2161 | return err; | 1403 | return err; |
2162 | } | 1404 | } |
@@ -2173,10 +1415,8 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
2173 | filename = dso__build_id_filename(dso, NULL, 0); | 1415 | filename = dso__build_id_filename(dso, NULL, 0); |
2174 | if (filename != NULL) { | 1416 | if (filename != NULL) { |
2175 | err = dso__load_vmlinux(dso, map, filename, filter); | 1417 | err = dso__load_vmlinux(dso, map, filename, filter); |
2176 | if (err > 0) { | 1418 | if (err > 0) |
2177 | dso__set_long_name(dso, filename); | ||
2178 | goto out; | 1419 | goto out; |
2179 | } | ||
2180 | free(filename); | 1420 | free(filename); |
2181 | } | 1421 | } |
2182 | 1422 | ||
@@ -2291,9 +1531,8 @@ do_kallsyms: | |||
2291 | free(kallsyms_allocated_filename); | 1531 | free(kallsyms_allocated_filename); |
2292 | 1532 | ||
2293 | if (err > 0) { | 1533 | if (err > 0) { |
1534 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); | ||
2294 | out_fixup: | 1535 | out_fixup: |
2295 | if (kallsyms_filename != NULL) | ||
2296 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); | ||
2297 | map__fixup_start(map); | 1536 | map__fixup_start(map); |
2298 | map__fixup_end(map); | 1537 | map__fixup_end(map); |
2299 | } | 1538 | } |
@@ -2352,12 +1591,12 @@ out_try_fixup: | |||
2352 | return err; | 1591 | return err; |
2353 | } | 1592 | } |
2354 | 1593 | ||
2355 | static void dsos__add(struct list_head *head, struct dso *dso) | 1594 | void dsos__add(struct list_head *head, struct dso *dso) |
2356 | { | 1595 | { |
2357 | list_add_tail(&dso->node, head); | 1596 | list_add_tail(&dso->node, head); |
2358 | } | 1597 | } |
2359 | 1598 | ||
2360 | static struct dso *dsos__find(struct list_head *head, const char *name) | 1599 | struct dso *dsos__find(struct list_head *head, const char *name) |
2361 | { | 1600 | { |
2362 | struct dso *pos; | 1601 | struct dso *pos; |
2363 | 1602 | ||
@@ -2516,7 +1755,7 @@ struct process_args { | |||
2516 | }; | 1755 | }; |
2517 | 1756 | ||
2518 | static int symbol__in_kernel(void *arg, const char *name, | 1757 | static int symbol__in_kernel(void *arg, const char *name, |
2519 | char type __used, u64 start, u64 end __used) | 1758 | char type __maybe_unused, u64 start) |
2520 | { | 1759 | { |
2521 | struct process_args *args = arg; | 1760 | struct process_args *args = arg; |
2522 | 1761 | ||
@@ -2752,9 +1991,10 @@ int symbol__init(void) | |||
2752 | if (symbol_conf.initialized) | 1991 | if (symbol_conf.initialized) |
2753 | return 0; | 1992 | return 0; |
2754 | 1993 | ||
2755 | symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); | 1994 | symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); |
1995 | |||
1996 | symbol__elf_init(); | ||
2756 | 1997 | ||
2757 | elf_version(EV_CURRENT); | ||
2758 | if (symbol_conf.sort_by_name) | 1998 | if (symbol_conf.sort_by_name) |
2759 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - | 1999 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - |
2760 | sizeof(struct symbol)); | 2000 | sizeof(struct symbol)); |