xref: /kvmtool/symbol.c (revision 49a8afd1b9a4e503bdafb2bbc04549e03d514836)
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