1 #include "kvm/symbol.h"
2
3 #include "kvm/kvm.h"
4
5 #include <linux/err.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <bfd.h>
10
11 static bfd *abfd;
12
symbol_init(struct kvm * kvm)13 int symbol_init(struct kvm *kvm)
14 {
15 int ret = 0;
16
17 if (!kvm->vmlinux)
18 return 0;
19
20 bfd_init();
21
22 abfd = bfd_openr(kvm->vmlinux, NULL);
23 if (abfd == NULL) {
24 bfd_error_type err = bfd_get_error();
25
26 switch (err) {
27 case bfd_error_no_memory:
28 ret = -ENOMEM;
29 break;
30 case bfd_error_invalid_target:
31 ret = -EINVAL;
32 break;
33 default:
34 ret = -EFAULT;
35 break;
36 }
37 }
38
39 return ret;
40 }
41 late_init(symbol_init);
42
lookup(asymbol ** symbols,int nr_symbols,const char * symbol_name)43 static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
44 {
45 int i, ret;
46
47 ret = -ENOENT;
48
49 for (i = 0; i < nr_symbols; i++) {
50 asymbol *symbol = symbols[i];
51
52 if (!strcmp(bfd_asymbol_name(symbol), symbol_name))
53 return symbol;
54 }
55
56 return ERR_PTR(ret);
57 }
58
symbol_lookup(struct kvm * kvm,unsigned long addr,char * sym,size_t size)59 char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
60 {
61 const char *filename;
62 bfd_vma sym_offset;
63 bfd_vma sym_start;
64 asection *section;
65 unsigned int line;
66 const char *func;
67 long symtab_size;
68 asymbol *symbol;
69 asymbol **syms;
70 int nr_syms, ret;
71
72 ret = -ENOENT;
73 if (!abfd)
74 goto not_found;
75
76 if (!bfd_check_format(abfd, bfd_object))
77 goto not_found;
78
79 symtab_size = bfd_get_symtab_upper_bound(abfd);
80 if (!symtab_size)
81 goto not_found;
82
83 ret = -ENOMEM;
84 syms = malloc(symtab_size);
85 if (!syms)
86 goto not_found;
87
88 nr_syms = bfd_canonicalize_symtab(abfd, syms);
89
90 ret = -ENOENT;
91 section = bfd_get_section_by_name(abfd, ".debug_aranges");
92 if (!section)
93 goto not_found;
94
95 if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line))
96 goto not_found;
97
98 if (!func)
99 goto not_found;
100
101 symbol = lookup(syms, nr_syms, func);
102 if (IS_ERR(symbol))
103 goto not_found;
104
105 sym_start = bfd_asymbol_value(symbol);
106
107 sym_offset = addr - sym_start;
108
109 snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line);
110
111 sym[size - 1] = '\0';
112
113 free(syms);
114
115 return sym;
116
117 not_found:
118 return ERR_PTR(ret);
119 }
120
symbol_exit(struct kvm * kvm)121 int symbol_exit(struct kvm *kvm)
122 {
123 bfd_boolean ret = TRUE;
124
125 if (abfd)
126 ret = bfd_close(abfd);
127
128 if (ret == TRUE)
129 return 0;
130
131 return -EFAULT;
132 }
133 late_exit(symbol_exit);
134