blob: c4ca974b36e36b8f0daaeba8a1342b12fcbb9dc2 [file] [log] [blame]
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001#include "util.h"
2#include "../perf.h"
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -03003#include "string.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03004#include "symbol.h"
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03005#include "thread.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03006
Frederic Weisbecker8f28827a2009-08-16 22:05:48 +02007#include "debug.h"
8
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02009#include <asm/bug.h>
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030010#include <libelf.h>
11#include <gelf.h>
12#include <elf.h>
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -020013#include <limits.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030014#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020015
Arnaldo Carvalho de Meloc12e15e2009-11-21 14:31:25 -020016#ifndef NT_GNU_BUILD_ID
17#define NT_GNU_BUILD_ID 3
18#endif
19
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030020enum dso_origin {
21 DSO__ORIG_KERNEL = 0,
22 DSO__ORIG_JAVA_JIT,
23 DSO__ORIG_FEDORA,
24 DSO__ORIG_UBUNTU,
25 DSO__ORIG_BUILDID,
26 DSO__ORIG_DSO,
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030027 DSO__ORIG_KMODULE,
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030028 DSO__ORIG_NOT_FOUND,
29};
30
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030031static void dsos__add(struct dso *dso);
32static struct dso *dsos__find(const char *name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030033static struct map *map__new2(u64 start, struct dso *dso);
34static void kernel_maps__insert(struct map *map);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020035static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 symbol_filter_t filter);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020037unsigned int symbol__priv_size;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020038static int vmlinux_path__nr_entries;
39static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030040
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020041static struct symbol_conf symbol_conf__defaults = {
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030046static struct rb_root kernel_maps;
47
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030048static void dso__fixup_sym_end(struct dso *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030049{
50 struct rb_node *nd, *prevnd = rb_first(&self->syms);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030051 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030052
53 if (prevnd == NULL)
54 return;
55
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030056 curr = rb_entry(prevnd, struct symbol, rb_node);
57
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030058 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030059 prev = curr;
60 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030061
62 if (prev->end == prev->start)
63 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030064 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030065
66 /* Last entry */
67 if (curr->end == curr->start)
68 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030069}
70
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030071static void kernel_maps__fixup_end(void)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030072{
73 struct map *prev, *curr;
74 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
75
76 if (prevnd == NULL)
77 return;
78
79 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030080
81 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
82 prev = curr;
83 curr = rb_entry(nd, struct map, rb_node);
84 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030085 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -020086
87 /*
88 * We still haven't the actual symbols, so guess the
89 * last map final address.
90 */
91 curr->end = ~0UL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030092}
93
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020094static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030095{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030096 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020097 struct symbol *self = calloc(1, (symbol__priv_size +
98 sizeof(*self) + namelen));
Ingo Molnar0b73da32009-06-06 15:48:52 +020099 if (!self)
100 return NULL;
101
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200102 if (symbol__priv_size) {
103 memset(self, 0, symbol__priv_size);
104 self = ((void *)self) + symbol__priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300105 }
Ingo Molnar0b73da32009-06-06 15:48:52 +0200106 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200107 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200108
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200109 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200110
Ingo Molnar0b73da32009-06-06 15:48:52 +0200111 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300112
113 return self;
114}
115
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200116static void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300117{
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200118 free(((void *)self) - symbol__priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300119}
120
121static size_t symbol__fprintf(struct symbol *self, FILE *fp)
122{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300123 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300124 self->start, self->end, self->name);
125}
126
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200127static void dso__set_long_name(struct dso *self, char *name)
128{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200129 if (name == NULL)
130 return;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200131 self->long_name = name;
132 self->long_name_len = strlen(name);
133}
134
135static void dso__set_basename(struct dso *self)
136{
137 self->short_name = basename(self->long_name);
138}
139
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200140struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300141{
142 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
143
144 if (self != NULL) {
145 strcpy(self->name, name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200146 dso__set_long_name(self, self->name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300147 self->short_name = self->name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300148 self->syms = RB_ROOT;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200149 self->find_symbol = dso__find_symbol;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300150 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300151 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200152 self->loaded = 0;
153 self->has_build_id = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300154 }
155
156 return self;
157}
158
159static void dso__delete_symbols(struct dso *self)
160{
161 struct symbol *pos;
162 struct rb_node *next = rb_first(&self->syms);
163
164 while (next) {
165 pos = rb_entry(next, struct symbol, rb_node);
166 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloc8c96522009-06-01 17:50:57 -0300167 rb_erase(&pos->rb_node, &self->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200168 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300169 }
170}
171
172void dso__delete(struct dso *self)
173{
174 dso__delete_symbols(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300175 if (self->long_name != self->name)
176 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300177 free(self);
178}
179
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200180void dso__set_build_id(struct dso *self, void *build_id)
181{
182 memcpy(self->build_id, build_id, sizeof(self->build_id));
183 self->has_build_id = 1;
184}
185
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300186static void dso__insert_symbol(struct dso *self, struct symbol *sym)
187{
188 struct rb_node **p = &self->syms.rb_node;
189 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000190 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300191 struct symbol *s;
192
193 while (*p != NULL) {
194 parent = *p;
195 s = rb_entry(parent, struct symbol, rb_node);
196 if (ip < s->start)
197 p = &(*p)->rb_left;
198 else
199 p = &(*p)->rb_right;
200 }
201 rb_link_node(&sym->rb_node, parent, p);
202 rb_insert_color(&sym->rb_node, &self->syms);
203}
204
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000205struct symbol *dso__find_symbol(struct dso *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300206{
207 struct rb_node *n;
208
209 if (self == NULL)
210 return NULL;
211
212 n = self->syms.rb_node;
213
214 while (n) {
215 struct symbol *s = rb_entry(n, struct symbol, rb_node);
216
217 if (ip < s->start)
218 n = n->rb_left;
219 else if (ip > s->end)
220 n = n->rb_right;
221 else
222 return s;
223 }
224
225 return NULL;
226}
227
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200228int build_id__sprintf(u8 *self, int len, char *bf)
229{
230 char *bid = bf;
231 u8 *raw = self;
232 int i;
233
234 for (i = 0; i < len; ++i) {
235 sprintf(bid, "%02x", *raw);
236 ++raw;
237 bid += 2;
238 }
239
240 return raw - self;
241}
242
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200243size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300244{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200245 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200246
247 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200248 return fprintf(fp, "%s", sbuild_id);
249}
250
251size_t dso__fprintf(struct dso *self, FILE *fp)
252{
253 struct rb_node *nd;
254 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
255
256 ret += dso__fprintf_buildid(self, fp);
257 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200258
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300259 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
260 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
261 ret += symbol__fprintf(pos, fp);
262 }
263
264 return ret;
265}
266
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300267/*
268 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
269 * so that we can in the next step set the symbol ->end address and then
270 * call kernel_maps__split_kallsyms.
271 */
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200272static int kernel_maps__load_all_kallsyms(void)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300273{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300274 char *line = NULL;
275 size_t n;
276 FILE *file = fopen("/proc/kallsyms", "r");
277
278 if (file == NULL)
279 goto out_failure;
280
281 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000282 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300283 struct symbol *sym;
284 int line_len, len;
285 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300286 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300287
288 line_len = getline(&line, &n, file);
289 if (line_len < 0)
290 break;
291
292 if (!line)
293 goto out_failure;
294
295 line[--line_len] = '\0'; /* \n */
296
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300297 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300298
299 len++;
300 if (len + 2 >= line_len)
301 continue;
302
303 symbol_type = toupper(line[len]);
304 /*
305 * We're interested only in code ('T'ext)
306 */
307 if (symbol_type != 'T' && symbol_type != 'W')
308 continue;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300309
310 symbol_name = line + len + 2;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300311 /*
312 * Will fix up the end later, when we have all symbols sorted.
313 */
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200314 sym = symbol__new(start, 0, symbol_name);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300315
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300316 if (sym == NULL)
317 goto out_delete_line;
318
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200319 /*
320 * We will pass the symbols to the filter later, in
321 * kernel_maps__split_kallsyms, when we have split the
322 * maps per module
323 */
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300324 dso__insert_symbol(kernel_map->dso, sym);
325 }
326
327 free(line);
328 fclose(file);
329
330 return 0;
331
332out_delete_line:
333 free(line);
334out_failure:
335 return -1;
336}
337
338/*
339 * Split the symbols into maps, making sure there are no overlaps, i.e. the
340 * kernel range is broken in several maps, named [kernel].N, as we don't have
341 * the original ELF section names vmlinux have.
342 */
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200343static int kernel_maps__split_kallsyms(symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300344{
345 struct map *map = kernel_map;
346 struct symbol *pos;
347 int count = 0;
348 struct rb_node *next = rb_first(&kernel_map->dso->syms);
349 int kernel_range = 0;
350
351 while (next) {
352 char *module;
353
354 pos = rb_entry(next, struct symbol, rb_node);
355 next = rb_next(&pos->rb_node);
356
357 module = strchr(pos->name, '\t');
358 if (module) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300359 *module++ = '\0';
360
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300361 if (strcmp(map->dso->name, module)) {
362 map = kernel_maps__find_by_dso_name(module);
363 if (!map) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200364 pr_err("/proc/{kallsyms,modules} "
365 "inconsistency!\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300366 return -1;
367 }
368 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300369 /*
370 * So that we look just like we get from .ko files,
371 * i.e. not prelinked, relative to map->start.
372 */
373 pos->start = map->map_ip(map, pos->start);
374 pos->end = map->map_ip(map, pos->end);
375 } else if (map != kernel_map) {
376 char dso_name[PATH_MAX];
377 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300378
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300379 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
380 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300381
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200382 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300383 if (dso == NULL)
384 return -1;
385
386 map = map__new2(pos->start, dso);
387 if (map == NULL) {
388 dso__delete(dso);
389 return -1;
390 }
391
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200392 map->map_ip = map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300393 kernel_maps__insert(map);
394 ++kernel_range;
395 }
396
397 if (filter && filter(map, pos)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300398 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200399 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300400 } else {
401 if (map != kernel_map) {
402 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
403 dso__insert_symbol(map->dso, pos);
404 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200405 count++;
406 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300407 }
408
Mike Galbraith9974f492009-07-02 08:05:58 +0200409 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300410}
411
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300412
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200413static int kernel_maps__load_kallsyms(symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300414{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200415 if (kernel_maps__load_all_kallsyms())
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300416 return -1;
417
418 dso__fixup_sym_end(kernel_map->dso);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200419 kernel_map->dso->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300420
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200421 return kernel_maps__split_kallsyms(filter);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300422}
423
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200424size_t kernel_maps__fprintf(FILE *fp)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300425{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200426 size_t printed = fprintf(fp, "Kernel maps:\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300427 struct rb_node *nd;
428
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300429 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
430 struct map *pos = rb_entry(nd, struct map, rb_node);
431
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300432 printed += fprintf(fp, "Map:");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300433 printed += map__fprintf(pos, fp);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200434 if (verbose > 1) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300435 printed += dso__fprintf(pos->dso, fp);
436 printed += fprintf(fp, "--\n");
437 }
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300438 }
439
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200440 return printed + fprintf(fp, "END kernel maps\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300441}
442
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300443static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200444 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300445{
446 char *line = NULL;
447 size_t n;
448 FILE *file;
449 int nr_syms = 0;
450
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300451 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300452 if (file == NULL)
453 goto out_failure;
454
455 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000456 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300457 struct symbol *sym;
458 int line_len, len;
459
460 line_len = getline(&line, &n, file);
461 if (line_len < 0)
462 break;
463
464 if (!line)
465 goto out_failure;
466
467 line[--line_len] = '\0'; /* \n */
468
469 len = hex2u64(line, &start);
470
471 len++;
472 if (len + 2 >= line_len)
473 continue;
474
475 len += hex2u64(line + len, &size);
476
477 len++;
478 if (len + 2 >= line_len)
479 continue;
480
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200481 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300482
483 if (sym == NULL)
484 goto out_delete_line;
485
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300486 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200487 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300488 else {
489 dso__insert_symbol(self, sym);
490 nr_syms++;
491 }
492 }
493
494 free(line);
495 fclose(file);
496
497 return nr_syms;
498
499out_delete_line:
500 free(line);
501out_failure:
502 return -1;
503}
504
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300505/**
506 * elf_symtab__for_each_symbol - iterate thru all the symbols
507 *
508 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200509 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300510 * @sym: GElf_Sym iterator
511 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200512#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
513 for (idx = 0, gelf_getsym(syms, idx, &sym);\
514 idx < nr_syms; \
515 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300516
517static inline uint8_t elf_sym__type(const GElf_Sym *sym)
518{
519 return GELF_ST_TYPE(sym->st_info);
520}
521
522static inline int elf_sym__is_function(const GElf_Sym *sym)
523{
524 return elf_sym__type(sym) == STT_FUNC &&
525 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300526 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300527}
528
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200529static inline int elf_sym__is_label(const GElf_Sym *sym)
530{
531 return elf_sym__type(sym) == STT_NOTYPE &&
532 sym->st_name != 0 &&
533 sym->st_shndx != SHN_UNDEF &&
534 sym->st_shndx != SHN_ABS;
535}
536
537static inline const char *elf_sec__name(const GElf_Shdr *shdr,
538 const Elf_Data *secstrs)
539{
540 return secstrs->d_buf + shdr->sh_name;
541}
542
543static inline int elf_sec__is_text(const GElf_Shdr *shdr,
544 const Elf_Data *secstrs)
545{
546 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
547}
548
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300549static inline const char *elf_sym__name(const GElf_Sym *sym,
550 const Elf_Data *symstrs)
551{
552 return symstrs->d_buf + sym->st_name;
553}
554
555static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
556 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200557 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300558{
559 Elf_Scn *sec = NULL;
560 size_t cnt = 1;
561
562 while ((sec = elf_nextscn(elf, sec)) != NULL) {
563 char *str;
564
565 gelf_getshdr(sec, shp);
566 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
567 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200568 if (idx)
569 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300570 break;
571 }
572 ++cnt;
573 }
574
575 return sec;
576}
577
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300578#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
579 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
580 idx < nr_entries; \
581 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
582
583#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
584 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
585 idx < nr_entries; \
586 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
587
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300588/*
589 * We need to check if we have a .dynsym, so that we can handle the
590 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
591 * .dynsym or .symtab).
592 * And always look at the original dso, not at debuginfo packages, that
593 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
594 */
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200595static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
596 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300597{
598 uint32_t nr_rel_entries, idx;
599 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000600 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300601 GElf_Shdr shdr_plt;
602 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300603 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300604 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300605 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
606 size_t dynsym_idx;
607 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300608 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300609 Elf *elf;
610 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300611
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300612 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300613 if (fd < 0)
614 goto out;
615
Marti Raudsepp84087122009-10-24 19:10:36 +0300616 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300617 if (elf == NULL)
618 goto out_close;
619
620 if (gelf_getehdr(elf, &ehdr) == NULL)
621 goto out_elf_end;
622
623 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
624 ".dynsym", &dynsym_idx);
625 if (scn_dynsym == NULL)
626 goto out_elf_end;
627
628 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300629 ".rela.plt", NULL);
630 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300631 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300632 ".rel.plt", NULL);
633 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300634 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300635 }
636
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300637 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300638
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300639 if (shdr_rel_plt.sh_link != dynsym_idx)
640 goto out_elf_end;
641
642 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
643 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300644
645 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200646 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300647 * and the symbols in the .dynsym they refer to.
648 */
649 reldata = elf_getdata(scn_plt_rel, NULL);
650 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300651 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300652
653 syms = elf_getdata(scn_dynsym, NULL);
654 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300655 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300656
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300657 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300658 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300659 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300660
661 symstrs = elf_getdata(scn_symstrs, NULL);
662 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300663 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300664
665 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
666 plt_offset = shdr_plt.sh_offset;
667
668 if (shdr_rel_plt.sh_type == SHT_RELA) {
669 GElf_Rela pos_mem, *pos;
670
671 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
672 nr_rel_entries) {
673 symidx = GELF_R_SYM(pos->r_info);
674 plt_offset += shdr_plt.sh_entsize;
675 gelf_getsym(syms, symidx, &sym);
676 snprintf(sympltname, sizeof(sympltname),
677 "%s@plt", elf_sym__name(&sym, symstrs));
678
679 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200680 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300681 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300682 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300683
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200684 if (filter && filter(map, f))
685 symbol__delete(f);
686 else {
687 dso__insert_symbol(self, f);
688 ++nr;
689 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300690 }
691 } else if (shdr_rel_plt.sh_type == SHT_REL) {
692 GElf_Rel pos_mem, *pos;
693 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
694 nr_rel_entries) {
695 symidx = GELF_R_SYM(pos->r_info);
696 plt_offset += shdr_plt.sh_entsize;
697 gelf_getsym(syms, symidx, &sym);
698 snprintf(sympltname, sizeof(sympltname),
699 "%s@plt", elf_sym__name(&sym, symstrs));
700
701 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200702 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300703 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300704 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300705
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200706 if (filter && filter(map, f))
707 symbol__delete(f);
708 else {
709 dso__insert_symbol(self, f);
710 ++nr;
711 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300712 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300713 }
714
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300715 err = 0;
716out_elf_end:
717 elf_end(elf);
718out_close:
719 close(fd);
720
721 if (err == 0)
722 return nr;
723out:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200724 pr_warning("%s: problems reading %s PLT info.\n",
725 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300726 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300727}
728
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300729static int dso__load_sym(struct dso *self, struct map *map, const char *name,
730 int fd, symbol_filter_t filter, int kernel,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200731 int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300732{
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300733 struct map *curr_map = map;
734 struct dso *curr_dso = self;
735 size_t dso_name_len = strlen(self->short_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200736 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300737 uint32_t nr_syms;
738 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200739 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300740 GElf_Ehdr ehdr;
741 GElf_Shdr shdr;
742 Elf_Data *syms;
743 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300744 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300745 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300746 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300747
Marti Raudsepp84087122009-10-24 19:10:36 +0300748 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300749 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200750 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300751 goto out_close;
752 }
753
754 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200755 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300756 goto out_elf_end;
757 }
758
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300759 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
760 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300761 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
762 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300763 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300764 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300765
766 syms = elf_getdata(sec, NULL);
767 if (syms == NULL)
768 goto out_elf_end;
769
770 sec = elf_getscn(elf, shdr.sh_link);
771 if (sec == NULL)
772 goto out_elf_end;
773
774 symstrs = elf_getdata(sec, NULL);
775 if (symstrs == NULL)
776 goto out_elf_end;
777
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200778 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
779 if (sec_strndx == NULL)
780 goto out_elf_end;
781
782 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500783 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200784 goto out_elf_end;
785
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300786 nr_syms = shdr.sh_size / shdr.sh_entsize;
787
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200788 memset(&sym, 0, sizeof(sym));
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200789 if (!kernel) {
790 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300791 elf_section_by_name(elf, &ehdr, &shdr,
792 ".gnu.prelink_undo",
793 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200794 } else self->adjust_symbols = 0;
795
Ingo Molnar83a09442009-08-15 12:26:57 +0200796 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300797 struct symbol *f;
Ingo Molnar83a09442009-08-15 12:26:57 +0200798 const char *elf_name;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300799 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200800 int is_label = elf_sym__is_label(&sym);
801 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300802
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200803 if (!is_label && !elf_sym__is_function(&sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300804 continue;
805
806 sec = elf_getscn(elf, sym.st_shndx);
807 if (!sec)
808 goto out_elf_end;
809
810 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200811
812 if (is_label && !elf_sec__is_text(&shdr, secstrs))
813 continue;
814
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300815 elf_name = elf_sym__name(&sym, symstrs);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200816 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200817
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300818 if (kernel || kmodule) {
819 char dso_name[PATH_MAX];
820
821 if (strcmp(section_name,
822 curr_dso->short_name + dso_name_len) == 0)
823 goto new_symbol;
824
825 if (strcmp(section_name, ".text") == 0) {
826 curr_map = map;
827 curr_dso = self;
828 goto new_symbol;
829 }
830
831 snprintf(dso_name, sizeof(dso_name),
832 "%s%s", self->short_name, section_name);
833
834 curr_map = kernel_maps__find_by_dso_name(dso_name);
835 if (curr_map == NULL) {
836 u64 start = sym.st_value;
837
838 if (kmodule)
839 start += map->start + shdr.sh_offset;
840
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200841 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300842 if (curr_dso == NULL)
843 goto out_elf_end;
844 curr_map = map__new2(start, curr_dso);
845 if (curr_map == NULL) {
846 dso__delete(curr_dso);
847 goto out_elf_end;
848 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200849 curr_map->map_ip = identity__map_ip;
850 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300851 curr_dso->origin = DSO__ORIG_KERNEL;
852 kernel_maps__insert(curr_map);
853 dsos__add(curr_dso);
854 } else
855 curr_dso = curr_map->dso;
856
857 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300858 }
859
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300860 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200861 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
862 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
863 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300864 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300865 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300866 /*
867 * We need to figure out if the object was created from C++ sources
868 * DWARF DW_compile_unit has this, but we don't always have access
869 * to it...
870 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200871 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300872 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +0200873 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300874new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200875 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300876 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300877 if (!f)
878 goto out_elf_end;
879
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300880 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200881 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300882 else {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300883 dso__insert_symbol(curr_dso, f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300884 nr++;
885 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300886 }
887
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300888 /*
889 * For misannotated, zeroed, ASM function sizes.
890 */
891 if (nr > 0)
892 dso__fixup_sym_end(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300893 err = nr;
894out_elf_end:
895 elf_end(elf);
896out_close:
897 return err;
898}
899
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -0200900static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
901{
902 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
903}
904
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200905bool dsos__read_build_ids(void)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100906{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200907 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100908 struct dso *pos;
909
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200910 list_for_each_entry(pos, &dsos, node)
911 if (filename__read_build_id(pos->long_name, pos->build_id,
912 sizeof(pos->build_id)) > 0) {
913 have_build_id = true;
914 pos->has_build_id = true;
915 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100916
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200917 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100918}
919
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200920/*
921 * Align offset to 4 bytes as needed for note name and descriptor data.
922 */
923#define NOTE_ALIGN(n) (((n) + 3) & -4U)
924
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -0200925int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300926{
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -0200927 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300928 GElf_Ehdr ehdr;
929 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200930 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300931 Elf_Scn *sec;
Pekka Enberge57cfcd2009-11-22 12:29:44 +0200932 Elf_Kind ek;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200933 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300934 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300935
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -0200936 if (size < BUILD_ID_SIZE)
937 goto out;
938
939 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300940 if (fd < 0)
941 goto out;
942
Marti Raudsepp84087122009-10-24 19:10:36 +0300943 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300944 if (elf == NULL) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200945 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300946 goto out_close;
947 }
948
Pekka Enberge57cfcd2009-11-22 12:29:44 +0200949 ek = elf_kind(elf);
950 if (ek != ELF_K_ELF)
951 goto out_elf_end;
952
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300953 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200954 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300955 goto out_elf_end;
956 }
957
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -0200958 sec = elf_section_by_name(elf, &ehdr, &shdr,
959 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200960 if (sec == NULL) {
961 sec = elf_section_by_name(elf, &ehdr, &shdr,
962 ".notes", NULL);
963 if (sec == NULL)
964 goto out_elf_end;
965 }
966
967 data = elf_getdata(sec, NULL);
968 if (data == NULL)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300969 goto out_elf_end;
970
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200971 ptr = data->d_buf;
972 while (ptr < (data->d_buf + data->d_size)) {
973 GElf_Nhdr *nhdr = ptr;
974 int namesz = NOTE_ALIGN(nhdr->n_namesz),
975 descsz = NOTE_ALIGN(nhdr->n_descsz);
976 const char *name;
977
978 ptr += sizeof(*nhdr);
979 name = ptr;
980 ptr += namesz;
981 if (nhdr->n_type == NT_GNU_BUILD_ID &&
982 nhdr->n_namesz == sizeof("GNU")) {
983 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
984 memcpy(bf, ptr, BUILD_ID_SIZE);
985 err = BUILD_ID_SIZE;
986 break;
987 }
988 }
989 ptr += descsz;
990 }
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -0200991out_elf_end:
992 elf_end(elf);
993out_close:
994 close(fd);
995out:
996 return err;
997}
998
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -0200999int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1000{
1001 int fd, err = -1;
1002
1003 if (size < BUILD_ID_SIZE)
1004 goto out;
1005
1006 fd = open(filename, O_RDONLY);
1007 if (fd < 0)
1008 goto out;
1009
1010 while (1) {
1011 char bf[BUFSIZ];
1012 GElf_Nhdr nhdr;
1013 int namesz, descsz;
1014
1015 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1016 break;
1017
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001018 namesz = NOTE_ALIGN(nhdr.n_namesz);
1019 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001020 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1021 nhdr.n_namesz == sizeof("GNU")) {
1022 if (read(fd, bf, namesz) != namesz)
1023 break;
1024 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1025 if (read(fd, build_id,
1026 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1027 err = 0;
1028 break;
1029 }
1030 } else if (read(fd, bf, descsz) != descsz)
1031 break;
1032 } else {
1033 int n = namesz + descsz;
1034 if (read(fd, bf, n) != n)
1035 break;
1036 }
1037 }
1038 close(fd);
1039out:
1040 return err;
1041}
1042
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001043char dso__symtab_origin(const struct dso *self)
1044{
1045 static const char origin[] = {
1046 [DSO__ORIG_KERNEL] = 'k',
1047 [DSO__ORIG_JAVA_JIT] = 'j',
1048 [DSO__ORIG_FEDORA] = 'f',
1049 [DSO__ORIG_UBUNTU] = 'u',
1050 [DSO__ORIG_BUILDID] = 'b',
1051 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001052 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001053 };
1054
1055 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
1056 return '!';
1057 return origin[self->origin];
1058}
1059
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001060int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001061{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001062 int size = PATH_MAX;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001063 char *name;
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001064 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001065 int ret = -1;
1066 int fd;
1067
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001068 self->loaded = 1;
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001069
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001070 if (self->kernel)
1071 return dso__load_kernel_sym(self, map, filter);
1072
1073 name = malloc(size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001074 if (!name)
1075 return -1;
1076
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001077 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001078
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001079 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001080 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001081 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
1082 DSO__ORIG_NOT_FOUND;
1083 return ret;
1084 }
1085
1086 self->origin = DSO__ORIG_FEDORA - 1;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001087
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001088more:
1089 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001090 self->origin++;
1091 switch (self->origin) {
1092 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001093 snprintf(name, size, "/usr/lib/debug%s.debug",
1094 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001095 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001096 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001097 snprintf(name, size, "/usr/lib/debug%s",
1098 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001099 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001100 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001101 if (filename__read_build_id(self->long_name, build_id,
1102 sizeof(build_id))) {
1103 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1104
1105 build_id__sprintf(build_id, sizeof(build_id),
1106 build_id_hex);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001107 snprintf(name, size,
1108 "/usr/lib/debug/.build-id/%.2s/%s.debug",
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001109 build_id_hex, build_id_hex + 2);
1110 if (self->has_build_id)
1111 goto compare_build_id;
1112 break;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001113 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001114 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001115 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001116 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001117 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001118 break;
1119
1120 default:
1121 goto out;
1122 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001123
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001124 if (self->has_build_id) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001125 if (filename__read_build_id(name, build_id,
1126 sizeof(build_id)) < 0)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001127 goto more;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001128compare_build_id:
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001129 if (!dso__build_id_equal(self, build_id))
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001130 goto more;
1131 }
1132
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001133 fd = open(name, O_RDONLY);
1134 } while (fd < 0);
1135
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001136 ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001137 close(fd);
1138
1139 /*
1140 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
1141 */
1142 if (!ret)
1143 goto more;
1144
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001145 if (ret > 0) {
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001146 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001147 if (nr_plt > 0)
1148 ret += nr_plt;
1149 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001150out:
1151 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001152 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1153 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001154 return ret;
1155}
1156
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001157struct map *kernel_map;
1158
1159static void kernel_maps__insert(struct map *map)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001160{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001161 maps__insert(&kernel_maps, map);
1162}
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001163
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001164struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp,
1165 symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001166{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001167 struct map *map = maps__find(&kernel_maps, ip);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001168
1169 if (mapp)
1170 *mapp = map;
1171
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001172 if (map) {
1173 ip = map->map_ip(map, ip);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001174 return map__find_symbol(map, ip, filter);
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001175 } else
1176 WARN_ONCE(RB_EMPTY_ROOT(&kernel_maps),
1177 "Empty kernel_maps, was symbol__init() called?\n");
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001178
1179 return NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001180}
1181
1182struct map *kernel_maps__find_by_dso_name(const char *name)
1183{
1184 struct rb_node *nd;
1185
1186 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1187 struct map *map = rb_entry(nd, struct map, rb_node);
1188
1189 if (map->dso && strcmp(map->dso->name, name) == 0)
1190 return map;
1191 }
1192
1193 return NULL;
1194}
1195
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001196static int dsos__set_modules_path_dir(char *dirname)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001197{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001198 struct dirent *dent;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001199 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001200
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001201 if (!dir) {
Arnaldo Carvalho de Melo87f8ea42009-11-22 13:21:41 -02001202 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001203 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001204 }
1205
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001206 while ((dent = readdir(dir)) != NULL) {
1207 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001208
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001209 if (dent->d_type == DT_DIR) {
1210 if (!strcmp(dent->d_name, ".") ||
1211 !strcmp(dent->d_name, ".."))
1212 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001213
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001214 snprintf(path, sizeof(path), "%s/%s",
1215 dirname, dent->d_name);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001216 if (dsos__set_modules_path_dir(path) < 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001217 goto failure;
1218 } else {
1219 char *dot = strrchr(dent->d_name, '.'),
1220 dso_name[PATH_MAX];
1221 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001222 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001223
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001224 if (dot == NULL || strcmp(dot, ".ko"))
1225 continue;
1226 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1227 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001228
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001229 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001230 map = kernel_maps__find_by_dso_name(dso_name);
1231 if (map == NULL)
1232 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001233
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001234 snprintf(path, sizeof(path), "%s/%s",
1235 dirname, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001236
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001237 long_name = strdup(path);
1238 if (long_name == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001239 goto failure;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001240 dso__set_long_name(map->dso, long_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001241 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001242 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001243
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001244 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001245failure:
1246 closedir(dir);
1247 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001248}
1249
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001250static int dsos__set_modules_path(void)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001251{
1252 struct utsname uts;
1253 char modules_path[PATH_MAX];
1254
1255 if (uname(&uts) < 0)
1256 return -1;
1257
1258 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1259 uts.release);
1260
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001261 return dsos__set_modules_path_dir(modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001262}
1263
1264/*
1265 * Constructor variant for modules (where we know from /proc/modules where
1266 * they are loaded) and for vmlinux, where only after we load all the
1267 * symbols we'll know where it starts and ends.
1268 */
1269static struct map *map__new2(u64 start, struct dso *dso)
1270{
1271 struct map *self = malloc(sizeof(*self));
1272
1273 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001274 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001275 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001276 */
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001277 map__init(self, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001278 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001279
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001280 return self;
1281}
1282
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001283static int kernel_maps__create_module_maps(void)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001284{
1285 char *line = NULL;
1286 size_t n;
1287 FILE *file = fopen("/proc/modules", "r");
1288 struct map *map;
1289
1290 if (file == NULL)
1291 return -1;
1292
1293 while (!feof(file)) {
1294 char name[PATH_MAX];
1295 u64 start;
1296 struct dso *dso;
1297 char *sep;
1298 int line_len;
1299
1300 line_len = getline(&line, &n, file);
1301 if (line_len < 0)
1302 break;
1303
1304 if (!line)
1305 goto out_failure;
1306
1307 line[--line_len] = '\0'; /* \n */
1308
1309 sep = strrchr(line, 'x');
1310 if (sep == NULL)
1311 continue;
1312
1313 hex2u64(sep + 1, &start);
1314
1315 sep = strchr(line, ' ');
1316 if (sep == NULL)
1317 continue;
1318
1319 *sep = '\0';
1320
1321 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001322 dso = dso__new(name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001323
1324 if (dso == NULL)
1325 goto out_delete_line;
1326
1327 map = map__new2(start, dso);
1328 if (map == NULL) {
1329 dso__delete(dso);
1330 goto out_delete_line;
1331 }
1332
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001333 snprintf(name, sizeof(name),
1334 "/sys/module/%s/notes/.note.gnu.build-id", line);
1335 if (sysfs__read_build_id(name, dso->build_id,
1336 sizeof(dso->build_id)) == 0)
1337 dso->has_build_id = true;
1338
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001339 dso->origin = DSO__ORIG_KMODULE;
1340 kernel_maps__insert(map);
1341 dsos__add(dso);
1342 }
1343
1344 free(line);
1345 fclose(file);
1346
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001347 return dsos__set_modules_path();
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001348
1349out_delete_line:
1350 free(line);
1351out_failure:
1352 return -1;
1353}
1354
1355static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001356 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001357{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001358 int err = -1, fd;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001359
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001360 if (self->has_build_id) {
1361 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001362
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001363 if (filename__read_build_id(vmlinux, build_id,
1364 sizeof(build_id)) < 0) {
1365 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1366 return -1;
1367 }
1368 if (!dso__build_id_equal(self, build_id)) {
1369 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1370 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1371
1372 build_id__sprintf(self->build_id,
1373 sizeof(self->build_id),
1374 expected_build_id);
1375 build_id__sprintf(build_id, sizeof(build_id),
1376 vmlinux_build_id);
1377 pr_debug("build_id in %s is %s while expected is %s, "
1378 "ignoring it\n", vmlinux, vmlinux_build_id,
1379 expected_build_id);
1380 return -1;
1381 }
1382 }
1383
1384 fd = open(vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001385 if (fd < 0)
1386 return -1;
1387
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001388 self->loaded = 1;
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001389 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001390
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001391 close(fd);
1392
1393 return err;
1394}
1395
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001396static int dso__load_kernel_sym(struct dso *self, struct map *map,
1397 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001398{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001399 int err;
1400 bool is_kallsyms;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001401
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001402 if (vmlinux_path != NULL) {
1403 int i;
1404 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1405 vmlinux_path__nr_entries);
1406 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1407 err = dso__load_vmlinux(self, map, vmlinux_path[i],
1408 filter);
1409 if (err > 0) {
1410 pr_debug("Using %s for symbols\n",
1411 vmlinux_path[i]);
1412 dso__set_long_name(self,
1413 strdup(vmlinux_path[i]));
1414 goto out_fixup;
1415 }
1416 }
1417 }
1418
1419 is_kallsyms = self->long_name[0] == '[';
1420 if (is_kallsyms)
1421 goto do_kallsyms;
1422
1423 err = dso__load_vmlinux(self, map, self->long_name, filter);
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001424 if (err <= 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001425 pr_info("The file %s cannot be used, "
1426 "trying to use /proc/kallsyms...", self->long_name);
1427 sleep(2);
1428do_kallsyms:
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001429 err = kernel_maps__load_kallsyms(filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001430 if (err > 0 && !is_kallsyms)
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001431 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1432 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001433
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001434 if (err > 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001435out_fixup:
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001436 map__fixup_start(map);
1437 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001438 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001439
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001440 return err;
1441}
1442
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001443LIST_HEAD(dsos);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001444struct dso *vdso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001445
1446static void dsos__add(struct dso *dso)
1447{
1448 list_add_tail(&dso->node, &dsos);
1449}
1450
1451static struct dso *dsos__find(const char *name)
1452{
1453 struct dso *pos;
1454
1455 list_for_each_entry(pos, &dsos, node)
1456 if (strcmp(pos->name, name) == 0)
1457 return pos;
1458 return NULL;
1459}
1460
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001461struct dso *dsos__findnew(const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001462{
1463 struct dso *dso = dsos__find(name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001464
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001465 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001466 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001467 if (dso != NULL) {
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001468 dsos__add(dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001469 dso__set_basename(dso);
1470 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001471 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001472
1473 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001474}
1475
1476void dsos__fprintf(FILE *fp)
1477{
1478 struct dso *pos;
1479
1480 list_for_each_entry(pos, &dsos, node)
1481 dso__fprintf(pos, fp);
1482}
1483
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001484size_t dsos__fprintf_buildid(FILE *fp)
1485{
1486 struct dso *pos;
1487 size_t ret = 0;
1488
1489 list_for_each_entry(pos, &dsos, node) {
1490 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02001491 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001492 }
1493 return ret;
1494}
1495
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001496static int kernel_maps__create_kernel_map(const struct symbol_conf *conf)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001497{
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001498 struct dso *kernel = dso__new(conf->vmlinux_name ?: "[kernel.kallsyms]");
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001499
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001500 if (kernel == NULL)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001501 return -1;
1502
1503 kernel_map = map__new2(0, kernel);
1504 if (kernel_map == NULL)
1505 goto out_delete_kernel_dso;
1506
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001507 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
1508 kernel->short_name = "[kernel]";
1509 kernel->kernel = 1;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001510
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001511 vdso = dso__new("[vdso]");
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001512 if (vdso == NULL)
1513 goto out_delete_kernel_map;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001514
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001515 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1516 sizeof(kernel->build_id)) == 0)
1517 kernel->has_build_id = true;
1518
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001519 kernel_maps__insert(kernel_map);
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001520 dsos__add(kernel);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001521 dsos__add(vdso);
1522
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001523 return 0;
1524
1525out_delete_kernel_map:
1526 map__delete(kernel_map);
1527 kernel_map = NULL;
1528out_delete_kernel_dso:
1529 dso__delete(kernel);
1530 return -1;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001531}
1532
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001533static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001534{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001535 while (--vmlinux_path__nr_entries >= 0) {
1536 free(vmlinux_path[vmlinux_path__nr_entries]);
1537 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1538 }
1539
1540 free(vmlinux_path);
1541 vmlinux_path = NULL;
1542}
1543
1544static int vmlinux_path__init(void)
1545{
1546 struct utsname uts;
1547 char bf[PATH_MAX];
1548
1549 if (uname(&uts) < 0)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001550 return -1;
1551
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001552 vmlinux_path = malloc(sizeof(char *) * 5);
1553 if (vmlinux_path == NULL)
1554 return -1;
1555
1556 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1557 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1558 goto out_fail;
1559 ++vmlinux_path__nr_entries;
1560 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1561 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1562 goto out_fail;
1563 ++vmlinux_path__nr_entries;
1564 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1565 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1566 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1567 goto out_fail;
1568 ++vmlinux_path__nr_entries;
1569 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1570 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1571 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1572 goto out_fail;
1573 ++vmlinux_path__nr_entries;
1574 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1575 uts.release);
1576 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1577 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1578 goto out_fail;
1579 ++vmlinux_path__nr_entries;
1580
1581 return 0;
1582
1583out_fail:
1584 vmlinux_path__exit();
1585 return -1;
1586}
1587
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001588static int kernel_maps__init(const struct symbol_conf *conf)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001589{
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001590 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1591
1592 symbol__priv_size = pconf->priv_size;
1593
1594 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001595 return -1;
1596
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001597 if (kernel_maps__create_kernel_map(pconf) < 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001598 vmlinux_path__exit();
1599 return -1;
1600 }
1601
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001602 if (pconf->use_modules && kernel_maps__create_module_maps() < 0)
Arnaldo Carvalho de Melo87f8ea42009-11-22 13:21:41 -02001603 pr_debug("Failed to load list of modules in use, "
1604 "continuing...\n");
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -02001605 /*
1606 * Now that we have all the maps created, just set the ->end of them:
1607 */
1608 kernel_maps__fixup_end();
Arnaldo Carvalho de Melo6671cb12009-11-20 20:51:24 -02001609 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001610}
1611
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001612int symbol__init(struct symbol_conf *conf)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001613{
1614 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001615 return kernel_maps__init(conf);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001616}