blob: 295f8d4feedfeb00afd11787c3e7538e5fb19c74 [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 Melo439d4732009-10-02 03:29:58 -030021#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020022
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -020023#ifndef KSYM_NAME_LEN
Ricardo Ribalda Delgadoc752d042011-10-20 09:43:26 +020024#define KSYM_NAME_LEN 256
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -020025#endif
26
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030027static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020028 symbol_filter_t filter);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030029static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080030 symbol_filter_t filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020031static int vmlinux_path__nr_entries;
32static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030033
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020034struct symbol_conf symbol_conf = {
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -020035 .exclude_other = true,
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020036 .use_modules = true,
37 .try_vmlinux_path = true,
Stephane Eranian3e6a2a72011-05-17 17:32:07 +020038 .annotate_src = true,
David Ahernec5761e2010-12-09 13:27:07 -070039 .symfs = "",
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020040};
41
Jiri Olsa44f24cb2012-07-22 14:14:32 +020042static enum dso_binary_type binary_type_symtab[] = {
43 DSO_BINARY_TYPE__KALLSYMS,
44 DSO_BINARY_TYPE__GUEST_KALLSYMS,
45 DSO_BINARY_TYPE__JAVA_JIT,
46 DSO_BINARY_TYPE__DEBUGLINK,
47 DSO_BINARY_TYPE__BUILD_ID_CACHE,
48 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
49 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
50 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
52 DSO_BINARY_TYPE__GUEST_KMODULE,
53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
54 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;
90
91 /* Prefer a symbol with non zero length */
92 a = syma->end - syma->start;
93 b = symb->end - symb->start;
94 if ((b == 0) && (a > 0))
95 return SYMBOL_A;
96 else if ((a == 0) && (b > 0))
97 return SYMBOL_B;
98
99 /* Prefer a non weak symbol over a weak one */
100 a = syma->binding == STB_WEAK;
101 b = symb->binding == STB_WEAK;
102 if (b && !a)
103 return SYMBOL_A;
104 if (a && !b)
105 return SYMBOL_B;
106
107 /* Prefer a global symbol over a non global one */
108 a = syma->binding == STB_GLOBAL;
109 b = symb->binding == STB_GLOBAL;
110 if (a && !b)
111 return SYMBOL_A;
112 if (b && !a)
113 return SYMBOL_B;
114
115 /* Prefer a symbol with less underscores */
116 a = prefix_underscores_count(syma->name);
117 b = prefix_underscores_count(symb->name);
118 if (b > a)
119 return SYMBOL_A;
120 else if (a > b)
121 return SYMBOL_B;
122
123 /* If all else fails, choose the symbol with the longest name */
124 if (strlen(syma->name) >= strlen(symb->name))
125 return SYMBOL_A;
126 else
127 return SYMBOL_B;
128}
129
Namhyung Kime5a18452012-08-06 13:41:20 +0900130void symbols__fixup_duplicate(struct rb_root *symbols)
Anton Blanchard694bf402011-08-24 16:40:17 +1000131{
132 struct rb_node *nd;
133 struct symbol *curr, *next;
134
135 nd = rb_first(symbols);
136
137 while (nd) {
138 curr = rb_entry(nd, struct symbol, rb_node);
139again:
140 nd = rb_next(&curr->rb_node);
141 next = rb_entry(nd, struct symbol, rb_node);
142
143 if (!nd)
144 break;
145
146 if (curr->start != next->start)
147 continue;
148
149 if (choose_best_symbol(curr, next) == SYMBOL_A) {
150 rb_erase(&next->rb_node, symbols);
151 goto again;
152 } else {
153 nd = rb_next(&curr->rb_node);
154 rb_erase(&curr->rb_node, symbols);
155 }
156 }
157}
158
Namhyung Kime5a18452012-08-06 13:41:20 +0900159void symbols__fixup_end(struct rb_root *symbols)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300160{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300161 struct rb_node *nd, *prevnd = rb_first(symbols);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300162 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300163
164 if (prevnd == NULL)
165 return;
166
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300167 curr = rb_entry(prevnd, struct symbol, rb_node);
168
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300169 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300170 prev = curr;
171 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300172
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200173 if (prev->end == prev->start && prev->end != curr->start)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300174 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300175 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300176
177 /* Last entry */
178 if (curr->end == curr->start)
179 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300180}
181
Namhyung Kime5a18452012-08-06 13:41:20 +0900182void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300183{
184 struct map *prev, *curr;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300185 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300186
187 if (prevnd == NULL)
188 return;
189
190 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300191
192 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
193 prev = curr;
194 curr = rb_entry(nd, struct map, rb_node);
195 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300196 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -0200197
198 /*
199 * We still haven't the actual symbols, so guess the
200 * last map final address.
201 */
Ian Munsie9d1faba2010-11-25 15:12:53 +1100202 curr->end = ~0ULL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300203}
204
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300205static void map_groups__fixup_end(struct map_groups *mg)
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200206{
207 int i;
208 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300209 __map_groups__fixup_end(mg, i);
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200210}
211
Namhyung Kime5a18452012-08-06 13:41:20 +0900212struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300213{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300214 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300215 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
216 sizeof(*sym) + namelen));
217 if (sym == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200218 return NULL;
219
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200220 if (symbol_conf.priv_size)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300221 sym = ((void *)sym) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200222
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300223 sym->start = start;
224 sym->end = len ? start + len - 1 : start;
225 sym->binding = binding;
226 sym->namelen = namelen - 1;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200227
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300228 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
229 __func__, name, start, sym->end);
230 memcpy(sym->name, name, namelen);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200231
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300232 return sym;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300233}
234
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300235void symbol__delete(struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300236{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300237 free(((void *)sym) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300238}
239
Jiri Olsacdd059d2012-10-27 23:18:32 +0200240size_t symbol__fprintf(struct symbol *sym, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300241{
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200242 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300243 sym->start, sym->end,
244 sym->binding == STB_GLOBAL ? 'g' :
245 sym->binding == STB_LOCAL ? 'l' : 'w',
246 sym->name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300247}
248
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900249size_t symbol__fprintf_symname_offs(const struct symbol *sym,
250 const struct addr_location *al, FILE *fp)
251{
252 unsigned long offset;
253 size_t length;
254
255 if (sym && sym->name) {
256 length = fprintf(fp, "%s", sym->name);
257 if (al) {
258 offset = al->addr - sym->start;
259 length += fprintf(fp, "+0x%lx", offset);
260 }
261 return length;
262 } else
263 return fprintf(fp, "[unknown]");
264}
265
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900266size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
267{
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900268 return symbol__fprintf_symname_offs(sym, NULL, fp);
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900269}
270
Jiri Olsacdd059d2012-10-27 23:18:32 +0200271void symbols__delete(struct rb_root *symbols)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300272{
273 struct symbol *pos;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300274 struct rb_node *next = rb_first(symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300275
276 while (next) {
277 pos = rb_entry(next, struct symbol, rb_node);
278 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300279 rb_erase(&pos->rb_node, symbols);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200280 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300281 }
282}
283
Namhyung Kime5a18452012-08-06 13:41:20 +0900284void symbols__insert(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300285{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300286 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300287 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000288 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300289 struct symbol *s;
290
291 while (*p != NULL) {
292 parent = *p;
293 s = rb_entry(parent, struct symbol, rb_node);
294 if (ip < s->start)
295 p = &(*p)->rb_left;
296 else
297 p = &(*p)->rb_right;
298 }
299 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300300 rb_insert_color(&sym->rb_node, symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300301}
302
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300303static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300304{
305 struct rb_node *n;
306
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300307 if (symbols == NULL)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300308 return NULL;
309
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300310 n = symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300311
312 while (n) {
313 struct symbol *s = rb_entry(n, struct symbol, rb_node);
314
315 if (ip < s->start)
316 n = n->rb_left;
317 else if (ip > s->end)
318 n = n->rb_right;
319 else
320 return s;
321 }
322
323 return NULL;
324}
325
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200326struct symbol_name_rb_node {
327 struct rb_node rb_node;
328 struct symbol sym;
329};
330
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300331static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200332{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300333 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200334 struct rb_node *parent = NULL;
Rabin Vincent02a9d032010-11-23 22:08:18 +0530335 struct symbol_name_rb_node *symn, *s;
336
337 symn = container_of(sym, struct symbol_name_rb_node, sym);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200338
339 while (*p != NULL) {
340 parent = *p;
341 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
342 if (strcmp(sym->name, s->sym.name) < 0)
343 p = &(*p)->rb_left;
344 else
345 p = &(*p)->rb_right;
346 }
347 rb_link_node(&symn->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300348 rb_insert_color(&symn->rb_node, symbols);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200349}
350
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300351static void symbols__sort_by_name(struct rb_root *symbols,
352 struct rb_root *source)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200353{
354 struct rb_node *nd;
355
356 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
357 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300358 symbols__insert_by_name(symbols, pos);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200359 }
360}
361
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300362static struct symbol *symbols__find_by_name(struct rb_root *symbols,
363 const char *name)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200364{
365 struct rb_node *n;
366
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300367 if (symbols == NULL)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200368 return NULL;
369
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300370 n = symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200371
372 while (n) {
373 struct symbol_name_rb_node *s;
374 int cmp;
375
376 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
377 cmp = strcmp(name, s->sym.name);
378
379 if (cmp < 0)
380 n = n->rb_left;
381 else if (cmp > 0)
382 n = n->rb_right;
383 else
384 return &s->sym;
385 }
386
387 return NULL;
388}
389
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300390struct symbol *dso__find_symbol(struct dso *dso,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200391 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200392{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300393 return symbols__find(&dso->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200394}
395
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300396struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200397 const char *name)
398{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300399 return symbols__find_by_name(&dso->symbol_names[type], name);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200400}
401
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300402void dso__sort_by_name(struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200403{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300404 dso__set_sorted_by_name(dso, type);
405 return symbols__sort_by_name(&dso->symbol_names[type],
406 &dso->symbols[type]);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200407}
408
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300409size_t dso__fprintf_symbols_by_name(struct dso *dso,
410 enum map_type type, FILE *fp)
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530411{
412 size_t ret = 0;
413 struct rb_node *nd;
414 struct symbol_name_rb_node *pos;
415
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300416 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530417 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
418 fprintf(fp, "%s\n", pos->sym.name);
419 }
420
421 return ret;
422}
423
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200424int kallsyms__parse(const char *filename, void *arg,
425 int (*process_symbol)(void *arg, const char *name,
Cody P Schafer82151522012-08-10 15:22:48 -0700426 char type, u64 start))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300427{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300428 char *line = NULL;
429 size_t n;
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200430 int err = -1;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200431 FILE *file = fopen(filename, "r");
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300432
433 if (file == NULL)
434 goto out_failure;
435
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200436 err = 0;
437
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300438 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000439 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300440 int line_len, len;
441 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300442 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300443
444 line_len = getline(&line, &n, file);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800445 if (line_len < 0 || !line)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300446 break;
447
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300448 line[--line_len] = '\0'; /* \n */
449
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300450 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300451
452 len++;
453 if (len + 2 >= line_len)
454 continue;
455
Anton Blanchard31877902011-08-24 16:40:16 +1000456 symbol_type = line[len];
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200457 len += 2;
458 symbol_name = line + len;
459 len = line_len - len;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300460
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200461 if (len >= KSYM_NAME_LEN) {
462 err = -1;
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200463 break;
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200464 }
465
Anton Blanchard3f5a4272011-08-24 16:40:15 +1000466 err = process_symbol(arg, symbol_name,
Cody P Schafer82151522012-08-10 15:22:48 -0700467 symbol_type, start);
Anton Blanchard3f5a4272011-08-24 16:40:15 +1000468 if (err)
469 break;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300470 }
471
472 free(line);
473 fclose(file);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200474 return err;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300475
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300476out_failure:
477 return -1;
478}
479
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200480struct process_kallsyms_args {
481 struct map *map;
482 struct dso *dso;
483};
484
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -0300485static u8 kallsyms2elf_type(char type)
486{
487 if (type == 'W')
488 return STB_WEAK;
489
490 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
491}
492
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200493static int map__process_kallsym_symbol(void *arg, const char *name,
Cody P Schafer82151522012-08-10 15:22:48 -0700494 char type, u64 start)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200495{
496 struct symbol *sym;
497 struct process_kallsyms_args *a = arg;
498 struct rb_root *root = &a->dso->symbols[a->map->type];
499
500 if (!symbol_type__is_a(type, a->map->type))
501 return 0;
502
Cody P Schafer82151522012-08-10 15:22:48 -0700503 /*
504 * module symbols are not sorted so we add all
505 * symbols, setting length to 0, and rely on
506 * symbols__fixup_end() to fix it up.
507 */
508 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200509 if (sym == NULL)
510 return -ENOMEM;
511 /*
512 * We will pass the symbols to the filter later, in
513 * map__split_kallsyms, when we have split the maps per module
514 */
515 symbols__insert(root, sym);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800516
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200517 return 0;
518}
519
520/*
521 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
522 * so that we can in the next step set the symbol ->end address and then
523 * call kernel_maps__split_kallsyms.
524 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300525static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200526 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200527{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300528 struct process_kallsyms_args args = { .map = map, .dso = dso, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200529 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200530}
531
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300532/*
533 * Split the symbols into maps, making sure there are no overlaps, i.e. the
534 * kernel range is broken in several maps, named [kernel].N, as we don't have
535 * the original ELF section names vmlinux have.
536 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300537static int dso__split_kallsyms(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200538 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300539{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200540 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300541 struct machine *machine = kmaps->machine;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200542 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300543 struct symbol *pos;
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200544 int count = 0, moved = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300545 struct rb_root *root = &dso->symbols[map->type];
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200546 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300547 int kernel_range = 0;
548
549 while (next) {
550 char *module;
551
552 pos = rb_entry(next, struct symbol, rb_node);
553 next = rb_next(&pos->rb_node);
554
555 module = strchr(pos->name, '\t');
556 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200557 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200558 goto discard_symbol;
559
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300560 *module++ = '\0';
561
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200562 if (strcmp(curr_map->dso->short_name, module)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800563 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300564 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300565 machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800566 /*
567 * We assume all symbols of a module are
568 * continuous in * kallsyms, so curr_map
569 * points to a module and all its
570 * symbols are in its kmap. Mark it as
571 * loaded.
572 */
573 dso__set_loaded(curr_map->dso,
574 curr_map->type);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300575 }
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200576
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800577 curr_map = map_groups__find_by_name(kmaps,
578 map->type, module);
579 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2f519032010-05-17 17:57:59 -0300580 pr_debug("%s/proc/{kallsyms,modules} "
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800581 "inconsistency while looking "
582 "for \"%s\" module!\n",
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300583 machine->root_dir, module);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800584 curr_map = map;
585 goto discard_symbol;
586 }
587
588 if (curr_map->dso->loaded &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300589 !machine__is_default_guest(machine))
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200590 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300591 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300592 /*
593 * So that we look just like we get from .ko files,
594 * i.e. not prelinked, relative to map->start.
595 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200596 pos->start = curr_map->map_ip(curr_map, pos->start);
597 pos->end = curr_map->map_ip(curr_map, pos->end);
598 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300599 char dso_name[PATH_MAX];
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300600 struct dso *ndso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300601
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200602 if (count == 0) {
603 curr_map = map;
604 goto filter_symbol;
605 }
606
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300607 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800608 snprintf(dso_name, sizeof(dso_name),
609 "[guest.kernel].%d",
610 kernel_range++);
611 else
612 snprintf(dso_name, sizeof(dso_name),
613 "[kernel].%d",
614 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300615
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300616 ndso = dso__new(dso_name);
617 if (ndso == NULL)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300618 return -1;
619
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300620 ndso->kernel = dso->kernel;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800621
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300622 curr_map = map__new2(pos->start, ndso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800623 if (curr_map == NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300624 dso__delete(ndso);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300625 return -1;
626 }
627
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200628 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200629 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300630 ++kernel_range;
631 }
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200632filter_symbol:
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200633 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200634discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200635 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300636 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200637 if (curr_map != map) {
638 rb_erase(&pos->rb_node, root);
639 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200640 ++moved;
641 } else
642 ++count;
Mike Galbraith9974f492009-07-02 08:05:58 +0200643 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300644 }
645
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800646 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300647 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300648 machine__is_default_guest(kmaps->machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800649 dso__set_loaded(curr_map->dso, curr_map->type);
650 }
651
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200652 return count + moved;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300653}
654
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300655static bool symbol__restricted_filename(const char *filename,
656 const char *restricted_filename)
657{
658 bool restricted = false;
659
660 if (symbol_conf.kptr_restrict) {
661 char *r = realpath(filename, NULL);
662
663 if (r != NULL) {
664 restricted = strcmp(r, restricted_filename) == 0;
665 free(r);
666 return restricted;
667 }
668 }
669
670 return restricted;
671}
672
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300673int dso__load_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200674 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300675{
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300676 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
677 return -1;
678
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300679 if (dso__load_all_kallsyms(dso, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300680 return -1;
681
Anton Blanchard694bf402011-08-24 16:40:17 +1000682 symbols__fixup_duplicate(&dso->symbols[map->type]);
Anton Blanchard3f5a4272011-08-24 16:40:15 +1000683 symbols__fixup_end(&dso->symbols[map->type]);
684
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300685 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200686 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800687 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200688 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300689
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300690 return dso__split_kallsyms(dso, map, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300691}
692
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300693static int dso__load_perf_map(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200694 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300695{
696 char *line = NULL;
697 size_t n;
698 FILE *file;
699 int nr_syms = 0;
700
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300701 file = fopen(dso->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300702 if (file == NULL)
703 goto out_failure;
704
705 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000706 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300707 struct symbol *sym;
708 int line_len, len;
709
710 line_len = getline(&line, &n, file);
711 if (line_len < 0)
712 break;
713
714 if (!line)
715 goto out_failure;
716
717 line[--line_len] = '\0'; /* \n */
718
719 len = hex2u64(line, &start);
720
721 len++;
722 if (len + 2 >= line_len)
723 continue;
724
725 len += hex2u64(line + len, &size);
726
727 len++;
728 if (len + 2 >= line_len)
729 continue;
730
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -0300731 sym = symbol__new(start, size, STB_GLOBAL, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300732
733 if (sym == NULL)
734 goto out_delete_line;
735
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300736 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200737 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300738 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300739 symbols__insert(&dso->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300740 nr_syms++;
741 }
742 }
743
744 free(line);
745 fclose(file);
746
747 return nr_syms;
748
749out_delete_line:
750 free(line);
751out_failure:
752 return -1;
753}
754
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300755int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300756{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200757 char *name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300758 int ret = -1;
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200759 u_int i;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300760 struct machine *machine;
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200761 char *root_dir = (char *) "";
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700762 int ss_pos = 0;
763 struct symsrc ss_[2];
764 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300765
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300766 dso__set_loaded(dso, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200767
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300768 if (dso->kernel == DSO_TYPE_KERNEL)
769 return dso__load_kernel_sym(dso, map, filter);
770 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
771 return dso__load_guest_kernel_sym(dso, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800772
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300773 if (map->groups && map->groups->machine)
774 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800775 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300776 machine = NULL;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200777
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200778 name = malloc(PATH_MAX);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300779 if (!name)
780 return -1;
781
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300782 dso->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300783
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300784 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
Pekka Enberg981c1252011-08-09 22:54:18 +0300785 struct stat st;
786
Vasiliy Kulikove9b52ef2011-08-12 00:55:37 +0400787 if (lstat(dso->name, &st) < 0)
Pekka Enberg981c1252011-08-09 22:54:18 +0300788 return -1;
789
790 if (st.st_uid && (st.st_uid != geteuid())) {
791 pr_warning("File %s not owned by current user or root, "
792 "ignoring it.\n", dso->name);
793 return -1;
794 }
795
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300796 ret = dso__load_perf_map(dso, map, filter);
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200797 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
798 DSO_BINARY_TYPE__NOT_FOUND;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300799 return ret;
800 }
801
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200802 if (machine)
803 root_dir = machine->root_dir;
804
Dave Martin6da80ce2010-07-30 09:50:09 -0300805 /* Iterate over candidate debug images.
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700806 * Keep track of "interesting" ones (those which have a symtab, dynsym,
807 * and/or opd section) for processing.
Dave Martin6da80ce2010-07-30 09:50:09 -0300808 */
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200809 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700810 struct symsrc *ss = &ss_[ss_pos];
811 bool next_slot = false;
Dave Martin6da80ce2010-07-30 09:50:09 -0300812
Cody P Schafer005f9292012-08-10 15:22:58 -0700813 enum dso_binary_type symtab_type = binary_type_symtab[i];
Dave Martin6da80ce2010-07-30 09:50:09 -0300814
Cody P Schafer005f9292012-08-10 15:22:58 -0700815 if (dso__binary_type_file(dso, symtab_type,
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200816 root_dir, name, PATH_MAX))
817 continue;
Dave Martin6da80ce2010-07-30 09:50:09 -0300818
819 /* Name is now the name of the next image to try */
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700820 if (symsrc__init(ss, dso, name, symtab_type) < 0)
Dave Martin6da80ce2010-07-30 09:50:09 -0300821 continue;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300822
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700823 if (!syms_ss && symsrc__has_symtab(ss)) {
824 syms_ss = ss;
825 next_slot = true;
Cody P Schaferd26cd122012-08-10 15:23:00 -0700826 }
827
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700828 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
829 runtime_ss = ss;
830 next_slot = true;
Cody P Schafera44f6052012-08-10 15:22:59 -0700831 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300832
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700833 if (next_slot) {
834 ss_pos++;
Jiri Olsa33ff5812012-04-18 15:46:58 +0200835
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700836 if (syms_ss && runtime_ss)
837 break;
Dave Martin6da80ce2010-07-30 09:50:09 -0300838 }
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700839
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300840 }
Dave Martin6da80ce2010-07-30 09:50:09 -0300841
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700842 if (!runtime_ss && !syms_ss)
843 goto out_free;
844
845 if (runtime_ss && !syms_ss) {
846 syms_ss = runtime_ss;
Arnaldo Carvalho de Melo60e4b102011-03-22 15:42:14 -0300847 }
848
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700849 /* We'll have to hope for the best */
850 if (!runtime_ss && syms_ss)
851 runtime_ss = syms_ss;
852
853 if (syms_ss)
854 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
855 else
856 ret = -1;
857
David Ahernf47b58b2012-08-19 09:47:14 -0600858 if (ret > 0) {
Cody P Schafer3aafe5a2012-08-10 15:23:02 -0700859 int nr_plt;
860
861 nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
862 if (nr_plt > 0)
863 ret += nr_plt;
864 }
865
866 for (; ss_pos > 0; ss_pos--)
867 symsrc__destroy(&ss_[ss_pos - 1]);
868out_free:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300869 free(name);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300870 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -0300871 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300872 return ret;
873}
874
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300875struct map *map_groups__find_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200876 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300877{
878 struct rb_node *nd;
879
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300880 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300881 struct map *map = rb_entry(nd, struct map, rb_node);
882
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200883 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300884 return map;
885 }
886
887 return NULL;
888}
889
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300890static int map_groups__set_modules_path_dir(struct map_groups *mg,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800891 const char *dir_name)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200892{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300893 struct dirent *dent;
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -0300894 DIR *dir = opendir(dir_name);
Gui Jianfeng74534342010-06-24 15:04:02 +0800895 int ret = 0;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200896
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300897 if (!dir) {
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -0300898 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300899 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200900 }
901
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300902 while ((dent = readdir(dir)) != NULL) {
903 char path[PATH_MAX];
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800904 struct stat st;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200905
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800906 /*sshfs might return bad dent->d_type, so we have to stat*/
Namhyung Kim2b600f92011-12-13 00:16:51 +0900907 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800908 if (stat(path, &st))
909 continue;
910
911 if (S_ISDIR(st.st_mode)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300912 if (!strcmp(dent->d_name, ".") ||
913 !strcmp(dent->d_name, ".."))
914 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200915
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300916 ret = map_groups__set_modules_path_dir(mg, path);
Gui Jianfeng74534342010-06-24 15:04:02 +0800917 if (ret < 0)
918 goto out;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300919 } else {
920 char *dot = strrchr(dent->d_name, '.'),
921 dso_name[PATH_MAX];
922 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200923 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200924
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300925 if (dot == NULL || strcmp(dot, ".ko"))
926 continue;
927 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
928 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200929
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -0300930 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300931 map = map_groups__find_by_name(mg, MAP__FUNCTION,
932 dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300933 if (map == NULL)
934 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200935
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200936 long_name = strdup(path);
Gui Jianfeng74534342010-06-24 15:04:02 +0800937 if (long_name == NULL) {
938 ret = -1;
939 goto out;
940 }
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200941 dso__set_long_name(map->dso, long_name);
Arnaldo Carvalho de Melo6e406252010-07-29 15:11:30 -0300942 map->dso->lname_alloc = 1;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800943 dso__kernel_module_get_build_id(map->dso, "");
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200944 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200945 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300946
Gui Jianfeng74534342010-06-24 15:04:02 +0800947out:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300948 closedir(dir);
Gui Jianfeng74534342010-06-24 15:04:02 +0800949 return ret;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200950}
951
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800952static char *get_kernel_version(const char *root_dir)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300953{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800954 char version[PATH_MAX];
955 FILE *file;
956 char *name, *tmp;
957 const char *prefix = "Linux version ";
958
959 sprintf(version, "%s/proc/version", root_dir);
960 file = fopen(version, "r");
961 if (!file)
962 return NULL;
963
964 version[0] = '\0';
965 tmp = fgets(version, sizeof(version), file);
966 fclose(file);
967
968 name = strstr(version, prefix);
969 if (!name)
970 return NULL;
971 name += strlen(prefix);
972 tmp = strchr(name, ' ');
973 if (tmp)
974 *tmp = '\0';
975
976 return strdup(name);
977}
978
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300979static int machine__set_modules_path(struct machine *machine)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800980{
981 char *version;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300982 char modules_path[PATH_MAX];
983
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300984 version = get_kernel_version(machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800985 if (!version)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300986 return -1;
987
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800988 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300989 machine->root_dir, version);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800990 free(version);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300991
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300992 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300993}
994
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300995struct map *machine__new_module(struct machine *machine, u64 start,
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -0300996 const char *filename)
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200997{
998 struct map *map;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300999 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001000
1001 if (dso == NULL)
1002 return NULL;
1003
1004 map = map__new2(start, dso, MAP__FUNCTION);
1005 if (map == NULL)
1006 return NULL;
1007
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001008 if (machine__is_host(machine))
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001009 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001010 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001011 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001012 map_groups__insert(&machine->kmaps, map);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001013 return map;
1014}
1015
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001016static int machine__create_modules(struct machine *machine)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001017{
1018 char *line = NULL;
1019 size_t n;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001020 FILE *file;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001021 struct map *map;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001022 const char *modules;
1023 char path[PATH_MAX];
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001024
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001025 if (machine__is_default_guest(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001026 modules = symbol_conf.default_guest_modules;
1027 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001028 sprintf(path, "%s/proc/modules", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001029 modules = path;
1030 }
1031
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001032 if (symbol__restricted_filename(path, "/proc/modules"))
1033 return -1;
1034
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001035 file = fopen(modules, "r");
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001036 if (file == NULL)
1037 return -1;
1038
1039 while (!feof(file)) {
1040 char name[PATH_MAX];
1041 u64 start;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001042 char *sep;
1043 int line_len;
1044
1045 line_len = getline(&line, &n, file);
1046 if (line_len < 0)
1047 break;
1048
1049 if (!line)
1050 goto out_failure;
1051
1052 line[--line_len] = '\0'; /* \n */
1053
1054 sep = strrchr(line, 'x');
1055 if (sep == NULL)
1056 continue;
1057
1058 hex2u64(sep + 1, &start);
1059
1060 sep = strchr(line, ' ');
1061 if (sep == NULL)
1062 continue;
1063
1064 *sep = '\0';
1065
1066 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001067 map = machine__new_module(machine, start, name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001068 if (map == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001069 goto out_delete_line;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001070 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001071 }
1072
1073 free(line);
1074 fclose(file);
1075
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001076 return machine__set_modules_path(machine);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001077
1078out_delete_line:
1079 free(line);
1080out_failure:
1081 return -1;
1082}
1083
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001084int dso__load_vmlinux(struct dso *dso, struct map *map,
Franck Bui-Huufd930ff2010-12-10 14:06:03 +01001085 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001086{
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001087 int err = -1;
1088 struct symsrc ss;
David Ahernec5761e2010-12-09 13:27:07 -07001089 char symfs_vmlinux[PATH_MAX];
Cody P Schafer005f9292012-08-10 15:22:58 -07001090 enum dso_binary_type symtab_type;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001091
Arnaldo Carvalho de Meloa639dc62011-02-28 13:54:38 -03001092 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
David Ahernec5761e2010-12-09 13:27:07 -07001093 symbol_conf.symfs, vmlinux);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001094
Cody P Schafer21ea4532012-08-10 15:22:56 -07001095 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Cody P Schafer005f9292012-08-10 15:22:58 -07001096 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001097 else
Cody P Schafer005f9292012-08-10 15:22:58 -07001098 symtab_type = DSO_BINARY_TYPE__VMLINUX;
Cody P Schafer21ea4532012-08-10 15:22:56 -07001099
Cody P Schafer005f9292012-08-10 15:22:58 -07001100 if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001101 return -1;
1102
Cody P Schafer261360b2012-08-10 15:23:01 -07001103 err = dso__load_sym(dso, map, &ss, &ss, filter, 0);
Cody P Schaferb68e2f92012-08-10 15:22:57 -07001104 symsrc__destroy(&ss);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001105
Cody P Schafer515850e2012-08-10 15:22:54 -07001106 if (err > 0) {
1107 dso__set_long_name(dso, (char *)vmlinux);
1108 dso__set_loaded(dso, map->type);
David Ahernec5761e2010-12-09 13:27:07 -07001109 pr_debug("Using %s for symbols\n", symfs_vmlinux);
Cody P Schafer515850e2012-08-10 15:22:54 -07001110 }
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001111
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001112 return err;
1113}
1114
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001115int dso__load_vmlinux_path(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001116 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001117{
1118 int i, err = 0;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001119 char *filename;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001120
1121 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001122 vmlinux_path__nr_entries + 1);
1123
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001124 filename = dso__build_id_filename(dso, NULL, 0);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001125 if (filename != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001126 err = dso__load_vmlinux(dso, map, filename, filter);
Cody P Schafer261ee822012-08-10 15:22:52 -07001127 if (err > 0)
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001128 goto out;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001129 free(filename);
1130 }
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001131
1132 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001133 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001134 if (err > 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001135 dso__set_long_name(dso, strdup(vmlinux_path[i]));
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001136 break;
1137 }
1138 }
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001139out:
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001140 return err;
1141}
1142
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001143static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001144 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001145{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001146 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001147 const char *kallsyms_filename = NULL;
1148 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001149 /*
David Ahernb226a5a72010-12-07 19:39:46 -07001150 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1151 * it and only it, reporting errors to the user if it cannot be used.
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001152 *
1153 * For instance, try to analyse an ARM perf.data file _without_ a
1154 * build-id, or if the user specifies the wrong path to the right
1155 * vmlinux file, obviously we can't fallback to another vmlinux (a
1156 * x86_86 one, on the machine where analysis is being performed, say),
1157 * or worse, /proc/kallsyms.
1158 *
1159 * If the specified file _has_ a build-id and there is a build-id
1160 * section in the perf.data file, we will still do the expected
1161 * validation in dso__load_vmlinux and will bail out if they don't
1162 * match.
1163 */
David Ahernb226a5a72010-12-07 19:39:46 -07001164 if (symbol_conf.kallsyms_name != NULL) {
1165 kallsyms_filename = symbol_conf.kallsyms_name;
1166 goto do_kallsyms;
1167 }
1168
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001169 if (symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001170 err = dso__load_vmlinux(dso, map,
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001171 symbol_conf.vmlinux_name, filter);
Arnaldo Carvalho de Meloe7dadc02010-06-03 18:35:55 -03001172 if (err > 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001173 dso__set_long_name(dso,
Arnaldo Carvalho de Meloe7dadc02010-06-03 18:35:55 -03001174 strdup(symbol_conf.vmlinux_name));
1175 goto out_fixup;
1176 }
1177 return err;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001178 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001179
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001180 if (vmlinux_path != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001181 err = dso__load_vmlinux_path(dso, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001182 if (err > 0)
1183 goto out_fixup;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001184 }
1185
David Ahernec5761e2010-12-09 13:27:07 -07001186 /* do not try local files if a symfs was given */
1187 if (symbol_conf.symfs[0] != 0)
1188 return -1;
1189
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001190 /*
1191 * Say the kernel DSO was created when processing the build-id header table,
1192 * we have a build-id, so check if it is the same as the running kernel,
1193 * using it if it is.
1194 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001195 if (dso->has_build_id) {
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001196 u8 kallsyms_build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001197 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001198
1199 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001200 sizeof(kallsyms_build_id)) == 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001201 if (dso__build_id_equal(dso, kallsyms_build_id)) {
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001202 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001203 goto do_kallsyms;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001204 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001205 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001206 /*
1207 * Now look if we have it on the build-id cache in
1208 * $HOME/.debug/[kernel.kallsyms].
1209 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001210 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001211 sbuild_id);
1212
1213 if (asprintf(&kallsyms_allocated_filename,
1214 "%s/.debug/[kernel.kallsyms]/%s",
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001215 getenv("HOME"), sbuild_id) == -1) {
1216 pr_err("Not enough memory for kallsyms file lookup\n");
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001217 return -1;
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001218 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001219
Arnaldo Carvalho de Melo19fc2de2010-01-22 14:35:02 -02001220 kallsyms_filename = kallsyms_allocated_filename;
1221
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001222 if (access(kallsyms_filename, F_OK)) {
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001223 pr_err("No kallsyms or vmlinux with build-id %s "
1224 "was found\n", sbuild_id);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001225 free(kallsyms_allocated_filename);
1226 return -1;
1227 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001228 } else {
1229 /*
1230 * Last resort, if we don't have a build-id and couldn't find
1231 * any vmlinux file, try the running kernel kallsyms table.
1232 */
1233 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001234 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001235
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001236do_kallsyms:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001237 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001238 if (err > 0)
1239 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001240 free(kallsyms_allocated_filename);
1241
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001242 if (err > 0) {
Cody P Schafer0a0317b2012-08-10 15:22:53 -07001243 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001244out_fixup:
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001245 map__fixup_start(map);
1246 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001247 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001248
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001249 return err;
1250}
1251
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001252static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1253 symbol_filter_t filter)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001254{
1255 int err;
1256 const char *kallsyms_filename = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001257 struct machine *machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001258 char path[PATH_MAX];
1259
1260 if (!map->groups) {
1261 pr_debug("Guest kernel map hasn't the point to groups\n");
1262 return -1;
1263 }
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001264 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001265
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001266 if (machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001267 /*
1268 * if the user specified a vmlinux filename, use it and only
1269 * it, reporting errors to the user if it cannot be used.
1270 * Or use file guest_kallsyms inputted by user on commandline
1271 */
1272 if (symbol_conf.default_guest_vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001273 err = dso__load_vmlinux(dso, map,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001274 symbol_conf.default_guest_vmlinux_name, filter);
1275 goto out_try_fixup;
1276 }
1277
1278 kallsyms_filename = symbol_conf.default_guest_kallsyms;
1279 if (!kallsyms_filename)
1280 return -1;
1281 } else {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001282 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001283 kallsyms_filename = path;
1284 }
1285
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001286 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001287 if (err > 0)
1288 pr_debug("Using %s for symbols\n", kallsyms_filename);
1289
1290out_try_fixup:
1291 if (err > 0) {
1292 if (kallsyms_filename != NULL) {
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -03001293 machine__mmap_name(machine, path, sizeof(path));
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001294 dso__set_long_name(dso, strdup(path));
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001295 }
1296 map__fixup_start(map);
1297 map__fixup_end(map);
1298 }
1299
1300 return err;
1301}
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001302
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001304{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001305 struct rb_node *nd;
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03001306 size_t ret = 0;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001307
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001308 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001309 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03001310 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1311 ret += __dsos__fprintf(&pos->user_dsos, fp);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001312 }
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03001313
1314 return ret;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001315}
1316
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1318 bool with_hits)
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03001319{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001320 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1321 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03001322}
1323
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001324size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1325 FILE *fp, bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001326{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001327 struct rb_node *nd;
1328 size_t ret = 0;
1329
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001330 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001331 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03001332 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001333 }
1334 return ret;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001335}
1336
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001337static struct dso *machine__get_kernel(struct machine *machine)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001338{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001339 const char *vmlinux_name = NULL;
1340 struct dso *kernel;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001341
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001342 if (machine__is_host(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001343 vmlinux_name = symbol_conf.vmlinux_name;
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001344 if (!vmlinux_name)
1345 vmlinux_name = "[kernel.kallsyms]";
1346
1347 kernel = dso__kernel_findnew(machine, vmlinux_name,
1348 "[kernel]",
1349 DSO_TYPE_KERNEL);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001350 } else {
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001351 char bf[PATH_MAX];
1352
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001353 if (machine__is_default_guest(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001354 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001355 if (!vmlinux_name)
1356 vmlinux_name = machine__mmap_name(machine, bf,
1357 sizeof(bf));
1358
1359 kernel = dso__kernel_findnew(machine, vmlinux_name,
1360 "[guest.kernel]",
1361 DSO_TYPE_GUEST_KERNEL);
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -02001362 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001363
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001364 if (kernel != NULL && (!kernel->has_build_id))
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001365 dso__read_running_kernel_build_id(kernel, machine);
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001366
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001367 return kernel;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001368}
1369
Ming Leid214afb2010-11-25 19:27:25 +08001370struct process_args {
1371 u64 start;
1372};
1373
1374static int symbol__in_kernel(void *arg, const char *name,
Irina Tirdea1d037ca2012-09-11 01:15:03 +03001375 char type __maybe_unused, u64 start)
Ming Leid214afb2010-11-25 19:27:25 +08001376{
1377 struct process_args *args = arg;
1378
1379 if (strchr(name, '['))
1380 return 0;
1381
1382 args->start = start;
1383 return 1;
1384}
1385
1386/* Figure out the start address of kernel map from /proc/kallsyms */
1387static u64 machine__get_kernel_start_addr(struct machine *machine)
1388{
1389 const char *filename;
1390 char path[PATH_MAX];
1391 struct process_args args;
1392
1393 if (machine__is_host(machine)) {
1394 filename = "/proc/kallsyms";
1395 } else {
1396 if (machine__is_default_guest(machine))
1397 filename = (char *)symbol_conf.default_guest_kallsyms;
1398 else {
1399 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1400 filename = path;
1401 }
1402 }
1403
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001404 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1405 return 0;
1406
Ming Leid214afb2010-11-25 19:27:25 +08001407 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1408 return 0;
1409
1410 return args.start;
1411}
1412
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001413int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001414{
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001415 enum map_type type;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001416 u64 start = machine__get_kernel_start_addr(machine);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001417
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001418 for (type = 0; type < MAP__NR_TYPES; ++type) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001419 struct kmap *kmap;
1420
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001421 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1422 if (machine->vmlinux_maps[type] == NULL)
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001423 return -1;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001424
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001425 machine->vmlinux_maps[type]->map_ip =
1426 machine->vmlinux_maps[type]->unmap_ip =
1427 identity__map_ip;
1428 kmap = map__kmap(machine->vmlinux_maps[type]);
1429 kmap->kmaps = &machine->kmaps;
1430 map_groups__insert(&machine->kmaps,
1431 machine->vmlinux_maps[type]);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001432 }
1433
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001434 return 0;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001435}
1436
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001437void machine__destroy_kernel_maps(struct machine *machine)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001438{
1439 enum map_type type;
1440
1441 for (type = 0; type < MAP__NR_TYPES; ++type) {
1442 struct kmap *kmap;
1443
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001444 if (machine->vmlinux_maps[type] == NULL)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001445 continue;
1446
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001447 kmap = map__kmap(machine->vmlinux_maps[type]);
1448 map_groups__remove(&machine->kmaps,
1449 machine->vmlinux_maps[type]);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001450 if (kmap->ref_reloc_sym) {
1451 /*
1452 * ref_reloc_sym is shared among all maps, so free just
1453 * on one of them.
1454 */
1455 if (type == MAP__FUNCTION) {
1456 free((char *)kmap->ref_reloc_sym->name);
1457 kmap->ref_reloc_sym->name = NULL;
1458 free(kmap->ref_reloc_sym);
1459 }
1460 kmap->ref_reloc_sym = NULL;
1461 }
1462
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001463 map__delete(machine->vmlinux_maps[type]);
1464 machine->vmlinux_maps[type] = NULL;
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001465 }
1466}
1467
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001468int machine__create_kernel_maps(struct machine *machine)
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001469{
Jiri Olsaf57b05e2011-06-01 21:43:46 +02001470 struct dso *kernel = machine__get_kernel(machine);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001471
1472 if (kernel == NULL ||
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001473 __machine__create_kernel_maps(machine, kernel) < 0)
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001474 return -1;
1475
David Ahernf51304d2012-07-20 17:25:46 -06001476 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1477 if (machine__is_host(machine))
1478 pr_debug("Problems creating module maps, "
1479 "continuing anyway...\n");
1480 else
1481 pr_debug("Problems creating module maps for guest %d, "
1482 "continuing anyway...\n", machine->pid);
1483 }
1484
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001485 /*
1486 * Now that we have all the maps created, just set the ->end of them:
1487 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001488 map_groups__fixup_end(&machine->kmaps);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001489 return 0;
1490}
1491
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001492static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001493{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001494 while (--vmlinux_path__nr_entries >= 0) {
1495 free(vmlinux_path[vmlinux_path__nr_entries]);
1496 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1497 }
1498
1499 free(vmlinux_path);
1500 vmlinux_path = NULL;
1501}
1502
1503static int vmlinux_path__init(void)
1504{
1505 struct utsname uts;
1506 char bf[PATH_MAX];
1507
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001508 vmlinux_path = malloc(sizeof(char *) * 5);
1509 if (vmlinux_path == NULL)
1510 return -1;
1511
1512 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1513 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1514 goto out_fail;
1515 ++vmlinux_path__nr_entries;
1516 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1517 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1518 goto out_fail;
1519 ++vmlinux_path__nr_entries;
David Ahernec5761e2010-12-09 13:27:07 -07001520
1521 /* only try running kernel version if no symfs was given */
1522 if (symbol_conf.symfs[0] != 0)
1523 return 0;
1524
1525 if (uname(&uts) < 0)
1526 return -1;
1527
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001528 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1529 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1530 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1531 goto out_fail;
1532 ++vmlinux_path__nr_entries;
1533 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1534 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1535 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1536 goto out_fail;
1537 ++vmlinux_path__nr_entries;
1538 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1539 uts.release);
1540 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1541 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1542 goto out_fail;
1543 ++vmlinux_path__nr_entries;
1544
1545 return 0;
1546
1547out_fail:
1548 vmlinux_path__exit();
1549 return -1;
1550}
1551
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001552size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001553{
1554 int i;
1555 size_t printed = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001556 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001557
1558 if (kdso->has_build_id) {
1559 char filename[PATH_MAX];
1560 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
1561 printed += fprintf(fp, "[0] %s\n", filename);
1562 }
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001563
1564 for (i = 0; i < vmlinux_path__nr_entries; ++i)
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03001565 printed += fprintf(fp, "[%d] %s\n",
1566 i + kdso->has_build_id, vmlinux_path[i]);
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001567
1568 return printed;
1569}
1570
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001571static int setup_list(struct strlist **list, const char *list_str,
1572 const char *list_name)
1573{
1574 if (list_str == NULL)
1575 return 0;
1576
1577 *list = strlist__new(true, list_str);
1578 if (!*list) {
1579 pr_err("problems parsing %s list\n", list_name);
1580 return -1;
1581 }
1582 return 0;
1583}
1584
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001585static bool symbol__read_kptr_restrict(void)
1586{
1587 bool value = false;
1588
1589 if (geteuid() != 0) {
1590 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
1591 if (fp != NULL) {
1592 char line[8];
1593
1594 if (fgets(line, sizeof(line), fp) != NULL)
1595 value = atoi(line) != 0;
1596
1597 fclose(fp);
1598 }
1599 }
1600
1601 return value;
1602}
1603
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001604int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001605{
David Ahernec5761e2010-12-09 13:27:07 -07001606 const char *symfs;
1607
Jovi Zhang85e00b52010-09-09 13:30:59 -03001608 if (symbol_conf.initialized)
1609 return 0;
1610
Irina Tirdea9ac3e482012-09-11 01:15:01 +03001611 symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64));
David S. Miller4d439512011-03-29 14:18:39 -03001612
Namhyung Kim166ccc92012-08-06 13:41:19 +09001613 symbol__elf_init();
1614
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001615 if (symbol_conf.sort_by_name)
1616 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1617 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001618
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001619 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001620 return -1;
1621
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001622 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1623 pr_err("'.' is the only non valid --field-separator argument\n");
1624 return -1;
1625 }
1626
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001627 if (setup_list(&symbol_conf.dso_list,
1628 symbol_conf.dso_list_str, "dso") < 0)
1629 return -1;
1630
1631 if (setup_list(&symbol_conf.comm_list,
1632 symbol_conf.comm_list_str, "comm") < 0)
1633 goto out_free_dso_list;
1634
1635 if (setup_list(&symbol_conf.sym_list,
1636 symbol_conf.sym_list_str, "symbol") < 0)
1637 goto out_free_comm_list;
1638
David Ahernec5761e2010-12-09 13:27:07 -07001639 /*
1640 * A path to symbols of "/" is identical to ""
1641 * reset here for simplicity.
1642 */
1643 symfs = realpath(symbol_conf.symfs, NULL);
1644 if (symfs == NULL)
1645 symfs = symbol_conf.symfs;
1646 if (strcmp(symfs, "/") == 0)
1647 symbol_conf.symfs = "";
1648 if (symfs != symbol_conf.symfs)
1649 free((void *)symfs);
1650
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03001651 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
1652
Jovi Zhang85e00b52010-09-09 13:30:59 -03001653 symbol_conf.initialized = true;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001654 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001655
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001656out_free_comm_list:
1657 strlist__delete(symbol_conf.comm_list);
Namhyung Kimd74c8962011-12-13 00:16:52 +09001658out_free_dso_list:
1659 strlist__delete(symbol_conf.dso_list);
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001660 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001661}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001662
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001663void symbol__exit(void)
1664{
Jovi Zhang85e00b52010-09-09 13:30:59 -03001665 if (!symbol_conf.initialized)
1666 return;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001667 strlist__delete(symbol_conf.sym_list);
1668 strlist__delete(symbol_conf.dso_list);
1669 strlist__delete(symbol_conf.comm_list);
1670 vmlinux_path__exit();
1671 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
Jovi Zhang85e00b52010-09-09 13:30:59 -03001672 symbol_conf.initialized = false;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03001673}
1674
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001675int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001676{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001677 struct machine *machine = machines__findnew(machines, pid);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001678
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001679 if (machine == NULL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001680 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001681
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001682 return machine__create_kernel_maps(machine);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001683}
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001684
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001685int machines__create_guest_kernel_maps(struct rb_root *machines)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001686{
1687 int ret = 0;
1688 struct dirent **namelist = NULL;
1689 int i, items = 0;
1690 char path[PATH_MAX];
1691 pid_t pid;
David Ahern347ed992012-07-29 20:54:35 -06001692 char *endp;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001693
1694 if (symbol_conf.default_guest_vmlinux_name ||
1695 symbol_conf.default_guest_modules ||
1696 symbol_conf.default_guest_kallsyms) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001697 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001698 }
1699
1700 if (symbol_conf.guestmount) {
1701 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
1702 if (items <= 0)
1703 return -ENOENT;
1704 for (i = 0; i < items; i++) {
1705 if (!isdigit(namelist[i]->d_name[0])) {
1706 /* Filter out . and .. */
1707 continue;
1708 }
David Ahern347ed992012-07-29 20:54:35 -06001709 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
1710 if ((*endp != '\0') ||
1711 (endp == namelist[i]->d_name) ||
1712 (errno == ERANGE)) {
1713 pr_debug("invalid directory (%s). Skipping.\n",
1714 namelist[i]->d_name);
1715 continue;
1716 }
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001717 sprintf(path, "%s/%s/proc/kallsyms",
1718 symbol_conf.guestmount,
1719 namelist[i]->d_name);
1720 ret = access(path, R_OK);
1721 if (ret) {
1722 pr_debug("Can't access file %s\n", path);
1723 goto failure;
1724 }
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001725 machines__create_kernel_maps(machines, pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001726 }
1727failure:
1728 free(namelist);
1729 }
1730
1731 return ret;
1732}
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001733
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001734void machines__destroy_guest_kernel_maps(struct rb_root *machines)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001735{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001736 struct rb_node *next = rb_first(machines);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001737
1738 while (next) {
1739 struct machine *pos = rb_entry(next, struct machine, rb_node);
1740
1741 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001742 rb_erase(&pos->rb_node, machines);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03001743 machine__delete(pos);
1744 }
1745}
1746
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001747int machine__load_kallsyms(struct machine *machine, const char *filename,
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001748 enum map_type type, symbol_filter_t filter)
1749{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001750 struct map *map = machine->vmlinux_maps[type];
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001751 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
1752
1753 if (ret > 0) {
1754 dso__set_loaded(map->dso, type);
1755 /*
1756 * Since /proc/kallsyms will have multiple sessions for the
1757 * kernel, with modules between them, fixup the end of all
1758 * sections.
1759 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001760 __map_groups__fixup_end(&machine->kmaps, type);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001761 }
1762
1763 return ret;
1764}
1765
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001766int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001767 symbol_filter_t filter)
1768{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001769 struct map *map = machine->vmlinux_maps[type];
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03001770 int ret = dso__load_vmlinux_path(map->dso, map, filter);
1771
1772 if (ret > 0) {
1773 dso__set_loaded(map->dso, type);
1774 map__reloc_vmlinux(map);
1775 }
1776
1777 return ret;
1778}