blob: f134ec1389347422731839f17d49a23ee77e3e52 [file] [log] [blame]
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001#include <dirent.h>
2#include <errno.h>
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03003#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <sys/param.h>
9#include <fcntl.h>
10#include <unistd.h>
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -020011#include <inttypes.h>
Arnaldo Carvalho de Melob36f19d2010-05-20 12:15:33 -030012#include "build-id.h"
Namhyung Kime334c722012-02-10 10:10:17 +090013#include "util.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030014#include "debug.h"
Arnaldo Carvalho de Melo69d25912012-11-09 11:32:52 -030015#include "machine.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030016#include "symbol.h"
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -030017#include "strlist.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030018
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030019#include <elf.h>
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -020020#include <limits.h>
Arnaldo Carvalho de Meloc506c962013-12-11 09:15:00 -030021#include <symbol/kallsyms.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030022#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020023
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030024static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020025 symbol_filter_t filter);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030026static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080027 symbol_filter_t filter);
Arnaldo Carvalho de Melo3f067dc2012-12-07 17:39:39 -030028int vmlinux_path__nr_entries;
29char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030030
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020031struct symbol_conf symbol_conf = {
Namhyung Kime511db52013-12-24 16:19:25 +090032 .use_modules = true,
33 .try_vmlinux_path = true,
34 .annotate_src = true,
35 .demangle = true,
36 .cumulate_callchain = true,
Jiri Olsac8302362014-06-27 18:26:58 +020037 .show_hist_headers = true,
Namhyung Kime511db52013-12-24 16:19:25 +090038 .symfs = "",
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020039};
40
Jiri Olsa44f24cb2012-07-22 14:14:32 +020041static enum dso_binary_type binary_type_symtab[] = {
42 DSO_BINARY_TYPE__KALLSYMS,
43 DSO_BINARY_TYPE__GUEST_KALLSYMS,
44 DSO_BINARY_TYPE__JAVA_JIT,
45 DSO_BINARY_TYPE__DEBUGLINK,
46 DSO_BINARY_TYPE__BUILD_ID_CACHE,
47 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
48 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
49 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
50 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
51 DSO_BINARY_TYPE__GUEST_KMODULE,
52 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
Ricardo Ribalda Delgado9cd00942013-09-18 15:56:14 +020053 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
Jiri Olsa44f24cb2012-07-22 14:14:32 +020054 DSO_BINARY_TYPE__NOT_FOUND,
55};
56
Jiri Olsa028df762012-08-01 14:47:57 +020057#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
Jiri Olsa44f24cb2012-07-22 14:14:32 +020058
Arnaldo Carvalho de Melo36a3e642010-01-04 16:19:27 -020059bool symbol_type__is_a(char symbol_type, enum map_type map_type)
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020060{
Anton Blanchard31877902011-08-24 16:40:16 +100061 symbol_type = toupper(symbol_type);
62
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020063 switch (map_type) {
64 case MAP__FUNCTION:
65 return symbol_type == 'T' || symbol_type == 'W';
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -020066 case MAP__VARIABLE:
Anton Blanchard31877902011-08-24 16:40:16 +100067 return symbol_type == 'D';
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020068 default:
69 return false;
70 }
71}
72
Anton Blanchard694bf402011-08-24 16:40:17 +100073static int prefix_underscores_count(const char *str)
74{
75 const char *tail = str;
76
77 while (*tail == '_')
78 tail++;
79
80 return tail - str;
81}
82
83#define SYMBOL_A 0
84#define SYMBOL_B 1
85
86static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
87{
88 s64 a;
89 s64 b;
Adrian Hunter34454322013-08-07 14:38:49 +030090 size_t na, nb;
Anton Blanchard694bf402011-08-24 16:40:17 +100091
92 /* Prefer a symbol with non zero length */
93 a = syma->end - syma->start;
94 b = symb->end - symb->start;
95 if ((b == 0) && (a > 0))
96 return SYMBOL_A;
97 else if ((a == 0) && (b > 0))
98 return SYMBOL_B;
99
100 /* Prefer a non weak symbol over a weak one */
101 a = syma->binding == STB_WEAK;
102 b = symb->binding == STB_WEAK;
103 if (b && !a)
104 return SYMBOL_A;
105 if (a && !b)
106 return SYMBOL_B;
107
108 /* Prefer a global symbol over a non global one */
109 a = syma->binding == STB_GLOBAL;
110 b = symb->binding == STB_GLOBAL;
111 if (a && !b)
112 return SYMBOL_A;
113 if (b && !a)
114 return SYMBOL_B;
115
116 /* Prefer a symbol with less underscores */
117 a = prefix_underscores_count(syma->name);
118 b = prefix_underscores_count(symb->name);
119 if (b > a)
120 return SYMBOL_A;
121 else if (a > b)
122 return SYMBOL_B;
123
Adrian Hunter34454322013-08-07 14:38:49 +0300124 /* Choose the symbol with the longest name */
125 na = strlen(syma->name);
126 nb = strlen(symb->name);
127 if (na > nb)
Anton Blanchard694bf402011-08-24 16:40:17 +1000128 return SYMBOL_A;
Adrian Hunter34454322013-08-07 14:38:49 +0300129 else if (na < nb)
Anton Blanchard694bf402011-08-24 16:40:17 +1000130 return SYMBOL_B;
Adrian Hunter34454322013-08-07 14:38:49 +0300131
132 /* Avoid "SyS" kernel syscall aliases */
133 if (na >= 3 && !strncmp(syma->name, "SyS", 3))
134 return SYMBOL_B;
135 if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
136 return SYMBOL_B;
137
138 return SYMBOL_A;
Anton Blanchard694bf402011-08-24 16:40:17 +1000139}
140
Namhyung Kime5a18452012-08-06 13:41:20 +0900141void symbols__fixup_duplicate(struct rb_root *symbols)
Anton Blanchard694bf402011-08-24 16:40:17 +1000142{
143 struct rb_node *nd;
144 struct symbol *curr, *next;
145
146 nd = rb_first(symbols);
147
148 while (nd) {
149 curr = rb_entry(nd, struct symbol, rb_node);
150again:
151 nd = rb_next(&curr->rb_node);
152 next = rb_entry(nd, struct symbol, rb_node);
153
154 if (!nd)
155 break;
156
157 if (curr->start != next->start)
158 continue;
159
160 if (choose_best_symbol(curr, next) == SYMBOL_A) {
161 rb_erase(&next->rb_node, symbols);
Chenggang Qind4f74eb2013-10-11 08:27:59 +0800162 symbol__delete(next);
Anton Blanchard694bf402011-08-24 16:40:17 +1000163 goto again;
164 } else {
165 nd = rb_next(&curr->rb_node);
166 rb_erase(&curr->rb_node, symbols);
Chenggang Qind4f74eb2013-10-11 08:27:59 +0800167 symbol__delete(curr);
Anton Blanchard694bf402011-08-24 16:40:17 +1000168 }
169 }
170}
171
Namhyung Kime5a18452012-08-06 13:41:20 +0900172void symbols__fixup_end(struct rb_root *symbols)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300173{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300174 struct rb_node *nd, *prevnd = rb_first(symbols);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300175 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300176
177 if (prevnd == NULL)
178 return;
179
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300180 curr = rb_entry(prevnd, struct symbol, rb_node);
181
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300182 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300183 prev = curr;
184 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300185
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200186 if (prev->end == prev->start && prev->end != curr->start)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300187 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300188 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300189
190 /* Last entry */
191 if (curr->end == curr->start)
192 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300193}
194
Namhyung Kime5a18452012-08-06 13:41:20 +0900195void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300196{
197 struct map *prev, *curr;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300198 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300199
200 if (prevnd == NULL)
201 return;
202
203 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300204
205 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
206 prev = curr;
207 curr = rb_entry(nd, struct map, rb_node);
208 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300209 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -0200210
211 /*
212 * We still haven't the actual symbols, so guess the
213 * last map final address.
214 */
Ian Munsie9d1faba2010-11-25 15:12:53 +1100215 curr->end = ~0ULL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300216}
217
Namhyung Kime5a18452012-08-06 13:41:20 +0900218struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300219{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300220 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300221 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
222 sizeof(*sym) + namelen));
223 if (sym == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200224 return NULL;
225
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200226 if (symbol_conf.priv_size)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300227 sym = ((void *)sym) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200228
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300229 sym->start = start;
230 sym->end = len ? start + len - 1 : start;
231 sym->binding = binding;
232 sym->namelen = namelen - 1;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200233
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300234 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
235 __func__, name, start, sym->end);
236 memcpy(sym->name, name, namelen);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200237
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300238 return sym;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300239}
240
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300241void symbol__delete(struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300242{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300243 free(((void *)sym) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300244}
245
Jiri Olsacdd059d2012-10-27 23:18:32 +0200246size_t symbol__fprintf(struct symbol *sym, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300247{
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200248 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300249 sym->start, sym->end,
250 sym->binding == STB_GLOBAL ? 'g' :
251 sym->binding == STB_LOCAL ? 'l' : 'w',
252 sym->name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300253}
254
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900255size_t symbol__fprintf_symname_offs(const struct symbol *sym,
256 const struct addr_location *al, FILE *fp)
257{
258 unsigned long offset;
259 size_t length;
260
261 if (sym && sym->name) {
262 length = fprintf(fp, "%s", sym->name);
263 if (al) {
David Ahern0b8c25d2013-07-28 09:48:32 -0600264 if (al->addr < sym->end)
265 offset = al->addr - sym->start;
266 else
267 offset = al->addr - al->map->start - sym->start;
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900268 length += fprintf(fp, "+0x%lx", offset);
269 }
270 return length;
271 } else
272 return fprintf(fp, "[unknown]");
273}
274
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900275size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
276{
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900277 return symbol__fprintf_symname_offs(sym, NULL, fp);
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900278}
279
Jiri Olsacdd059d2012-10-27 23:18:32 +0200280void symbols__delete(struct rb_root *symbols)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300281{
282 struct symbol *pos;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300283 struct rb_node *next = rb_first(symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300284
285 while (next) {
286 pos = rb_entry(next, struct symbol, rb_node);
287 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300288 rb_erase(&pos->rb_node, symbols);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200289 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300290 }
291}
292
Namhyung Kime5a18452012-08-06 13:41:20 +0900293void symbols__insert(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300294{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300295 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300296 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000297 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300298 struct symbol *s;
299
300 while (*p != NULL) {
301 parent = *p;
302 s = rb_entry(parent, struct symbol, rb_node);
303 if (ip < s->start)
304 p = &(*p)->rb_left;
305 else
306 p = &(*p)->rb_right;
307 }
308 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300309 rb_insert_color(&sym->rb_node, symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300310}
311
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300312static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300313{
314 struct rb_node *n;
315
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300316 if (symbols == NULL)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300317 return NULL;
318
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300319 n = symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300320
321 while (n) {
322 struct symbol *s = rb_entry(n, struct symbol, rb_node);
323
324 if (ip < s->start)
325 n = n->rb_left;
326 else if (ip > s->end)
327 n = n->rb_right;
328 else
329 return s;
330 }
331
332 return NULL;
333}
334
Adrian Hunter8e0cf962013-08-07 14:38:51 +0300335static struct symbol *symbols__first(struct rb_root *symbols)
336{
337 struct rb_node *n = rb_first(symbols);
338
339 if (n)
340 return rb_entry(n, struct symbol, rb_node);
341
342 return NULL;
343}
344
Adrian Hunter9c00a812014-07-14 13:02:50 +0300345static struct symbol *symbols__next(struct symbol *sym)
346{
347 struct rb_node *n = rb_next(&sym->rb_node);
348
349 if (n)
350 return rb_entry(n, struct symbol, rb_node);
351
352 return NULL;
353}
354
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200355struct symbol_name_rb_node {
356 struct rb_node rb_node;
357 struct symbol sym;
358};
359
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300360static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200361{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300362 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200363 struct rb_node *parent = NULL;
Rabin Vincent02a9d032010-11-23 22:08:18 +0530364 struct symbol_name_rb_node *symn, *s;
365
366 symn = container_of(sym, struct symbol_name_rb_node, sym);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200367
368 while (*p != NULL) {
369 parent = *p;
370 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
371 if (strcmp(sym->name, s->sym.name) < 0)
372 p = &(*p)->rb_left;
373 else
374 p = &(*p)->rb_right;
375 }
376 rb_link_node(&symn->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300377 rb_insert_color(&symn->rb_node, symbols);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200378}
379
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300380static void symbols__sort_by_name(struct rb_root *symbols,
381 struct rb_root *source)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200382{
383 struct rb_node *nd;
384
385 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
386 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300387 symbols__insert_by_name(symbols, pos);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200388 }
389}
390
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300391static struct symbol *symbols__find_by_name(struct rb_root *symbols,
392 const char *name)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200393{
394 struct rb_node *n;
395
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300396 if (symbols == NULL)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200397 return NULL;
398
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300399 n = symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200400
401 while (n) {
402 struct symbol_name_rb_node *s;
403 int cmp;
404
405 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
406 cmp = strcmp(name, s->sym.name);
407
408 if (cmp < 0)
409 n = n->rb_left;
410 else if (cmp > 0)
411 n = n->rb_right;
412 else
413 return &s->sym;
414 }
415
416 return NULL;
417}
418
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300419struct symbol *dso__find_symbol(struct dso *dso,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200420 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200421{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300422 return symbols__find(&dso->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200423}
424
Adrian Hunter9c00a812014-07-14 13:02:50 +0300425struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
Adrian Hunter8e0cf962013-08-07 14:38:51 +0300426{
427 return symbols__first(&dso->symbols[type]);
428}
429
Adrian Hunter9c00a812014-07-14 13:02:50 +0300430struct symbol *dso__next_symbol(struct symbol *sym)
431{
432 return symbols__next(sym);
433}
434
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300435struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200436 const char *name)
437{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300438 return symbols__find_by_name(&dso->symbol_names[type], name);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200439}
440
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300441void dso__sort_by_name(struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200442{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300443 dso__set_sorted_by_name(dso, type);
444 return symbols__sort_by_name(&dso->symbol_names[type],
445 &dso->symbols[type]);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200446}
447
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300448size_t dso__fprintf_symbols_by_name(struct dso *dso,
449 enum map_type type, FILE *fp)
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530450{
451 size_t ret = 0;
452 struct rb_node *nd;
453 struct symbol_name_rb_node *pos;
454
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300455 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530456 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
457 fprintf(fp, "%s\n", pos->sym.name);
458 }
459
460 return ret;
461}
462
Adrian Hunter316d70d2013-10-08 11:45:48 +0300463int modules__parse(const char *filename, void *arg,
464 int (*process_module)(void *arg, const char *name,
465 u64 start))
466{
467 char *line = NULL;
468 size_t n;
469 FILE *file;
470 int err = 0;
471
472 file = fopen(filename, "r");
473 if (file == NULL)
474 return -1;
475
476 while (1) {
477 char name[PATH_MAX];
478 u64 start;
479 char *sep;
480 ssize_t line_len;
481
482 line_len = getline(&line, &n, file);
483 if (line_len < 0) {
484 if (feof(file))
485 break;
486 err = -1;
487 goto out;
488 }
489
490 if (!line) {
491 err = -1;
492 goto out;
493 }
494
495 line[--line_len] = '\0'; /* \n */
496
497 sep = strrchr(line, 'x');
498 if (sep == NULL)
499 continue;
500
501 hex2u64(sep + 1, &start);
502
503 sep = strchr(line, ' ');
504 if (sep == NULL)
505 continue;
506
507 *sep = '\0';
508
509 scnprintf(name, sizeof(name), "[%s]", line);
510
511 err = process_module(arg, name, start);
512 if (err)
513 break;
514 }
515out:
516 free(line);
517 fclose(file);
518 return err;
519}
520
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200521struct process_kallsyms_args {
522 struct map *map;
523 struct dso *dso;
524};
525
David Ahern82d1deb2013-11-18 13:32:45 -0700526bool symbol__is_idle(struct symbol *sym)
527{
528 const char * const idle_symbols[] = {
529 "cpu_idle",
530 "intel_idle",
531 "default_idle",
532 "native_safe_halt",
533 "enter_idle",
534 "exit_idle",
535 "mwait_idle",
536 "mwait_idle_with_hints",
537 "poll_idle",
538 "ppc64_runlatch_off",
539 "pseries_dedicated_idle_sleep",
540 NULL
541 };
542
543 int i;
544
545 if (!sym)
546 return false;
547
548 for (i = 0; idle_symbols[i]; i++) {
549 if (!strcmp(idle_symbols[i], sym->name))
550 return true;
551 }
552
553 return false;
554}
555
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200556static int map__process_kallsym_symbol(void *arg, const char *name,
Cody P Schafer82151522012-08-10 15:22:48 -0700557 char type, u64 start)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200558{
559 struct symbol *sym;
560 struct process_kallsyms_args *a = arg;
561 struct rb_root *root = &a->dso->symbols[a->map->type];
562
563 if (!symbol_type__is_a(type, a->map->type))
564 return 0;
565
Cody P Schafer82151522012-08-10 15:22:48 -0700566 /*
567 * module symbols are not sorted so we add all
568 * symbols, setting length to 0, and rely on
569 * symbols__fixup_end() to fix it up.
570 */
571 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200572 if (sym == NULL)
573 return -ENOMEM;
574 /*
575 * We will pass the symbols to the filter later, in
576 * map__split_kallsyms, when we have split the maps per module
577 */
578 symbols__insert(root, sym);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800579
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200580 return 0;
581}
582
583/*
584 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
585 * so that we can in the next step set the symbol ->end address and then
586 * call kernel_maps__split_kallsyms.
587 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300588static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200589 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200590{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300591 struct process_kallsyms_args args = { .map = map, .dso = dso, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200592 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200593}
594
Adrian Hunter8e0cf962013-08-07 14:38:51 +0300595static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
596 symbol_filter_t filter)
597{
598 struct map_groups *kmaps = map__kmap(map)->kmaps;
599 struct map *curr_map;
600 struct symbol *pos;
601 int count = 0, moved = 0;
602 struct rb_root *root = &dso->symbols[map->type];
603 struct rb_node *next = rb_first(root);
604
605 while (next) {
606 char *module;
607
608 pos = rb_entry(next, struct symbol, rb_node);
609 next = rb_next(&pos->rb_node);
610
611 module = strchr(pos->name, '\t');
612 if (module)
613 *module = '\0';
614
615 curr_map = map_groups__find(kmaps, map->type, pos->start);
616
617 if (!curr_map || (filter && filter(curr_map, pos))) {
618 rb_erase(&pos->rb_node, root);
619 symbol__delete(pos);
620 } else {
621 pos->start -= curr_map->start - curr_map->pgoff;
622 if (pos->end)
623 pos->end -= curr_map->start - curr_map->pgoff;
624 if (curr_map != map) {
625 rb_erase(&pos->rb_node, root);
626 symbols__insert(
627 &curr_map->dso->symbols[curr_map->type],
628 pos);
629 ++moved;
630 } else {
631 ++count;
632 }
633 }
634 }
635
636 /* Symbols have been adjusted */
637 dso->adjust_symbols = 1;
638
639 return count + moved;
640}
641
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300642/*
643 * Split the symbols into maps, making sure there are no overlaps, i.e. the
644 * kernel range is broken in several maps, named [kernel].N, as we don't have
645 * the original ELF section names vmlinux have.
646 */
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200647static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200648 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300649{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200650 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300651 struct machine *machine = kmaps->machine;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200652 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300653 struct symbol *pos;
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200654 int count = 0, moved = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300655 struct rb_root *root = &dso->symbols[map->type];
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200656 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300657 int kernel_range = 0;
658
659 while (next) {
660 char *module;
661
662 pos = rb_entry(next, struct symbol, rb_node);
663 next = rb_next(&pos->rb_node);
664
665 module = strchr(pos->name, '\t');
666 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200667 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200668 goto discard_symbol;
669
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300670 *module++ = '\0';
671
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200672 if (strcmp(curr_map->dso->short_name, module)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800673 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300674 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300675 machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800676 /*
677 * We assume all symbols of a module are
678 * continuous in * kallsyms, so curr_map
679 * points to a module and all its
680 * symbols are in its kmap. Mark it as
681 * loaded.
682 */
683 dso__set_loaded(curr_map->dso,
684 curr_map->type);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300685 }
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200686
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800687 curr_map = map_groups__find_by_name(kmaps,
688 map->type, module);
689 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2f519032010-05-17 17:57:59 -0300690 pr_debug("%s/proc/{kallsyms,modules} "
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800691 "inconsistency while looking "
692 "for \"%s\" module!\n",
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300693 machine->root_dir, module);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800694 curr_map = map;
695 goto discard_symbol;
696 }
697
698 if (curr_map->dso->loaded &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300699 !machine__is_default_guest(machine))
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200700 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300701 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300702 /*
703 * So that we look just like we get from .ko files,
704 * i.e. not prelinked, relative to map->start.
705 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200706 pos->start = curr_map->map_ip(curr_map, pos->start);
707 pos->end = curr_map->map_ip(curr_map, pos->end);
708 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300709 char dso_name[PATH_MAX];
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300710 struct dso *ndso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300711
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200712 if (delta) {
713 /* Kernel was relocated at boot time */
714 pos->start -= delta;
715 pos->end -= delta;
716 }
717
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200718 if (count == 0) {
719 curr_map = map;
720 goto filter_symbol;
721 }
722
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300723 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800724 snprintf(dso_name, sizeof(dso_name),
725 "[guest.kernel].%d",
726 kernel_range++);
727 else
728 snprintf(dso_name, sizeof(dso_name),
729 "[kernel].%d",
730 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300731
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300732 ndso = dso__new(dso_name);
733 if (ndso == NULL)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300734 return -1;
735
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300736 ndso->kernel = dso->kernel;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800737
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300738 curr_map = map__new2(pos->start, ndso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800739 if (curr_map == NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300740 dso__delete(ndso);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300741 return -1;
742 }
743
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200744 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200745 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300746 ++kernel_range;
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200747 } else if (delta) {
748 /* Kernel was relocated at boot time */
749 pos->start -= delta;
750 pos->end -= delta;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300751 }
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200752filter_symbol:
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200753 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200754discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200755 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300756 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200757 if (curr_map != map) {
758 rb_erase(&pos->rb_node, root);
759 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200760 ++moved;
761 } else
762 ++count;
Mike Galbraith9974f492009-07-02 08:05:58 +0200763 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300764 }
765
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800766 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300767 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300768 machine__is_default_guest(kmaps->machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800769 dso__set_loaded(curr_map->dso, curr_map->type);
770 }
771
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200772 return count + moved;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300773}
774
Arnaldo Carvalho de Melo3f067dc2012-12-07 17:39:39 -0300775bool symbol__restricted_filename(const char *filename,
776 const char *restricted_filename)
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300777{
778 bool restricted = false;
779
780 if (symbol_conf.kptr_restrict) {
781 char *r = realpath(filename, NULL);
782
783 if (r != NULL) {
784 restricted = strcmp(r, restricted_filename) == 0;
785 free(r);
786 return restricted;
787 }
788 }
789
790 return restricted;
791}
792
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300793struct module_info {
794 struct rb_node rb_node;
795 char *name;
796 u64 start;
797};
798
799static void add_module(struct module_info *mi, struct rb_root *modules)
800{
801 struct rb_node **p = &modules->rb_node;
802 struct rb_node *parent = NULL;
803 struct module_info *m;
804
805 while (*p != NULL) {
806 parent = *p;
807 m = rb_entry(parent, struct module_info, rb_node);
808 if (strcmp(mi->name, m->name) < 0)
809 p = &(*p)->rb_left;
810 else
811 p = &(*p)->rb_right;
812 }
813 rb_link_node(&mi->rb_node, parent, p);
814 rb_insert_color(&mi->rb_node, modules);
815}
816
817static void delete_modules(struct rb_root *modules)
818{
819 struct module_info *mi;
820 struct rb_node *next = rb_first(modules);
821
822 while (next) {
823 mi = rb_entry(next, struct module_info, rb_node);
824 next = rb_next(&mi->rb_node);
825 rb_erase(&mi->rb_node, modules);
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300826 zfree(&mi->name);
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300827 free(mi);
828 }
829}
830
831static struct module_info *find_module(const char *name,
832 struct rb_root *modules)
833{
834 struct rb_node *n = modules->rb_node;
835
836 while (n) {
837 struct module_info *m;
838 int cmp;
839
840 m = rb_entry(n, struct module_info, rb_node);
841 cmp = strcmp(name, m->name);
842 if (cmp < 0)
843 n = n->rb_left;
844 else if (cmp > 0)
845 n = n->rb_right;
846 else
847 return m;
848 }
849
850 return NULL;
851}
852
853static int __read_proc_modules(void *arg, const char *name, u64 start)
854{
855 struct rb_root *modules = arg;
856 struct module_info *mi;
857
858 mi = zalloc(sizeof(struct module_info));
859 if (!mi)
860 return -ENOMEM;
861
862 mi->name = strdup(name);
863 mi->start = start;
864
865 if (!mi->name) {
866 free(mi);
867 return -ENOMEM;
868 }
869
870 add_module(mi, modules);
871
872 return 0;
873}
874
875static int read_proc_modules(const char *filename, struct rb_root *modules)
876{
877 if (symbol__restricted_filename(filename, "/proc/modules"))
878 return -1;
879
880 if (modules__parse(filename, modules, __read_proc_modules)) {
881 delete_modules(modules);
882 return -1;
883 }
884
885 return 0;
886}
887
Adrian Hunterfc1b6912013-10-14 16:57:29 +0300888int compare_proc_modules(const char *from, const char *to)
889{
890 struct rb_root from_modules = RB_ROOT;
891 struct rb_root to_modules = RB_ROOT;
892 struct rb_node *from_node, *to_node;
893 struct module_info *from_m, *to_m;
894 int ret = -1;
895
896 if (read_proc_modules(from, &from_modules))
897 return -1;
898
899 if (read_proc_modules(to, &to_modules))
900 goto out_delete_from;
901
902 from_node = rb_first(&from_modules);
903 to_node = rb_first(&to_modules);
904 while (from_node) {
905 if (!to_node)
906 break;
907
908 from_m = rb_entry(from_node, struct module_info, rb_node);
909 to_m = rb_entry(to_node, struct module_info, rb_node);
910
911 if (from_m->start != to_m->start ||
912 strcmp(from_m->name, to_m->name))
913 break;
914
915 from_node = rb_next(from_node);
916 to_node = rb_next(to_node);
917 }
918
919 if (!from_node && !to_node)
920 ret = 0;
921
922 delete_modules(&to_modules);
923out_delete_from:
924 delete_modules(&from_modules);
925
926 return ret;
927}
928
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300929static int do_validate_kcore_modules(const char *filename, struct map *map,
930 struct map_groups *kmaps)
931{
932 struct rb_root modules = RB_ROOT;
933 struct map *old_map;
934 int err;
935
936 err = read_proc_modules(filename, &modules);
937 if (err)
938 return err;
939
940 old_map = map_groups__first(kmaps, map->type);
941 while (old_map) {
942 struct map *next = map_groups__next(old_map);
943 struct module_info *mi;
944
945 if (old_map == map || old_map->start == map->start) {
946 /* The kernel map */
947 old_map = next;
948 continue;
949 }
950
951 /* Module must be in memory at the same address */
952 mi = find_module(old_map->dso->short_name, &modules);
953 if (!mi || mi->start != old_map->start) {
954 err = -EINVAL;
955 goto out;
956 }
957
958 old_map = next;
959 }
960out:
961 delete_modules(&modules);
962 return err;
963}
964
965/*
966 * If kallsyms is referenced by name then we look for filename in the same
967 * directory.
968 */
969static bool filename_from_kallsyms_filename(char *filename,
970 const char *base_name,
971 const char *kallsyms_filename)
972{
973 char *name;
974
975 strcpy(filename, kallsyms_filename);
976 name = strrchr(filename, '/');
977 if (!name)
978 return false;
979
980 name += 1;
981
982 if (!strcmp(name, "kallsyms")) {
983 strcpy(name, base_name);
984 return true;
985 }
986
987 return false;
988}
989
990static int validate_kcore_modules(const char *kallsyms_filename,
991 struct map *map)
992{
993 struct map_groups *kmaps = map__kmap(map)->kmaps;
994 char modules_filename[PATH_MAX];
995
996 if (!filename_from_kallsyms_filename(modules_filename, "modules",
997 kallsyms_filename))
998 return -EINVAL;
999
1000 if (do_validate_kcore_modules(modules_filename, map, kmaps))
1001 return -EINVAL;
1002
1003 return 0;
1004}
1005
Adrian Huntera00d28c2014-01-29 16:14:41 +02001006static int validate_kcore_addresses(const char *kallsyms_filename,
1007 struct map *map)
1008{
1009 struct kmap *kmap = map__kmap(map);
1010
1011 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1012 u64 start;
1013
1014 start = kallsyms__get_function_start(kallsyms_filename,
1015 kmap->ref_reloc_sym->name);
1016 if (start != kmap->ref_reloc_sym->addr)
1017 return -EINVAL;
1018 }
1019
1020 return validate_kcore_modules(kallsyms_filename, map);
1021}
1022
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001023struct kcore_mapfn_data {
1024 struct dso *dso;
1025 enum map_type type;
1026 struct list_head maps;
1027};
1028
1029static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
1030{
1031 struct kcore_mapfn_data *md = data;
1032 struct map *map;
1033
1034 map = map__new2(start, md->dso, md->type);
1035 if (map == NULL)
1036 return -ENOMEM;
1037
1038 map->end = map->start + len;
1039 map->pgoff = pgoff;
1040
1041 list_add(&map->node, &md->maps);
1042
1043 return 0;
1044}
1045
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001046static int dso__load_kcore(struct dso *dso, struct map *map,
1047 const char *kallsyms_filename)
1048{
1049 struct map_groups *kmaps = map__kmap(map)->kmaps;
1050 struct machine *machine = kmaps->machine;
1051 struct kcore_mapfn_data md;
1052 struct map *old_map, *new_map, *replacement_map = NULL;
1053 bool is_64_bit;
1054 int err, fd;
1055 char kcore_filename[PATH_MAX];
1056 struct symbol *sym;
1057
1058 /* This function requires that the map is the kernel map */
1059 if (map != machine->vmlinux_maps[map->type])
1060 return -EINVAL;
1061
Adrian Hunter52afdaf2013-10-09 15:01:11 +03001062 if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
1063 kallsyms_filename))
1064 return -EINVAL;
1065
Adrian Huntera00d28c2014-01-29 16:14:41 +02001066 /* Modules and kernel must be present at their original addresses */
1067 if (validate_kcore_addresses(kallsyms_filename, map))
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001068 return -EINVAL;
1069
1070 md.dso = dso;
1071 md.type = map->type;
1072 INIT_LIST_HEAD(&md.maps);
1073
1074 fd = open(kcore_filename, O_RDONLY);
1075 if (fd < 0)
1076 return -EINVAL;
1077
1078 /* Read new maps into temporary lists */
1079 err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
1080 &is_64_bit);
1081 if (err)
1082 goto out_err;
Adrian Hunterc6d8f2a2014-07-14 13:02:41 +03001083 dso->is_64_bit = is_64_bit;
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001084
1085 if (list_empty(&md.maps)) {
1086 err = -EINVAL;
1087 goto out_err;
1088 }
1089
1090 /* Remove old maps */
1091 old_map = map_groups__first(kmaps, map->type);
1092 while (old_map) {
1093 struct map *next = map_groups__next(old_map);
1094
1095 if (old_map != map)
1096 map_groups__remove(kmaps, old_map);
1097 old_map = next;
1098 }
1099
1100 /* Find the kernel map using the first symbol */
1101 sym = dso__first_symbol(dso, map->type);
1102 list_for_each_entry(new_map, &md.maps, node) {
1103 if (sym && sym->start >= new_map->start &&
1104 sym->start < new_map->end) {
1105 replacement_map = new_map;
1106 break;
1107 }
1108 }
1109
1110 if (!replacement_map)
1111 replacement_map = list_entry(md.maps.next, struct map, node);
1112
1113 /* Add new maps */
1114 while (!list_empty(&md.maps)) {
1115 new_map = list_entry(md.maps.next, struct map, node);
1116 list_del(&new_map->node);
1117 if (new_map == replacement_map) {
1118 map->start = new_map->start;
1119 map->end = new_map->end;
1120 map->pgoff = new_map->pgoff;
1121 map->map_ip = new_map->map_ip;
1122 map->unmap_ip = new_map->unmap_ip;
1123 map__delete(new_map);
1124 /* Ensure maps are correctly ordered */
1125 map_groups__remove(kmaps, map);
1126 map_groups__insert(kmaps, map);
1127 } else {
1128 map_groups__insert(kmaps, new_map);
1129 }
1130 }
1131
1132 /*
1133 * Set the data type and long name so that kcore can be read via
1134 * dso__data_read_addr().
1135 */
1136 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001137 dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001138 else
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001139 dso->binary_type = DSO_BINARY_TYPE__KCORE;
Arnaldo Carvalho de Melo7e155d42013-12-10 15:08:44 -03001140 dso__set_long_name(dso, strdup(kcore_filename), true);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001141
1142 close(fd);
1143
1144 if (map->type == MAP__FUNCTION)
1145 pr_debug("Using %s for kernel object code\n", kcore_filename);
1146 else
1147 pr_debug("Using %s for kernel data\n", kcore_filename);
1148
1149 return 0;
1150
1151out_err:
1152 while (!list_empty(&md.maps)) {
1153 map = list_entry(md.maps.next, struct map, node);
1154 list_del(&map->node);
1155 map__delete(map);
1156 }
1157 close(fd);
1158 return -EINVAL;
1159}
1160
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001161/*
1162 * If the kernel is relocated at boot time, kallsyms won't match. Compute the
1163 * delta based on the relocation reference symbol.
1164 */
1165static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1166{
1167 struct kmap *kmap = map__kmap(map);
1168 u64 addr;
1169
1170 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1171 return 0;
1172
1173 addr = kallsyms__get_function_start(filename,
1174 kmap->ref_reloc_sym->name);
1175 if (!addr)
1176 return -1;
1177
1178 *delta = addr - kmap->ref_reloc_sym->addr;
1179 return 0;
1180}
1181
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001182int dso__load_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001183 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001184{
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001185 u64 delta = 0;
1186
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001187 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1188 return -1;
1189
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001190 if (dso__load_all_kallsyms(dso, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001191 return -1;
1192
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001193 if (kallsyms__delta(map, filename, &delta))
1194 return -1;
1195
Anton Blanchard694bf402011-08-24 16:40:17 +10001196 symbols__fixup_duplicate(&dso->symbols[map->type]);
Anton Blanchard3f5a4272011-08-24 16:40:15 +10001197 symbols__fixup_end(&dso->symbols[map->type]);
1198
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001199 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001200 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001201 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001202 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001203
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001204 if (!dso__load_kcore(dso, map, filename))
1205 return dso__split_kallsyms_for_kcore(dso, map, filter);
1206 else
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001207 return dso__split_kallsyms(dso, map, delta, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001208}
1209
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001210static int dso__load_perf_map(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001211 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +03001212{
1213 char *line = NULL;
1214 size_t n;
1215 FILE *file;
1216 int nr_syms = 0;
1217
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001218 file = fopen(dso->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +03001219 if (file == NULL)
1220 goto out_failure;
1221
1222 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001223 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001224 struct symbol *sym;
1225 int line_len, len;
1226
1227 line_len = getline(&line, &n, file);
1228 if (line_len < 0)
1229 break;
1230
1231 if (!line)
1232 goto out_failure;
1233
1234 line[--line_len] = '\0'; /* \n */
1235
1236 len = hex2u64(line, &start);
1237
1238 len++;
1239 if (len + 2 >= line_len)
1240 continue;
1241
1242 len += hex2u64(line + len, &size);
1243
1244 len++;
1245 if (len + 2 >= line_len)
1246 continue;
1247
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -03001248 sym = symbol__new(start, size, STB_GLOBAL, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001249
1250 if (sym == NULL)
1251 goto out_delete_line;
1252
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001253 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001254 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001255 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001256 symbols__insert(&dso->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001257 nr_syms++;
1258 }
1259 }
1260
1261 free(line);
1262 fclose(file);
1263
1264 return nr_syms;
1265
1266out_delete_line:
1267 free(line);
1268out_failure:
1269 return -1;
1270}
1271
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001272static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1273 enum dso_binary_type type)
1274{
1275 switch (type) {
1276 case DSO_BINARY_TYPE__JAVA_JIT:
1277 case DSO_BINARY_TYPE__DEBUGLINK:
1278 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1279 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1280 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1281 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1282 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
1283 return !kmod && dso->kernel == DSO_TYPE_USER;
1284
1285 case DSO_BINARY_TYPE__KALLSYMS:
1286 case DSO_BINARY_TYPE__VMLINUX:
1287 case DSO_BINARY_TYPE__KCORE:
1288 return dso->kernel == DSO_TYPE_KERNEL;
1289
1290 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1291 case DSO_BINARY_TYPE__GUEST_VMLINUX:
1292 case DSO_BINARY_TYPE__GUEST_KCORE:
1293 return dso->kernel == DSO_TYPE_GUEST_KERNEL;
1294
1295 case DSO_BINARY_TYPE__GUEST_KMODULE:
1296 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1297 /*
1298 * kernel modules know their symtab type - it's set when
1299 * creating a module dso in machine__new_module().
1300 */
1301 return kmod && dso->symtab_type == type;
1302
1303 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1304 return true;
1305
1306 case DSO_BINARY_TYPE__NOT_FOUND:
1307 default:
1308 return false;
1309 }
1310}
1311
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001312int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001313{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001314 char *name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001315 int ret = -1;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001316 u_int i;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001317 struct machine *machine;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001318 char *root_dir = (char *) "";
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001319 int ss_pos = 0;
1320 struct symsrc ss_[2];
1321 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001322 bool kmod;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001323
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001324 dso__set_loaded(dso, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001325
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001326 if (dso->kernel == DSO_TYPE_KERNEL)
1327 return dso__load_kernel_sym(dso, map, filter);
1328 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1329 return dso__load_guest_kernel_sym(dso, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001330
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001331 if (map->groups && map->groups->machine)
1332 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001333 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001334 machine = NULL;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001335
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001336 dso->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001337
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001338 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
Pekka Enberg981c1252011-08-09 22:54:18 +03001339 struct stat st;
1340
Vasiliy Kulikove9b52ef2011-08-12 00:55:37 +04001341 if (lstat(dso->name, &st) < 0)
Pekka Enberg981c1252011-08-09 22:54:18 +03001342 return -1;
1343
1344 if (st.st_uid && (st.st_uid != geteuid())) {
1345 pr_warning("File %s not owned by current user or root, "
1346 "ignoring it.\n", dso->name);
1347 return -1;
1348 }
1349
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001350 ret = dso__load_perf_map(dso, map, filter);
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001351 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
1352 DSO_BINARY_TYPE__NOT_FOUND;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001353 return ret;
1354 }
1355
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001356 if (machine)
1357 root_dir = machine->root_dir;
1358
David Ahern164c8002013-01-14 10:46:47 -07001359 name = malloc(PATH_MAX);
1360 if (!name)
1361 return -1;
1362
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001363 kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1364 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1365
1366 /*
1367 * Iterate over candidate debug images.
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001368 * Keep track of "interesting" ones (those which have a symtab, dynsym,
1369 * and/or opd section) for processing.
Dave Martin6da80ce2010-07-30 09:50:09 -03001370 */
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001371 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001372 struct symsrc *ss = &ss_[ss_pos];
1373 bool next_slot = false;
Dave Martin6da80ce2010-07-30 09:50:09 -03001374
Cody P Schafer005f9292012-08-10 15:22:58 -07001375 enum dso_binary_type symtab_type = binary_type_symtab[i];
Dave Martin6da80ce2010-07-30 09:50:09 -03001376
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001377 if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
1378 continue;
1379
Arnaldo Carvalho de Meloee4e9622013-12-16 17:03:18 -03001380 if (dso__read_binary_type_filename(dso, symtab_type,
1381 root_dir, name, PATH_MAX))
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001382 continue;
Dave Martin6da80ce2010-07-30 09:50:09 -03001383
1384 /* Name is now the name of the next image to try */
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001385 if (symsrc__init(ss, dso, name, symtab_type) < 0)
Dave Martin6da80ce2010-07-30 09:50:09 -03001386 continue;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001387
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001388 if (!syms_ss && symsrc__has_symtab(ss)) {
1389 syms_ss = ss;
1390 next_slot = true;
Adrian Hunter0058aef2013-12-03 09:23:08 +02001391 if (!dso->symsrc_filename)
1392 dso->symsrc_filename = strdup(name);
Cody P Schaferd26cd122012-08-10 15:23:00 -07001393 }
1394
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001395 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
1396 runtime_ss = ss;
1397 next_slot = true;
Cody P Schafera44f6052012-08-10 15:22:59 -07001398 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001399
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001400 if (next_slot) {
1401 ss_pos++;
Jiri Olsa33ff5812012-04-18 15:46:58 +02001402
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001403 if (syms_ss && runtime_ss)
1404 break;
Namhyung Kim98e9f032014-02-20 10:32:54 +09001405 } else {
1406 symsrc__destroy(ss);
Dave Martin6da80ce2010-07-30 09:50:09 -03001407 }
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001408
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001409 }
Dave Martin6da80ce2010-07-30 09:50:09 -03001410
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001411 if (!runtime_ss && !syms_ss)
1412 goto out_free;
1413
1414 if (runtime_ss && !syms_ss) {
1415 syms_ss = runtime_ss;
Arnaldo Carvalho de Melo60e4b102011-03-22 15:42:14 -03001416 }
1417
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001418 /* We'll have to hope for the best */
1419 if (!runtime_ss && syms_ss)
1420 runtime_ss = syms_ss;
1421
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001422 if (syms_ss)
1423 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
1424 else
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001425 ret = -1;
1426
David Ahernf47b58b2012-08-19 09:47:14 -06001427 if (ret > 0) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001428 int nr_plt;
1429
1430 nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
1431 if (nr_plt > 0)
1432 ret += nr_plt;
1433 }
1434
1435 for (; ss_pos > 0; ss_pos--)
1436 symsrc__destroy(&ss_[ss_pos - 1]);
1437out_free:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001438 free(name);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001439 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001440 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001441 return ret;
1442}
1443
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001444struct map *map_groups__find_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001445 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001446{
1447 struct rb_node *nd;
1448
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001449 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001450 struct map *map = rb_entry(nd, struct map, rb_node);
1451
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001452 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001453 return map;
1454 }
1455
1456 return NULL;
1457}
1458
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001459int dso__load_vmlinux(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001460 const char *vmlinux, bool vmlinux_allocated,
1461 symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001462{
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001463 int err = -1;
1464 struct symsrc ss;
David Ahernec5761e2010-12-09 13:27:07 -07001465 char symfs_vmlinux[PATH_MAX];
Cody P Schafer005f9292012-08-10 15:22:58 -07001466 enum dso_binary_type symtab_type;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001467
Namhyung Kim5698d2c2013-07-17 17:08:15 +09001468 if (vmlinux[0] == '/')
1469 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
1470 else
Arnaldo Carvalho de Melo972f3932014-07-29 10:21:58 -03001471 symbol__join_symfs(symfs_vmlinux, vmlinux);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001472
Cody P Schafer21ea4532012-08-10 15:22:56 -07001473 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Cody P Schafer005f9292012-08-10 15:22:58 -07001474 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001475 else
Cody P Schafer005f9292012-08-10 15:22:58 -07001476 symtab_type = DSO_BINARY_TYPE__VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001477
Cody P Schafer005f9292012-08-10 15:22:58 -07001478 if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001479 return -1;
1480
Cody P Schafer261360b2012-08-10 15:23:01 -07001481 err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001482 symsrc__destroy(&ss);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001483
Cody P Schafer515850e2012-08-10 15:22:54 -07001484 if (err > 0) {
Adrian Hunter39b12f782013-08-07 14:38:47 +03001485 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001486 dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
Adrian Hunter39b12f782013-08-07 14:38:47 +03001487 else
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001488 dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
Arnaldo Carvalho de Melobf4414a2013-12-10 15:19:23 -03001489 dso__set_long_name(dso, vmlinux, vmlinux_allocated);
Cody P Schafer515850e2012-08-10 15:22:54 -07001490 dso__set_loaded(dso, map->type);
David Ahernec5761e2010-12-09 13:27:07 -07001491 pr_debug("Using %s for symbols\n", symfs_vmlinux);
Cody P Schafer515850e2012-08-10 15:22:54 -07001492 }
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001493
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001494 return err;
1495}
1496
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001497int dso__load_vmlinux_path(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001498 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001499{
1500 int i, err = 0;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001501 char *filename;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001502
1503 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001504 vmlinux_path__nr_entries + 1);
1505
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001506 filename = dso__build_id_filename(dso, NULL, 0);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001507 if (filename != NULL) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001508 err = dso__load_vmlinux(dso, map, filename, true, filter);
1509 if (err > 0)
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001510 goto out;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001511 free(filename);
1512 }
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001513
1514 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001515 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1516 if (err > 0)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001517 break;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001518 }
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001519out:
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001520 return err;
1521}
1522
Adrian Hunter0544d422013-10-14 13:43:43 +03001523static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1524{
1525 char kallsyms_filename[PATH_MAX];
1526 struct dirent *dent;
1527 int ret = -1;
1528 DIR *d;
1529
1530 d = opendir(dir);
1531 if (!d)
1532 return -1;
1533
1534 while (1) {
1535 dent = readdir(d);
1536 if (!dent)
1537 break;
1538 if (dent->d_type != DT_DIR)
1539 continue;
1540 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1541 "%s/%s/kallsyms", dir, dent->d_name);
Adrian Huntera00d28c2014-01-29 16:14:41 +02001542 if (!validate_kcore_addresses(kallsyms_filename, map)) {
Adrian Hunter0544d422013-10-14 13:43:43 +03001543 strlcpy(dir, kallsyms_filename, dir_sz);
1544 ret = 0;
1545 break;
1546 }
1547 }
1548
1549 closedir(d);
1550
1551 return ret;
1552}
1553
1554static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1555{
1556 u8 host_build_id[BUILD_ID_SIZE];
1557 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1558 bool is_host = false;
1559 char path[PATH_MAX];
1560
1561 if (!dso->has_build_id) {
1562 /*
1563 * Last resort, if we don't have a build-id and couldn't find
1564 * any vmlinux file, try the running kernel kallsyms table.
1565 */
1566 goto proc_kallsyms;
1567 }
1568
1569 if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
1570 sizeof(host_build_id)) == 0)
1571 is_host = dso__build_id_equal(dso, host_build_id);
1572
1573 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1574
Adrian Hunter449867e2013-11-26 15:19:24 +02001575 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1576 sbuild_id);
1577
Adrian Hunter0544d422013-10-14 13:43:43 +03001578 /* Use /proc/kallsyms if possible */
1579 if (is_host) {
1580 DIR *d;
1581 int fd;
1582
1583 /* If no cached kcore go with /proc/kallsyms */
Adrian Hunter0544d422013-10-14 13:43:43 +03001584 d = opendir(path);
1585 if (!d)
1586 goto proc_kallsyms;
1587 closedir(d);
1588
1589 /*
1590 * Do not check the build-id cache, until we know we cannot use
1591 * /proc/kcore.
1592 */
1593 fd = open("/proc/kcore", O_RDONLY);
1594 if (fd != -1) {
1595 close(fd);
1596 /* If module maps match go with /proc/kallsyms */
Adrian Huntera00d28c2014-01-29 16:14:41 +02001597 if (!validate_kcore_addresses("/proc/kallsyms", map))
Adrian Hunter0544d422013-10-14 13:43:43 +03001598 goto proc_kallsyms;
1599 }
1600
1601 /* Find kallsyms in build-id cache with kcore */
1602 if (!find_matching_kcore(map, path, sizeof(path)))
1603 return strdup(path);
1604
1605 goto proc_kallsyms;
1606 }
1607
Adrian Hunter449867e2013-11-26 15:19:24 +02001608 /* Find kallsyms in build-id cache with kcore */
1609 if (!find_matching_kcore(map, path, sizeof(path)))
1610 return strdup(path);
1611
Adrian Hunter0544d422013-10-14 13:43:43 +03001612 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1613 buildid_dir, sbuild_id);
1614
1615 if (access(path, F_OK)) {
1616 pr_err("No kallsyms or vmlinux with build-id %s was found\n",
1617 sbuild_id);
1618 return NULL;
1619 }
1620
1621 return strdup(path);
1622
1623proc_kallsyms:
1624 return strdup("/proc/kallsyms");
1625}
1626
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001627static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001628 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001629{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001630 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001631 const char *kallsyms_filename = NULL;
1632 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001633 /*
David Ahernb226a5a72010-12-07 19:39:46 -07001634 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1635 * it and only it, reporting errors to the user if it cannot be used.
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001636 *
1637 * For instance, try to analyse an ARM perf.data file _without_ a
1638 * build-id, or if the user specifies the wrong path to the right
1639 * vmlinux file, obviously we can't fallback to another vmlinux (a
1640 * x86_86 one, on the machine where analysis is being performed, say),
1641 * or worse, /proc/kallsyms.
1642 *
1643 * If the specified file _has_ a build-id and there is a build-id
1644 * section in the perf.data file, we will still do the expected
1645 * validation in dso__load_vmlinux and will bail out if they don't
1646 * match.
1647 */
David Ahernb226a5a72010-12-07 19:39:46 -07001648 if (symbol_conf.kallsyms_name != NULL) {
1649 kallsyms_filename = symbol_conf.kallsyms_name;
1650 goto do_kallsyms;
1651 }
1652
Willy Tarreaufc2be692013-09-14 10:32:59 +02001653 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001654 return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
1655 false, filter);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001656 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001657
Willy Tarreaufc2be692013-09-14 10:32:59 +02001658 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001659 err = dso__load_vmlinux_path(dso, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001660 if (err > 0)
Adrian Hunter39b12f782013-08-07 14:38:47 +03001661 return err;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001662 }
1663
David Ahernec5761e2010-12-09 13:27:07 -07001664 /* do not try local files if a symfs was given */
1665 if (symbol_conf.symfs[0] != 0)
1666 return -1;
1667
Adrian Hunter0544d422013-10-14 13:43:43 +03001668 kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
1669 if (!kallsyms_allocated_filename)
1670 return -1;
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001671
Adrian Hunter0544d422013-10-14 13:43:43 +03001672 kallsyms_filename = kallsyms_allocated_filename;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001673
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001674do_kallsyms:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001675 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001676 if (err > 0)
1677 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001678 free(kallsyms_allocated_filename);
1679
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001680 if (err > 0 && !dso__is_kcore(dso)) {
Adrian Hunterbdac0bc2014-07-14 13:02:43 +03001681 dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melobf4414a2013-12-10 15:19:23 -03001682 dso__set_long_name(dso, "[kernel.kallsyms]", false);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001683 map__fixup_start(map);
1684 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001685 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001686
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001687 return err;
1688}
1689
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001690static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1691 symbol_filter_t filter)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001692{
1693 int err;
1694 const char *kallsyms_filename = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001695 struct machine *machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001696 char path[PATH_MAX];
1697
1698 if (!map->groups) {
1699 pr_debug("Guest kernel map hasn't the point to groups\n");
1700 return -1;
1701 }
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001702 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001703
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001704 if (machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001705 /*
1706 * if the user specified a vmlinux filename, use it and only
1707 * it, reporting errors to the user if it cannot be used.
1708 * Or use file guest_kallsyms inputted by user on commandline
1709 */
1710 if (symbol_conf.default_guest_vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001711 err = dso__load_vmlinux(dso, map,
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001712 symbol_conf.default_guest_vmlinux_name,
1713 false, filter);
Adrian Hunter39b12f782013-08-07 14:38:47 +03001714 return err;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001715 }
1716
1717 kallsyms_filename = symbol_conf.default_guest_kallsyms;
1718 if (!kallsyms_filename)
1719 return -1;
1720 } else {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001721 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001722 kallsyms_filename = path;
1723 }
1724
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001725 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001726 if (err > 0)
Adrian Hunter39b12f782013-08-07 14:38:47 +03001727 pr_debug("Using %s for symbols\n", kallsyms_filename);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001728 if (err > 0 && !dso__is_kcore(dso)) {
Adrian Hunterbdac0bc2014-07-14 13:02:43 +03001729 dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Adrian Hunter39b12f782013-08-07 14:38:47 +03001730 machine__mmap_name(machine, path, sizeof(path));
Arnaldo Carvalho de Melo7e155d42013-12-10 15:08:44 -03001731 dso__set_long_name(dso, strdup(path), true);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001732 map__fixup_start(map);
1733 map__fixup_end(map);
1734 }
1735
1736 return err;
1737}
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001738
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001739static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001740{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001741 while (--vmlinux_path__nr_entries >= 0)
1742 zfree(&vmlinux_path[vmlinux_path__nr_entries]);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001743
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001744 zfree(&vmlinux_path);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001745}
1746
1747static int vmlinux_path__init(void)
1748{
1749 struct utsname uts;
1750 char bf[PATH_MAX];
1751
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001752 vmlinux_path = malloc(sizeof(char *) * 5);
1753 if (vmlinux_path == NULL)
1754 return -1;
1755
1756 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1757 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1758 goto out_fail;
1759 ++vmlinux_path__nr_entries;
1760 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1761 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1762 goto out_fail;
1763 ++vmlinux_path__nr_entries;
David Ahernec5761e2010-12-09 13:27:07 -07001764
1765 /* only try running kernel version if no symfs was given */
1766 if (symbol_conf.symfs[0] != 0)
1767 return 0;
1768
1769 if (uname(&uts) < 0)
1770 return -1;
1771
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001772 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1773 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1774 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1775 goto out_fail;
1776 ++vmlinux_path__nr_entries;
1777 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1778 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1779 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1780 goto out_fail;
1781 ++vmlinux_path__nr_entries;
1782 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1783 uts.release);
1784 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1785 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1786 goto out_fail;
1787 ++vmlinux_path__nr_entries;
1788
1789 return 0;
1790
1791out_fail:
1792 vmlinux_path__exit();
1793 return -1;
1794}
1795
David Ahern3bfe5f82013-11-18 13:32:48 -07001796int setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001797 const char *list_name)
1798{
1799 if (list_str == NULL)
1800 return 0;
1801
1802 *list = strlist__new(true, list_str);
1803 if (!*list) {
1804 pr_err("problems parsing %s list\n", list_name);
1805 return -1;
1806 }
1807 return 0;
1808}
1809
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001810static bool symbol__read_kptr_restrict(void)
1811{
1812 bool value = false;
1813
1814 if (geteuid() != 0) {
1815 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1816 if (fp != NULL) {
1817 char line[8];
1818
1819 if (fgets(line, sizeof(line), fp) != NULL)
1820 value = atoi(line) != 0;
1821
1822 fclose(fp);
1823 }
1824 }
1825
1826 return value;
1827}
1828
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001829int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001830{
David Ahernec5761e2010-12-09 13:27:07 -07001831 const char *symfs;
1832
Jovi Zhang85e00b52010-09-09 13:30:59 -03001833 if (symbol_conf.initialized)
1834 return 0;
1835
Irina Tirdea9ac3e482012-09-11 01:15:01 +03001836 symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
David S. Miller4d439512011-03-29 14:18:39 -03001837
Namhyung Kim166ccc92012-08-06 13:41:19 +09001838 symbol__elf_init();
1839
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001840 if (symbol_conf.sort_by_name)
1841 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1842 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001843
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001844 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001845 return -1;
1846
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001847 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1848 pr_err("'.' is the only non valid --field-separator argument\n");
1849 return -1;
1850 }
1851
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001852 if (setup_list(&symbol_conf.dso_list,
1853 symbol_conf.dso_list_str, "dso") < 0)
1854 return -1;
1855
1856 if (setup_list(&symbol_conf.comm_list,
1857 symbol_conf.comm_list_str, "comm") < 0)
1858 goto out_free_dso_list;
1859
1860 if (setup_list(&symbol_conf.sym_list,
1861 symbol_conf.sym_list_str, "symbol") < 0)
1862 goto out_free_comm_list;
1863
David Ahernec5761e2010-12-09 13:27:07 -07001864 /*
1865 * A path to symbols of "/" is identical to ""
1866 * reset here for simplicity.
1867 */
1868 symfs = realpath(symbol_conf.symfs, NULL);
1869 if (symfs == NULL)
1870 symfs = symbol_conf.symfs;
1871 if (strcmp(symfs, "/") == 0)
1872 symbol_conf.symfs = "";
1873 if (symfs != symbol_conf.symfs)
1874 free((void *)symfs);
1875
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001876 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
1877
Jovi Zhang85e00b52010-09-09 13:30:59 -03001878 symbol_conf.initialized = true;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001879 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001880
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001881out_free_comm_list:
1882 strlist__delete(symbol_conf.comm_list);
Namhyung Kimd74c8962011-12-13 00:16:52 +09001883out_free_dso_list:
1884 strlist__delete(symbol_conf.dso_list);
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001885 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001886}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001887
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001888void symbol__exit(void)
1889{
Jovi Zhang85e00b52010-09-09 13:30:59 -03001890 if (!symbol_conf.initialized)
1891 return;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001892 strlist__delete(symbol_conf.sym_list);
1893 strlist__delete(symbol_conf.dso_list);
1894 strlist__delete(symbol_conf.comm_list);
1895 vmlinux_path__exit();
1896 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
Jovi Zhang85e00b52010-09-09 13:30:59 -03001897 symbol_conf.initialized = false;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001898}