blob: e7c7cdb851c29fdaf99b021c38e33a16bc26c69d [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 Weisbecker8f288272009-08-16 22:05:48 +02007#include "debug.h"
8
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03009#include <libelf.h>
10#include <gelf.h>
11#include <elf.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030012#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020013
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030014enum dso_origin {
15 DSO__ORIG_KERNEL = 0,
16 DSO__ORIG_JAVA_JIT,
17 DSO__ORIG_FEDORA,
18 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO,
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030021 DSO__ORIG_KMODULE,
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030022 DSO__ORIG_NOT_FOUND,
23};
24
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030025static void dsos__add(struct dso *dso);
26static struct dso *dsos__find(const char *name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030027static struct map *map__new2(u64 start, struct dso *dso);
28static void kernel_maps__insert(struct map *map);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020029unsigned int symbol__priv_size;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030030
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030031static struct rb_root kernel_maps;
32
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030033static void dso__fixup_sym_end(struct dso *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030034{
35 struct rb_node *nd, *prevnd = rb_first(&self->syms);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030036 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030037
38 if (prevnd == NULL)
39 return;
40
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030041 curr = rb_entry(prevnd, struct symbol, rb_node);
42
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030043 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030044 prev = curr;
45 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030046
47 if (prev->end == prev->start)
48 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030049 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030050
51 /* Last entry */
52 if (curr->end == curr->start)
53 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030054}
55
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030056static void kernel_maps__fixup_end(void)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030057{
58 struct map *prev, *curr;
59 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
60
61 if (prevnd == NULL)
62 return;
63
64 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030065
66 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
67 prev = curr;
68 curr = rb_entry(nd, struct map, rb_node);
69 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030070 }
71
72 nd = rb_last(&curr->dso->syms);
73 if (nd) {
74 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
75 curr->end = sym->end;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030076 }
77}
78
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020079static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030080{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030081 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020082 struct symbol *self = calloc(1, (symbol__priv_size +
83 sizeof(*self) + namelen));
Ingo Molnar0b73da32009-06-06 15:48:52 +020084 if (!self)
85 return NULL;
86
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020087 if (symbol__priv_size) {
88 memset(self, 0, symbol__priv_size);
89 self = ((void *)self) + symbol__priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030090 }
Ingo Molnar0b73da32009-06-06 15:48:52 +020091 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +020092 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020093
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -020094 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020095
Ingo Molnar0b73da32009-06-06 15:48:52 +020096 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030097
98 return self;
99}
100
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200101static void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300102{
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200103 free(((void *)self) - symbol__priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300104}
105
106static size_t symbol__fprintf(struct symbol *self, FILE *fp)
107{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300108 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300109 self->start, self->end, self->name);
110}
111
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200112struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300113{
114 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
115
116 if (self != NULL) {
117 strcpy(self->name, name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300118 self->long_name = self->name;
119 self->short_name = self->name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300120 self->syms = RB_ROOT;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200121 self->find_symbol = dso__find_symbol;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300122 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300123 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo6d7aa9d2009-11-03 15:52:18 -0200124 self->loaded = false;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300125 }
126
127 return self;
128}
129
130static void dso__delete_symbols(struct dso *self)
131{
132 struct symbol *pos;
133 struct rb_node *next = rb_first(&self->syms);
134
135 while (next) {
136 pos = rb_entry(next, struct symbol, rb_node);
137 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloc8c96522009-06-01 17:50:57 -0300138 rb_erase(&pos->rb_node, &self->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200139 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300140 }
141}
142
143void dso__delete(struct dso *self)
144{
145 dso__delete_symbols(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300146 if (self->long_name != self->name)
147 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300148 free(self);
149}
150
151static void dso__insert_symbol(struct dso *self, struct symbol *sym)
152{
153 struct rb_node **p = &self->syms.rb_node;
154 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000155 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300156 struct symbol *s;
157
158 while (*p != NULL) {
159 parent = *p;
160 s = rb_entry(parent, struct symbol, rb_node);
161 if (ip < s->start)
162 p = &(*p)->rb_left;
163 else
164 p = &(*p)->rb_right;
165 }
166 rb_link_node(&sym->rb_node, parent, p);
167 rb_insert_color(&sym->rb_node, &self->syms);
168}
169
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000170struct symbol *dso__find_symbol(struct dso *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300171{
172 struct rb_node *n;
173
174 if (self == NULL)
175 return NULL;
176
177 n = self->syms.rb_node;
178
179 while (n) {
180 struct symbol *s = rb_entry(n, struct symbol, rb_node);
181
182 if (ip < s->start)
183 n = n->rb_left;
184 else if (ip > s->end)
185 n = n->rb_right;
186 else
187 return s;
188 }
189
190 return NULL;
191}
192
193size_t dso__fprintf(struct dso *self, FILE *fp)
194{
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -0300195 size_t ret = fprintf(fp, "dso: %s\n", self->short_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300196
197 struct rb_node *nd;
198 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
199 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
200 ret += symbol__fprintf(pos, fp);
201 }
202
203 return ret;
204}
205
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300206/*
207 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
208 * so that we can in the next step set the symbol ->end address and then
209 * call kernel_maps__split_kallsyms.
210 */
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200211static int kernel_maps__load_all_kallsyms(void)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300212{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300213 char *line = NULL;
214 size_t n;
215 FILE *file = fopen("/proc/kallsyms", "r");
216
217 if (file == NULL)
218 goto out_failure;
219
220 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000221 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300222 struct symbol *sym;
223 int line_len, len;
224 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300225 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300226
227 line_len = getline(&line, &n, file);
228 if (line_len < 0)
229 break;
230
231 if (!line)
232 goto out_failure;
233
234 line[--line_len] = '\0'; /* \n */
235
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300236 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300237
238 len++;
239 if (len + 2 >= line_len)
240 continue;
241
242 symbol_type = toupper(line[len]);
243 /*
244 * We're interested only in code ('T'ext)
245 */
246 if (symbol_type != 'T' && symbol_type != 'W')
247 continue;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300248
249 symbol_name = line + len + 2;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300250 /*
251 * Will fix up the end later, when we have all symbols sorted.
252 */
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200253 sym = symbol__new(start, 0, symbol_name);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300254
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300255 if (sym == NULL)
256 goto out_delete_line;
257
258 dso__insert_symbol(kernel_map->dso, sym);
259 }
260
261 free(line);
262 fclose(file);
263
264 return 0;
265
266out_delete_line:
267 free(line);
268out_failure:
269 return -1;
270}
271
272/*
273 * Split the symbols into maps, making sure there are no overlaps, i.e. the
274 * kernel range is broken in several maps, named [kernel].N, as we don't have
275 * the original ELF section names vmlinux have.
276 */
277static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
278{
279 struct map *map = kernel_map;
280 struct symbol *pos;
281 int count = 0;
282 struct rb_node *next = rb_first(&kernel_map->dso->syms);
283 int kernel_range = 0;
284
285 while (next) {
286 char *module;
287
288 pos = rb_entry(next, struct symbol, rb_node);
289 next = rb_next(&pos->rb_node);
290
291 module = strchr(pos->name, '\t');
292 if (module) {
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300293 if (!use_modules)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300294 goto delete_symbol;
295
296 *module++ = '\0';
297
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300298 if (strcmp(map->dso->name, module)) {
299 map = kernel_maps__find_by_dso_name(module);
300 if (!map) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200301 pr_err("/proc/{kallsyms,modules} "
302 "inconsistency!\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300303 return -1;
304 }
305 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300306 /*
307 * So that we look just like we get from .ko files,
308 * i.e. not prelinked, relative to map->start.
309 */
310 pos->start = map->map_ip(map, pos->start);
311 pos->end = map->map_ip(map, pos->end);
312 } else if (map != kernel_map) {
313 char dso_name[PATH_MAX];
314 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300315
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300316 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
317 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300318
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200319 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300320 if (dso == NULL)
321 return -1;
322
323 map = map__new2(pos->start, dso);
324 if (map == NULL) {
325 dso__delete(dso);
326 return -1;
327 }
328
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200329 map->map_ip = map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300330 kernel_maps__insert(map);
331 ++kernel_range;
332 }
333
334 if (filter && filter(map, pos)) {
335delete_symbol:
336 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200337 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300338 } else {
339 if (map != kernel_map) {
340 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
341 dso__insert_symbol(map->dso, pos);
342 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200343 count++;
344 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300345 }
346
Mike Galbraith9974f492009-07-02 08:05:58 +0200347 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300348}
349
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300350
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200351static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300352{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200353 if (kernel_maps__load_all_kallsyms())
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300354 return -1;
355
356 dso__fixup_sym_end(kernel_map->dso);
357
358 return kernel_maps__split_kallsyms(filter, use_modules);
359}
360
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200361static size_t kernel_maps__fprintf(FILE *fp)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300362{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200363 size_t printed = fprintf(fp, "Kernel maps:\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300364 struct rb_node *nd;
365
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300366 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
367 struct map *pos = rb_entry(nd, struct map, rb_node);
368
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300369 printed += fprintf(fp, "Map:");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300370 printed += map__fprintf(pos, fp);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200371 if (verbose > 1) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300372 printed += dso__fprintf(pos->dso, fp);
373 printed += fprintf(fp, "--\n");
374 }
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300375 }
376
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200377 return printed + fprintf(fp, "END kernel maps\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300378}
379
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300380static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200381 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300382{
383 char *line = NULL;
384 size_t n;
385 FILE *file;
386 int nr_syms = 0;
387
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300388 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300389 if (file == NULL)
390 goto out_failure;
391
392 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000393 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300394 struct symbol *sym;
395 int line_len, len;
396
397 line_len = getline(&line, &n, file);
398 if (line_len < 0)
399 break;
400
401 if (!line)
402 goto out_failure;
403
404 line[--line_len] = '\0'; /* \n */
405
406 len = hex2u64(line, &start);
407
408 len++;
409 if (len + 2 >= line_len)
410 continue;
411
412 len += hex2u64(line + len, &size);
413
414 len++;
415 if (len + 2 >= line_len)
416 continue;
417
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200418 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300419
420 if (sym == NULL)
421 goto out_delete_line;
422
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300423 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200424 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300425 else {
426 dso__insert_symbol(self, sym);
427 nr_syms++;
428 }
429 }
430
431 free(line);
432 fclose(file);
433
434 return nr_syms;
435
436out_delete_line:
437 free(line);
438out_failure:
439 return -1;
440}
441
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300442/**
443 * elf_symtab__for_each_symbol - iterate thru all the symbols
444 *
445 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200446 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300447 * @sym: GElf_Sym iterator
448 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200449#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
450 for (idx = 0, gelf_getsym(syms, idx, &sym);\
451 idx < nr_syms; \
452 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300453
454static inline uint8_t elf_sym__type(const GElf_Sym *sym)
455{
456 return GELF_ST_TYPE(sym->st_info);
457}
458
459static inline int elf_sym__is_function(const GElf_Sym *sym)
460{
461 return elf_sym__type(sym) == STT_FUNC &&
462 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300463 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300464}
465
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200466static inline int elf_sym__is_label(const GElf_Sym *sym)
467{
468 return elf_sym__type(sym) == STT_NOTYPE &&
469 sym->st_name != 0 &&
470 sym->st_shndx != SHN_UNDEF &&
471 sym->st_shndx != SHN_ABS;
472}
473
474static inline const char *elf_sec__name(const GElf_Shdr *shdr,
475 const Elf_Data *secstrs)
476{
477 return secstrs->d_buf + shdr->sh_name;
478}
479
480static inline int elf_sec__is_text(const GElf_Shdr *shdr,
481 const Elf_Data *secstrs)
482{
483 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
484}
485
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300486static inline const char *elf_sym__name(const GElf_Sym *sym,
487 const Elf_Data *symstrs)
488{
489 return symstrs->d_buf + sym->st_name;
490}
491
492static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
493 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200494 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300495{
496 Elf_Scn *sec = NULL;
497 size_t cnt = 1;
498
499 while ((sec = elf_nextscn(elf, sec)) != NULL) {
500 char *str;
501
502 gelf_getshdr(sec, shp);
503 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
504 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200505 if (idx)
506 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300507 break;
508 }
509 ++cnt;
510 }
511
512 return sec;
513}
514
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300515#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
516 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
517 idx < nr_entries; \
518 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
519
520#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
521 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
522 idx < nr_entries; \
523 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
524
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300525/*
526 * We need to check if we have a .dynsym, so that we can handle the
527 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
528 * .dynsym or .symtab).
529 * And always look at the original dso, not at debuginfo packages, that
530 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
531 */
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200532static int dso__synthesize_plt_symbols(struct dso *self)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300533{
534 uint32_t nr_rel_entries, idx;
535 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000536 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300537 GElf_Shdr shdr_plt;
538 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300539 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300540 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300541 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
542 size_t dynsym_idx;
543 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300544 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300545 Elf *elf;
546 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300547
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300548 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300549 if (fd < 0)
550 goto out;
551
Marti Raudsepp84087122009-10-24 19:10:36 +0300552 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300553 if (elf == NULL)
554 goto out_close;
555
556 if (gelf_getehdr(elf, &ehdr) == NULL)
557 goto out_elf_end;
558
559 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
560 ".dynsym", &dynsym_idx);
561 if (scn_dynsym == NULL)
562 goto out_elf_end;
563
564 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300565 ".rela.plt", NULL);
566 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300567 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300568 ".rel.plt", NULL);
569 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300570 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300571 }
572
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300573 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300574
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300575 if (shdr_rel_plt.sh_link != dynsym_idx)
576 goto out_elf_end;
577
578 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
579 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300580
581 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200582 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300583 * and the symbols in the .dynsym they refer to.
584 */
585 reldata = elf_getdata(scn_plt_rel, NULL);
586 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300587 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300588
589 syms = elf_getdata(scn_dynsym, NULL);
590 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300591 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300592
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300593 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300594 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300595 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300596
597 symstrs = elf_getdata(scn_symstrs, NULL);
598 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300599 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300600
601 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
602 plt_offset = shdr_plt.sh_offset;
603
604 if (shdr_rel_plt.sh_type == SHT_RELA) {
605 GElf_Rela pos_mem, *pos;
606
607 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
608 nr_rel_entries) {
609 symidx = GELF_R_SYM(pos->r_info);
610 plt_offset += shdr_plt.sh_entsize;
611 gelf_getsym(syms, symidx, &sym);
612 snprintf(sympltname, sizeof(sympltname),
613 "%s@plt", elf_sym__name(&sym, symstrs));
614
615 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200616 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300617 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300618 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300619
620 dso__insert_symbol(self, f);
621 ++nr;
622 }
623 } else if (shdr_rel_plt.sh_type == SHT_REL) {
624 GElf_Rel pos_mem, *pos;
625 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
626 nr_rel_entries) {
627 symidx = GELF_R_SYM(pos->r_info);
628 plt_offset += shdr_plt.sh_entsize;
629 gelf_getsym(syms, symidx, &sym);
630 snprintf(sympltname, sizeof(sympltname),
631 "%s@plt", elf_sym__name(&sym, symstrs));
632
633 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200634 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300635 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300636 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300637
638 dso__insert_symbol(self, f);
639 ++nr;
640 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300641 }
642
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300643 err = 0;
644out_elf_end:
645 elf_end(elf);
646out_close:
647 close(fd);
648
649 if (err == 0)
650 return nr;
651out:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200652 pr_warning("%s: problems reading %s PLT info.\n",
653 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300654 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300655}
656
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300657static int dso__load_sym(struct dso *self, struct map *map, const char *name,
658 int fd, symbol_filter_t filter, int kernel,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200659 int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300660{
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300661 struct map *curr_map = map;
662 struct dso *curr_dso = self;
663 size_t dso_name_len = strlen(self->short_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200664 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300665 uint32_t nr_syms;
666 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200667 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300668 GElf_Ehdr ehdr;
669 GElf_Shdr shdr;
670 Elf_Data *syms;
671 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300672 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300673 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300674 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300675
Marti Raudsepp84087122009-10-24 19:10:36 +0300676 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300677 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200678 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300679 goto out_close;
680 }
681
682 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200683 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300684 goto out_elf_end;
685 }
686
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300687 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
688 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300689 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
690 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300691 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300692 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300693
694 syms = elf_getdata(sec, NULL);
695 if (syms == NULL)
696 goto out_elf_end;
697
698 sec = elf_getscn(elf, shdr.sh_link);
699 if (sec == NULL)
700 goto out_elf_end;
701
702 symstrs = elf_getdata(sec, NULL);
703 if (symstrs == NULL)
704 goto out_elf_end;
705
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200706 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
707 if (sec_strndx == NULL)
708 goto out_elf_end;
709
710 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500711 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200712 goto out_elf_end;
713
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300714 nr_syms = shdr.sh_size / shdr.sh_entsize;
715
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200716 memset(&sym, 0, sizeof(sym));
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200717 if (!kernel) {
718 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300719 elf_section_by_name(elf, &ehdr, &shdr,
720 ".gnu.prelink_undo",
721 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200722 } else self->adjust_symbols = 0;
723
Ingo Molnar83a09442009-08-15 12:26:57 +0200724 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300725 struct symbol *f;
Ingo Molnar83a09442009-08-15 12:26:57 +0200726 const char *elf_name;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300727 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200728 int is_label = elf_sym__is_label(&sym);
729 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300730
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200731 if (!is_label && !elf_sym__is_function(&sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300732 continue;
733
734 sec = elf_getscn(elf, sym.st_shndx);
735 if (!sec)
736 goto out_elf_end;
737
738 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200739
740 if (is_label && !elf_sec__is_text(&shdr, secstrs))
741 continue;
742
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300743 elf_name = elf_sym__name(&sym, symstrs);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200744 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200745
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300746 if (kernel || kmodule) {
747 char dso_name[PATH_MAX];
748
749 if (strcmp(section_name,
750 curr_dso->short_name + dso_name_len) == 0)
751 goto new_symbol;
752
753 if (strcmp(section_name, ".text") == 0) {
754 curr_map = map;
755 curr_dso = self;
756 goto new_symbol;
757 }
758
759 snprintf(dso_name, sizeof(dso_name),
760 "%s%s", self->short_name, section_name);
761
762 curr_map = kernel_maps__find_by_dso_name(dso_name);
763 if (curr_map == NULL) {
764 u64 start = sym.st_value;
765
766 if (kmodule)
767 start += map->start + shdr.sh_offset;
768
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200769 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300770 if (curr_dso == NULL)
771 goto out_elf_end;
772 curr_map = map__new2(start, curr_dso);
773 if (curr_map == NULL) {
774 dso__delete(curr_dso);
775 goto out_elf_end;
776 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200777 curr_map->map_ip = identity__map_ip;
778 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300779 curr_dso->origin = DSO__ORIG_KERNEL;
780 kernel_maps__insert(curr_map);
781 dsos__add(curr_dso);
782 } else
783 curr_dso = curr_map->dso;
784
785 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300786 }
787
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300788 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200789 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
790 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
791 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300792 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300793 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300794 /*
795 * We need to figure out if the object was created from C++ sources
796 * DWARF DW_compile_unit has this, but we don't always have access
797 * to it...
798 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200799 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300800 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +0200801 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300802new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200803 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300804 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300805 if (!f)
806 goto out_elf_end;
807
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300808 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200809 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300810 else {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300811 dso__insert_symbol(curr_dso, f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300812 nr++;
813 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300814 }
815
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300816 /*
817 * For misannotated, zeroed, ASM function sizes.
818 */
819 if (nr > 0)
820 dso__fixup_sym_end(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300821 err = nr;
822out_elf_end:
823 elf_end(elf);
824out_close:
825 return err;
826}
827
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200828#define BUILD_ID_SIZE 20
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300829
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200830int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300831{
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200832 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300833 GElf_Ehdr ehdr;
834 GElf_Shdr shdr;
835 Elf_Data *build_id_data;
836 Elf_Scn *sec;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300837 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300838
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200839 if (size < BUILD_ID_SIZE)
840 goto out;
841
842 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300843 if (fd < 0)
844 goto out;
845
Marti Raudsepp84087122009-10-24 19:10:36 +0300846 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300847 if (elf == NULL) {
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200848 pr_err("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300849 goto out_close;
850 }
851
852 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200853 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300854 goto out_elf_end;
855 }
856
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200857 sec = elf_section_by_name(elf, &ehdr, &shdr,
858 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300859 if (sec == NULL)
860 goto out_elf_end;
861
862 build_id_data = elf_getdata(sec, NULL);
863 if (build_id_data == NULL)
864 goto out_elf_end;
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200865 memcpy(bf, build_id_data->d_buf + 16, BUILD_ID_SIZE);
866 err = BUILD_ID_SIZE;
867out_elf_end:
868 elf_end(elf);
869out_close:
870 close(fd);
871out:
872 return err;
873}
874
875static char *dso__read_build_id(struct dso *self)
876{
877 int i, len;
878 char *build_id = NULL, *bid;
879 unsigned char rawbf[BUILD_ID_SIZE], *raw;
880
881 len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf));
882 if (len < 0)
883 goto out;
884
885 build_id = malloc(len * 2 + 1);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300886 if (build_id == NULL)
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200887 goto out;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300888 bid = build_id;
889
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200890 raw = rawbf;
891 for (i = 0; i < len; ++i) {
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300892 sprintf(bid, "%02x", *raw);
893 ++raw;
894 bid += 2;
895 }
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200896 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300897out:
898 return build_id;
899}
900
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300901char dso__symtab_origin(const struct dso *self)
902{
903 static const char origin[] = {
904 [DSO__ORIG_KERNEL] = 'k',
905 [DSO__ORIG_JAVA_JIT] = 'j',
906 [DSO__ORIG_FEDORA] = 'f',
907 [DSO__ORIG_UBUNTU] = 'u',
908 [DSO__ORIG_BUILDID] = 'b',
909 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300910 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300911 };
912
913 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
914 return '!';
915 return origin[self->origin];
916}
917
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200918int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300919{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300920 int size = PATH_MAX;
921 char *name = malloc(size), *build_id = NULL;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300922 int ret = -1;
923 int fd;
924
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200925 self->loaded = true;
926
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300927 if (!name)
928 return -1;
929
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300930 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300931
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300932 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200933 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300934 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
935 DSO__ORIG_NOT_FOUND;
936 return ret;
937 }
938
939 self->origin = DSO__ORIG_FEDORA - 1;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300940
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300941more:
942 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300943 self->origin++;
944 switch (self->origin) {
945 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300946 snprintf(name, size, "/usr/lib/debug%s.debug",
947 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300948 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300949 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300950 snprintf(name, size, "/usr/lib/debug%s",
951 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300952 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300953 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200954 build_id = dso__read_build_id(self);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300955 if (build_id != NULL) {
956 snprintf(name, size,
957 "/usr/lib/debug/.build-id/%.2s/%s.debug",
958 build_id, build_id + 2);
959 free(build_id);
960 break;
961 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300962 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300963 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300964 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300965 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300966 break;
967
968 default:
969 goto out;
970 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300971
972 fd = open(name, O_RDONLY);
973 } while (fd < 0);
974
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200975 ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300976 close(fd);
977
978 /*
979 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
980 */
981 if (!ret)
982 goto more;
983
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300984 if (ret > 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200985 int nr_plt = dso__synthesize_plt_symbols(self);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300986 if (nr_plt > 0)
987 ret += nr_plt;
988 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300989out:
990 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -0300991 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
992 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300993 return ret;
994}
995
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300996struct map *kernel_map;
997
998static void kernel_maps__insert(struct map *map)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200999{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001000 maps__insert(&kernel_maps, map);
1001}
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001002
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001003struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
1004{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001005 struct map *map = maps__find(&kernel_maps, ip);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001006
1007 if (mapp)
1008 *mapp = map;
1009
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001010 if (map) {
1011 ip = map->map_ip(map, ip);
1012 return map->dso->find_symbol(map->dso, ip);
1013 }
1014
1015 return NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001016}
1017
1018struct map *kernel_maps__find_by_dso_name(const char *name)
1019{
1020 struct rb_node *nd;
1021
1022 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1023 struct map *map = rb_entry(nd, struct map, rb_node);
1024
1025 if (map->dso && strcmp(map->dso->name, name) == 0)
1026 return map;
1027 }
1028
1029 return NULL;
1030}
1031
1032static int dso__load_module_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001033 symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001034{
1035 int err = 0, fd = open(self->long_name, O_RDONLY);
1036
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001037 self->loaded = true;
1038
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001039 if (fd < 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001040 pr_err("%s: cannot open %s\n", __func__, self->long_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001041 return err;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001042 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001043
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001044 err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001045 close(fd);
1046
1047 return err;
1048}
1049
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001050static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001051{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001052 struct dirent *dent;
1053 int nr_symbols = 0, err;
1054 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001055
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001056 if (!dir) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001057 pr_err("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001058 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001059 }
1060
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001061 while ((dent = readdir(dir)) != NULL) {
1062 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001063
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001064 if (dent->d_type == DT_DIR) {
1065 if (!strcmp(dent->d_name, ".") ||
1066 !strcmp(dent->d_name, ".."))
1067 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001068
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001069 snprintf(path, sizeof(path), "%s/%s",
1070 dirname, dent->d_name);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001071 err = dsos__load_modules_sym_dir(path, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001072 if (err < 0)
1073 goto failure;
1074 } else {
1075 char *dot = strrchr(dent->d_name, '.'),
1076 dso_name[PATH_MAX];
1077 struct map *map;
1078 struct rb_node *last;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001079
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001080 if (dot == NULL || strcmp(dot, ".ko"))
1081 continue;
1082 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1083 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001084
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001085 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001086 map = kernel_maps__find_by_dso_name(dso_name);
1087 if (map == NULL)
1088 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001089
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001090 snprintf(path, sizeof(path), "%s/%s",
1091 dirname, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001092
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001093 map->dso->long_name = strdup(path);
1094 if (map->dso->long_name == NULL)
1095 goto failure;
1096
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001097 err = dso__load_module_sym(map->dso, map, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001098 if (err < 0)
1099 goto failure;
1100 last = rb_last(&map->dso->syms);
1101 if (last) {
1102 struct symbol *sym;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001103 /*
1104 * We do this here as well, even having the
1105 * symbol size found in the symtab because
1106 * misannotated ASM symbols may have the size
1107 * set to zero.
1108 */
1109 dso__fixup_sym_end(map->dso);
1110
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001111 sym = rb_entry(last, struct symbol, rb_node);
1112 map->end = map->start + sym->end;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001113 }
1114 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001115 nr_symbols += err;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001116 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001117
1118 return nr_symbols;
1119failure:
1120 closedir(dir);
1121 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001122}
1123
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001124static int dsos__load_modules_sym(symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001125{
1126 struct utsname uts;
1127 char modules_path[PATH_MAX];
1128
1129 if (uname(&uts) < 0)
1130 return -1;
1131
1132 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1133 uts.release);
1134
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001135 return dsos__load_modules_sym_dir(modules_path, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001136}
1137
1138/*
1139 * Constructor variant for modules (where we know from /proc/modules where
1140 * they are loaded) and for vmlinux, where only after we load all the
1141 * symbols we'll know where it starts and ends.
1142 */
1143static struct map *map__new2(u64 start, struct dso *dso)
1144{
1145 struct map *self = malloc(sizeof(*self));
1146
1147 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001148 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001149 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001150 */
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001151 map__init(self, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001152 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001153
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001154 return self;
1155}
1156
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001157static int dsos__load_modules(void)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001158{
1159 char *line = NULL;
1160 size_t n;
1161 FILE *file = fopen("/proc/modules", "r");
1162 struct map *map;
1163
1164 if (file == NULL)
1165 return -1;
1166
1167 while (!feof(file)) {
1168 char name[PATH_MAX];
1169 u64 start;
1170 struct dso *dso;
1171 char *sep;
1172 int line_len;
1173
1174 line_len = getline(&line, &n, file);
1175 if (line_len < 0)
1176 break;
1177
1178 if (!line)
1179 goto out_failure;
1180
1181 line[--line_len] = '\0'; /* \n */
1182
1183 sep = strrchr(line, 'x');
1184 if (sep == NULL)
1185 continue;
1186
1187 hex2u64(sep + 1, &start);
1188
1189 sep = strchr(line, ' ');
1190 if (sep == NULL)
1191 continue;
1192
1193 *sep = '\0';
1194
1195 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001196 dso = dso__new(name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001197
1198 if (dso == NULL)
1199 goto out_delete_line;
1200
1201 map = map__new2(start, dso);
1202 if (map == NULL) {
1203 dso__delete(dso);
1204 goto out_delete_line;
1205 }
1206
1207 dso->origin = DSO__ORIG_KMODULE;
1208 kernel_maps__insert(map);
1209 dsos__add(dso);
1210 }
1211
1212 free(line);
1213 fclose(file);
1214
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001215 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001216
1217out_delete_line:
1218 free(line);
1219out_failure:
1220 return -1;
1221}
1222
1223static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001224 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001225{
1226 int err, fd = open(vmlinux, O_RDONLY);
1227
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001228 self->loaded = true;
1229
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001230 if (fd < 0)
1231 return -1;
1232
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001233 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001234
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001235 close(fd);
1236
1237 return err;
1238}
1239
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001240int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter,
1241 int use_modules)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001242{
1243 int err = -1;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001244 struct dso *dso = dso__new(vmlinux);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001245
1246 if (dso == NULL)
1247 return -1;
1248
1249 dso->short_name = "[kernel]";
1250 kernel_map = map__new2(0, dso);
1251 if (kernel_map == NULL)
1252 goto out_delete_dso;
1253
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001254 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001255
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001256 if (use_modules && dsos__load_modules() < 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001257 pr_warning("Failed to load list of modules in use! "
1258 "Continuing...\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001259 use_modules = 0;
1260 }
1261
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001262 if (vmlinux) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001263 err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter);
Mike Galbraith508c4d02009-09-23 11:20:58 +02001264 if (err > 0 && use_modules) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001265 int syms = dsos__load_modules_sym(filter);
Mike Galbraith508c4d02009-09-23 11:20:58 +02001266
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001267 if (syms < 0)
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001268 pr_warning("Failed to read module symbols!"
1269 " Continuing...\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001270 else
1271 err += syms;
Mike Galbraith508c4d02009-09-23 11:20:58 +02001272 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001273 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001274
Mike Galbraith9974f492009-07-02 08:05:58 +02001275 if (err <= 0)
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001276 err = kernel_maps__load_kallsyms(filter, use_modules);
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001277
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001278 if (err > 0) {
1279 struct rb_node *node = rb_first(&dso->syms);
1280 struct symbol *sym = rb_entry(node, struct symbol, rb_node);
1281
1282 kernel_map->start = sym->start;
1283 node = rb_last(&dso->syms);
1284 sym = rb_entry(node, struct symbol, rb_node);
1285 kernel_map->end = sym->end;
1286
1287 dso->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001288 kernel_maps__insert(kernel_map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001289 /*
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001290 * Now that we have all sorted out, just set the ->end of all
1291 * maps:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001292 */
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001293 kernel_maps__fixup_end();
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001294 dsos__add(dso);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001295
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001296 if (verbose)
1297 kernel_maps__fprintf(stderr);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001298 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001299
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001300 return err;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001301
1302out_delete_dso:
1303 dso__delete(dso);
1304 return -1;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001305}
1306
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001307LIST_HEAD(dsos);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001308struct dso *vdso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001309
Ingo Molnar83a09442009-08-15 12:26:57 +02001310const char *vmlinux_name = "vmlinux";
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001311int modules;
1312
1313static void dsos__add(struct dso *dso)
1314{
1315 list_add_tail(&dso->node, &dsos);
1316}
1317
1318static struct dso *dsos__find(const char *name)
1319{
1320 struct dso *pos;
1321
1322 list_for_each_entry(pos, &dsos, node)
1323 if (strcmp(pos->name, name) == 0)
1324 return pos;
1325 return NULL;
1326}
1327
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001328struct dso *dsos__findnew(const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001329{
1330 struct dso *dso = dsos__find(name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001331
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001332 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001333 dso = dso__new(name);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001334 if (dso != NULL)
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001335 dsos__add(dso);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001336 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001337
1338 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001339}
1340
1341void dsos__fprintf(FILE *fp)
1342{
1343 struct dso *pos;
1344
1345 list_for_each_entry(pos, &dsos, node)
1346 dso__fprintf(pos, fp);
1347}
1348
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001349int load_kernel(symbol_filter_t filter)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001350{
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001351 if (dsos__load_kernel(vmlinux_name, filter, modules) <= 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001352 return -1;
1353
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001354 vdso = dso__new("[vdso]");
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001355 if (!vdso)
1356 return -1;
1357
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001358 dsos__add(vdso);
1359
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001360 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001361}
1362
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001363void symbol__init(unsigned int priv_size)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001364{
1365 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001366 symbol__priv_size = priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001367}