blob: 8131949d10f3258fb906a6175003dcb7a9cd3c1b [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 Meloa2928c42009-05-28 14:55:04 -030015#include "symbol.h"
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -030016#include "strlist.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030017
18#include <libelf.h>
19#include <gelf.h>
20#include <elf.h>
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -020021#include <limits.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 Melo3b01a412010-12-22 01:08:36 -020024#ifndef KSYM_NAME_LEN
Ricardo Ribalda Delgadoc752d042011-10-20 09:43:26 +020025#define KSYM_NAME_LEN 256
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -020026#endif
27
Arnaldo Carvalho de Meloc12e15e2009-11-21 14:31:25 -020028#ifndef NT_GNU_BUILD_ID
29#define NT_GNU_BUILD_ID 3
30#endif
31
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030032static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
Dave Martin21916c32010-07-30 09:08:08 -030033static int elf_read_build_id(Elf *elf, void *bf, size_t size);
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -020034static void dsos__add(struct list_head *head, struct dso *dso);
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020035static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030036static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020037 symbol_filter_t filter);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030038static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080039 symbol_filter_t filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020040static int vmlinux_path__nr_entries;
41static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030042
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020043struct symbol_conf symbol_conf = {
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -020044 .exclude_other = true,
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020045 .use_modules = true,
46 .try_vmlinux_path = true,
Stephane Eranian3e6a2a72011-05-17 17:32:07 +020047 .annotate_src = true,
David Ahernec5761e2010-12-09 13:27:07 -070048 .symfs = "",
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020049};
50
Jiri Olsa44f24cb2012-07-22 14:14:32 +020051static enum dso_binary_type binary_type_symtab[] = {
52 DSO_BINARY_TYPE__KALLSYMS,
53 DSO_BINARY_TYPE__GUEST_KALLSYMS,
54 DSO_BINARY_TYPE__JAVA_JIT,
55 DSO_BINARY_TYPE__DEBUGLINK,
56 DSO_BINARY_TYPE__BUILD_ID_CACHE,
57 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
58 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
59 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
60 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
61 DSO_BINARY_TYPE__GUEST_KMODULE,
62 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
63 DSO_BINARY_TYPE__NOT_FOUND,
64};
65
66#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
67
Jiri Olsa949d1602012-07-22 14:14:33 +020068static enum dso_binary_type binary_type_data[] = {
69 DSO_BINARY_TYPE__BUILD_ID_CACHE,
70 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
71 DSO_BINARY_TYPE__NOT_FOUND,
72};
73
74#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
75
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030076int dso__name_len(const struct dso *dso)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030077{
David Miller1e2dd2f2012-03-25 16:28:22 -040078 if (!dso)
79 return strlen("[unknown]");
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030080 if (verbose)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030081 return dso->long_name_len;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030082
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030083 return dso->short_name_len;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030084}
85
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030086bool dso__loaded(const struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020087{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030088 return dso->loaded & (1 << type);
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020089}
90
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030091bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020092{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030093 return dso->sorted_by_name & (1 << type);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020094}
95
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030096static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020097{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -030098 dso->sorted_by_name |= (1 << type);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020099}
100
Arnaldo Carvalho de Melo36a3e642010-01-04 16:19:27 -0200101bool symbol_type__is_a(char symbol_type, enum map_type map_type)
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -0200102{
Anton Blanchard31877902011-08-24 16:40:16 +1000103 symbol_type = toupper(symbol_type);
104
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -0200105 switch (map_type) {
106 case MAP__FUNCTION:
107 return symbol_type == 'T' || symbol_type == 'W';
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200108 case MAP__VARIABLE:
Anton Blanchard31877902011-08-24 16:40:16 +1000109 return symbol_type == 'D';
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -0200110 default:
111 return false;
112 }
113}
114
Anton Blanchard694bf402011-08-24 16:40:17 +1000115static int prefix_underscores_count(const char *str)
116{
117 const char *tail = str;
118
119 while (*tail == '_')
120 tail++;
121
122 return tail - str;
123}
124
125#define SYMBOL_A 0
126#define SYMBOL_B 1
127
128static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
129{
130 s64 a;
131 s64 b;
132
133 /* Prefer a symbol with non zero length */
134 a = syma->end - syma->start;
135 b = symb->end - symb->start;
136 if ((b == 0) && (a > 0))
137 return SYMBOL_A;
138 else if ((a == 0) && (b > 0))
139 return SYMBOL_B;
140
141 /* Prefer a non weak symbol over a weak one */
142 a = syma->binding == STB_WEAK;
143 b = symb->binding == STB_WEAK;
144 if (b && !a)
145 return SYMBOL_A;
146 if (a && !b)
147 return SYMBOL_B;
148
149 /* Prefer a global symbol over a non global one */
150 a = syma->binding == STB_GLOBAL;
151 b = symb->binding == STB_GLOBAL;
152 if (a && !b)
153 return SYMBOL_A;
154 if (b && !a)
155 return SYMBOL_B;
156
157 /* Prefer a symbol with less underscores */
158 a = prefix_underscores_count(syma->name);
159 b = prefix_underscores_count(symb->name);
160 if (b > a)
161 return SYMBOL_A;
162 else if (a > b)
163 return SYMBOL_B;
164
165 /* If all else fails, choose the symbol with the longest name */
166 if (strlen(syma->name) >= strlen(symb->name))
167 return SYMBOL_A;
168 else
169 return SYMBOL_B;
170}
171
172static void symbols__fixup_duplicate(struct rb_root *symbols)
173{
174 struct rb_node *nd;
175 struct symbol *curr, *next;
176
177 nd = rb_first(symbols);
178
179 while (nd) {
180 curr = rb_entry(nd, struct symbol, rb_node);
181again:
182 nd = rb_next(&curr->rb_node);
183 next = rb_entry(nd, struct symbol, rb_node);
184
185 if (!nd)
186 break;
187
188 if (curr->start != next->start)
189 continue;
190
191 if (choose_best_symbol(curr, next) == SYMBOL_A) {
192 rb_erase(&next->rb_node, symbols);
193 goto again;
194 } else {
195 nd = rb_next(&curr->rb_node);
196 rb_erase(&curr->rb_node, symbols);
197 }
198 }
199}
200
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300201static void symbols__fixup_end(struct rb_root *symbols)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300202{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300203 struct rb_node *nd, *prevnd = rb_first(symbols);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300204 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300205
206 if (prevnd == NULL)
207 return;
208
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300209 curr = rb_entry(prevnd, struct symbol, rb_node);
210
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300211 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300212 prev = curr;
213 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300214
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200215 if (prev->end == prev->start && prev->end != curr->start)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300216 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300217 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300218
219 /* Last entry */
220 if (curr->end == curr->start)
221 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300222}
223
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300224static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300225{
226 struct map *prev, *curr;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300227 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300228
229 if (prevnd == NULL)
230 return;
231
232 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300233
234 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
235 prev = curr;
236 curr = rb_entry(nd, struct map, rb_node);
237 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300238 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -0200239
240 /*
241 * We still haven't the actual symbols, so guess the
242 * last map final address.
243 */
Ian Munsie9d1faba2010-11-25 15:12:53 +1100244 curr->end = ~0ULL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300245}
246
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300247static void map_groups__fixup_end(struct map_groups *mg)
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200248{
249 int i;
250 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300251 __map_groups__fixup_end(mg, i);
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200252}
253
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -0300254static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
255 const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300256{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300257 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300258 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
259 sizeof(*sym) + namelen));
260 if (sym == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200261 return NULL;
262
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200263 if (symbol_conf.priv_size)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300264 sym = ((void *)sym) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200265
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300266 sym->start = start;
267 sym->end = len ? start + len - 1 : start;
268 sym->binding = binding;
269 sym->namelen = namelen - 1;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200270
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300271 pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
272 __func__, name, start, sym->end);
273 memcpy(sym->name, name, namelen);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200274
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300275 return sym;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300276}
277
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300278void symbol__delete(struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300279{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300280 free(((void *)sym) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300281}
282
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300283static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300284{
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200285 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300286 sym->start, sym->end,
287 sym->binding == STB_GLOBAL ? 'g' :
288 sym->binding == STB_LOCAL ? 'l' : 'w',
289 sym->name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300290}
291
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900292size_t symbol__fprintf_symname_offs(const struct symbol *sym,
293 const struct addr_location *al, FILE *fp)
294{
295 unsigned long offset;
296 size_t length;
297
298 if (sym && sym->name) {
299 length = fprintf(fp, "%s", sym->name);
300 if (al) {
301 offset = al->addr - sym->start;
302 length += fprintf(fp, "+0x%lx", offset);
303 }
304 return length;
305 } else
306 return fprintf(fp, "[unknown]");
307}
308
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900309size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
310{
Akihiro Nagaia978f2a2012-01-30 13:43:15 +0900311 return symbol__fprintf_symname_offs(sym, NULL, fp);
Akihiro Nagai547a92e2012-01-30 13:42:57 +0900312}
313
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300314void dso__set_long_name(struct dso *dso, char *name)
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200315{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200316 if (name == NULL)
317 return;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300318 dso->long_name = name;
319 dso->long_name_len = strlen(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200320}
321
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300322static void dso__set_short_name(struct dso *dso, const char *name)
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300323{
324 if (name == NULL)
325 return;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300326 dso->short_name = name;
327 dso->short_name_len = strlen(name);
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300328}
329
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300330static void dso__set_basename(struct dso *dso)
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200331{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300332 dso__set_short_name(dso, basename(dso->long_name));
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200333}
334
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200335struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300336{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300337 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300338
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300339 if (dso != NULL) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200340 int i;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300341 strcpy(dso->name, name);
342 dso__set_long_name(dso, dso->name);
343 dso__set_short_name(dso, dso->name);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200344 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300345 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200346 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
Jiri Olsa949d1602012-07-22 14:14:33 +0200347 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300348 dso->loaded = 0;
349 dso->sorted_by_name = 0;
350 dso->has_build_id = 0;
351 dso->kernel = DSO_TYPE_USER;
Jiri Olsa8db48412012-05-30 14:23:42 +0200352 dso->needs_swap = DSO_SWAP__UNSET;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300353 INIT_LIST_HEAD(&dso->node);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300354 }
355
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300356 return dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300357}
358
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300359static void symbols__delete(struct rb_root *symbols)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300360{
361 struct symbol *pos;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300362 struct rb_node *next = rb_first(symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300363
364 while (next) {
365 pos = rb_entry(next, struct symbol, rb_node);
366 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300367 rb_erase(&pos->rb_node, symbols);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200368 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300369 }
370}
371
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300372void dso__delete(struct dso *dso)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300373{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200374 int i;
375 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300376 symbols__delete(&dso->symbols[i]);
377 if (dso->sname_alloc)
378 free((char *)dso->short_name);
379 if (dso->lname_alloc)
380 free(dso->long_name);
381 free(dso);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300382}
383
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300384void dso__set_build_id(struct dso *dso, void *build_id)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200385{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300386 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
387 dso->has_build_id = 1;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200388}
389
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300390static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300391{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300392 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300393 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000394 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300395 struct symbol *s;
396
397 while (*p != NULL) {
398 parent = *p;
399 s = rb_entry(parent, struct symbol, rb_node);
400 if (ip < s->start)
401 p = &(*p)->rb_left;
402 else
403 p = &(*p)->rb_right;
404 }
405 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300406 rb_insert_color(&sym->rb_node, symbols);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300407}
408
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300409static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300410{
411 struct rb_node *n;
412
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300413 if (symbols == NULL)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300414 return NULL;
415
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300416 n = symbols->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300417
418 while (n) {
419 struct symbol *s = rb_entry(n, struct symbol, rb_node);
420
421 if (ip < s->start)
422 n = n->rb_left;
423 else if (ip > s->end)
424 n = n->rb_right;
425 else
426 return s;
427 }
428
429 return NULL;
430}
431
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200432struct symbol_name_rb_node {
433 struct rb_node rb_node;
434 struct symbol sym;
435};
436
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300437static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200438{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300439 struct rb_node **p = &symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200440 struct rb_node *parent = NULL;
Rabin Vincent02a9d032010-11-23 22:08:18 +0530441 struct symbol_name_rb_node *symn, *s;
442
443 symn = container_of(sym, struct symbol_name_rb_node, sym);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200444
445 while (*p != NULL) {
446 parent = *p;
447 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
448 if (strcmp(sym->name, s->sym.name) < 0)
449 p = &(*p)->rb_left;
450 else
451 p = &(*p)->rb_right;
452 }
453 rb_link_node(&symn->rb_node, parent, p);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300454 rb_insert_color(&symn->rb_node, symbols);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200455}
456
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300457static void symbols__sort_by_name(struct rb_root *symbols,
458 struct rb_root *source)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200459{
460 struct rb_node *nd;
461
462 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
463 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300464 symbols__insert_by_name(symbols, pos);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200465 }
466}
467
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300468static struct symbol *symbols__find_by_name(struct rb_root *symbols,
469 const char *name)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200470{
471 struct rb_node *n;
472
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300473 if (symbols == NULL)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200474 return NULL;
475
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300476 n = symbols->rb_node;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200477
478 while (n) {
479 struct symbol_name_rb_node *s;
480 int cmp;
481
482 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
483 cmp = strcmp(name, s->sym.name);
484
485 if (cmp < 0)
486 n = n->rb_left;
487 else if (cmp > 0)
488 n = n->rb_right;
489 else
490 return &s->sym;
491 }
492
493 return NULL;
494}
495
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300496struct symbol *dso__find_symbol(struct dso *dso,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200497 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200498{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300499 return symbols__find(&dso->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200500}
501
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300502struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200503 const char *name)
504{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300505 return symbols__find_by_name(&dso->symbol_names[type], name);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200506}
507
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300508void dso__sort_by_name(struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200509{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300510 dso__set_sorted_by_name(dso, type);
511 return symbols__sort_by_name(&dso->symbol_names[type],
512 &dso->symbols[type]);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200513}
514
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300515int build_id__sprintf(const u8 *build_id, int len, char *bf)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200516{
517 char *bid = bf;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300518 const u8 *raw = build_id;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200519 int i;
520
521 for (i = 0; i < len; ++i) {
522 sprintf(bid, "%02x", *raw);
523 ++raw;
524 bid += 2;
525 }
526
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300527 return raw - build_id;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200528}
529
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300530size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300531{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200532 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200533
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300534 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200535 return fprintf(fp, "%s", sbuild_id);
536}
537
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300538size_t dso__fprintf_symbols_by_name(struct dso *dso,
539 enum map_type type, FILE *fp)
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530540{
541 size_t ret = 0;
542 struct rb_node *nd;
543 struct symbol_name_rb_node *pos;
544
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300545 for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
Srikar Dronamraju90f18e62010-08-25 19:13:29 +0530546 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
547 fprintf(fp, "%s\n", pos->sym.name);
548 }
549
550 return ret;
551}
552
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300553size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200554{
555 struct rb_node *nd;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300556 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200557
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300558 if (dso->short_name != dso->long_name)
559 ret += fprintf(fp, "%s, ", dso->long_name);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -0300560 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300561 dso->loaded ? "" : "NOT ");
562 ret += dso__fprintf_buildid(dso, fp);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200563 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300564 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200565 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
566 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300567 }
568
569 return ret;
570}
571
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200572int kallsyms__parse(const char *filename, void *arg,
573 int (*process_symbol)(void *arg, const char *name,
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200574 char type, u64 start, u64 end))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300575{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300576 char *line = NULL;
577 size_t n;
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200578 int err = -1;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200579 FILE *file = fopen(filename, "r");
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300580
581 if (file == NULL)
582 goto out_failure;
583
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200584 err = 0;
585
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300586 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000587 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300588 int line_len, len;
589 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300590 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300591
592 line_len = getline(&line, &n, file);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800593 if (line_len < 0 || !line)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300594 break;
595
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300596 line[--line_len] = '\0'; /* \n */
597
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300598 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300599
600 len++;
601 if (len + 2 >= line_len)
602 continue;
603
Anton Blanchard31877902011-08-24 16:40:16 +1000604 symbol_type = line[len];
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200605 len += 2;
606 symbol_name = line + len;
607 len = line_len - len;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300608
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200609 if (len >= KSYM_NAME_LEN) {
610 err = -1;
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200611 break;
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200612 }
613
Anton Blanchard3f5a4272011-08-24 16:40:15 +1000614 /*
615 * module symbols are not sorted so we add all
616 * symbols with zero length and rely on
617 * symbols__fixup_end() to fix it up.
618 */
619 err = process_symbol(arg, symbol_name,
620 symbol_type, start, start);
621 if (err)
622 break;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300623 }
624
625 free(line);
626 fclose(file);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200627 return err;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300628
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300629out_failure:
630 return -1;
631}
632
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200633struct process_kallsyms_args {
634 struct map *map;
635 struct dso *dso;
636};
637
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -0300638static u8 kallsyms2elf_type(char type)
639{
640 if (type == 'W')
641 return STB_WEAK;
642
643 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
644}
645
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200646static int map__process_kallsym_symbol(void *arg, const char *name,
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200647 char type, u64 start, u64 end)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200648{
649 struct symbol *sym;
650 struct process_kallsyms_args *a = arg;
651 struct rb_root *root = &a->dso->symbols[a->map->type];
652
653 if (!symbol_type__is_a(type, a->map->type))
654 return 0;
655
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -0200656 sym = symbol__new(start, end - start + 1,
657 kallsyms2elf_type(type), name);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200658 if (sym == NULL)
659 return -ENOMEM;
660 /*
661 * We will pass the symbols to the filter later, in
662 * map__split_kallsyms, when we have split the maps per module
663 */
664 symbols__insert(root, sym);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800665
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200666 return 0;
667}
668
669/*
670 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
671 * so that we can in the next step set the symbol ->end address and then
672 * call kernel_maps__split_kallsyms.
673 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300674static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200675 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200676{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300677 struct process_kallsyms_args args = { .map = map, .dso = dso, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200678 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200679}
680
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300681/*
682 * Split the symbols into maps, making sure there are no overlaps, i.e. the
683 * kernel range is broken in several maps, named [kernel].N, as we don't have
684 * the original ELF section names vmlinux have.
685 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300686static int dso__split_kallsyms(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200687 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300688{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200689 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300690 struct machine *machine = kmaps->machine;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200691 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300692 struct symbol *pos;
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200693 int count = 0, moved = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300694 struct rb_root *root = &dso->symbols[map->type];
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200695 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300696 int kernel_range = 0;
697
698 while (next) {
699 char *module;
700
701 pos = rb_entry(next, struct symbol, rb_node);
702 next = rb_next(&pos->rb_node);
703
704 module = strchr(pos->name, '\t');
705 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200706 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200707 goto discard_symbol;
708
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300709 *module++ = '\0';
710
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200711 if (strcmp(curr_map->dso->short_name, module)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800712 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300713 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300714 machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800715 /*
716 * We assume all symbols of a module are
717 * continuous in * kallsyms, so curr_map
718 * points to a module and all its
719 * symbols are in its kmap. Mark it as
720 * loaded.
721 */
722 dso__set_loaded(curr_map->dso,
723 curr_map->type);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300724 }
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200725
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800726 curr_map = map_groups__find_by_name(kmaps,
727 map->type, module);
728 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2f519032010-05-17 17:57:59 -0300729 pr_debug("%s/proc/{kallsyms,modules} "
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800730 "inconsistency while looking "
731 "for \"%s\" module!\n",
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300732 machine->root_dir, module);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800733 curr_map = map;
734 goto discard_symbol;
735 }
736
737 if (curr_map->dso->loaded &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300738 !machine__is_default_guest(machine))
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200739 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300740 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300741 /*
742 * So that we look just like we get from .ko files,
743 * i.e. not prelinked, relative to map->start.
744 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200745 pos->start = curr_map->map_ip(curr_map, pos->start);
746 pos->end = curr_map->map_ip(curr_map, pos->end);
747 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300748 char dso_name[PATH_MAX];
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300749 struct dso *ndso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300750
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200751 if (count == 0) {
752 curr_map = map;
753 goto filter_symbol;
754 }
755
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300756 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800757 snprintf(dso_name, sizeof(dso_name),
758 "[guest.kernel].%d",
759 kernel_range++);
760 else
761 snprintf(dso_name, sizeof(dso_name),
762 "[kernel].%d",
763 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300764
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300765 ndso = dso__new(dso_name);
766 if (ndso == NULL)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300767 return -1;
768
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300769 ndso->kernel = dso->kernel;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800770
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300771 curr_map = map__new2(pos->start, ndso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800772 if (curr_map == NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300773 dso__delete(ndso);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300774 return -1;
775 }
776
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200777 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200778 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300779 ++kernel_range;
780 }
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200781filter_symbol:
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200782 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200783discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200784 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300785 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200786 if (curr_map != map) {
787 rb_erase(&pos->rb_node, root);
788 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200789 ++moved;
790 } else
791 ++count;
Mike Galbraith9974f492009-07-02 08:05:58 +0200792 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300793 }
794
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800795 if (curr_map != map &&
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300796 dso->kernel == DSO_TYPE_GUEST_KERNEL &&
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -0300797 machine__is_default_guest(kmaps->machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800798 dso__set_loaded(curr_map->dso, curr_map->type);
799 }
800
Arnaldo Carvalho de Melo8a953312010-11-29 12:44:15 -0200801 return count + moved;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300802}
803
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300804static bool symbol__restricted_filename(const char *filename,
805 const char *restricted_filename)
806{
807 bool restricted = false;
808
809 if (symbol_conf.kptr_restrict) {
810 char *r = realpath(filename, NULL);
811
812 if (r != NULL) {
813 restricted = strcmp(r, restricted_filename) == 0;
814 free(r);
815 return restricted;
816 }
817 }
818
819 return restricted;
820}
821
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300822int dso__load_kallsyms(struct dso *dso, const char *filename,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200823 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300824{
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -0300825 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
826 return -1;
827
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300828 if (dso__load_all_kallsyms(dso, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300829 return -1;
830
Anton Blanchard694bf402011-08-24 16:40:17 +1000831 symbols__fixup_duplicate(&dso->symbols[map->type]);
Anton Blanchard3f5a4272011-08-24 16:40:15 +1000832 symbols__fixup_end(&dso->symbols[map->type]);
833
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300834 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200835 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800836 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +0200837 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300838
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300839 return dso__split_kallsyms(dso, map, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300840}
841
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300842static int dso__load_perf_map(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200843 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300844{
845 char *line = NULL;
846 size_t n;
847 FILE *file;
848 int nr_syms = 0;
849
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300850 file = fopen(dso->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300851 if (file == NULL)
852 goto out_failure;
853
854 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000855 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300856 struct symbol *sym;
857 int line_len, len;
858
859 line_len = getline(&line, &n, file);
860 if (line_len < 0)
861 break;
862
863 if (!line)
864 goto out_failure;
865
866 line[--line_len] = '\0'; /* \n */
867
868 len = hex2u64(line, &start);
869
870 len++;
871 if (len + 2 >= line_len)
872 continue;
873
874 len += hex2u64(line + len, &size);
875
876 len++;
877 if (len + 2 >= line_len)
878 continue;
879
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -0300880 sym = symbol__new(start, size, STB_GLOBAL, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300881
882 if (sym == NULL)
883 goto out_delete_line;
884
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300885 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200886 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300887 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300888 symbols__insert(&dso->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300889 nr_syms++;
890 }
891 }
892
893 free(line);
894 fclose(file);
895
896 return nr_syms;
897
898out_delete_line:
899 free(line);
900out_failure:
901 return -1;
902}
903
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300904/**
905 * elf_symtab__for_each_symbol - iterate thru all the symbols
906 *
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -0300907 * @syms: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200908 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300909 * @sym: GElf_Sym iterator
910 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200911#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
912 for (idx = 0, gelf_getsym(syms, idx, &sym);\
913 idx < nr_syms; \
914 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300915
916static inline uint8_t elf_sym__type(const GElf_Sym *sym)
917{
918 return GELF_ST_TYPE(sym->st_info);
919}
920
921static inline int elf_sym__is_function(const GElf_Sym *sym)
922{
923 return elf_sym__type(sym) == STT_FUNC &&
924 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300925 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300926}
927
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200928static inline bool elf_sym__is_object(const GElf_Sym *sym)
929{
930 return elf_sym__type(sym) == STT_OBJECT &&
931 sym->st_name != 0 &&
932 sym->st_shndx != SHN_UNDEF;
933}
934
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200935static inline int elf_sym__is_label(const GElf_Sym *sym)
936{
937 return elf_sym__type(sym) == STT_NOTYPE &&
938 sym->st_name != 0 &&
939 sym->st_shndx != SHN_UNDEF &&
940 sym->st_shndx != SHN_ABS;
941}
942
943static inline const char *elf_sec__name(const GElf_Shdr *shdr,
944 const Elf_Data *secstrs)
945{
946 return secstrs->d_buf + shdr->sh_name;
947}
948
949static inline int elf_sec__is_text(const GElf_Shdr *shdr,
950 const Elf_Data *secstrs)
951{
952 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
953}
954
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200955static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
956 const Elf_Data *secstrs)
957{
958 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
959}
960
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300961static inline const char *elf_sym__name(const GElf_Sym *sym,
962 const Elf_Data *symstrs)
963{
964 return symstrs->d_buf + sym->st_name;
965}
966
967static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
968 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200969 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300970{
971 Elf_Scn *sec = NULL;
972 size_t cnt = 1;
973
974 while ((sec = elf_nextscn(elf, sec)) != NULL) {
975 char *str;
976
977 gelf_getshdr(sec, shp);
978 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
979 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200980 if (idx)
981 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300982 break;
983 }
984 ++cnt;
985 }
986
987 return sec;
988}
989
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300990#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
991 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
992 idx < nr_entries; \
993 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
994
995#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
996 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
997 idx < nr_entries; \
998 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
999
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001000/*
1001 * We need to check if we have a .dynsym, so that we can handle the
1002 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
1003 * .dynsym or .symtab).
1004 * And always look at the original dso, not at debuginfo packages, that
1005 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
1006 */
Jiri Olsa33ff5812012-04-18 15:46:58 +02001007static int
1008dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
1009 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001010{
1011 uint32_t nr_rel_entries, idx;
1012 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001013 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001014 GElf_Shdr shdr_plt;
1015 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001016 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001017 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001018 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
1019 size_t dynsym_idx;
1020 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001021 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001022 Elf *elf;
1023 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001024
David Ahernec5761e2010-12-09 13:27:07 -07001025 fd = open(name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001026 if (fd < 0)
1027 goto out;
1028
Marti Raudsepp84087122009-10-24 19:10:36 +03001029 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001030 if (elf == NULL)
1031 goto out_close;
1032
1033 if (gelf_getehdr(elf, &ehdr) == NULL)
1034 goto out_elf_end;
1035
1036 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
1037 ".dynsym", &dynsym_idx);
1038 if (scn_dynsym == NULL)
1039 goto out_elf_end;
1040
1041 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001042 ".rela.plt", NULL);
1043 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001044 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001045 ".rel.plt", NULL);
1046 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001047 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001048 }
1049
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001050 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001051
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001052 if (shdr_rel_plt.sh_link != dynsym_idx)
1053 goto out_elf_end;
1054
1055 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
1056 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001057
1058 /*
Ingo Molnar83a09442009-08-15 12:26:57 +02001059 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001060 * and the symbols in the .dynsym they refer to.
1061 */
1062 reldata = elf_getdata(scn_plt_rel, NULL);
1063 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001064 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001065
1066 syms = elf_getdata(scn_dynsym, NULL);
1067 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001068 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001069
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001070 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001071 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001072 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001073
1074 symstrs = elf_getdata(scn_symstrs, NULL);
1075 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001076 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001077
1078 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
1079 plt_offset = shdr_plt.sh_offset;
1080
1081 if (shdr_rel_plt.sh_type == SHT_RELA) {
1082 GElf_Rela pos_mem, *pos;
1083
1084 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
1085 nr_rel_entries) {
1086 symidx = GELF_R_SYM(pos->r_info);
1087 plt_offset += shdr_plt.sh_entsize;
1088 gelf_getsym(syms, symidx, &sym);
1089 snprintf(sympltname, sizeof(sympltname),
1090 "%s@plt", elf_sym__name(&sym, symstrs));
1091
1092 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -03001093 STB_GLOBAL, sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001094 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001095 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001096
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001097 if (filter && filter(map, f))
1098 symbol__delete(f);
1099 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001100 symbols__insert(&dso->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001101 ++nr;
1102 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001103 }
1104 } else if (shdr_rel_plt.sh_type == SHT_REL) {
1105 GElf_Rel pos_mem, *pos;
1106 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
1107 nr_rel_entries) {
1108 symidx = GELF_R_SYM(pos->r_info);
1109 plt_offset += shdr_plt.sh_entsize;
1110 gelf_getsym(syms, symidx, &sym);
1111 snprintf(sympltname, sizeof(sympltname),
1112 "%s@plt", elf_sym__name(&sym, symstrs));
1113
1114 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -03001115 STB_GLOBAL, sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001116 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001117 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001118
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001119 if (filter && filter(map, f))
1120 symbol__delete(f);
1121 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001122 symbols__insert(&dso->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001123 ++nr;
1124 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001125 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001126 }
1127
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001128 err = 0;
1129out_elf_end:
1130 elf_end(elf);
1131out_close:
1132 close(fd);
1133
1134 if (err == 0)
1135 return nr;
1136out:
Arnaldo Carvalho de Melofe2197b2010-03-11 20:12:40 -03001137 pr_debug("%s: problems reading %s PLT info.\n",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001138 __func__, dso->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001139 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001140}
1141
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001142static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001143{
1144 switch (type) {
1145 case MAP__FUNCTION:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001146 return elf_sym__is_function(sym);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001147 case MAP__VARIABLE:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001148 return elf_sym__is_object(sym);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001149 default:
1150 return false;
1151 }
1152}
1153
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001154static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1155 enum map_type type)
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001156{
1157 switch (type) {
1158 case MAP__FUNCTION:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001159 return elf_sec__is_text(shdr, secstrs);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001160 case MAP__VARIABLE:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001161 return elf_sec__is_data(shdr, secstrs);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001162 default:
1163 return false;
1164 }
1165}
1166
Eric B Munson70c38562010-06-14 14:56:33 +01001167static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
1168{
1169 Elf_Scn *sec = NULL;
1170 GElf_Shdr shdr;
1171 size_t cnt = 1;
1172
1173 while ((sec = elf_nextscn(elf, sec)) != NULL) {
1174 gelf_getshdr(sec, &shdr);
1175
1176 if ((addr >= shdr.sh_addr) &&
1177 (addr < (shdr.sh_addr + shdr.sh_size)))
1178 return cnt;
1179
1180 ++cnt;
1181 }
1182
1183 return -1;
1184}
1185
Jiri Olsa8db48412012-05-30 14:23:42 +02001186static int dso__swap_init(struct dso *dso, unsigned char eidata)
1187{
1188 static unsigned int const endian = 1;
1189
1190 dso->needs_swap = DSO_SWAP__NO;
1191
1192 switch (eidata) {
1193 case ELFDATA2LSB:
1194 /* We are big endian, DSO is little endian. */
1195 if (*(unsigned char const *)&endian != 1)
1196 dso->needs_swap = DSO_SWAP__YES;
1197 break;
1198
1199 case ELFDATA2MSB:
1200 /* We are little endian, DSO is big endian. */
1201 if (*(unsigned char const *)&endian != 0)
1202 dso->needs_swap = DSO_SWAP__YES;
1203 break;
1204
1205 default:
1206 pr_err("unrecognized DSO data encoding %d\n", eidata);
1207 return -EINVAL;
1208 }
1209
1210 return 0;
1211}
1212
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001213static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
Dave Martin6da80ce2010-07-30 09:50:09 -03001214 int fd, symbol_filter_t filter, int kmodule,
1215 int want_symtab)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001216{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001217 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001218 struct map *curr_map = map;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001219 struct dso *curr_dso = dso;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001220 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001221 uint32_t nr_syms;
1222 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +02001223 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001224 GElf_Ehdr ehdr;
Eric B Munson70c38562010-06-14 14:56:33 +01001225 GElf_Shdr shdr, opdshdr;
1226 Elf_Data *syms, *opddata = NULL;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001227 GElf_Sym sym;
Eric B Munson70c38562010-06-14 14:56:33 +01001228 Elf_Scn *sec, *sec_strndx, *opdsec;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001229 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001230 int nr = 0;
Eric B Munson70c38562010-06-14 14:56:33 +01001231 size_t opdidx = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001232
Marti Raudsepp84087122009-10-24 19:10:36 +03001233 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001234 if (elf == NULL) {
Dave Martin8b1389e2010-07-30 09:36:08 -03001235 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001236 goto out_close;
1237 }
1238
1239 if (gelf_getehdr(elf, &ehdr) == NULL) {
Dave Martin8b1389e2010-07-30 09:36:08 -03001240 pr_debug("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001241 goto out_elf_end;
1242 }
1243
Jiri Olsa8db48412012-05-30 14:23:42 +02001244 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
1245 goto out_elf_end;
1246
Dave Martin6da80ce2010-07-30 09:50:09 -03001247 /* Always reject images with a mismatched build-id: */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001248 if (dso->has_build_id) {
Dave Martin21916c32010-07-30 09:08:08 -03001249 u8 build_id[BUILD_ID_SIZE];
1250
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001251 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
Dave Martin21916c32010-07-30 09:08:08 -03001252 goto out_elf_end;
1253
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001254 if (!dso__build_id_equal(dso, build_id))
Dave Martin21916c32010-07-30 09:08:08 -03001255 goto out_elf_end;
1256 }
1257
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001258 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
1259 if (sec == NULL) {
Dave Martin6da80ce2010-07-30 09:50:09 -03001260 if (want_symtab)
1261 goto out_elf_end;
1262
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001263 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1264 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001265 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -03001266 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001267
Eric B Munson70c38562010-06-14 14:56:33 +01001268 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
Anton Blanchardadb09182011-08-24 16:40:14 +10001269 if (opdshdr.sh_type != SHT_PROGBITS)
1270 opdsec = NULL;
Eric B Munson70c38562010-06-14 14:56:33 +01001271 if (opdsec)
1272 opddata = elf_rawdata(opdsec, NULL);
1273
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001274 syms = elf_getdata(sec, NULL);
1275 if (syms == NULL)
1276 goto out_elf_end;
1277
1278 sec = elf_getscn(elf, shdr.sh_link);
1279 if (sec == NULL)
1280 goto out_elf_end;
1281
1282 symstrs = elf_getdata(sec, NULL);
1283 if (symstrs == NULL)
1284 goto out_elf_end;
1285
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001286 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
1287 if (sec_strndx == NULL)
1288 goto out_elf_end;
1289
1290 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -05001291 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001292 goto out_elf_end;
1293
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001294 nr_syms = shdr.sh_size / shdr.sh_entsize;
1295
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +02001296 memset(&sym, 0, sizeof(sym));
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001297 if (dso->kernel == DSO_TYPE_USER) {
1298 dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001299 elf_section_by_name(elf, &ehdr, &shdr,
1300 ".gnu.prelink_undo",
1301 NULL) != NULL);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001302 } else {
1303 dso->adjust_symbols = 0;
1304 }
Ingo Molnar83a09442009-08-15 12:26:57 +02001305 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001306 struct symbol *f;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -02001307 const char *elf_name = elf_sym__name(&sym, symstrs);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001308 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001309 int is_label = elf_sym__is_label(&sym);
1310 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001311
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001312 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
1313 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
1314 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -02001315
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001316 if (!is_label && !elf_sym__is_a(&sym, map->type))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001317 continue;
1318
Dave Martin696b97a2010-08-09 12:21:18 +01001319 /* Reject ARM ELF "mapping symbols": these aren't unique and
1320 * don't identify functions, so will confuse the profile
1321 * output: */
1322 if (ehdr.e_machine == EM_ARM) {
1323 if (!strcmp(elf_name, "$a") ||
1324 !strcmp(elf_name, "$d") ||
1325 !strcmp(elf_name, "$t"))
1326 continue;
1327 }
1328
Eric B Munson70c38562010-06-14 14:56:33 +01001329 if (opdsec && sym.st_shndx == opdidx) {
1330 u32 offset = sym.st_value - opdshdr.sh_addr;
1331 u64 *opd = opddata->d_buf + offset;
Jiri Olsa8db48412012-05-30 14:23:42 +02001332 sym.st_value = DSO__SWAP(dso, u64, *opd);
Eric B Munson70c38562010-06-14 14:56:33 +01001333 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1334 }
1335
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001336 sec = elf_getscn(elf, sym.st_shndx);
1337 if (!sec)
1338 goto out_elf_end;
1339
1340 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001341
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -02001342 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001343 continue;
1344
1345 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +02001346
Dr. David Alan Gilbertb2f8fb22011-01-21 16:40:19 +00001347 /* On ARM, symbols for thumb functions have 1 added to
1348 * the symbol address as a flag - remove it */
1349 if ((ehdr.e_machine == EM_ARM) &&
1350 (map->type == MAP__FUNCTION) &&
1351 (sym.st_value & 1))
1352 --sym.st_value;
1353
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001354 if (dso->kernel != DSO_TYPE_USER || kmodule) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001355 char dso_name[PATH_MAX];
1356
1357 if (strcmp(section_name,
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -03001358 (curr_dso->short_name +
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001359 dso->short_name_len)) == 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001360 goto new_symbol;
1361
1362 if (strcmp(section_name, ".text") == 0) {
1363 curr_map = map;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001364 curr_dso = dso;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001365 goto new_symbol;
1366 }
1367
1368 snprintf(dso_name, sizeof(dso_name),
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001369 "%s%s", dso->short_name, section_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001370
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001371 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001372 if (curr_map == NULL) {
1373 u64 start = sym.st_value;
1374
1375 if (kmodule)
1376 start += map->start + shdr.sh_offset;
1377
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001378 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001379 if (curr_dso == NULL)
1380 goto out_elf_end;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001381 curr_dso->kernel = dso->kernel;
1382 curr_dso->long_name = dso->long_name;
1383 curr_dso->long_name_len = dso->long_name_len;
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001384 curr_map = map__new2(start, curr_dso,
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001385 map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001386 if (curr_map == NULL) {
1387 dso__delete(curr_dso);
1388 goto out_elf_end;
1389 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001390 curr_map->map_ip = identity__map_ip;
1391 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001392 curr_dso->symtab_type = dso->symtab_type;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001393 map_groups__insert(kmap->kmaps, curr_map);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001394 dsos__add(&dso->node, curr_dso);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001395 dso__set_loaded(curr_dso, map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001396 } else
1397 curr_dso = curr_map->dso;
1398
1399 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001400 }
1401
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001402 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -02001403 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
1404 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -02001405 (u64)sym.st_value, (u64)shdr.sh_addr,
1406 (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001407 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001408 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001409 /*
1410 * We need to figure out if the object was created from C++ sources
1411 * DWARF DW_compile_unit has this, but we don't always have access
1412 * to it...
1413 */
Ingo Molnar83a09442009-08-15 12:26:57 +02001414 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001415 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +02001416 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001417new_symbol:
Arnaldo Carvalho de Meloc408fed2010-08-05 12:59:47 -03001418 f = symbol__new(sym.st_value, sym.st_size,
1419 GELF_ST_BIND(sym.st_info), elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001420 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001421 if (!f)
1422 goto out_elf_end;
1423
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001424 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001425 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001426 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001427 symbols__insert(&curr_dso->symbols[curr_map->type], f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001428 nr++;
1429 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001430 }
1431
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001432 /*
1433 * For misannotated, zeroed, ASM function sizes.
1434 */
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001435 if (nr > 0) {
Anton Blanchard694bf402011-08-24 16:40:17 +10001436 symbols__fixup_duplicate(&dso->symbols[map->type]);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001437 symbols__fixup_end(&dso->symbols[map->type]);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001438 if (kmap) {
1439 /*
1440 * We need to fixup this here too because we create new
1441 * maps here, for things like vsyscall sections.
1442 */
1443 __map_groups__fixup_end(kmap->kmaps, map->type);
1444 }
1445 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001446 err = nr;
1447out_elf_end:
1448 elf_end(elf);
1449out_close:
1450 return err;
1451}
1452
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001453static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001454{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001455 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001456}
1457
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001458bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001459{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001460 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001461 struct dso *pos;
1462
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001463 list_for_each_entry(pos, head, node) {
1464 if (with_hits && !pos->hit)
1465 continue;
Arnaldo Carvalho de Melof6e14672010-05-19 11:13:02 -03001466 if (pos->has_build_id) {
1467 have_build_id = true;
1468 continue;
1469 }
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001470 if (filename__read_build_id(pos->long_name, pos->build_id,
1471 sizeof(pos->build_id)) > 0) {
1472 have_build_id = true;
1473 pos->has_build_id = true;
1474 }
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001475 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001476
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001477 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001478}
1479
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001480/*
1481 * Align offset to 4 bytes as needed for note name and descriptor data.
1482 */
1483#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1484
Dave Martin21916c32010-07-30 09:08:08 -03001485static int elf_read_build_id(Elf *elf, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001486{
Dave Martin21916c32010-07-30 09:08:08 -03001487 int err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001488 GElf_Ehdr ehdr;
1489 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001490 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001491 Elf_Scn *sec;
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001492 Elf_Kind ek;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001493 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001494
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001495 if (size < BUILD_ID_SIZE)
1496 goto out;
1497
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001498 ek = elf_kind(elf);
1499 if (ek != ELF_K_ELF)
Dave Martin21916c32010-07-30 09:08:08 -03001500 goto out;
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001501
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001502 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001503 pr_err("%s: cannot get elf header.\n", __func__);
Dave Martin21916c32010-07-30 09:08:08 -03001504 goto out;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001505 }
1506
Jiri Olsa1388d715d2012-06-19 17:48:05 +02001507 /*
1508 * Check following sections for notes:
1509 * '.note.gnu.build-id'
1510 * '.notes'
1511 * '.note' (VDSO specific)
1512 */
1513 do {
1514 sec = elf_section_by_name(elf, &ehdr, &shdr,
1515 ".note.gnu.build-id", NULL);
1516 if (sec)
1517 break;
1518
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001519 sec = elf_section_by_name(elf, &ehdr, &shdr,
1520 ".notes", NULL);
Jiri Olsa1388d715d2012-06-19 17:48:05 +02001521 if (sec)
1522 break;
1523
1524 sec = elf_section_by_name(elf, &ehdr, &shdr,
1525 ".note", NULL);
1526 if (sec)
1527 break;
1528
1529 return err;
1530
1531 } while (0);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001532
1533 data = elf_getdata(sec, NULL);
1534 if (data == NULL)
Dave Martin21916c32010-07-30 09:08:08 -03001535 goto out;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001536
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001537 ptr = data->d_buf;
1538 while (ptr < (data->d_buf + data->d_size)) {
1539 GElf_Nhdr *nhdr = ptr;
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001540 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1541 descsz = NOTE_ALIGN(nhdr->n_descsz);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001542 const char *name;
1543
1544 ptr += sizeof(*nhdr);
1545 name = ptr;
1546 ptr += namesz;
1547 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1548 nhdr->n_namesz == sizeof("GNU")) {
1549 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001550 size_t sz = min(size, descsz);
1551 memcpy(bf, ptr, sz);
1552 memset(bf + sz, 0, size - sz);
1553 err = descsz;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001554 break;
1555 }
1556 }
1557 ptr += descsz;
1558 }
Dave Martin21916c32010-07-30 09:08:08 -03001559
1560out:
1561 return err;
1562}
1563
1564int filename__read_build_id(const char *filename, void *bf, size_t size)
1565{
1566 int fd, err = -1;
1567 Elf *elf;
1568
1569 if (size < BUILD_ID_SIZE)
1570 goto out;
1571
1572 fd = open(filename, O_RDONLY);
1573 if (fd < 0)
1574 goto out;
1575
1576 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1577 if (elf == NULL) {
1578 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1579 goto out_close;
1580 }
1581
1582 err = elf_read_build_id(elf, bf, size);
1583
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001584 elf_end(elf);
1585out_close:
1586 close(fd);
1587out:
1588 return err;
1589}
1590
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001591int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1592{
1593 int fd, err = -1;
1594
1595 if (size < BUILD_ID_SIZE)
1596 goto out;
1597
1598 fd = open(filename, O_RDONLY);
1599 if (fd < 0)
1600 goto out;
1601
1602 while (1) {
1603 char bf[BUFSIZ];
1604 GElf_Nhdr nhdr;
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001605 size_t namesz, descsz;
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001606
1607 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1608 break;
1609
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001610 namesz = NOTE_ALIGN(nhdr.n_namesz);
1611 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001612 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1613 nhdr.n_namesz == sizeof("GNU")) {
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001614 if (read(fd, bf, namesz) != (ssize_t)namesz)
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001615 break;
1616 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001617 size_t sz = min(descsz, size);
1618 if (read(fd, build_id, sz) == (ssize_t)sz) {
1619 memset(build_id + sz, 0, size - sz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001620 err = 0;
1621 break;
1622 }
Stephane Eranianbe96ea82010-10-22 17:25:01 +02001623 } else if (read(fd, bf, descsz) != (ssize_t)descsz)
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001624 break;
1625 } else {
1626 int n = namesz + descsz;
1627 if (read(fd, bf, n) != n)
1628 break;
1629 }
1630 }
1631 close(fd);
1632out:
1633 return err;
1634}
1635
Pierre-Loup A. Griffais209bd9e2012-06-22 11:38:13 -07001636static int filename__read_debuglink(const char *filename,
1637 char *debuglink, size_t size)
1638{
1639 int fd, err = -1;
1640 Elf *elf;
1641 GElf_Ehdr ehdr;
1642 GElf_Shdr shdr;
1643 Elf_Data *data;
1644 Elf_Scn *sec;
1645 Elf_Kind ek;
1646
1647 fd = open(filename, O_RDONLY);
1648 if (fd < 0)
1649 goto out;
1650
1651 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1652 if (elf == NULL) {
1653 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1654 goto out_close;
1655 }
1656
1657 ek = elf_kind(elf);
1658 if (ek != ELF_K_ELF)
1659 goto out_close;
1660
1661 if (gelf_getehdr(elf, &ehdr) == NULL) {
1662 pr_err("%s: cannot get elf header.\n", __func__);
1663 goto out_close;
1664 }
1665
1666 sec = elf_section_by_name(elf, &ehdr, &shdr,
1667 ".gnu_debuglink", NULL);
1668 if (sec == NULL)
1669 goto out_close;
1670
1671 data = elf_getdata(sec, NULL);
1672 if (data == NULL)
1673 goto out_close;
1674
1675 /* the start of this section is a zero-terminated string */
1676 strncpy(debuglink, data->d_buf, size);
1677
1678 elf_end(elf);
1679
1680out_close:
1681 close(fd);
1682out:
1683 return err;
1684}
1685
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001686char dso__symtab_origin(const struct dso *dso)
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001687{
1688 static const char origin[] = {
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001689 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
1690 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
1691 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
1692 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
1693 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
1694 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
1695 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
1696 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
1697 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
1698 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
1699 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001700 };
1701
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001702 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001703 return '!';
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001704 return origin[dso->symtab_type];
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001705}
1706
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001707int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
1708 char *root_dir, char *file, size_t size)
1709{
1710 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1711 int ret = 0;
1712
1713 switch (type) {
1714 case DSO_BINARY_TYPE__DEBUGLINK: {
1715 char *debuglink;
1716
1717 strncpy(file, dso->long_name, size);
1718 debuglink = file + dso->long_name_len;
1719 while (debuglink != file && *debuglink != '/')
1720 debuglink--;
1721 if (*debuglink == '/')
1722 debuglink++;
1723 filename__read_debuglink(dso->long_name, debuglink,
1724 size - (debuglink - file));
1725 }
1726 break;
1727 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1728 /* skip the locally configured cache if a symfs is given */
1729 if (symbol_conf.symfs[0] ||
1730 (dso__build_id_filename(dso, file, size) == NULL))
1731 ret = -1;
1732 break;
1733
1734 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1735 snprintf(file, size, "%s/usr/lib/debug%s.debug",
1736 symbol_conf.symfs, dso->long_name);
1737 break;
1738
1739 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1740 snprintf(file, size, "%s/usr/lib/debug%s",
1741 symbol_conf.symfs, dso->long_name);
1742 break;
1743
1744 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1745 if (!dso->has_build_id) {
1746 ret = -1;
1747 break;
1748 }
1749
1750 build_id__sprintf(dso->build_id,
1751 sizeof(dso->build_id),
1752 build_id_hex);
1753 snprintf(file, size,
1754 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1755 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1756 break;
1757
1758 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1759 snprintf(file, size, "%s%s",
1760 symbol_conf.symfs, dso->long_name);
1761 break;
1762
1763 case DSO_BINARY_TYPE__GUEST_KMODULE:
1764 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
1765 root_dir, dso->long_name);
1766 break;
1767
1768 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1769 snprintf(file, size, "%s%s", symbol_conf.symfs,
1770 dso->long_name);
1771 break;
1772
1773 default:
1774 case DSO_BINARY_TYPE__KALLSYMS:
1775 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1776 case DSO_BINARY_TYPE__JAVA_JIT:
1777 case DSO_BINARY_TYPE__NOT_FOUND:
1778 ret = -1;
1779 break;
1780 }
1781
1782 return ret;
1783}
1784
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001785int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001786{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001787 char *name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001788 int ret = -1;
1789 int fd;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001790 u_int i;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001791 struct machine *machine;
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001792 char *root_dir = (char *) "";
Dave Martin6da80ce2010-07-30 09:50:09 -03001793 int want_symtab;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001794
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001795 dso__set_loaded(dso, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001796
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001797 if (dso->kernel == DSO_TYPE_KERNEL)
1798 return dso__load_kernel_sym(dso, map, filter);
1799 else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1800 return dso__load_guest_kernel_sym(dso, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001801
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001802 if (map->groups && map->groups->machine)
1803 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001804 else
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03001805 machine = NULL;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001806
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001807 name = malloc(PATH_MAX);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001808 if (!name)
1809 return -1;
1810
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001811 dso->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001812
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001813 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
Pekka Enberg981c1252011-08-09 22:54:18 +03001814 struct stat st;
1815
Vasiliy Kulikove9b52ef2011-08-12 00:55:37 +04001816 if (lstat(dso->name, &st) < 0)
Pekka Enberg981c1252011-08-09 22:54:18 +03001817 return -1;
1818
1819 if (st.st_uid && (st.st_uid != geteuid())) {
1820 pr_warning("File %s not owned by current user or root, "
1821 "ignoring it.\n", dso->name);
1822 return -1;
1823 }
1824
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001825 ret = dso__load_perf_map(dso, map, filter);
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001826 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
1827 DSO_BINARY_TYPE__NOT_FOUND;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001828 return ret;
1829 }
1830
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001831 if (machine)
1832 root_dir = machine->root_dir;
1833
Dave Martin6da80ce2010-07-30 09:50:09 -03001834 /* Iterate over candidate debug images.
1835 * On the first pass, only load images if they have a full symtab.
1836 * Failing that, do a second pass where we accept .dynsym also
1837 */
Arnaldo Carvalho de Melo60e4b102011-03-22 15:42:14 -03001838 want_symtab = 1;
1839restart:
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001840 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
Dave Martin6da80ce2010-07-30 09:50:09 -03001841
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001842 dso->symtab_type = binary_type_symtab[i];
Dave Martin6da80ce2010-07-30 09:50:09 -03001843
Jiri Olsa44f24cb2012-07-22 14:14:32 +02001844 if (dso__binary_type_file(dso, dso->symtab_type,
1845 root_dir, name, PATH_MAX))
1846 continue;
Dave Martin6da80ce2010-07-30 09:50:09 -03001847
1848 /* Name is now the name of the next image to try */
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001849 fd = open(name, O_RDONLY);
Dave Martin6da80ce2010-07-30 09:50:09 -03001850 if (fd < 0)
1851 continue;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001852
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001853 ret = dso__load_sym(dso, map, name, fd, filter, 0,
Dave Martin6da80ce2010-07-30 09:50:09 -03001854 want_symtab);
1855 close(fd);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001856
Dave Martin6da80ce2010-07-30 09:50:09 -03001857 /*
1858 * Some people seem to have debuginfo files _WITHOUT_ debug
1859 * info!?!?
1860 */
1861 if (!ret)
1862 continue;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001863
Dave Martin6da80ce2010-07-30 09:50:09 -03001864 if (ret > 0) {
Jiri Olsa33ff5812012-04-18 15:46:58 +02001865 int nr_plt;
1866
1867 nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
Dave Martin6da80ce2010-07-30 09:50:09 -03001868 if (nr_plt > 0)
1869 ret += nr_plt;
1870 break;
1871 }
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001872 }
Dave Martin6da80ce2010-07-30 09:50:09 -03001873
Arnaldo Carvalho de Melo60e4b102011-03-22 15:42:14 -03001874 /*
1875 * If we wanted a full symtab but no image had one,
1876 * relax our requirements and repeat the search.
1877 */
1878 if (ret <= 0 && want_symtab) {
1879 want_symtab = 0;
1880 goto restart;
1881 }
1882
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001883 free(name);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001884 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001885 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001886 return ret;
1887}
1888
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001889struct map *map_groups__find_by_name(struct map_groups *mg,
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001890 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001891{
1892 struct rb_node *nd;
1893
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001894 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001895 struct map *map = rb_entry(nd, struct map, rb_node);
1896
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001897 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001898 return map;
1899 }
1900
1901 return NULL;
1902}
1903
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001904static int dso__kernel_module_get_build_id(struct dso *dso,
1905 const char *root_dir)
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001906{
1907 char filename[PATH_MAX];
1908 /*
1909 * kernel module short names are of the form "[module]" and
1910 * we need just "module" here.
1911 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001912 const char *name = dso->short_name + 1;
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001913
1914 snprintf(filename, sizeof(filename),
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001915 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1916 root_dir, (int)strlen(name) - 1, name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001917
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001918 if (sysfs__read_build_id(filename, dso->build_id,
1919 sizeof(dso->build_id)) == 0)
1920 dso->has_build_id = true;
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001921
1922 return 0;
1923}
1924
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001925static int map_groups__set_modules_path_dir(struct map_groups *mg,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001926 const char *dir_name)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001927{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001928 struct dirent *dent;
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001929 DIR *dir = opendir(dir_name);
Gui Jianfeng74534342010-06-24 15:04:02 +08001930 int ret = 0;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001931
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001932 if (!dir) {
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001933 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001934 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001935 }
1936
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001937 while ((dent = readdir(dir)) != NULL) {
1938 char path[PATH_MAX];
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001939 struct stat st;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001940
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001941 /*sshfs might return bad dent->d_type, so we have to stat*/
Namhyung Kim2b600f92011-12-13 00:16:51 +09001942 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001943 if (stat(path, &st))
1944 continue;
1945
1946 if (S_ISDIR(st.st_mode)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001947 if (!strcmp(dent->d_name, ".") ||
1948 !strcmp(dent->d_name, ".."))
1949 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001950
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001951 ret = map_groups__set_modules_path_dir(mg, path);
Gui Jianfeng74534342010-06-24 15:04:02 +08001952 if (ret < 0)
1953 goto out;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001954 } else {
1955 char *dot = strrchr(dent->d_name, '.'),
1956 dso_name[PATH_MAX];
1957 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001958 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001959
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001960 if (dot == NULL || strcmp(dot, ".ko"))
1961 continue;
1962 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1963 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001964
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001965 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03001966 map = map_groups__find_by_name(mg, MAP__FUNCTION,
1967 dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001968 if (map == NULL)
1969 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001970
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001971 long_name = strdup(path);
Gui Jianfeng74534342010-06-24 15:04:02 +08001972 if (long_name == NULL) {
1973 ret = -1;
1974 goto out;
1975 }
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001976 dso__set_long_name(map->dso, long_name);
Arnaldo Carvalho de Melo6e406252010-07-29 15:11:30 -03001977 map->dso->lname_alloc = 1;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001978 dso__kernel_module_get_build_id(map->dso, "");
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001979 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001980 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001981
Gui Jianfeng74534342010-06-24 15:04:02 +08001982out:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001983 closedir(dir);
Gui Jianfeng74534342010-06-24 15:04:02 +08001984 return ret;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001985}
1986
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001987static char *get_kernel_version(const char *root_dir)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001988{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08001989 char version[PATH_MAX];
1990 FILE *file;
1991 char *name, *tmp;
1992 const char *prefix = "Linux version ";
1993
1994 sprintf(version, "%s/proc/version", root_dir);
1995 file = fopen(version, "r");
1996 if (!file)
1997 return NULL;
1998
1999 version[0] = '\0';
2000 tmp = fgets(version, sizeof(version), file);
2001 fclose(file);
2002
2003 name = strstr(version, prefix);
2004 if (!name)
2005 return NULL;
2006 name += strlen(prefix);
2007 tmp = strchr(name, ' ');
2008 if (tmp)
2009 *tmp = '\0';
2010
2011 return strdup(name);
2012}
2013
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002014static int machine__set_modules_path(struct machine *machine)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002015{
2016 char *version;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002017 char modules_path[PATH_MAX];
2018
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002019 version = get_kernel_version(machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002020 if (!version)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002021 return -1;
2022
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002023 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002024 machine->root_dir, version);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002025 free(version);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002026
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002027 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002028}
2029
2030/*
2031 * Constructor variant for modules (where we know from /proc/modules where
2032 * they are loaded) and for vmlinux, where only after we load all the
2033 * symbols we'll know where it starts and ends.
2034 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02002035static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002036{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002037 struct map *map = calloc(1, (sizeof(*map) +
2038 (dso->kernel ? sizeof(struct kmap) : 0)));
2039 if (map != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002040 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02002041 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002042 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002043 map__init(map, type, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002044 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02002045
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002046 return map;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002047}
2048
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002049struct map *machine__new_module(struct machine *machine, u64 start,
Arnaldo Carvalho de Melod28c6222010-04-27 21:20:43 -03002050 const char *filename)
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002051{
2052 struct map *map;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002053 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002054
2055 if (dso == NULL)
2056 return NULL;
2057
2058 map = map__new2(start, dso, MAP__FUNCTION);
2059 if (map == NULL)
2060 return NULL;
2061
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002062 if (machine__is_host(machine))
Jiri Olsa44f24cb2012-07-22 14:14:32 +02002063 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002064 else
Jiri Olsa44f24cb2012-07-22 14:14:32 +02002065 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002066 map_groups__insert(&machine->kmaps, map);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002067 return map;
2068}
2069
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002070static int machine__create_modules(struct machine *machine)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002071{
2072 char *line = NULL;
2073 size_t n;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002074 FILE *file;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002075 struct map *map;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002076 const char *modules;
2077 char path[PATH_MAX];
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002078
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002079 if (machine__is_default_guest(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002080 modules = symbol_conf.default_guest_modules;
2081 else {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002082 sprintf(path, "%s/proc/modules", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002083 modules = path;
2084 }
2085
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03002086 if (symbol__restricted_filename(path, "/proc/modules"))
2087 return -1;
2088
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002089 file = fopen(modules, "r");
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002090 if (file == NULL)
2091 return -1;
2092
2093 while (!feof(file)) {
2094 char name[PATH_MAX];
2095 u64 start;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002096 char *sep;
2097 int line_len;
2098
2099 line_len = getline(&line, &n, file);
2100 if (line_len < 0)
2101 break;
2102
2103 if (!line)
2104 goto out_failure;
2105
2106 line[--line_len] = '\0'; /* \n */
2107
2108 sep = strrchr(line, 'x');
2109 if (sep == NULL)
2110 continue;
2111
2112 hex2u64(sep + 1, &start);
2113
2114 sep = strchr(line, ' ');
2115 if (sep == NULL)
2116 continue;
2117
2118 *sep = '\0';
2119
2120 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002121 map = machine__new_module(machine, start, name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002122 if (map == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002123 goto out_delete_line;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002124 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002125 }
2126
2127 free(line);
2128 fclose(file);
2129
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002130 return machine__set_modules_path(machine);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002131
2132out_delete_line:
2133 free(line);
2134out_failure:
2135 return -1;
2136}
2137
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002138int dso__load_vmlinux(struct dso *dso, struct map *map,
Franck Bui-Huufd930ff2010-12-10 14:06:03 +01002139 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002140{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02002141 int err = -1, fd;
David Ahernec5761e2010-12-09 13:27:07 -07002142 char symfs_vmlinux[PATH_MAX];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002143
Arnaldo Carvalho de Meloa639dc62011-02-28 13:54:38 -03002144 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
David Ahernec5761e2010-12-09 13:27:07 -07002145 symbol_conf.symfs, vmlinux);
2146 fd = open(symfs_vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002147 if (fd < 0)
2148 return -1;
2149
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002150 dso__set_long_name(dso, (char *)vmlinux);
2151 dso__set_loaded(dso, map->type);
2152 err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002153 close(fd);
2154
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002155 if (err > 0)
David Ahernec5761e2010-12-09 13:27:07 -07002156 pr_debug("Using %s for symbols\n", symfs_vmlinux);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002157
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002158 return err;
2159}
2160
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002161int dso__load_vmlinux_path(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02002162 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002163{
2164 int i, err = 0;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002165 char *filename;
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002166
2167 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002168 vmlinux_path__nr_entries + 1);
2169
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002170 filename = dso__build_id_filename(dso, NULL, 0);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002171 if (filename != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002172 err = dso__load_vmlinux(dso, map, filename, filter);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002173 if (err > 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002174 dso__set_long_name(dso, filename);
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002175 goto out;
2176 }
2177 free(filename);
2178 }
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002179
2180 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002181 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002182 if (err > 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002183 dso__set_long_name(dso, strdup(vmlinux_path[i]));
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002184 break;
2185 }
2186 }
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002187out:
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002188 return err;
2189}
2190
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002191static int dso__load_kernel_sym(struct dso *dso, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02002192 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03002193{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002194 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02002195 const char *kallsyms_filename = NULL;
2196 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002197 /*
David Ahernb226a5a72010-12-07 19:39:46 -07002198 * Step 1: if the user specified a kallsyms or vmlinux filename, use
2199 * it and only it, reporting errors to the user if it cannot be used.
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002200 *
2201 * For instance, try to analyse an ARM perf.data file _without_ a
2202 * build-id, or if the user specifies the wrong path to the right
2203 * vmlinux file, obviously we can't fallback to another vmlinux (a
2204 * x86_86 one, on the machine where analysis is being performed, say),
2205 * or worse, /proc/kallsyms.
2206 *
2207 * If the specified file _has_ a build-id and there is a build-id
2208 * section in the perf.data file, we will still do the expected
2209 * validation in dso__load_vmlinux and will bail out if they don't
2210 * match.
2211 */
David Ahernb226a5a72010-12-07 19:39:46 -07002212 if (symbol_conf.kallsyms_name != NULL) {
2213 kallsyms_filename = symbol_conf.kallsyms_name;
2214 goto do_kallsyms;
2215 }
2216
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002217 if (symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002218 err = dso__load_vmlinux(dso, map,
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002219 symbol_conf.vmlinux_name, filter);
Arnaldo Carvalho de Meloe7dadc02010-06-03 18:35:55 -03002220 if (err > 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002221 dso__set_long_name(dso,
Arnaldo Carvalho de Meloe7dadc02010-06-03 18:35:55 -03002222 strdup(symbol_conf.vmlinux_name));
2223 goto out_fixup;
2224 }
2225 return err;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002226 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002227
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002228 if (vmlinux_path != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002229 err = dso__load_vmlinux_path(dso, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02002230 if (err > 0)
2231 goto out_fixup;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002232 }
2233
David Ahernec5761e2010-12-09 13:27:07 -07002234 /* do not try local files if a symfs was given */
2235 if (symbol_conf.symfs[0] != 0)
2236 return -1;
2237
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002238 /*
2239 * Say the kernel DSO was created when processing the build-id header table,
2240 * we have a build-id, so check if it is the same as the running kernel,
2241 * using it if it is.
2242 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002243 if (dso->has_build_id) {
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002244 u8 kallsyms_build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02002245 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02002246
2247 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02002248 sizeof(kallsyms_build_id)) == 0) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002249 if (dso__build_id_equal(dso, kallsyms_build_id)) {
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02002250 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02002251 goto do_kallsyms;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02002252 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02002253 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002254 /*
2255 * Now look if we have it on the build-id cache in
2256 * $HOME/.debug/[kernel.kallsyms].
2257 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002258 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02002259 sbuild_id);
2260
2261 if (asprintf(&kallsyms_allocated_filename,
2262 "%s/.debug/[kernel.kallsyms]/%s",
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002263 getenv("HOME"), sbuild_id) == -1) {
2264 pr_err("Not enough memory for kallsyms file lookup\n");
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02002265 return -1;
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002266 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02002267
Arnaldo Carvalho de Melo19fc2de2010-01-22 14:35:02 -02002268 kallsyms_filename = kallsyms_allocated_filename;
2269
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002270 if (access(kallsyms_filename, F_OK)) {
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002271 pr_err("No kallsyms or vmlinux with build-id %s "
2272 "was found\n", sbuild_id);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002273 free(kallsyms_allocated_filename);
2274 return -1;
2275 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002276 } else {
2277 /*
2278 * Last resort, if we don't have a build-id and couldn't find
2279 * any vmlinux file, try the running kernel kallsyms table.
2280 */
2281 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02002282 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03002283
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002284do_kallsyms:
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002285 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03002286 if (err > 0)
2287 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02002288 free(kallsyms_allocated_filename);
2289
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002290 if (err > 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002291out_fixup:
Arnaldo Carvalho de Meloe1c7c6a2010-01-22 14:35:01 -02002292 if (kallsyms_filename != NULL)
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002293 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02002294 map__fixup_start(map);
2295 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03002296 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03002297
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03002298 return err;
2299}
2300
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002301static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
2302 symbol_filter_t filter)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002303{
2304 int err;
2305 const char *kallsyms_filename = NULL;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002306 struct machine *machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002307 char path[PATH_MAX];
2308
2309 if (!map->groups) {
2310 pr_debug("Guest kernel map hasn't the point to groups\n");
2311 return -1;
2312 }
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002313 machine = map->groups->machine;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002314
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002315 if (machine__is_default_guest(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002316 /*
2317 * if the user specified a vmlinux filename, use it and only
2318 * it, reporting errors to the user if it cannot be used.
2319 * Or use file guest_kallsyms inputted by user on commandline
2320 */
2321 if (symbol_conf.default_guest_vmlinux_name != NULL) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002322 err = dso__load_vmlinux(dso, map,
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002323 symbol_conf.default_guest_vmlinux_name, filter);
2324 goto out_try_fixup;
2325 }
2326
2327 kallsyms_filename = symbol_conf.default_guest_kallsyms;
2328 if (!kallsyms_filename)
2329 return -1;
2330 } else {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002331 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002332 kallsyms_filename = path;
2333 }
2334
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002335 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002336 if (err > 0)
2337 pr_debug("Using %s for symbols\n", kallsyms_filename);
2338
2339out_try_fixup:
2340 if (err > 0) {
2341 if (kallsyms_filename != NULL) {
Arnaldo Carvalho de Melo48ea8f52010-04-27 21:19:05 -03002342 machine__mmap_name(machine, path, sizeof(path));
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002343 dso__set_long_name(dso, strdup(path));
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002344 }
2345 map__fixup_start(map);
2346 map__fixup_end(map);
2347 }
2348
2349 return err;
2350}
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002351
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002352static void dsos__add(struct list_head *head, struct dso *dso)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002353{
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002354 list_add_tail(&dso->node, head);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002355}
2356
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002357static struct dso *dsos__find(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002358{
2359 struct dso *pos;
2360
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002361 list_for_each_entry(pos, head, node)
Arnaldo Carvalho de Melocf4e5b02010-01-14 23:45:27 -02002362 if (strcmp(pos->long_name, name) == 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002363 return pos;
2364 return NULL;
2365}
2366
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -02002367struct dso *__dsos__findnew(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002368{
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -02002369 struct dso *dso = dsos__find(head, name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002370
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02002371 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02002372 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02002373 if (dso != NULL) {
Arnaldo Carvalho de Meloa89e5ab2010-01-07 19:59:39 -02002374 dsos__add(head, dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02002375 dso__set_basename(dso);
2376 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02002377 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002378
2379 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002380}
2381
Arnaldo Carvalho de Melo1f626bc2010-05-09 19:57:08 -03002382size_t __dsos__fprintf(struct list_head *head, FILE *fp)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002383{
2384 struct dso *pos;
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002385 size_t ret = 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002386
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02002387 list_for_each_entry(pos, head, node) {
2388 int i;
2389 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002390 ret += dso__fprintf(pos, i, fp);
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02002391 }
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002392
2393 return ret;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002394}
2395
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002396size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002397{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002398 struct rb_node *nd;
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002399 size_t ret = 0;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002400
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002401 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002402 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002403 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2404 ret += __dsos__fprintf(&pos->user_dsos, fp);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002405 }
Arnaldo Carvalho de Melocbf69682010-04-27 21:22:44 -03002406
2407 return ret;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002408}
2409
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02002410static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2411 bool with_hits)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02002412{
2413 struct dso *pos;
2414 size_t ret = 0;
2415
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002416 list_for_each_entry(pos, head, node) {
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02002417 if (with_hits && !pos->hit)
2418 continue;
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02002419 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02002420 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02002421 }
2422 return ret;
2423}
2424
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002425size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
2426 bool with_hits)
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03002427{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002428 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
2429 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03002430}
2431
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002432size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
2433 FILE *fp, bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002434{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002435 struct rb_node *nd;
2436 size_t ret = 0;
2437
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002438 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002439 struct machine *pos = rb_entry(nd, struct machine, rb_node);
Arnaldo Carvalho de Melof8690972010-05-19 13:41:23 -03002440 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002441 }
2442 return ret;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02002443}
2444
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002445static struct dso*
2446dso__kernel_findnew(struct machine *machine, const char *name,
2447 const char *short_name, int dso_type)
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02002448{
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002449 /*
2450 * The kernel dso could be created by build_id processing.
2451 */
2452 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02002453
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002454 /*
2455 * We need to run this in all cases, since during the build_id
2456 * processing we had no idea this was the kernel dso.
2457 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002458 if (dso != NULL) {
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002459 dso__set_short_name(dso, short_name);
2460 dso->kernel = dso_type;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002461 }
2462
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002463 return dso;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002464}
2465
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002466void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002467{
2468 char path[PATH_MAX];
2469
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002470 if (machine__is_default_guest(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002471 return;
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002472 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002473 if (sysfs__read_build_id(path, dso->build_id,
2474 sizeof(dso->build_id)) == 0)
2475 dso->has_build_id = true;
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02002476}
2477
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002478static struct dso *machine__get_kernel(struct machine *machine)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002479{
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002480 const char *vmlinux_name = NULL;
2481 struct dso *kernel;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002482
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002483 if (machine__is_host(machine)) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002484 vmlinux_name = symbol_conf.vmlinux_name;
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002485 if (!vmlinux_name)
2486 vmlinux_name = "[kernel.kallsyms]";
2487
2488 kernel = dso__kernel_findnew(machine, vmlinux_name,
2489 "[kernel]",
2490 DSO_TYPE_KERNEL);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002491 } else {
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002492 char bf[PATH_MAX];
2493
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002494 if (machine__is_default_guest(machine))
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002495 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002496 if (!vmlinux_name)
2497 vmlinux_name = machine__mmap_name(machine, bf,
2498 sizeof(bf));
2499
2500 kernel = dso__kernel_findnew(machine, vmlinux_name,
2501 "[guest.kernel]",
2502 DSO_TYPE_GUEST_KERNEL);
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -02002503 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002504
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002505 if (kernel != NULL && (!kernel->has_build_id))
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002506 dso__read_running_kernel_build_id(kernel, machine);
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002507
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002508 return kernel;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002509}
2510
Ming Leid214afb2010-11-25 19:27:25 +08002511struct process_args {
2512 u64 start;
2513};
2514
2515static int symbol__in_kernel(void *arg, const char *name,
Arnaldo Carvalho de Melo3b01a412010-12-22 01:08:36 -02002516 char type __used, u64 start, u64 end __used)
Ming Leid214afb2010-11-25 19:27:25 +08002517{
2518 struct process_args *args = arg;
2519
2520 if (strchr(name, '['))
2521 return 0;
2522
2523 args->start = start;
2524 return 1;
2525}
2526
2527/* Figure out the start address of kernel map from /proc/kallsyms */
2528static u64 machine__get_kernel_start_addr(struct machine *machine)
2529{
2530 const char *filename;
2531 char path[PATH_MAX];
2532 struct process_args args;
2533
2534 if (machine__is_host(machine)) {
2535 filename = "/proc/kallsyms";
2536 } else {
2537 if (machine__is_default_guest(machine))
2538 filename = (char *)symbol_conf.default_guest_kallsyms;
2539 else {
2540 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2541 filename = path;
2542 }
2543 }
2544
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03002545 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
2546 return 0;
2547
Ming Leid214afb2010-11-25 19:27:25 +08002548 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
2549 return 0;
2550
2551 return args.start;
2552}
2553
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002554int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002555{
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02002556 enum map_type type;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002557 u64 start = machine__get_kernel_start_addr(machine);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002558
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02002559 for (type = 0; type < MAP__NR_TYPES; ++type) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02002560 struct kmap *kmap;
2561
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002562 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
2563 if (machine->vmlinux_maps[type] == NULL)
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02002564 return -1;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002565
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002566 machine->vmlinux_maps[type]->map_ip =
2567 machine->vmlinux_maps[type]->unmap_ip =
2568 identity__map_ip;
2569 kmap = map__kmap(machine->vmlinux_maps[type]);
2570 kmap->kmaps = &machine->kmaps;
2571 map_groups__insert(&machine->kmaps,
2572 machine->vmlinux_maps[type]);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002573 }
2574
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02002575 return 0;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02002576}
2577
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002578void machine__destroy_kernel_maps(struct machine *machine)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002579{
2580 enum map_type type;
2581
2582 for (type = 0; type < MAP__NR_TYPES; ++type) {
2583 struct kmap *kmap;
2584
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002585 if (machine->vmlinux_maps[type] == NULL)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002586 continue;
2587
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002588 kmap = map__kmap(machine->vmlinux_maps[type]);
2589 map_groups__remove(&machine->kmaps,
2590 machine->vmlinux_maps[type]);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002591 if (kmap->ref_reloc_sym) {
2592 /*
2593 * ref_reloc_sym is shared among all maps, so free just
2594 * on one of them.
2595 */
2596 if (type == MAP__FUNCTION) {
2597 free((char *)kmap->ref_reloc_sym->name);
2598 kmap->ref_reloc_sym->name = NULL;
2599 free(kmap->ref_reloc_sym);
2600 }
2601 kmap->ref_reloc_sym = NULL;
2602 }
2603
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002604 map__delete(machine->vmlinux_maps[type]);
2605 machine->vmlinux_maps[type] = NULL;
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002606 }
2607}
2608
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002609int machine__create_kernel_maps(struct machine *machine)
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002610{
Jiri Olsaf57b05e2011-06-01 21:43:46 +02002611 struct dso *kernel = machine__get_kernel(machine);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002612
2613 if (kernel == NULL ||
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002614 __machine__create_kernel_maps(machine, kernel) < 0)
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002615 return -1;
2616
David Ahernf51304d2012-07-20 17:25:46 -06002617 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
2618 if (machine__is_host(machine))
2619 pr_debug("Problems creating module maps, "
2620 "continuing anyway...\n");
2621 else
2622 pr_debug("Problems creating module maps for guest %d, "
2623 "continuing anyway...\n", machine->pid);
2624 }
2625
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002626 /*
2627 * Now that we have all the maps created, just set the ->end of them:
2628 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002629 map_groups__fixup_end(&machine->kmaps);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002630 return 0;
2631}
2632
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002633static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02002634{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002635 while (--vmlinux_path__nr_entries >= 0) {
2636 free(vmlinux_path[vmlinux_path__nr_entries]);
2637 vmlinux_path[vmlinux_path__nr_entries] = NULL;
2638 }
2639
2640 free(vmlinux_path);
2641 vmlinux_path = NULL;
2642}
2643
2644static int vmlinux_path__init(void)
2645{
2646 struct utsname uts;
2647 char bf[PATH_MAX];
2648
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002649 vmlinux_path = malloc(sizeof(char *) * 5);
2650 if (vmlinux_path == NULL)
2651 return -1;
2652
2653 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2654 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2655 goto out_fail;
2656 ++vmlinux_path__nr_entries;
2657 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2658 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2659 goto out_fail;
2660 ++vmlinux_path__nr_entries;
David Ahernec5761e2010-12-09 13:27:07 -07002661
2662 /* only try running kernel version if no symfs was given */
2663 if (symbol_conf.symfs[0] != 0)
2664 return 0;
2665
2666 if (uname(&uts) < 0)
2667 return -1;
2668
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002669 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2670 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2671 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2672 goto out_fail;
2673 ++vmlinux_path__nr_entries;
2674 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2675 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2676 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2677 goto out_fail;
2678 ++vmlinux_path__nr_entries;
2679 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2680 uts.release);
2681 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2682 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2683 goto out_fail;
2684 ++vmlinux_path__nr_entries;
2685
2686 return 0;
2687
2688out_fail:
2689 vmlinux_path__exit();
2690 return -1;
2691}
2692
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002693size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03002694{
2695 int i;
2696 size_t printed = 0;
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002697 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002698
2699 if (kdso->has_build_id) {
2700 char filename[PATH_MAX];
2701 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
2702 printed += fprintf(fp, "[0] %s\n", filename);
2703 }
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03002704
2705 for (i = 0; i < vmlinux_path__nr_entries; ++i)
Arnaldo Carvalho de Melo5ad90e42010-05-26 13:26:02 -03002706 printed += fprintf(fp, "[%d] %s\n",
2707 i + kdso->has_build_id, vmlinux_path[i]);
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03002708
2709 return printed;
2710}
2711
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02002712static int setup_list(struct strlist **list, const char *list_str,
2713 const char *list_name)
2714{
2715 if (list_str == NULL)
2716 return 0;
2717
2718 *list = strlist__new(true, list_str);
2719 if (!*list) {
2720 pr_err("problems parsing %s list\n", list_name);
2721 return -1;
2722 }
2723 return 0;
2724}
2725
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03002726static bool symbol__read_kptr_restrict(void)
2727{
2728 bool value = false;
2729
2730 if (geteuid() != 0) {
2731 FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
2732 if (fp != NULL) {
2733 char line[8];
2734
2735 if (fgets(line, sizeof(line), fp) != NULL)
2736 value = atoi(line) != 0;
2737
2738 fclose(fp);
2739 }
2740 }
2741
2742 return value;
2743}
2744
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02002745int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002746{
David Ahernec5761e2010-12-09 13:27:07 -07002747 const char *symfs;
2748
Jovi Zhang85e00b52010-09-09 13:30:59 -03002749 if (symbol_conf.initialized)
2750 return 0;
2751
David S. Miller4d439512011-03-29 14:18:39 -03002752 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
2753
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02002754 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02002755 if (symbol_conf.sort_by_name)
2756 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
2757 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02002758
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02002759 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002760 return -1;
2761
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02002762 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2763 pr_err("'.' is the only non valid --field-separator argument\n");
2764 return -1;
2765 }
2766
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02002767 if (setup_list(&symbol_conf.dso_list,
2768 symbol_conf.dso_list_str, "dso") < 0)
2769 return -1;
2770
2771 if (setup_list(&symbol_conf.comm_list,
2772 symbol_conf.comm_list_str, "comm") < 0)
2773 goto out_free_dso_list;
2774
2775 if (setup_list(&symbol_conf.sym_list,
2776 symbol_conf.sym_list_str, "symbol") < 0)
2777 goto out_free_comm_list;
2778
David Ahernec5761e2010-12-09 13:27:07 -07002779 /*
2780 * A path to symbols of "/" is identical to ""
2781 * reset here for simplicity.
2782 */
2783 symfs = realpath(symbol_conf.symfs, NULL);
2784 if (symfs == NULL)
2785 symfs = symbol_conf.symfs;
2786 if (strcmp(symfs, "/") == 0)
2787 symbol_conf.symfs = "";
2788 if (symfs != symbol_conf.symfs)
2789 free((void *)symfs);
2790
Arnaldo Carvalho de Meloec80fde2011-05-26 09:53:51 -03002791 symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
2792
Jovi Zhang85e00b52010-09-09 13:30:59 -03002793 symbol_conf.initialized = true;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02002794 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02002795
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02002796out_free_comm_list:
2797 strlist__delete(symbol_conf.comm_list);
Namhyung Kimd74c8962011-12-13 00:16:52 +09002798out_free_dso_list:
2799 strlist__delete(symbol_conf.dso_list);
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02002800 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02002801}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02002802
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03002803void symbol__exit(void)
2804{
Jovi Zhang85e00b52010-09-09 13:30:59 -03002805 if (!symbol_conf.initialized)
2806 return;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03002807 strlist__delete(symbol_conf.sym_list);
2808 strlist__delete(symbol_conf.dso_list);
2809 strlist__delete(symbol_conf.comm_list);
2810 vmlinux_path__exit();
2811 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
Jovi Zhang85e00b52010-09-09 13:30:59 -03002812 symbol_conf.initialized = false;
Arnaldo Carvalho de Melod65a4582010-07-30 18:31:28 -03002813}
2814
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002815int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02002816{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002817 struct machine *machine = machines__findnew(machines, pid);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02002818
Arnaldo Carvalho de Melo23346f22010-04-27 21:17:50 -03002819 if (machine == NULL)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002820 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02002821
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002822 return machine__create_kernel_maps(machine);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02002823}
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03002824
2825static int hex(char ch)
2826{
2827 if ((ch >= '0') && (ch <= '9'))
2828 return ch - '0';
2829 if ((ch >= 'a') && (ch <= 'f'))
2830 return ch - 'a' + 10;
2831 if ((ch >= 'A') && (ch <= 'F'))
2832 return ch - 'A' + 10;
2833 return -1;
2834}
2835
2836/*
2837 * While we find nice hex chars, build a long_val.
2838 * Return number of chars processed.
2839 */
2840int hex2u64(const char *ptr, u64 *long_val)
2841{
2842 const char *p = ptr;
2843 *long_val = 0;
2844
2845 while (*p) {
2846 const int hex_val = hex(*p);
2847
2848 if (hex_val < 0)
2849 break;
2850
2851 *long_val = (*long_val << 4) | hex_val;
2852 p++;
2853 }
2854
2855 return p - ptr;
2856}
2857
2858char *strxfrchar(char *s, char from, char to)
2859{
2860 char *p = s;
2861
2862 while ((p = strchr(p, from)) != NULL)
2863 *p++ = to;
2864
2865 return s;
2866}
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002867
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002868int machines__create_guest_kernel_maps(struct rb_root *machines)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002869{
2870 int ret = 0;
2871 struct dirent **namelist = NULL;
2872 int i, items = 0;
2873 char path[PATH_MAX];
2874 pid_t pid;
2875
2876 if (symbol_conf.default_guest_vmlinux_name ||
2877 symbol_conf.default_guest_modules ||
2878 symbol_conf.default_guest_kallsyms) {
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002879 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002880 }
2881
2882 if (symbol_conf.guestmount) {
2883 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2884 if (items <= 0)
2885 return -ENOENT;
2886 for (i = 0; i < items; i++) {
2887 if (!isdigit(namelist[i]->d_name[0])) {
2888 /* Filter out . and .. */
2889 continue;
2890 }
2891 pid = atoi(namelist[i]->d_name);
2892 sprintf(path, "%s/%s/proc/kallsyms",
2893 symbol_conf.guestmount,
2894 namelist[i]->d_name);
2895 ret = access(path, R_OK);
2896 if (ret) {
2897 pr_debug("Can't access file %s\n", path);
2898 goto failure;
2899 }
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002900 machines__create_kernel_maps(machines, pid);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +08002901 }
2902failure:
2903 free(namelist);
2904 }
2905
2906 return ret;
2907}
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002908
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002909void machines__destroy_guest_kernel_maps(struct rb_root *machines)
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002910{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002911 struct rb_node *next = rb_first(machines);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002912
2913 while (next) {
2914 struct machine *pos = rb_entry(next, struct machine, rb_node);
2915
2916 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002917 rb_erase(&pos->rb_node, machines);
Arnaldo Carvalho de Melo076c6e452010-08-02 18:18:28 -03002918 machine__delete(pos);
2919 }
2920}
2921
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002922int machine__load_kallsyms(struct machine *machine, const char *filename,
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002923 enum map_type type, symbol_filter_t filter)
2924{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002925 struct map *map = machine->vmlinux_maps[type];
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002926 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2927
2928 if (ret > 0) {
2929 dso__set_loaded(map->dso, type);
2930 /*
2931 * Since /proc/kallsyms will have multiple sessions for the
2932 * kernel, with modules between them, fixup the end of all
2933 * sections.
2934 */
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002935 __map_groups__fixup_end(&machine->kmaps, type);
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002936 }
2937
2938 return ret;
2939}
2940
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002941int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002942 symbol_filter_t filter)
2943{
Arnaldo Carvalho de Meloaeafcba2011-03-31 10:56:28 -03002944 struct map *map = machine->vmlinux_maps[type];
Arnaldo Carvalho de Melo5c0541d2010-04-29 15:25:23 -03002945 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2946
2947 if (ret > 0) {
2948 dso__set_loaded(map->dso, type);
2949 map__reloc_vmlinux(map);
2950 }
2951
2952 return ret;
2953}
Srikar Dronamraju225466f2012-04-16 17:39:09 +05302954
2955struct map *dso__new_map(const char *name)
2956{
Srikar Dronamraju378474e2012-05-31 17:16:56 +05302957 struct map *map = NULL;
Srikar Dronamraju225466f2012-04-16 17:39:09 +05302958 struct dso *dso = dso__new(name);
Srikar Dronamraju378474e2012-05-31 17:16:56 +05302959
2960 if (dso)
2961 map = map__new2(0, dso, MAP__FUNCTION);
Srikar Dronamraju225466f2012-04-16 17:39:09 +05302962
2963 return map;
2964}
Jiri Olsa949d1602012-07-22 14:14:33 +02002965
2966static int open_dso(struct dso *dso, struct machine *machine)
2967{
2968 char *root_dir = (char *) "";
2969 char *name;
2970 int fd;
2971
2972 name = malloc(PATH_MAX);
2973 if (!name)
2974 return -ENOMEM;
2975
2976 if (machine)
2977 root_dir = machine->root_dir;
2978
2979 if (dso__binary_type_file(dso, dso->data_type,
2980 root_dir, name, PATH_MAX)) {
2981 free(name);
2982 return -EINVAL;
2983 }
2984
2985 fd = open(name, O_RDONLY);
2986 free(name);
2987 return fd;
2988}
2989
2990int dso__data_fd(struct dso *dso, struct machine *machine)
2991{
2992 int i = 0;
2993
2994 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
2995 return open_dso(dso, machine);
2996
2997 do {
2998 int fd;
2999
3000 dso->data_type = binary_type_data[i++];
3001
3002 fd = open_dso(dso, machine);
3003 if (fd >= 0)
3004 return fd;
3005
3006 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
3007
3008 return -EINVAL;
3009}
3010
3011static ssize_t dso_cache_read(struct dso *dso __used, u64 offset __used,
3012 u8 *data __used, ssize_t size __used)
3013{
3014 return -EINVAL;
3015}
3016
3017static int dso_cache_add(struct dso *dso __used, u64 offset __used,
3018 u8 *data __used, ssize_t size __used)
3019{
3020 return 0;
3021}
3022
3023static ssize_t read_dso_data(struct dso *dso, struct machine *machine,
3024 u64 offset, u8 *data, ssize_t size)
3025{
3026 ssize_t rsize = -1;
3027 int fd;
3028
3029 fd = dso__data_fd(dso, machine);
3030 if (fd < 0)
3031 return -1;
3032
3033 do {
3034 if (-1 == lseek(fd, offset, SEEK_SET))
3035 break;
3036
3037 rsize = read(fd, data, size);
3038 if (-1 == rsize)
3039 break;
3040
3041 if (dso_cache_add(dso, offset, data, size))
3042 pr_err("Failed to add data int dso cache.");
3043
3044 } while (0);
3045
3046 close(fd);
3047 return rsize;
3048}
3049
3050ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
3051 u64 offset, u8 *data, ssize_t size)
3052{
3053 if (dso_cache_read(dso, offset, data, size))
3054 return read_dso_data(dso, machine, offset, data, size);
3055 return 0;
3056}
3057
3058ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
3059 struct machine *machine, u64 addr,
3060 u8 *data, ssize_t size)
3061{
3062 u64 offset = map->map_ip(map, addr);
3063 return dso__data_read_offset(dso, machine, offset, data, size);
3064}