blob: 13677b5dbe5ec365738993e90f1d5178bda6ad69 [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 Melo439d4732009-10-02 03:29:58 -030029
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030030static struct rb_root kernel_maps;
31
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030032static void dso__fixup_sym_end(struct dso *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030033{
34 struct rb_node *nd, *prevnd = rb_first(&self->syms);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030035 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030036
37 if (prevnd == NULL)
38 return;
39
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030040 curr = rb_entry(prevnd, struct symbol, rb_node);
41
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030042 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030043 prev = curr;
44 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030045
46 if (prev->end == prev->start)
47 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030048 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030049
50 /* Last entry */
51 if (curr->end == curr->start)
52 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030053}
54
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030055static void kernel_maps__fixup_end(void)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030056{
57 struct map *prev, *curr;
58 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
59
60 if (prevnd == NULL)
61 return;
62
63 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030064
65 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
66 prev = curr;
67 curr = rb_entry(nd, struct map, rb_node);
68 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030069 }
70
71 nd = rb_last(&curr->dso->syms);
72 if (nd) {
73 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
74 curr->end = sym->end;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030075 }
76}
77
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030078static struct symbol *symbol__new(u64 start, u64 len, const char *name,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -020079 unsigned int priv_size)
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;
Ingo Molnar0b73da32009-06-06 15:48:52 +020082 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030083
Ingo Molnar0b73da32009-06-06 15:48:52 +020084 if (!self)
85 return NULL;
86
Ingo Molnar0b73da32009-06-06 15:48:52 +020087 if (priv_size) {
88 memset(self, 0, priv_size);
89 self = ((void *)self) + 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 Melo0085c9542009-05-28 14:55:13 -0300101static void symbol__delete(struct symbol *self, unsigned int priv_size)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300102{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300103 free(((void *)self) - 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 Melo0085c9542009-05-28 14:55:13 -0300112struct dso *dso__new(const char *name, unsigned int sym_priv_size)
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;
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300121 self->sym_priv_size = sym_priv_size;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200122 self->find_symbol = dso__find_symbol;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300123 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300124 self->origin = DSO__ORIG_NOT_FOUND;
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 Melo0085c9542009-05-28 14:55:13 -0300139 symbol__delete(pos, self->sym_priv_size);
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 */
253 sym = symbol__new(start, 0, symbol_name,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200254 kernel_map->dso->sym_priv_size);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300255
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300256 if (sym == NULL)
257 goto out_delete_line;
258
259 dso__insert_symbol(kernel_map->dso, sym);
260 }
261
262 free(line);
263 fclose(file);
264
265 return 0;
266
267out_delete_line:
268 free(line);
269out_failure:
270 return -1;
271}
272
273/*
274 * Split the symbols into maps, making sure there are no overlaps, i.e. the
275 * kernel range is broken in several maps, named [kernel].N, as we don't have
276 * the original ELF section names vmlinux have.
277 */
278static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
279{
280 struct map *map = kernel_map;
281 struct symbol *pos;
282 int count = 0;
283 struct rb_node *next = rb_first(&kernel_map->dso->syms);
284 int kernel_range = 0;
285
286 while (next) {
287 char *module;
288
289 pos = rb_entry(next, struct symbol, rb_node);
290 next = rb_next(&pos->rb_node);
291
292 module = strchr(pos->name, '\t');
293 if (module) {
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300294 if (!use_modules)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300295 goto delete_symbol;
296
297 *module++ = '\0';
298
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300299 if (strcmp(map->dso->name, module)) {
300 map = kernel_maps__find_by_dso_name(module);
301 if (!map) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200302 pr_err("/proc/{kallsyms,modules} "
303 "inconsistency!\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300304 return -1;
305 }
306 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300307 /*
308 * So that we look just like we get from .ko files,
309 * i.e. not prelinked, relative to map->start.
310 */
311 pos->start = map->map_ip(map, pos->start);
312 pos->end = map->map_ip(map, pos->end);
313 } else if (map != kernel_map) {
314 char dso_name[PATH_MAX];
315 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300316
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300317 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
318 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300319
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300320 dso = dso__new(dso_name,
321 kernel_map->dso->sym_priv_size);
322 if (dso == NULL)
323 return -1;
324
325 map = map__new2(pos->start, dso);
326 if (map == NULL) {
327 dso__delete(dso);
328 return -1;
329 }
330
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200331 map->map_ip = map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300332 kernel_maps__insert(map);
333 ++kernel_range;
334 }
335
336 if (filter && filter(map, pos)) {
337delete_symbol:
338 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
339 symbol__delete(pos, kernel_map->dso->sym_priv_size);
340 } else {
341 if (map != kernel_map) {
342 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
343 dso__insert_symbol(map->dso, pos);
344 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200345 count++;
346 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300347 }
348
Mike Galbraith9974f492009-07-02 08:05:58 +0200349 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300350}
351
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300352
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200353static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300354{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200355 if (kernel_maps__load_all_kallsyms())
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300356 return -1;
357
358 dso__fixup_sym_end(kernel_map->dso);
359
360 return kernel_maps__split_kallsyms(filter, use_modules);
361}
362
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200363static size_t kernel_maps__fprintf(FILE *fp)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300364{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200365 size_t printed = fprintf(fp, "Kernel maps:\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300366 struct rb_node *nd;
367
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300368 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
369 struct map *pos = rb_entry(nd, struct map, rb_node);
370
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300371 printed += fprintf(fp, "Map:");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300372 printed += map__fprintf(pos, fp);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200373 if (verbose > 1) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300374 printed += dso__fprintf(pos->dso, fp);
375 printed += fprintf(fp, "--\n");
376 }
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300377 }
378
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200379 return printed + fprintf(fp, "END kernel maps\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300380}
381
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300382static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200383 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300384{
385 char *line = NULL;
386 size_t n;
387 FILE *file;
388 int nr_syms = 0;
389
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300390 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300391 if (file == NULL)
392 goto out_failure;
393
394 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000395 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300396 struct symbol *sym;
397 int line_len, len;
398
399 line_len = getline(&line, &n, file);
400 if (line_len < 0)
401 break;
402
403 if (!line)
404 goto out_failure;
405
406 line[--line_len] = '\0'; /* \n */
407
408 len = hex2u64(line, &start);
409
410 len++;
411 if (len + 2 >= line_len)
412 continue;
413
414 len += hex2u64(line + len, &size);
415
416 len++;
417 if (len + 2 >= line_len)
418 continue;
419
420 sym = symbol__new(start, size, line + len,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200421 self->sym_priv_size);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300422
423 if (sym == NULL)
424 goto out_delete_line;
425
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300426 if (filter && filter(map, sym))
Pekka Enberg80d496b2009-06-08 21:12:48 +0300427 symbol__delete(sym, self->sym_priv_size);
428 else {
429 dso__insert_symbol(self, sym);
430 nr_syms++;
431 }
432 }
433
434 free(line);
435 fclose(file);
436
437 return nr_syms;
438
439out_delete_line:
440 free(line);
441out_failure:
442 return -1;
443}
444
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300445/**
446 * elf_symtab__for_each_symbol - iterate thru all the symbols
447 *
448 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200449 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300450 * @sym: GElf_Sym iterator
451 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200452#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
453 for (idx = 0, gelf_getsym(syms, idx, &sym);\
454 idx < nr_syms; \
455 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300456
457static inline uint8_t elf_sym__type(const GElf_Sym *sym)
458{
459 return GELF_ST_TYPE(sym->st_info);
460}
461
462static inline int elf_sym__is_function(const GElf_Sym *sym)
463{
464 return elf_sym__type(sym) == STT_FUNC &&
465 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300466 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300467}
468
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200469static inline int elf_sym__is_label(const GElf_Sym *sym)
470{
471 return elf_sym__type(sym) == STT_NOTYPE &&
472 sym->st_name != 0 &&
473 sym->st_shndx != SHN_UNDEF &&
474 sym->st_shndx != SHN_ABS;
475}
476
477static inline const char *elf_sec__name(const GElf_Shdr *shdr,
478 const Elf_Data *secstrs)
479{
480 return secstrs->d_buf + shdr->sh_name;
481}
482
483static inline int elf_sec__is_text(const GElf_Shdr *shdr,
484 const Elf_Data *secstrs)
485{
486 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
487}
488
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300489static inline const char *elf_sym__name(const GElf_Sym *sym,
490 const Elf_Data *symstrs)
491{
492 return symstrs->d_buf + sym->st_name;
493}
494
495static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
496 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200497 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300498{
499 Elf_Scn *sec = NULL;
500 size_t cnt = 1;
501
502 while ((sec = elf_nextscn(elf, sec)) != NULL) {
503 char *str;
504
505 gelf_getshdr(sec, shp);
506 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
507 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200508 if (idx)
509 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300510 break;
511 }
512 ++cnt;
513 }
514
515 return sec;
516}
517
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300518#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
519 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
520 idx < nr_entries; \
521 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
522
523#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
524 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
525 idx < nr_entries; \
526 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
527
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300528/*
529 * We need to check if we have a .dynsym, so that we can handle the
530 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
531 * .dynsym or .symtab).
532 * And always look at the original dso, not at debuginfo packages, that
533 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
534 */
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200535static int dso__synthesize_plt_symbols(struct dso *self)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300536{
537 uint32_t nr_rel_entries, idx;
538 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000539 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300540 GElf_Shdr shdr_plt;
541 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300542 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300543 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300544 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
545 size_t dynsym_idx;
546 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300547 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300548 Elf *elf;
549 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300550
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300551 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300552 if (fd < 0)
553 goto out;
554
555 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
556 if (elf == NULL)
557 goto out_close;
558
559 if (gelf_getehdr(elf, &ehdr) == NULL)
560 goto out_elf_end;
561
562 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
563 ".dynsym", &dynsym_idx);
564 if (scn_dynsym == NULL)
565 goto out_elf_end;
566
567 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300568 ".rela.plt", NULL);
569 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300570 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300571 ".rel.plt", NULL);
572 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300573 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300574 }
575
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300576 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300577
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300578 if (shdr_rel_plt.sh_link != dynsym_idx)
579 goto out_elf_end;
580
581 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
582 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300583
584 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200585 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300586 * and the symbols in the .dynsym they refer to.
587 */
588 reldata = elf_getdata(scn_plt_rel, NULL);
589 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300590 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300591
592 syms = elf_getdata(scn_dynsym, NULL);
593 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300594 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300595
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300596 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300597 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300598 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300599
600 symstrs = elf_getdata(scn_symstrs, NULL);
601 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300602 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300603
604 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
605 plt_offset = shdr_plt.sh_offset;
606
607 if (shdr_rel_plt.sh_type == SHT_RELA) {
608 GElf_Rela pos_mem, *pos;
609
610 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
611 nr_rel_entries) {
612 symidx = GELF_R_SYM(pos->r_info);
613 plt_offset += shdr_plt.sh_entsize;
614 gelf_getsym(syms, symidx, &sym);
615 snprintf(sympltname, sizeof(sympltname),
616 "%s@plt", elf_sym__name(&sym, symstrs));
617
618 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200619 sympltname, self->sym_priv_size);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300620 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300621 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300622
623 dso__insert_symbol(self, f);
624 ++nr;
625 }
626 } else if (shdr_rel_plt.sh_type == SHT_REL) {
627 GElf_Rel pos_mem, *pos;
628 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
629 nr_rel_entries) {
630 symidx = GELF_R_SYM(pos->r_info);
631 plt_offset += shdr_plt.sh_entsize;
632 gelf_getsym(syms, symidx, &sym);
633 snprintf(sympltname, sizeof(sympltname),
634 "%s@plt", elf_sym__name(&sym, symstrs));
635
636 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200637 sympltname, self->sym_priv_size);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300638 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300639 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300640
641 dso__insert_symbol(self, f);
642 ++nr;
643 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300644 }
645
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300646 err = 0;
647out_elf_end:
648 elf_end(elf);
649out_close:
650 close(fd);
651
652 if (err == 0)
653 return nr;
654out:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200655 pr_warning("%s: problems reading %s PLT info.\n",
656 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300657 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300658}
659
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300660static int dso__load_sym(struct dso *self, struct map *map, const char *name,
661 int fd, symbol_filter_t filter, int kernel,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200662 int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300663{
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300664 struct map *curr_map = map;
665 struct dso *curr_dso = self;
666 size_t dso_name_len = strlen(self->short_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200667 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300668 uint32_t nr_syms;
669 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200670 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300671 GElf_Ehdr ehdr;
672 GElf_Shdr shdr;
673 Elf_Data *syms;
674 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300675 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300676 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300677 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300678
679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
680 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200681 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300682 goto out_close;
683 }
684
685 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200686 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300687 goto out_elf_end;
688 }
689
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300690 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
691 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
693 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300694 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300695 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300696
697 syms = elf_getdata(sec, NULL);
698 if (syms == NULL)
699 goto out_elf_end;
700
701 sec = elf_getscn(elf, shdr.sh_link);
702 if (sec == NULL)
703 goto out_elf_end;
704
705 symstrs = elf_getdata(sec, NULL);
706 if (symstrs == NULL)
707 goto out_elf_end;
708
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200709 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
710 if (sec_strndx == NULL)
711 goto out_elf_end;
712
713 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500714 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200715 goto out_elf_end;
716
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300717 nr_syms = shdr.sh_size / shdr.sh_entsize;
718
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200719 memset(&sym, 0, sizeof(sym));
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200720 if (!kernel) {
721 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300722 elf_section_by_name(elf, &ehdr, &shdr,
723 ".gnu.prelink_undo",
724 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200725 } else self->adjust_symbols = 0;
726
Ingo Molnar83a09442009-08-15 12:26:57 +0200727 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300728 struct symbol *f;
Ingo Molnar83a09442009-08-15 12:26:57 +0200729 const char *elf_name;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300730 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200731 int is_label = elf_sym__is_label(&sym);
732 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300733
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200734 if (!is_label && !elf_sym__is_function(&sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300735 continue;
736
737 sec = elf_getscn(elf, sym.st_shndx);
738 if (!sec)
739 goto out_elf_end;
740
741 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200742
743 if (is_label && !elf_sec__is_text(&shdr, secstrs))
744 continue;
745
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300746 elf_name = elf_sym__name(&sym, symstrs);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200747 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200748
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300749 if (kernel || kmodule) {
750 char dso_name[PATH_MAX];
751
752 if (strcmp(section_name,
753 curr_dso->short_name + dso_name_len) == 0)
754 goto new_symbol;
755
756 if (strcmp(section_name, ".text") == 0) {
757 curr_map = map;
758 curr_dso = self;
759 goto new_symbol;
760 }
761
762 snprintf(dso_name, sizeof(dso_name),
763 "%s%s", self->short_name, section_name);
764
765 curr_map = kernel_maps__find_by_dso_name(dso_name);
766 if (curr_map == NULL) {
767 u64 start = sym.st_value;
768
769 if (kmodule)
770 start += map->start + shdr.sh_offset;
771
772 curr_dso = dso__new(dso_name, self->sym_priv_size);
773 if (curr_dso == NULL)
774 goto out_elf_end;
775 curr_map = map__new2(start, curr_dso);
776 if (curr_map == NULL) {
777 dso__delete(curr_dso);
778 goto out_elf_end;
779 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200780 curr_map->map_ip = identity__map_ip;
781 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300782 curr_dso->origin = DSO__ORIG_KERNEL;
783 kernel_maps__insert(curr_map);
784 dsos__add(curr_dso);
785 } else
786 curr_dso = curr_map->dso;
787
788 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300789 }
790
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300791 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200792 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
793 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
794 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300795 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300796 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300797 /*
798 * We need to figure out if the object was created from C++ sources
799 * DWARF DW_compile_unit has this, but we don't always have access
800 * to it...
801 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200802 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300803 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +0200804 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300805new_symbol:
806 f = symbol__new(sym.st_value, sym.st_size, elf_name,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200807 curr_dso->sym_priv_size);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300808 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300809 if (!f)
810 goto out_elf_end;
811
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300812 if (filter && filter(curr_map, f))
813 symbol__delete(f, curr_dso->sym_priv_size);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300814 else {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300815 dso__insert_symbol(curr_dso, f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300816 nr++;
817 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300818 }
819
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300820 /*
821 * For misannotated, zeroed, ASM function sizes.
822 */
823 if (nr > 0)
824 dso__fixup_sym_end(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300825 err = nr;
826out_elf_end:
827 elf_end(elf);
828out_close:
829 return err;
830}
831
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300832#define BUILD_ID_SIZE 128
833
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200834static char *dso__read_build_id(struct dso *self)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300835{
836 int i;
837 GElf_Ehdr ehdr;
838 GElf_Shdr shdr;
839 Elf_Data *build_id_data;
840 Elf_Scn *sec;
841 char *build_id = NULL, *bid;
842 unsigned char *raw;
843 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300844 int fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300845
846 if (fd < 0)
847 goto out;
848
849 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
850 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200851 pr_err("%s: cannot read %s ELF file.\n", __func__,
852 self->long_name);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300853 goto out_close;
854 }
855
856 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200857 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300858 goto out_elf_end;
859 }
860
861 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
862 if (sec == NULL)
863 goto out_elf_end;
864
865 build_id_data = elf_getdata(sec, NULL);
866 if (build_id_data == NULL)
867 goto out_elf_end;
868 build_id = malloc(BUILD_ID_SIZE);
869 if (build_id == NULL)
870 goto out_elf_end;
871 raw = build_id_data->d_buf + 16;
872 bid = build_id;
873
874 for (i = 0; i < 20; ++i) {
875 sprintf(bid, "%02x", *raw);
876 ++raw;
877 bid += 2;
878 }
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200879 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300880out_elf_end:
881 elf_end(elf);
882out_close:
883 close(fd);
884out:
885 return build_id;
886}
887
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300888char dso__symtab_origin(const struct dso *self)
889{
890 static const char origin[] = {
891 [DSO__ORIG_KERNEL] = 'k',
892 [DSO__ORIG_JAVA_JIT] = 'j',
893 [DSO__ORIG_FEDORA] = 'f',
894 [DSO__ORIG_UBUNTU] = 'u',
895 [DSO__ORIG_BUILDID] = 'b',
896 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300897 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300898 };
899
900 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
901 return '!';
902 return origin[self->origin];
903}
904
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200905int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300906{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300907 int size = PATH_MAX;
908 char *name = malloc(size), *build_id = NULL;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300909 int ret = -1;
910 int fd;
911
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200912 self->loaded = true;
913
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300914 if (!name)
915 return -1;
916
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300917 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300918
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300919 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200920 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300921 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
922 DSO__ORIG_NOT_FOUND;
923 return ret;
924 }
925
926 self->origin = DSO__ORIG_FEDORA - 1;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300927
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300928more:
929 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300930 self->origin++;
931 switch (self->origin) {
932 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300933 snprintf(name, size, "/usr/lib/debug%s.debug",
934 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300935 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300936 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300937 snprintf(name, size, "/usr/lib/debug%s",
938 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300939 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300940 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200941 build_id = dso__read_build_id(self);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300942 if (build_id != NULL) {
943 snprintf(name, size,
944 "/usr/lib/debug/.build-id/%.2s/%s.debug",
945 build_id, build_id + 2);
946 free(build_id);
947 break;
948 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300949 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300950 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300951 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300952 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300953 break;
954
955 default:
956 goto out;
957 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300958
959 fd = open(name, O_RDONLY);
960 } while (fd < 0);
961
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200962 ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300963 close(fd);
964
965 /*
966 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
967 */
968 if (!ret)
969 goto more;
970
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300971 if (ret > 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200972 int nr_plt = dso__synthesize_plt_symbols(self);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300973 if (nr_plt > 0)
974 ret += nr_plt;
975 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300976out:
977 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -0300978 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
979 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300980 return ret;
981}
982
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300983struct map *kernel_map;
984
985static void kernel_maps__insert(struct map *map)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200986{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300987 maps__insert(&kernel_maps, map);
988}
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200989
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300990struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
991{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300992 struct map *map = maps__find(&kernel_maps, ip);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300993
994 if (mapp)
995 *mapp = map;
996
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300997 if (map) {
998 ip = map->map_ip(map, ip);
999 return map->dso->find_symbol(map->dso, ip);
1000 }
1001
1002 return NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001003}
1004
1005struct map *kernel_maps__find_by_dso_name(const char *name)
1006{
1007 struct rb_node *nd;
1008
1009 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1010 struct map *map = rb_entry(nd, struct map, rb_node);
1011
1012 if (map->dso && strcmp(map->dso->name, name) == 0)
1013 return map;
1014 }
1015
1016 return NULL;
1017}
1018
1019static int dso__load_module_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001020 symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001021{
1022 int err = 0, fd = open(self->long_name, O_RDONLY);
1023
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001024 self->loaded = true;
1025
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001026 if (fd < 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001027 pr_err("%s: cannot open %s\n", __func__, self->long_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001028 return err;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001029 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001030
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001031 err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001032 close(fd);
1033
1034 return err;
1035}
1036
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001037static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001038{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001039 struct dirent *dent;
1040 int nr_symbols = 0, err;
1041 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001042
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001043 if (!dir) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001044 pr_err("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001045 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001046 }
1047
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001048 while ((dent = readdir(dir)) != NULL) {
1049 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001050
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001051 if (dent->d_type == DT_DIR) {
1052 if (!strcmp(dent->d_name, ".") ||
1053 !strcmp(dent->d_name, ".."))
1054 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001055
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001056 snprintf(path, sizeof(path), "%s/%s",
1057 dirname, dent->d_name);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001058 err = dsos__load_modules_sym_dir(path, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001059 if (err < 0)
1060 goto failure;
1061 } else {
1062 char *dot = strrchr(dent->d_name, '.'),
1063 dso_name[PATH_MAX];
1064 struct map *map;
1065 struct rb_node *last;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001066
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001067 if (dot == NULL || strcmp(dot, ".ko"))
1068 continue;
1069 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1070 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001071
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001072 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001073 map = kernel_maps__find_by_dso_name(dso_name);
1074 if (map == NULL)
1075 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001076
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001077 snprintf(path, sizeof(path), "%s/%s",
1078 dirname, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001079
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001080 map->dso->long_name = strdup(path);
1081 if (map->dso->long_name == NULL)
1082 goto failure;
1083
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001084 err = dso__load_module_sym(map->dso, map, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001085 if (err < 0)
1086 goto failure;
1087 last = rb_last(&map->dso->syms);
1088 if (last) {
1089 struct symbol *sym;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001090 /*
1091 * We do this here as well, even having the
1092 * symbol size found in the symtab because
1093 * misannotated ASM symbols may have the size
1094 * set to zero.
1095 */
1096 dso__fixup_sym_end(map->dso);
1097
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001098 sym = rb_entry(last, struct symbol, rb_node);
1099 map->end = map->start + sym->end;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001100 }
1101 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001102 nr_symbols += err;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001103 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001104
1105 return nr_symbols;
1106failure:
1107 closedir(dir);
1108 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001109}
1110
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001111static int dsos__load_modules_sym(symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001112{
1113 struct utsname uts;
1114 char modules_path[PATH_MAX];
1115
1116 if (uname(&uts) < 0)
1117 return -1;
1118
1119 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1120 uts.release);
1121
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001122 return dsos__load_modules_sym_dir(modules_path, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001123}
1124
1125/*
1126 * Constructor variant for modules (where we know from /proc/modules where
1127 * they are loaded) and for vmlinux, where only after we load all the
1128 * symbols we'll know where it starts and ends.
1129 */
1130static struct map *map__new2(u64 start, struct dso *dso)
1131{
1132 struct map *self = malloc(sizeof(*self));
1133
1134 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001135 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001136 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001137 */
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001138 map__init(self, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001139 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001140
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001141 return self;
1142}
1143
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001144static int dsos__load_modules(unsigned int sym_priv_size)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001145{
1146 char *line = NULL;
1147 size_t n;
1148 FILE *file = fopen("/proc/modules", "r");
1149 struct map *map;
1150
1151 if (file == NULL)
1152 return -1;
1153
1154 while (!feof(file)) {
1155 char name[PATH_MAX];
1156 u64 start;
1157 struct dso *dso;
1158 char *sep;
1159 int line_len;
1160
1161 line_len = getline(&line, &n, file);
1162 if (line_len < 0)
1163 break;
1164
1165 if (!line)
1166 goto out_failure;
1167
1168 line[--line_len] = '\0'; /* \n */
1169
1170 sep = strrchr(line, 'x');
1171 if (sep == NULL)
1172 continue;
1173
1174 hex2u64(sep + 1, &start);
1175
1176 sep = strchr(line, ' ');
1177 if (sep == NULL)
1178 continue;
1179
1180 *sep = '\0';
1181
1182 snprintf(name, sizeof(name), "[%s]", line);
1183 dso = dso__new(name, sym_priv_size);
1184
1185 if (dso == NULL)
1186 goto out_delete_line;
1187
1188 map = map__new2(start, dso);
1189 if (map == NULL) {
1190 dso__delete(dso);
1191 goto out_delete_line;
1192 }
1193
1194 dso->origin = DSO__ORIG_KMODULE;
1195 kernel_maps__insert(map);
1196 dsos__add(dso);
1197 }
1198
1199 free(line);
1200 fclose(file);
1201
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001202 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001203
1204out_delete_line:
1205 free(line);
1206out_failure:
1207 return -1;
1208}
1209
1210static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001211 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001212{
1213 int err, fd = open(vmlinux, O_RDONLY);
1214
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001215 self->loaded = true;
1216
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001217 if (fd < 0)
1218 return -1;
1219
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001220 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001221
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001222 close(fd);
1223
1224 return err;
1225}
1226
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001227int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001228 symbol_filter_t filter, int use_modules)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001229{
1230 int err = -1;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001231 struct dso *dso = dso__new(vmlinux, sym_priv_size);
1232
1233 if (dso == NULL)
1234 return -1;
1235
1236 dso->short_name = "[kernel]";
1237 kernel_map = map__new2(0, dso);
1238 if (kernel_map == NULL)
1239 goto out_delete_dso;
1240
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001241 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001242
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001243 if (use_modules && dsos__load_modules(sym_priv_size) < 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001244 pr_warning("Failed to load list of modules in use! "
1245 "Continuing...\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001246 use_modules = 0;
1247 }
1248
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001249 if (vmlinux) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001250 err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter);
Mike Galbraith508c4d02009-09-23 11:20:58 +02001251 if (err > 0 && use_modules) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001252 int syms = dsos__load_modules_sym(filter);
Mike Galbraith508c4d02009-09-23 11:20:58 +02001253
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001254 if (syms < 0)
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001255 pr_warning("Failed to read module symbols!"
1256 " Continuing...\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001257 else
1258 err += syms;
Mike Galbraith508c4d02009-09-23 11:20:58 +02001259 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001260 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001261
Mike Galbraith9974f492009-07-02 08:05:58 +02001262 if (err <= 0)
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001263 err = kernel_maps__load_kallsyms(filter, use_modules);
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001264
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001265 if (err > 0) {
1266 struct rb_node *node = rb_first(&dso->syms);
1267 struct symbol *sym = rb_entry(node, struct symbol, rb_node);
1268
1269 kernel_map->start = sym->start;
1270 node = rb_last(&dso->syms);
1271 sym = rb_entry(node, struct symbol, rb_node);
1272 kernel_map->end = sym->end;
1273
1274 dso->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001275 kernel_maps__insert(kernel_map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001276 /*
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001277 * Now that we have all sorted out, just set the ->end of all
1278 * maps:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001279 */
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001280 kernel_maps__fixup_end();
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001281 dsos__add(dso);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001282
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001283 if (verbose)
1284 kernel_maps__fprintf(stderr);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001285 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001286
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001287 return err;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001288
1289out_delete_dso:
1290 dso__delete(dso);
1291 return -1;
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001292}
1293
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001294LIST_HEAD(dsos);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001295struct dso *vdso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001296
Ingo Molnar83a09442009-08-15 12:26:57 +02001297const char *vmlinux_name = "vmlinux";
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001298int modules;
1299
1300static void dsos__add(struct dso *dso)
1301{
1302 list_add_tail(&dso->node, &dsos);
1303}
1304
1305static struct dso *dsos__find(const char *name)
1306{
1307 struct dso *pos;
1308
1309 list_for_each_entry(pos, &dsos, node)
1310 if (strcmp(pos->name, name) == 0)
1311 return pos;
1312 return NULL;
1313}
1314
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001315struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001316{
1317 struct dso *dso = dsos__find(name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001318
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001319 if (!dso) {
1320 dso = dso__new(name, sym_priv_size);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001321 if (dso != NULL)
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001322 dsos__add(dso);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001323 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001324
1325 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001326}
1327
1328void dsos__fprintf(FILE *fp)
1329{
1330 struct dso *pos;
1331
1332 list_for_each_entry(pos, &dsos, node)
1333 dso__fprintf(pos, fp);
1334}
1335
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001336int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001337{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001338 if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter,
1339 modules) <= 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001340 return -1;
1341
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001342 vdso = dso__new("[vdso]", 0);
1343 if (!vdso)
1344 return -1;
1345
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001346 dsos__add(vdso);
1347
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001348 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001349}
1350
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001351void symbol__init(void)
1352{
1353 elf_version(EV_CURRENT);
1354}