blob: 009a9d064f11d80ca665b6b8734a3065323ad5ec [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
Arnaldo Carvalho de Meloe7110b92014-08-08 18:00:39 -0300526/*
527 * These are symbols in the kernel image, so make sure that
528 * sym is from a kernel DSO.
529 */
David Ahern82d1deb2013-11-18 13:32:45 -0700530bool symbol__is_idle(struct symbol *sym)
531{
532 const char * const idle_symbols[] = {
533 "cpu_idle",
Arnaldo Carvalho de Meloe0336ed2014-08-08 18:02:41 -0300534 "cpu_startup_entry",
David Ahern82d1deb2013-11-18 13:32:45 -0700535 "intel_idle",
536 "default_idle",
537 "native_safe_halt",
538 "enter_idle",
539 "exit_idle",
540 "mwait_idle",
541 "mwait_idle_with_hints",
542 "poll_idle",
543 "ppc64_runlatch_off",
544 "pseries_dedicated_idle_sleep",
545 NULL
546 };
547
548 int i;
549
550 if (!sym)
551 return false;
552
553 for (i = 0; idle_symbols[i]; i++) {
554 if (!strcmp(idle_symbols[i], sym->name))
555 return true;
556 }
557
558 return false;
559}
560
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200561static int map__process_kallsym_symbol(void *arg, const char *name,
Cody P Schafer82151522012-08-10 15:22:48 -0700562 char type, u64 start)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200563{
564 struct symbol *sym;
565 struct process_kallsyms_args *a = arg;
566 struct rb_root *root = &a->dso->symbols[a->map->type];
567
568 if (!symbol_type__is_a(type, a->map->type))
569 return 0;
570
Cody P Schafer82151522012-08-10 15:22:48 -0700571 /*
572 * module symbols are not sorted so we add all
573 * symbols, setting length to 0, and rely on
574 * symbols__fixup_end() to fix it up.
575 */
576 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200577 if (sym == NULL)
578 return -ENOMEM;
579 /*
580 * We will pass the symbols to the filter later, in
581 * map__split_kallsyms, when we have split the maps per module
582 */
583 symbols__insert(root, sym);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800584
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200585 return 0;
586}
587
588/*
589 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
590 * so that we can in the next step set the symbol ->end address and then
591 * call kernel_maps__split_kallsyms.
592 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300593static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200594 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200595{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300596 struct process_kallsyms_args args = { .map = map, .dso = dso, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200597 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200598}
599
Adrian Hunter8e0cf962013-08-07 14:38:51 +0300600static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
601 symbol_filter_t filter)
602{
603 struct map_groups *kmaps = map__kmap(map)->kmaps;
604 struct map *curr_map;
605 struct symbol *pos;
606 int count = 0, moved = 0;
607 struct rb_root *root = &dso->symbols[map->type];
608 struct rb_node *next = rb_first(root);
609
610 while (next) {
611 char *module;
612
613 pos = rb_entry(next, struct symbol, rb_node);
614 next = rb_next(&pos->rb_node);
615
616 module = strchr(pos->name, '\t');
617 if (module)
618 *module = '\0';
619
620 curr_map = map_groups__find(kmaps, map->type, pos->start);
621
622 if (!curr_map || (filter && filter(curr_map, pos))) {
623 rb_erase(&pos->rb_node, root);
624 symbol__delete(pos);
625 } else {
626 pos->start -= curr_map->start - curr_map->pgoff;
627 if (pos->end)
628 pos->end -= curr_map->start - curr_map->pgoff;
629 if (curr_map != map) {
630 rb_erase(&pos->rb_node, root);
631 symbols__insert(
632 &curr_map->dso->symbols[curr_map->type],
633 pos);
634 ++moved;
635 } else {
636 ++count;
637 }
638 }
639 }
640
641 /* Symbols have been adjusted */
642 dso->adjust_symbols = 1;
643
644 return count + moved;
645}
646
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300647/*
648 * Split the symbols into maps, making sure there are no overlaps, i.e. the
649 * kernel range is broken in several maps, named [kernel].N, as we don't have
650 * the original ELF section names vmlinux have.
651 */
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200652static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200653 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300654{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200655 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300656 struct machine *machine = kmaps->machine;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200657 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300658 struct symbol *pos;
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200659 int count = 0, moved = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300660 struct rb_root *root = &dso->symbols[map->type];
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200661 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300662 int kernel_range = 0;
663
664 while (next) {
665 char *module;
666
667 pos = rb_entry(next, struct symbol, rb_node);
668 next = rb_next(&pos->rb_node);
669
670 module = strchr(pos->name, '\t');
671 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200672 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200673 goto discard_symbol;
674
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300675 *module++ = '\0';
676
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200677 if (strcmp(curr_map->dso->short_name, module)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800678 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300679 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300680 machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800681 /*
682 * We assume all symbols of a module are
683 * continuous in * kallsyms, so curr_map
684 * points to a module and all its
685 * symbols are in its kmap. Mark it as
686 * loaded.
687 */
688 dso__set_loaded(curr_map->dso,
689 curr_map->type);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300690 }
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200691
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800692 curr_map = map_groups__find_by_name(kmaps,
693 map->type, module);
694 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2f519032010-05-17 17:57:59 -0300695 pr_debug("%s/proc/{kallsyms,modules} "
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800696 "inconsistency while looking "
697 "for \"%s\" module!\n",
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300698 machine->root_dir, module);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800699 curr_map = map;
700 goto discard_symbol;
701 }
702
703 if (curr_map->dso->loaded &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300704 !machine__is_default_guest(machine))
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200705 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300706 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300707 /*
708 * So that we look just like we get from .ko files,
709 * i.e. not prelinked, relative to map->start.
710 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200711 pos->start = curr_map->map_ip(curr_map, pos->start);
712 pos->end = curr_map->map_ip(curr_map, pos->end);
713 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300714 char dso_name[PATH_MAX];
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300715 struct dso *ndso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300716
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200717 if (delta) {
718 /* Kernel was relocated at boot time */
719 pos->start -= delta;
720 pos->end -= delta;
721 }
722
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200723 if (count == 0) {
724 curr_map = map;
725 goto filter_symbol;
726 }
727
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300728 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800729 snprintf(dso_name, sizeof(dso_name),
730 "[guest.kernel].%d",
731 kernel_range++);
732 else
733 snprintf(dso_name, sizeof(dso_name),
734 "[kernel].%d",
735 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300736
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300737 ndso = dso__new(dso_name);
738 if (ndso == NULL)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300739 return -1;
740
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300741 ndso->kernel = dso->kernel;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800742
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300743 curr_map = map__new2(pos->start, ndso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800744 if (curr_map == NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300745 dso__delete(ndso);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300746 return -1;
747 }
748
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200749 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200750 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300751 ++kernel_range;
Adrian Hunterd9b62ab2014-01-29 16:14:43 +0200752 } else if (delta) {
753 /* Kernel was relocated at boot time */
754 pos->start -= delta;
755 pos->end -= delta;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300756 }
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200757filter_symbol:
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200758 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200759discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200760 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300761 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200762 if (curr_map != map) {
763 rb_erase(&pos->rb_node, root);
764 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200765 ++moved;
766 } else
767 ++count;
Mike Galbraith9974f492009-07-02 08:05:58 +0200768 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300769 }
770
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800771 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300772 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300773 machine__is_default_guest(kmaps->machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800774 dso__set_loaded(curr_map->dso, curr_map->type);
775 }
776
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200777 return count + moved;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300778}
779
Arnaldo Carvalho de Melo3f067dc2012-12-07 17:39:39 -0300780bool symbol__restricted_filename(const char *filename,
781 const char *restricted_filename)
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300782{
783 bool restricted = false;
784
785 if (symbol_conf.kptr_restrict) {
786 char *r = realpath(filename, NULL);
787
788 if (r != NULL) {
789 restricted = strcmp(r, restricted_filename) == 0;
790 free(r);
791 return restricted;
792 }
793 }
794
795 return restricted;
796}
797
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300798struct module_info {
799 struct rb_node rb_node;
800 char *name;
801 u64 start;
802};
803
804static void add_module(struct module_info *mi, struct rb_root *modules)
805{
806 struct rb_node **p = &modules->rb_node;
807 struct rb_node *parent = NULL;
808 struct module_info *m;
809
810 while (*p != NULL) {
811 parent = *p;
812 m = rb_entry(parent, struct module_info, rb_node);
813 if (strcmp(mi->name, m->name) < 0)
814 p = &(*p)->rb_left;
815 else
816 p = &(*p)->rb_right;
817 }
818 rb_link_node(&mi->rb_node, parent, p);
819 rb_insert_color(&mi->rb_node, modules);
820}
821
822static void delete_modules(struct rb_root *modules)
823{
824 struct module_info *mi;
825 struct rb_node *next = rb_first(modules);
826
827 while (next) {
828 mi = rb_entry(next, struct module_info, rb_node);
829 next = rb_next(&mi->rb_node);
830 rb_erase(&mi->rb_node, modules);
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300831 zfree(&mi->name);
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300832 free(mi);
833 }
834}
835
836static struct module_info *find_module(const char *name,
837 struct rb_root *modules)
838{
839 struct rb_node *n = modules->rb_node;
840
841 while (n) {
842 struct module_info *m;
843 int cmp;
844
845 m = rb_entry(n, struct module_info, rb_node);
846 cmp = strcmp(name, m->name);
847 if (cmp < 0)
848 n = n->rb_left;
849 else if (cmp > 0)
850 n = n->rb_right;
851 else
852 return m;
853 }
854
855 return NULL;
856}
857
858static int __read_proc_modules(void *arg, const char *name, u64 start)
859{
860 struct rb_root *modules = arg;
861 struct module_info *mi;
862
863 mi = zalloc(sizeof(struct module_info));
864 if (!mi)
865 return -ENOMEM;
866
867 mi->name = strdup(name);
868 mi->start = start;
869
870 if (!mi->name) {
871 free(mi);
872 return -ENOMEM;
873 }
874
875 add_module(mi, modules);
876
877 return 0;
878}
879
880static int read_proc_modules(const char *filename, struct rb_root *modules)
881{
882 if (symbol__restricted_filename(filename, "/proc/modules"))
883 return -1;
884
885 if (modules__parse(filename, modules, __read_proc_modules)) {
886 delete_modules(modules);
887 return -1;
888 }
889
890 return 0;
891}
892
Adrian Hunterfc1b6912013-10-14 16:57:29 +0300893int compare_proc_modules(const char *from, const char *to)
894{
895 struct rb_root from_modules = RB_ROOT;
896 struct rb_root to_modules = RB_ROOT;
897 struct rb_node *from_node, *to_node;
898 struct module_info *from_m, *to_m;
899 int ret = -1;
900
901 if (read_proc_modules(from, &from_modules))
902 return -1;
903
904 if (read_proc_modules(to, &to_modules))
905 goto out_delete_from;
906
907 from_node = rb_first(&from_modules);
908 to_node = rb_first(&to_modules);
909 while (from_node) {
910 if (!to_node)
911 break;
912
913 from_m = rb_entry(from_node, struct module_info, rb_node);
914 to_m = rb_entry(to_node, struct module_info, rb_node);
915
916 if (from_m->start != to_m->start ||
917 strcmp(from_m->name, to_m->name))
918 break;
919
920 from_node = rb_next(from_node);
921 to_node = rb_next(to_node);
922 }
923
924 if (!from_node && !to_node)
925 ret = 0;
926
927 delete_modules(&to_modules);
928out_delete_from:
929 delete_modules(&from_modules);
930
931 return ret;
932}
933
Adrian Hunter52afdaf2013-10-09 15:01:11 +0300934static int do_validate_kcore_modules(const char *filename, struct map *map,
935 struct map_groups *kmaps)
936{
937 struct rb_root modules = RB_ROOT;
938 struct map *old_map;
939 int err;
940
941 err = read_proc_modules(filename, &modules);
942 if (err)
943 return err;
944
945 old_map = map_groups__first(kmaps, map->type);
946 while (old_map) {
947 struct map *next = map_groups__next(old_map);
948 struct module_info *mi;
949
950 if (old_map == map || old_map->start == map->start) {
951 /* The kernel map */
952 old_map = next;
953 continue;
954 }
955
956 /* Module must be in memory at the same address */
957 mi = find_module(old_map->dso->short_name, &modules);
958 if (!mi || mi->start != old_map->start) {
959 err = -EINVAL;
960 goto out;
961 }
962
963 old_map = next;
964 }
965out:
966 delete_modules(&modules);
967 return err;
968}
969
970/*
971 * If kallsyms is referenced by name then we look for filename in the same
972 * directory.
973 */
974static bool filename_from_kallsyms_filename(char *filename,
975 const char *base_name,
976 const char *kallsyms_filename)
977{
978 char *name;
979
980 strcpy(filename, kallsyms_filename);
981 name = strrchr(filename, '/');
982 if (!name)
983 return false;
984
985 name += 1;
986
987 if (!strcmp(name, "kallsyms")) {
988 strcpy(name, base_name);
989 return true;
990 }
991
992 return false;
993}
994
995static int validate_kcore_modules(const char *kallsyms_filename,
996 struct map *map)
997{
998 struct map_groups *kmaps = map__kmap(map)->kmaps;
999 char modules_filename[PATH_MAX];
1000
1001 if (!filename_from_kallsyms_filename(modules_filename, "modules",
1002 kallsyms_filename))
1003 return -EINVAL;
1004
1005 if (do_validate_kcore_modules(modules_filename, map, kmaps))
1006 return -EINVAL;
1007
1008 return 0;
1009}
1010
Adrian Huntera00d28c2014-01-29 16:14:41 +02001011static int validate_kcore_addresses(const char *kallsyms_filename,
1012 struct map *map)
1013{
1014 struct kmap *kmap = map__kmap(map);
1015
1016 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1017 u64 start;
1018
1019 start = kallsyms__get_function_start(kallsyms_filename,
1020 kmap->ref_reloc_sym->name);
1021 if (start != kmap->ref_reloc_sym->addr)
1022 return -EINVAL;
1023 }
1024
1025 return validate_kcore_modules(kallsyms_filename, map);
1026}
1027
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001028struct kcore_mapfn_data {
1029 struct dso *dso;
1030 enum map_type type;
1031 struct list_head maps;
1032};
1033
1034static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
1035{
1036 struct kcore_mapfn_data *md = data;
1037 struct map *map;
1038
1039 map = map__new2(start, md->dso, md->type);
1040 if (map == NULL)
1041 return -ENOMEM;
1042
1043 map->end = map->start + len;
1044 map->pgoff = pgoff;
1045
1046 list_add(&map->node, &md->maps);
1047
1048 return 0;
1049}
1050
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001051static int dso__load_kcore(struct dso *dso, struct map *map,
1052 const char *kallsyms_filename)
1053{
1054 struct map_groups *kmaps = map__kmap(map)->kmaps;
1055 struct machine *machine = kmaps->machine;
1056 struct kcore_mapfn_data md;
1057 struct map *old_map, *new_map, *replacement_map = NULL;
1058 bool is_64_bit;
1059 int err, fd;
1060 char kcore_filename[PATH_MAX];
1061 struct symbol *sym;
1062
1063 /* This function requires that the map is the kernel map */
1064 if (map != machine->vmlinux_maps[map->type])
1065 return -EINVAL;
1066
Adrian Hunter52afdaf2013-10-09 15:01:11 +03001067 if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
1068 kallsyms_filename))
1069 return -EINVAL;
1070
Adrian Huntera00d28c2014-01-29 16:14:41 +02001071 /* Modules and kernel must be present at their original addresses */
1072 if (validate_kcore_addresses(kallsyms_filename, map))
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001073 return -EINVAL;
1074
1075 md.dso = dso;
1076 md.type = map->type;
1077 INIT_LIST_HEAD(&md.maps);
1078
1079 fd = open(kcore_filename, O_RDONLY);
1080 if (fd < 0)
1081 return -EINVAL;
1082
1083 /* Read new maps into temporary lists */
1084 err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
1085 &is_64_bit);
1086 if (err)
1087 goto out_err;
Adrian Hunterc6d8f2a2014-07-14 13:02:41 +03001088 dso->is_64_bit = is_64_bit;
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001089
1090 if (list_empty(&md.maps)) {
1091 err = -EINVAL;
1092 goto out_err;
1093 }
1094
1095 /* Remove old maps */
1096 old_map = map_groups__first(kmaps, map->type);
1097 while (old_map) {
1098 struct map *next = map_groups__next(old_map);
1099
1100 if (old_map != map)
1101 map_groups__remove(kmaps, old_map);
1102 old_map = next;
1103 }
1104
1105 /* Find the kernel map using the first symbol */
1106 sym = dso__first_symbol(dso, map->type);
1107 list_for_each_entry(new_map, &md.maps, node) {
1108 if (sym && sym->start >= new_map->start &&
1109 sym->start < new_map->end) {
1110 replacement_map = new_map;
1111 break;
1112 }
1113 }
1114
1115 if (!replacement_map)
1116 replacement_map = list_entry(md.maps.next, struct map, node);
1117
1118 /* Add new maps */
1119 while (!list_empty(&md.maps)) {
1120 new_map = list_entry(md.maps.next, struct map, node);
1121 list_del(&new_map->node);
1122 if (new_map == replacement_map) {
1123 map->start = new_map->start;
1124 map->end = new_map->end;
1125 map->pgoff = new_map->pgoff;
1126 map->map_ip = new_map->map_ip;
1127 map->unmap_ip = new_map->unmap_ip;
1128 map__delete(new_map);
1129 /* Ensure maps are correctly ordered */
1130 map_groups__remove(kmaps, map);
1131 map_groups__insert(kmaps, map);
1132 } else {
1133 map_groups__insert(kmaps, new_map);
1134 }
1135 }
1136
1137 /*
1138 * Set the data type and long name so that kcore can be read via
1139 * dso__data_read_addr().
1140 */
1141 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001142 dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001143 else
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001144 dso->binary_type = DSO_BINARY_TYPE__KCORE;
Arnaldo Carvalho de Melo7e155d42013-12-10 15:08:44 -03001145 dso__set_long_name(dso, strdup(kcore_filename), true);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001146
1147 close(fd);
1148
1149 if (map->type == MAP__FUNCTION)
1150 pr_debug("Using %s for kernel object code\n", kcore_filename);
1151 else
1152 pr_debug("Using %s for kernel data\n", kcore_filename);
1153
1154 return 0;
1155
1156out_err:
1157 while (!list_empty(&md.maps)) {
1158 map = list_entry(md.maps.next, struct map, node);
1159 list_del(&map->node);
1160 map__delete(map);
1161 }
1162 close(fd);
1163 return -EINVAL;
1164}
1165
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001166/*
1167 * If the kernel is relocated at boot time, kallsyms won't match. Compute the
1168 * delta based on the relocation reference symbol.
1169 */
1170static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1171{
1172 struct kmap *kmap = map__kmap(map);
1173 u64 addr;
1174
1175 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1176 return 0;
1177
1178 addr = kallsyms__get_function_start(filename,
1179 kmap->ref_reloc_sym->name);
1180 if (!addr)
1181 return -1;
1182
1183 *delta = addr - kmap->ref_reloc_sym->addr;
1184 return 0;
1185}
1186
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001187int dso__load_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001188 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001189{
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001190 u64 delta = 0;
1191
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001192 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1193 return -1;
1194
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001195 if (dso__load_all_kallsyms(dso, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001196 return -1;
1197
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001198 if (kallsyms__delta(map, filename, &delta))
1199 return -1;
1200
Anton Blanchard694bf402011-08-24 16:40:17 +10001201 symbols__fixup_duplicate(&dso->symbols[map->type]);
Anton Blanchard3f5a4272011-08-24 16:40:15 +10001202 symbols__fixup_end(&dso->symbols[map->type]);
1203
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001204 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001205 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001206 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001207 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001208
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001209 if (!dso__load_kcore(dso, map, filename))
1210 return dso__split_kallsyms_for_kcore(dso, map, filter);
1211 else
Adrian Hunterd9b62ab2014-01-29 16:14:43 +02001212 return dso__split_kallsyms(dso, map, delta, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001213}
1214
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001215static int dso__load_perf_map(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001216 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +03001217{
1218 char *line = NULL;
1219 size_t n;
1220 FILE *file;
1221 int nr_syms = 0;
1222
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001223 file = fopen(dso->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +03001224 if (file == NULL)
1225 goto out_failure;
1226
1227 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001228 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001229 struct symbol *sym;
1230 int line_len, len;
1231
1232 line_len = getline(&line, &n, file);
1233 if (line_len < 0)
1234 break;
1235
1236 if (!line)
1237 goto out_failure;
1238
1239 line[--line_len] = '\0'; /* \n */
1240
1241 len = hex2u64(line, &start);
1242
1243 len++;
1244 if (len + 2 >= line_len)
1245 continue;
1246
1247 len += hex2u64(line + len, &size);
1248
1249 len++;
1250 if (len + 2 >= line_len)
1251 continue;
1252
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -03001253 sym = symbol__new(start, size, STB_GLOBAL, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001254
1255 if (sym == NULL)
1256 goto out_delete_line;
1257
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001258 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001259 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001260 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001261 symbols__insert(&dso->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +03001262 nr_syms++;
1263 }
1264 }
1265
1266 free(line);
1267 fclose(file);
1268
1269 return nr_syms;
1270
1271out_delete_line:
1272 free(line);
1273out_failure:
1274 return -1;
1275}
1276
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001277static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1278 enum dso_binary_type type)
1279{
1280 switch (type) {
1281 case DSO_BINARY_TYPE__JAVA_JIT:
1282 case DSO_BINARY_TYPE__DEBUGLINK:
1283 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1284 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1285 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1286 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1287 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
1288 return !kmod && dso->kernel == DSO_TYPE_USER;
1289
1290 case DSO_BINARY_TYPE__KALLSYMS:
1291 case DSO_BINARY_TYPE__VMLINUX:
1292 case DSO_BINARY_TYPE__KCORE:
1293 return dso->kernel == DSO_TYPE_KERNEL;
1294
1295 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1296 case DSO_BINARY_TYPE__GUEST_VMLINUX:
1297 case DSO_BINARY_TYPE__GUEST_KCORE:
1298 return dso->kernel == DSO_TYPE_GUEST_KERNEL;
1299
1300 case DSO_BINARY_TYPE__GUEST_KMODULE:
1301 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1302 /*
1303 * kernel modules know their symtab type - it's set when
1304 * creating a module dso in machine__new_module().
1305 */
1306 return kmod && dso->symtab_type == type;
1307
1308 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1309 return true;
1310
1311 case DSO_BINARY_TYPE__NOT_FOUND:
1312 default:
1313 return false;
1314 }
1315}
1316
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001317int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001318{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001319 char *name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001320 int ret = -1;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001321 u_int i;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001322 struct machine *machine;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001323 char *root_dir = (char *) "";
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001324 int ss_pos = 0;
1325 struct symsrc ss_[2];
1326 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001327 bool kmod;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001328
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001329 dso__set_loaded(dso, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001330
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001331 if (dso->kernel == DSO_TYPE_KERNEL)
1332 return dso__load_kernel_sym(dso, map, filter);
1333 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1334 return dso__load_guest_kernel_sym(dso, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001335
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001336 if (map->groups && map->groups->machine)
1337 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001338 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001339 machine = NULL;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001340
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001341 dso->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001342
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001343 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
Pekka Enberg981c1252011-08-09 22:54:18 +03001344 struct stat st;
1345
Vasiliy Kulikove9b52ef2011-08-12 00:55:37 +04001346 if (lstat(dso->name, &st) < 0)
Pekka Enberg981c1252011-08-09 22:54:18 +03001347 return -1;
1348
1349 if (st.st_uid && (st.st_uid != geteuid())) {
1350 pr_warning("File %s not owned by current user or root, "
1351 "ignoring it.\n", dso->name);
1352 return -1;
1353 }
1354
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001355 ret = dso__load_perf_map(dso, map, filter);
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001356 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
1357 DSO_BINARY_TYPE__NOT_FOUND;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001358 return ret;
1359 }
1360
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001361 if (machine)
1362 root_dir = machine->root_dir;
1363
David Ahern164c8002013-01-14 10:46:47 -07001364 name = malloc(PATH_MAX);
1365 if (!name)
1366 return -1;
1367
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001368 kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1369 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
1370
1371 /*
1372 * Iterate over candidate debug images.
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001373 * Keep track of "interesting" ones (those which have a symtab, dynsym,
1374 * and/or opd section) for processing.
Dave Martin6da80ce2010-07-30 09:50:09 -03001375 */
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001376 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001377 struct symsrc *ss = &ss_[ss_pos];
1378 bool next_slot = false;
Dave Martin6da80ce2010-07-30 09:50:09 -03001379
Cody P Schafer005f9292012-08-10 15:22:58 -07001380 enum dso_binary_type symtab_type = binary_type_symtab[i];
Dave Martin6da80ce2010-07-30 09:50:09 -03001381
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001382 if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type))
1383 continue;
1384
Arnaldo Carvalho de Meloee4e9622013-12-16 17:03:18 -03001385 if (dso__read_binary_type_filename(dso, symtab_type,
1386 root_dir, name, PATH_MAX))
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001387 continue;
Dave Martin6da80ce2010-07-30 09:50:09 -03001388
1389 /* Name is now the name of the next image to try */
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001390 if (symsrc__init(ss, dso, name, symtab_type) < 0)
Dave Martin6da80ce2010-07-30 09:50:09 -03001391 continue;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001392
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001393 if (!syms_ss && symsrc__has_symtab(ss)) {
1394 syms_ss = ss;
1395 next_slot = true;
Adrian Hunter0058aef2013-12-03 09:23:08 +02001396 if (!dso->symsrc_filename)
1397 dso->symsrc_filename = strdup(name);
Cody P Schaferd26cd122012-08-10 15:23:00 -07001398 }
1399
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001400 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
1401 runtime_ss = ss;
1402 next_slot = true;
Cody P Schafera44f6052012-08-10 15:22:59 -07001403 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001404
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001405 if (next_slot) {
1406 ss_pos++;
Jiri Olsa33ff5812012-04-18 15:46:58 +02001407
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001408 if (syms_ss && runtime_ss)
1409 break;
Namhyung Kim98e9f032014-02-20 10:32:54 +09001410 } else {
1411 symsrc__destroy(ss);
Dave Martin6da80ce2010-07-30 09:50:09 -03001412 }
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001413
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001414 }
Dave Martin6da80ce2010-07-30 09:50:09 -03001415
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001416 if (!runtime_ss && !syms_ss)
1417 goto out_free;
1418
1419 if (runtime_ss && !syms_ss) {
1420 syms_ss = runtime_ss;
Arnaldo Carvalho de Melo60e4b102011-03-22 15:42:14 -03001421 }
1422
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001423 /* We'll have to hope for the best */
1424 if (!runtime_ss && syms_ss)
1425 runtime_ss = syms_ss;
1426
Namhyung Kim1029f9f2014-02-20 10:32:56 +09001427 if (syms_ss)
1428 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
1429 else
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001430 ret = -1;
1431
David Ahernf47b58b2012-08-19 09:47:14 -06001432 if (ret > 0) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -07001433 int nr_plt;
1434
1435 nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
1436 if (nr_plt > 0)
1437 ret += nr_plt;
1438 }
1439
1440 for (; ss_pos > 0; ss_pos--)
1441 symsrc__destroy(&ss_[ss_pos - 1]);
1442out_free:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001443 free(name);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001444 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001445 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001446 return ret;
1447}
1448
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001449struct map *map_groups__find_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001450 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001451{
1452 struct rb_node *nd;
1453
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001454 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001455 struct map *map = rb_entry(nd, struct map, rb_node);
1456
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001457 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001458 return map;
1459 }
1460
1461 return NULL;
1462}
1463
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001464int dso__load_vmlinux(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001465 const char *vmlinux, bool vmlinux_allocated,
1466 symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001467{
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001468 int err = -1;
1469 struct symsrc ss;
David Ahernec5761e2010-12-09 13:27:07 -07001470 char symfs_vmlinux[PATH_MAX];
Cody P Schafer005f9292012-08-10 15:22:58 -07001471 enum dso_binary_type symtab_type;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001472
Namhyung Kim5698d2c2013-07-17 17:08:15 +09001473 if (vmlinux[0] == '/')
1474 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
1475 else
Arnaldo Carvalho de Melo972f3932014-07-29 10:21:58 -03001476 symbol__join_symfs(symfs_vmlinux, vmlinux);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001477
Cody P Schafer21ea4532012-08-10 15:22:56 -07001478 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Cody P Schafer005f9292012-08-10 15:22:58 -07001479 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001480 else
Cody P Schafer005f9292012-08-10 15:22:58 -07001481 symtab_type = DSO_BINARY_TYPE__VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001482
Cody P Schafer005f9292012-08-10 15:22:58 -07001483 if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001484 return -1;
1485
Cody P Schafer261360b2012-08-10 15:23:01 -07001486 err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001487 symsrc__destroy(&ss);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001488
Cody P Schafer515850e2012-08-10 15:22:54 -07001489 if (err > 0) {
Adrian Hunter39b12f782013-08-07 14:38:47 +03001490 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001491 dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
Adrian Hunter39b12f782013-08-07 14:38:47 +03001492 else
Arnaldo Carvalho de Melo5f706192013-12-17 16:14:07 -03001493 dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
Arnaldo Carvalho de Melobf4414a2013-12-10 15:19:23 -03001494 dso__set_long_name(dso, vmlinux, vmlinux_allocated);
Cody P Schafer515850e2012-08-10 15:22:54 -07001495 dso__set_loaded(dso, map->type);
David Ahernec5761e2010-12-09 13:27:07 -07001496 pr_debug("Using %s for symbols\n", symfs_vmlinux);
Cody P Schafer515850e2012-08-10 15:22:54 -07001497 }
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001498
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001499 return err;
1500}
1501
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001502int dso__load_vmlinux_path(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001503 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001504{
1505 int i, err = 0;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001506 char *filename;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001507
1508 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001509 vmlinux_path__nr_entries + 1);
1510
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001511 filename = dso__build_id_filename(dso, NULL, 0);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001512 if (filename != NULL) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001513 err = dso__load_vmlinux(dso, map, filename, true, filter);
1514 if (err > 0)
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001515 goto out;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001516 free(filename);
1517 }
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001518
1519 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001520 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1521 if (err > 0)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001522 break;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001523 }
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001524out:
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001525 return err;
1526}
1527
Adrian Hunter0544d422013-10-14 13:43:43 +03001528static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1529{
1530 char kallsyms_filename[PATH_MAX];
1531 struct dirent *dent;
1532 int ret = -1;
1533 DIR *d;
1534
1535 d = opendir(dir);
1536 if (!d)
1537 return -1;
1538
1539 while (1) {
1540 dent = readdir(d);
1541 if (!dent)
1542 break;
1543 if (dent->d_type != DT_DIR)
1544 continue;
1545 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1546 "%s/%s/kallsyms", dir, dent->d_name);
Adrian Huntera00d28c2014-01-29 16:14:41 +02001547 if (!validate_kcore_addresses(kallsyms_filename, map)) {
Adrian Hunter0544d422013-10-14 13:43:43 +03001548 strlcpy(dir, kallsyms_filename, dir_sz);
1549 ret = 0;
1550 break;
1551 }
1552 }
1553
1554 closedir(d);
1555
1556 return ret;
1557}
1558
1559static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1560{
1561 u8 host_build_id[BUILD_ID_SIZE];
1562 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1563 bool is_host = false;
1564 char path[PATH_MAX];
1565
1566 if (!dso->has_build_id) {
1567 /*
1568 * Last resort, if we don't have a build-id and couldn't find
1569 * any vmlinux file, try the running kernel kallsyms table.
1570 */
1571 goto proc_kallsyms;
1572 }
1573
1574 if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
1575 sizeof(host_build_id)) == 0)
1576 is_host = dso__build_id_equal(dso, host_build_id);
1577
1578 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1579
Adrian Hunter449867e2013-11-26 15:19:24 +02001580 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1581 sbuild_id);
1582
Adrian Hunter0544d422013-10-14 13:43:43 +03001583 /* Use /proc/kallsyms if possible */
1584 if (is_host) {
1585 DIR *d;
1586 int fd;
1587
1588 /* If no cached kcore go with /proc/kallsyms */
Adrian Hunter0544d422013-10-14 13:43:43 +03001589 d = opendir(path);
1590 if (!d)
1591 goto proc_kallsyms;
1592 closedir(d);
1593
1594 /*
1595 * Do not check the build-id cache, until we know we cannot use
1596 * /proc/kcore.
1597 */
1598 fd = open("/proc/kcore", O_RDONLY);
1599 if (fd != -1) {
1600 close(fd);
1601 /* If module maps match go with /proc/kallsyms */
Adrian Huntera00d28c2014-01-29 16:14:41 +02001602 if (!validate_kcore_addresses("/proc/kallsyms", map))
Adrian Hunter0544d422013-10-14 13:43:43 +03001603 goto proc_kallsyms;
1604 }
1605
1606 /* Find kallsyms in build-id cache with kcore */
1607 if (!find_matching_kcore(map, path, sizeof(path)))
1608 return strdup(path);
1609
1610 goto proc_kallsyms;
1611 }
1612
Adrian Hunter449867e2013-11-26 15:19:24 +02001613 /* Find kallsyms in build-id cache with kcore */
1614 if (!find_matching_kcore(map, path, sizeof(path)))
1615 return strdup(path);
1616
Adrian Hunter0544d422013-10-14 13:43:43 +03001617 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1618 buildid_dir, sbuild_id);
1619
1620 if (access(path, F_OK)) {
1621 pr_err("No kallsyms or vmlinux with build-id %s was found\n",
1622 sbuild_id);
1623 return NULL;
1624 }
1625
1626 return strdup(path);
1627
1628proc_kallsyms:
1629 return strdup("/proc/kallsyms");
1630}
1631
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001632static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001633 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001634{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001635 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001636 const char *kallsyms_filename = NULL;
1637 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001638 /*
David Ahernb226a5a72010-12-07 19:39:46 -07001639 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1640 * it and only it, reporting errors to the user if it cannot be used.
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001641 *
1642 * For instance, try to analyse an ARM perf.data file _without_ a
1643 * build-id, or if the user specifies the wrong path to the right
1644 * vmlinux file, obviously we can't fallback to another vmlinux (a
1645 * x86_86 one, on the machine where analysis is being performed, say),
1646 * or worse, /proc/kallsyms.
1647 *
1648 * If the specified file _has_ a build-id and there is a build-id
1649 * section in the perf.data file, we will still do the expected
1650 * validation in dso__load_vmlinux and will bail out if they don't
1651 * match.
1652 */
David Ahernb226a5a72010-12-07 19:39:46 -07001653 if (symbol_conf.kallsyms_name != NULL) {
1654 kallsyms_filename = symbol_conf.kallsyms_name;
1655 goto do_kallsyms;
1656 }
1657
Willy Tarreaufc2be692013-09-14 10:32:59 +02001658 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001659 return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
1660 false, filter);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001661 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001662
Willy Tarreaufc2be692013-09-14 10:32:59 +02001663 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001664 err = dso__load_vmlinux_path(dso, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001665 if (err > 0)
Adrian Hunter39b12f782013-08-07 14:38:47 +03001666 return err;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001667 }
1668
David Ahernec5761e2010-12-09 13:27:07 -07001669 /* do not try local files if a symfs was given */
1670 if (symbol_conf.symfs[0] != 0)
1671 return -1;
1672
Adrian Hunter0544d422013-10-14 13:43:43 +03001673 kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
1674 if (!kallsyms_allocated_filename)
1675 return -1;
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001676
Adrian Hunter0544d422013-10-14 13:43:43 +03001677 kallsyms_filename = kallsyms_allocated_filename;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001678
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001679do_kallsyms:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001680 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001681 if (err > 0)
1682 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001683 free(kallsyms_allocated_filename);
1684
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001685 if (err > 0 && !dso__is_kcore(dso)) {
Adrian Hunterbdac0bc2014-07-14 13:02:43 +03001686 dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melobf4414a2013-12-10 15:19:23 -03001687 dso__set_long_name(dso, "[kernel.kallsyms]", false);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001688 map__fixup_start(map);
1689 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001690 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001691
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001692 return err;
1693}
1694
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001695static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1696 symbol_filter_t filter)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001697{
1698 int err;
1699 const char *kallsyms_filename = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001700 struct machine *machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001701 char path[PATH_MAX];
1702
1703 if (!map->groups) {
1704 pr_debug("Guest kernel map hasn't the point to groups\n");
1705 return -1;
1706 }
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001707 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001708
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001709 if (machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001710 /*
1711 * if the user specified a vmlinux filename, use it and only
1712 * it, reporting errors to the user if it cannot be used.
1713 * Or use file guest_kallsyms inputted by user on commandline
1714 */
1715 if (symbol_conf.default_guest_vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001716 err = dso__load_vmlinux(dso, map,
Arnaldo Carvalho de Melo5230fb72013-12-10 11:58:52 -03001717 symbol_conf.default_guest_vmlinux_name,
1718 false, filter);
Adrian Hunter39b12f782013-08-07 14:38:47 +03001719 return err;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001720 }
1721
1722 kallsyms_filename = symbol_conf.default_guest_kallsyms;
1723 if (!kallsyms_filename)
1724 return -1;
1725 } else {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001726 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001727 kallsyms_filename = path;
1728 }
1729
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001730 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001731 if (err > 0)
Adrian Hunter39b12f782013-08-07 14:38:47 +03001732 pr_debug("Using %s for symbols\n", kallsyms_filename);
Adrian Hunter8e0cf962013-08-07 14:38:51 +03001733 if (err > 0 && !dso__is_kcore(dso)) {
Adrian Hunterbdac0bc2014-07-14 13:02:43 +03001734 dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Adrian Hunter39b12f782013-08-07 14:38:47 +03001735 machine__mmap_name(machine, path, sizeof(path));
Arnaldo Carvalho de Melo7e155d42013-12-10 15:08:44 -03001736 dso__set_long_name(dso, strdup(path), true);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001737 map__fixup_start(map);
1738 map__fixup_end(map);
1739 }
1740
1741 return err;
1742}
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001743
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001744static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001745{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001746 while (--vmlinux_path__nr_entries >= 0)
1747 zfree(&vmlinux_path[vmlinux_path__nr_entries]);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001748
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001749 zfree(&vmlinux_path);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001750}
1751
1752static int vmlinux_path__init(void)
1753{
1754 struct utsname uts;
1755 char bf[PATH_MAX];
1756
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001757 vmlinux_path = malloc(sizeof(char *) * 5);
1758 if (vmlinux_path == NULL)
1759 return -1;
1760
1761 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1762 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1763 goto out_fail;
1764 ++vmlinux_path__nr_entries;
1765 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1766 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1767 goto out_fail;
1768 ++vmlinux_path__nr_entries;
David Ahernec5761e2010-12-09 13:27:07 -07001769
1770 /* only try running kernel version if no symfs was given */
1771 if (symbol_conf.symfs[0] != 0)
1772 return 0;
1773
1774 if (uname(&uts) < 0)
Namhyung Kime96c6742014-08-12 15:40:34 +09001775 goto out_fail;
David Ahernec5761e2010-12-09 13:27:07 -07001776
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001777 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", 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), "/lib/modules/%s/build/vmlinux", uts.release);
1783 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1784 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1785 goto out_fail;
1786 ++vmlinux_path__nr_entries;
1787 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1788 uts.release);
1789 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1790 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1791 goto out_fail;
1792 ++vmlinux_path__nr_entries;
1793
1794 return 0;
1795
1796out_fail:
1797 vmlinux_path__exit();
1798 return -1;
1799}
1800
David Ahern3bfe5f82013-11-18 13:32:48 -07001801int setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001802 const char *list_name)
1803{
1804 if (list_str == NULL)
1805 return 0;
1806
1807 *list = strlist__new(true, list_str);
1808 if (!*list) {
1809 pr_err("problems parsing %s list\n", list_name);
1810 return -1;
1811 }
1812 return 0;
1813}
1814
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001815static bool symbol__read_kptr_restrict(void)
1816{
1817 bool value = false;
1818
1819 if (geteuid() != 0) {
1820 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1821 if (fp != NULL) {
1822 char line[8];
1823
1824 if (fgets(line, sizeof(line), fp) != NULL)
1825 value = atoi(line) != 0;
1826
1827 fclose(fp);
1828 }
1829 }
1830
1831 return value;
1832}
1833
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001834int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001835{
David Ahernec5761e2010-12-09 13:27:07 -07001836 const char *symfs;
1837
Jovi Zhang85e00b52010-09-09 13:30:59 -03001838 if (symbol_conf.initialized)
1839 return 0;
1840
Irina Tirdea9ac3e482012-09-11 01:15:01 +03001841 symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
David S. Miller4d439512011-03-29 14:18:39 -03001842
Namhyung Kim166ccc92012-08-06 13:41:19 +09001843 symbol__elf_init();
1844
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001845 if (symbol_conf.sort_by_name)
1846 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1847 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001848
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001849 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001850 return -1;
1851
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001852 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1853 pr_err("'.' is the only non valid --field-separator argument\n");
1854 return -1;
1855 }
1856
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001857 if (setup_list(&symbol_conf.dso_list,
1858 symbol_conf.dso_list_str, "dso") < 0)
1859 return -1;
1860
1861 if (setup_list(&symbol_conf.comm_list,
1862 symbol_conf.comm_list_str, "comm") < 0)
1863 goto out_free_dso_list;
1864
1865 if (setup_list(&symbol_conf.sym_list,
1866 symbol_conf.sym_list_str, "symbol") < 0)
1867 goto out_free_comm_list;
1868
David Ahernec5761e2010-12-09 13:27:07 -07001869 /*
1870 * A path to symbols of "/" is identical to ""
1871 * reset here for simplicity.
1872 */
1873 symfs = realpath(symbol_conf.symfs, NULL);
1874 if (symfs == NULL)
1875 symfs = symbol_conf.symfs;
1876 if (strcmp(symfs, "/") == 0)
1877 symbol_conf.symfs = "";
1878 if (symfs != symbol_conf.symfs)
1879 free((void *)symfs);
1880
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001881 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
1882
Jovi Zhang85e00b52010-09-09 13:30:59 -03001883 symbol_conf.initialized = true;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001884 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001885
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001886out_free_comm_list:
1887 strlist__delete(symbol_conf.comm_list);
Namhyung Kimd74c8962011-12-13 00:16:52 +09001888out_free_dso_list:
1889 strlist__delete(symbol_conf.dso_list);
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001890 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001891}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001892
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001893void symbol__exit(void)
1894{
Jovi Zhang85e00b52010-09-09 13:30:59 -03001895 if (!symbol_conf.initialized)
1896 return;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001897 strlist__delete(symbol_conf.sym_list);
1898 strlist__delete(symbol_conf.dso_list);
1899 strlist__delete(symbol_conf.comm_list);
1900 vmlinux_path__exit();
1901 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
Jovi Zhang85e00b52010-09-09 13:30:59 -03001902 symbol_conf.initialized = false;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001903}