xref: /kvmtool/symbol.c (revision 807b77b9145074c0b47e2754a75518eedb5a701c)
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 
13*807b77b9SCyrill Gorcunov int symbol_init(struct kvm *kvm)
14b0b42ba0SPekka Enberg {
15*807b77b9SCyrill Gorcunov 	int ret = 0;
164932d174SSasha Levin 
174932d174SSasha Levin 	if (!kvm->vmlinux)
184932d174SSasha Levin 		return -EINVAL;
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:
28*807b77b9SCyrill Gorcunov 			ret = -ENOMEM;
294932d174SSasha Levin 			break;
304932d174SSasha Levin 		case bfd_error_invalid_target:
31*807b77b9SCyrill Gorcunov 			ret = -EINVAL;
324932d174SSasha Levin 			break;
334932d174SSasha Levin 		default:
34*807b77b9SCyrill Gorcunov 			ret = -EFAULT;
354932d174SSasha Levin 			break;
364932d174SSasha Levin 		}
374932d174SSasha Levin 	}
384932d174SSasha Levin 
39*807b77b9SCyrill Gorcunov 	return ret;
40b0b42ba0SPekka Enberg }
41b0b42ba0SPekka Enberg 
42b0b42ba0SPekka Enberg static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
43b0b42ba0SPekka Enberg {
44*807b77b9SCyrill Gorcunov 	int i, ret;
454932d174SSasha Levin 
46*807b77b9SCyrill Gorcunov 	ret = -ENOENT;
47b0b42ba0SPekka Enberg 
48b0b42ba0SPekka Enberg 	for (i = 0; i < nr_symbols; i++) {
49b0b42ba0SPekka Enberg 		asymbol *symbol = symbols[i];
50b0b42ba0SPekka Enberg 
51b0b42ba0SPekka Enberg 		if (!strcmp(bfd_asymbol_name(symbol), symbol_name))
52b0b42ba0SPekka Enberg 			return symbol;
53b0b42ba0SPekka Enberg 	}
54b0b42ba0SPekka Enberg 
55*807b77b9SCyrill Gorcunov 	return ERR_PTR(ret);
56b0b42ba0SPekka Enberg }
57b0b42ba0SPekka Enberg 
58*807b77b9SCyrill Gorcunov char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
59b0b42ba0SPekka Enberg {
60b0b42ba0SPekka Enberg 	const char *filename;
61b0b42ba0SPekka Enberg 	bfd_vma sym_offset;
62b0b42ba0SPekka Enberg 	bfd_vma sym_start;
63b0b42ba0SPekka Enberg 	asection *section;
64b0b42ba0SPekka Enberg 	unsigned int line;
65b0b42ba0SPekka Enberg 	const char *func;
66b0b42ba0SPekka Enberg 	long symtab_size;
67b0b42ba0SPekka Enberg 	asymbol *symbol;
68b0b42ba0SPekka Enberg 	asymbol **syms;
69*807b77b9SCyrill Gorcunov 	int nr_syms, ret;
70b0b42ba0SPekka Enberg 
71*807b77b9SCyrill Gorcunov 	ret = -ENOENT;
72b0b42ba0SPekka Enberg 	if (!abfd)
73b0b42ba0SPekka Enberg 		goto not_found;
74b0b42ba0SPekka Enberg 
75b0b42ba0SPekka Enberg 	if (!bfd_check_format(abfd, bfd_object))
76b0b42ba0SPekka Enberg 		goto not_found;
77b0b42ba0SPekka Enberg 
78b0b42ba0SPekka Enberg 	symtab_size = bfd_get_symtab_upper_bound(abfd);
79b0b42ba0SPekka Enberg 	if (!symtab_size)
80b0b42ba0SPekka Enberg 		goto not_found;
81b0b42ba0SPekka Enberg 
82*807b77b9SCyrill Gorcunov 	ret = -ENOMEM;
83b0b42ba0SPekka Enberg 	syms = malloc(symtab_size);
84b0b42ba0SPekka Enberg 	if (!syms)
85b0b42ba0SPekka Enberg 		goto not_found;
86b0b42ba0SPekka Enberg 
87b0b42ba0SPekka Enberg 	nr_syms = bfd_canonicalize_symtab(abfd, syms);
88b0b42ba0SPekka Enberg 
89*807b77b9SCyrill Gorcunov 	ret = -ENOENT;
90b0b42ba0SPekka Enberg 	section = bfd_get_section_by_name(abfd, ".debug_aranges");
91b0b42ba0SPekka Enberg 	if (!section)
92b0b42ba0SPekka Enberg 		goto not_found;
93b0b42ba0SPekka Enberg 
94b0b42ba0SPekka Enberg 	if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line))
95b0b42ba0SPekka Enberg 		goto not_found;
96b0b42ba0SPekka Enberg 
97b0b42ba0SPekka Enberg 	if (!func)
98b0b42ba0SPekka Enberg 		goto not_found;
99b0b42ba0SPekka Enberg 
100b0b42ba0SPekka Enberg 	symbol = lookup(syms, nr_syms, func);
1014932d174SSasha Levin 	if (IS_ERR(symbol))
102b0b42ba0SPekka Enberg 		goto not_found;
103b0b42ba0SPekka Enberg 
104b0b42ba0SPekka Enberg 	sym_start = bfd_asymbol_value(symbol);
105b0b42ba0SPekka Enberg 
106b0b42ba0SPekka Enberg 	sym_offset = addr - sym_start;
107b0b42ba0SPekka Enberg 
108b0b42ba0SPekka Enberg 	snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line);
109b0b42ba0SPekka Enberg 
110b0b42ba0SPekka Enberg 	sym[size - 1] = '\0';
111b0b42ba0SPekka Enberg 
112b0b42ba0SPekka Enberg 	free(syms);
113b0b42ba0SPekka Enberg 
114b0b42ba0SPekka Enberg 	return sym;
115b0b42ba0SPekka Enberg 
116b0b42ba0SPekka Enberg not_found:
117*807b77b9SCyrill Gorcunov 	return ERR_PTR(ret);
1184932d174SSasha Levin }
119b0b42ba0SPekka Enberg 
120*807b77b9SCyrill Gorcunov int symbol_exit(struct kvm *kvm)
1214932d174SSasha Levin {
122*807b77b9SCyrill Gorcunov 	bfd_boolean ret = TRUE;
123b0b42ba0SPekka Enberg 
1244932d174SSasha Levin 	if (abfd)
125*807b77b9SCyrill Gorcunov 		ret = bfd_close(abfd);
1264932d174SSasha Levin 
127*807b77b9SCyrill Gorcunov 	if (ret == TRUE)
1284932d174SSasha Levin 		return 0;
1294932d174SSasha Levin 
1304932d174SSasha Levin 	return -EFAULT;
131b0b42ba0SPekka Enberg }
132