blob: 07dd9d541065a30cca15fdfa1b2c97d961a12b39 [file] [log] [blame]
Pekka Enbergb0b42ba2011-05-11 19:14:39 +03001#include "kvm/symbol.h"
2
3#include "kvm/kvm.h"
4
Sasha Levin4932d172012-01-29 09:37:23 -05005#include <linux/err.h>
Pekka Enbergb0b42ba2011-05-11 19:14:39 +03006#include <stdlib.h>
7#include <string.h>
8#include <stdio.h>
9#include <bfd.h>
10
Sasha Levin3a60be02011-12-16 10:40:06 +020011static bfd *abfd;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030012
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040013int symbol_init(struct kvm *kvm)
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030014{
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040015 int ret = 0;
Sasha Levin4932d172012-01-29 09:37:23 -050016
17 if (!kvm->vmlinux)
Sasha Levin49a8afd2012-09-17 10:03:30 +020018 return 0;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030019
20 bfd_init();
21
Sasha Levin4932d172012-01-29 09:37:23 -050022 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:
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040028 ret = -ENOMEM;
Sasha Levin4932d172012-01-29 09:37:23 -050029 break;
30 case bfd_error_invalid_target:
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040031 ret = -EINVAL;
Sasha Levin4932d172012-01-29 09:37:23 -050032 break;
33 default:
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040034 ret = -EFAULT;
Sasha Levin4932d172012-01-29 09:37:23 -050035 break;
36 }
37 }
38
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040039 return ret;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030040}
Sasha Levin49a8afd2012-09-17 10:03:30 +020041late_init(symbol_init);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030042
43static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
44{
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040045 int i, ret;
Sasha Levin4932d172012-01-29 09:37:23 -050046
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040047 ret = -ENOENT;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030048
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
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040056 return ERR_PTR(ret);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030057}
58
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040059char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030060{
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;
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040070 int nr_syms, ret;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030071
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040072 ret = -ENOENT;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030073 if (!abfd)
74 goto not_found;
75
76 if (!bfd_check_format(abfd, bfd_object))
77 goto not_found;
78
Sasha Levin3a60be02011-12-16 10:40:06 +020079 symtab_size = bfd_get_symtab_upper_bound(abfd);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030080 if (!symtab_size)
81 goto not_found;
82
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040083 ret = -ENOMEM;
Sasha Levin3a60be02011-12-16 10:40:06 +020084 syms = malloc(symtab_size);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030085 if (!syms)
86 goto not_found;
87
Sasha Levin3a60be02011-12-16 10:40:06 +020088 nr_syms = bfd_canonicalize_symtab(abfd, syms);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030089
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +040090 ret = -ENOENT;
Sasha Levin3a60be02011-12-16 10:40:06 +020091 section = bfd_get_section_by_name(abfd, ".debug_aranges");
Pekka Enbergb0b42ba2011-05-11 19:14:39 +030092 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
Sasha Levin3a60be02011-12-16 10:40:06 +0200101 symbol = lookup(syms, nr_syms, func);
Sasha Levin4932d172012-01-29 09:37:23 -0500102 if (IS_ERR(symbol))
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300103 goto not_found;
104
Sasha Levin3a60be02011-12-16 10:40:06 +0200105 sym_start = bfd_asymbol_value(symbol);
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300106
Sasha Levin3a60be02011-12-16 10:40:06 +0200107 sym_offset = addr - sym_start;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300108
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
117not_found:
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +0400118 return ERR_PTR(ret);
Sasha Levin4932d172012-01-29 09:37:23 -0500119}
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300120
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +0400121int symbol_exit(struct kvm *kvm)
Sasha Levin4932d172012-01-29 09:37:23 -0500122{
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +0400123 bfd_boolean ret = TRUE;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300124
Sasha Levin4932d172012-01-29 09:37:23 -0500125 if (abfd)
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +0400126 ret = bfd_close(abfd);
Sasha Levin4932d172012-01-29 09:37:23 -0500127
Cyrill Gorcunov807b77b2012-02-01 12:41:05 +0400128 if (ret == TRUE)
Sasha Levin4932d172012-01-29 09:37:23 -0500129 return 0;
130
131 return -EFAULT;
Pekka Enbergb0b42ba2011-05-11 19:14:39 +0300132}
Sasha Levin49a8afd2012-09-17 10:03:30 +0200133late_exit(symbol_exit);