1b0b42ba0SPekka Enberg #include "kvm/symbol.h"
2b0b42ba0SPekka Enberg
3b0b42ba0SPekka Enberg #include "kvm/kvm.h"
4b0b42ba0SPekka Enberg
54932d174SSasha Levin #include <linux/err.h>
6b0b42ba0SPekka Enberg #include <stdlib.h>
7b0b42ba0SPekka Enberg #include <string.h>
8b0b42ba0SPekka Enberg #include <stdio.h>
9b0b42ba0SPekka Enberg #include <bfd.h>
10b0b42ba0SPekka Enberg
11b0b42ba0SPekka Enberg static bfd *abfd;
12b0b42ba0SPekka Enberg
symbol_init(struct kvm * kvm)13807b77b9SCyrill Gorcunov int symbol_init(struct kvm *kvm)
14b0b42ba0SPekka Enberg {
15807b77b9SCyrill Gorcunov int ret = 0;
164932d174SSasha Levin
174932d174SSasha Levin if (!kvm->vmlinux)
18*49a8afd1SSasha Levin return 0;
19b0b42ba0SPekka Enberg
20b0b42ba0SPekka Enberg bfd_init();
21b0b42ba0SPekka Enberg
224932d174SSasha Levin abfd = bfd_openr(kvm->vmlinux, NULL);
234932d174SSasha Levin if (abfd == NULL) {
244932d174SSasha Levin bfd_error_type err = bfd_get_error();
254932d174SSasha Levin
264932d174SSasha Levin switch (err) {
274932d174SSasha Levin case bfd_error_no_memory:
28807b77b9SCyrill Gorcunov ret = -ENOMEM;
294932d174SSasha Levin break;
304932d174SSasha Levin case bfd_error_invalid_target:
31807b77b9SCyrill Gorcunov ret = -EINVAL;
324932d174SSasha Levin break;
334932d174SSasha Levin default:
34807b77b9SCyrill Gorcunov ret = -EFAULT;
354932d174SSasha Levin break;
364932d174SSasha Levin }
374932d174SSasha Levin }
384932d174SSasha Levin
39807b77b9SCyrill Gorcunov return ret;
40b0b42ba0SPekka Enberg }
41*49a8afd1SSasha Levin late_init(symbol_init);
42b0b42ba0SPekka Enberg
lookup(asymbol ** symbols,int nr_symbols,const char * symbol_name)43b0b42ba0SPekka Enberg static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
44b0b42ba0SPekka Enberg {
45807b77b9SCyrill Gorcunov int i, ret;
464932d174SSasha Levin
47807b77b9SCyrill Gorcunov ret = -ENOENT;
48b0b42ba0SPekka Enberg
49b0b42ba0SPekka Enberg for (i = 0; i < nr_symbols; i++) {
50b0b42ba0SPekka Enberg asymbol *symbol = symbols[i];
51b0b42ba0SPekka Enberg
52b0b42ba0SPekka Enberg if (!strcmp(bfd_asymbol_name(symbol), symbol_name))
53b0b42ba0SPekka Enberg return symbol;
54b0b42ba0SPekka Enberg }
55b0b42ba0SPekka Enberg
56807b77b9SCyrill Gorcunov return ERR_PTR(ret);
57b0b42ba0SPekka Enberg }
58b0b42ba0SPekka Enberg
symbol_lookup(struct kvm * kvm,unsigned long addr,char * sym,size_t size)59807b77b9SCyrill Gorcunov char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
60b0b42ba0SPekka Enberg {
61b0b42ba0SPekka Enberg const char *filename;
62b0b42ba0SPekka Enberg bfd_vma sym_offset;
63b0b42ba0SPekka Enberg bfd_vma sym_start;
64b0b42ba0SPekka Enberg asection *section;
65b0b42ba0SPekka Enberg unsigned int line;
66b0b42ba0SPekka Enberg const char *func;
67b0b42ba0SPekka Enberg long symtab_size;
68b0b42ba0SPekka Enberg asymbol *symbol;
69b0b42ba0SPekka Enberg asymbol **syms;
70807b77b9SCyrill Gorcunov int nr_syms, ret;
71b0b42ba0SPekka Enberg
72807b77b9SCyrill Gorcunov ret = -ENOENT;
73b0b42ba0SPekka Enberg if (!abfd)
74b0b42ba0SPekka Enberg goto not_found;
75b0b42ba0SPekka Enberg
76b0b42ba0SPekka Enberg if (!bfd_check_format(abfd, bfd_object))
77b0b42ba0SPekka Enberg goto not_found;
78b0b42ba0SPekka Enberg
79b0b42ba0SPekka Enberg symtab_size = bfd_get_symtab_upper_bound(abfd);
80b0b42ba0SPekka Enberg if (!symtab_size)
81b0b42ba0SPekka Enberg goto not_found;
82b0b42ba0SPekka Enberg
83807b77b9SCyrill Gorcunov ret = -ENOMEM;
84b0b42ba0SPekka Enberg syms = malloc(symtab_size);
85b0b42ba0SPekka Enberg if (!syms)
86b0b42ba0SPekka Enberg goto not_found;
87b0b42ba0SPekka Enberg
88b0b42ba0SPekka Enberg nr_syms = bfd_canonicalize_symtab(abfd, syms);
89b0b42ba0SPekka Enberg
90807b77b9SCyrill Gorcunov ret = -ENOENT;
91b0b42ba0SPekka Enberg section = bfd_get_section_by_name(abfd, ".debug_aranges");
92b0b42ba0SPekka Enberg if (!section)
93b0b42ba0SPekka Enberg goto not_found;
94b0b42ba0SPekka Enberg
95b0b42ba0SPekka Enberg if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line))
96b0b42ba0SPekka Enberg goto not_found;
97b0b42ba0SPekka Enberg
98b0b42ba0SPekka Enberg if (!func)
99b0b42ba0SPekka Enberg goto not_found;
100b0b42ba0SPekka Enberg
101b0b42ba0SPekka Enberg symbol = lookup(syms, nr_syms, func);
1024932d174SSasha Levin if (IS_ERR(symbol))
103b0b42ba0SPekka Enberg goto not_found;
104b0b42ba0SPekka Enberg
105b0b42ba0SPekka Enberg sym_start = bfd_asymbol_value(symbol);
106b0b42ba0SPekka Enberg
107b0b42ba0SPekka Enberg sym_offset = addr - sym_start;
108b0b42ba0SPekka Enberg
109b0b42ba0SPekka Enberg snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line);
110b0b42ba0SPekka Enberg
111b0b42ba0SPekka Enberg sym[size - 1] = '\0';
112b0b42ba0SPekka Enberg
113b0b42ba0SPekka Enberg free(syms);
114b0b42ba0SPekka Enberg
115b0b42ba0SPekka Enberg return sym;
116b0b42ba0SPekka Enberg
117b0b42ba0SPekka Enberg not_found:
118807b77b9SCyrill Gorcunov return ERR_PTR(ret);
1194932d174SSasha Levin }
120b0b42ba0SPekka Enberg
symbol_exit(struct kvm * kvm)121807b77b9SCyrill Gorcunov int symbol_exit(struct kvm *kvm)
1224932d174SSasha Levin {
123807b77b9SCyrill Gorcunov bfd_boolean ret = TRUE;
124b0b42ba0SPekka Enberg
1254932d174SSasha Levin if (abfd)
126807b77b9SCyrill Gorcunov ret = bfd_close(abfd);
1274932d174SSasha Levin
128807b77b9SCyrill Gorcunov if (ret == TRUE)
1294932d174SSasha Levin return 0;
1304932d174SSasha Levin
1314932d174SSasha Levin return -EFAULT;
132b0b42ba0SPekka Enberg }
133*49a8afd1SSasha Levin late_exit(symbol_exit);
134