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