blob: 48f87f065a2ef6586386a07efdb1cd2c3312d547 [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 Melof1617b42009-11-18 20:20:52 -020012#include <limits.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030013#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020014
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030015enum dso_origin {
16 DSO__ORIG_KERNEL = 0,
17 DSO__ORIG_JAVA_JIT,
18 DSO__ORIG_FEDORA,
19 DSO__ORIG_UBUNTU,
20 DSO__ORIG_BUILDID,
21 DSO__ORIG_DSO,
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030022 DSO__ORIG_KMODULE,
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030023 DSO__ORIG_NOT_FOUND,
24};
25
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030026static void dsos__add(struct dso *dso);
27static struct dso *dsos__find(const char *name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030028static struct map *map__new2(u64 start, struct dso *dso);
29static void kernel_maps__insert(struct map *map);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020030static int dso__load_kernel_sym(struct dso *self, struct map *map,
31 symbol_filter_t filter);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020032unsigned int symbol__priv_size;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030033
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030034static struct rb_root kernel_maps;
35
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030036static void dso__fixup_sym_end(struct dso *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030037{
38 struct rb_node *nd, *prevnd = rb_first(&self->syms);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030039 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030040
41 if (prevnd == NULL)
42 return;
43
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030044 curr = rb_entry(prevnd, struct symbol, rb_node);
45
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030046 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030047 prev = curr;
48 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030049
50 if (prev->end == prev->start)
51 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030052 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030053
54 /* Last entry */
55 if (curr->end == curr->start)
56 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030057}
58
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030059static void kernel_maps__fixup_end(void)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030060{
61 struct map *prev, *curr;
62 struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
63
64 if (prevnd == NULL)
65 return;
66
67 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030068
69 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
70 prev = curr;
71 curr = rb_entry(nd, struct map, rb_node);
72 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030073 }
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030074}
75
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020076static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030077{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030078 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020079 struct symbol *self = calloc(1, (symbol__priv_size +
80 sizeof(*self) + namelen));
Ingo Molnar0b73da32009-06-06 15:48:52 +020081 if (!self)
82 return NULL;
83
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020084 if (symbol__priv_size) {
85 memset(self, 0, symbol__priv_size);
86 self = ((void *)self) + symbol__priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030087 }
Ingo Molnar0b73da32009-06-06 15:48:52 +020088 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +020089 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020090
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -020091 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -020092
Ingo Molnar0b73da32009-06-06 15:48:52 +020093 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030094
95 return self;
96}
97
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020098static void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030099{
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200100 free(((void *)self) - symbol__priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300101}
102
103static size_t symbol__fprintf(struct symbol *self, FILE *fp)
104{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300105 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300106 self->start, self->end, self->name);
107}
108
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200109static void dso__set_long_name(struct dso *self, char *name)
110{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200111 if (name == NULL)
112 return;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200113 self->long_name = name;
114 self->long_name_len = strlen(name);
115}
116
117static void dso__set_basename(struct dso *self)
118{
119 self->short_name = basename(self->long_name);
120}
121
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200122struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300123{
124 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
125
126 if (self != NULL) {
127 strcpy(self->name, name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200128 dso__set_long_name(self, self->name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300129 self->short_name = self->name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300130 self->syms = RB_ROOT;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200131 self->find_symbol = dso__find_symbol;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300132 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300133 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200134 self->loaded = 0;
135 self->has_build_id = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300136 }
137
138 return self;
139}
140
141static void dso__delete_symbols(struct dso *self)
142{
143 struct symbol *pos;
144 struct rb_node *next = rb_first(&self->syms);
145
146 while (next) {
147 pos = rb_entry(next, struct symbol, rb_node);
148 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Meloc8c96522009-06-01 17:50:57 -0300149 rb_erase(&pos->rb_node, &self->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200150 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300151 }
152}
153
154void dso__delete(struct dso *self)
155{
156 dso__delete_symbols(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300157 if (self->long_name != self->name)
158 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300159 free(self);
160}
161
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200162void dso__set_build_id(struct dso *self, void *build_id)
163{
164 memcpy(self->build_id, build_id, sizeof(self->build_id));
165 self->has_build_id = 1;
166}
167
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300168static void dso__insert_symbol(struct dso *self, struct symbol *sym)
169{
170 struct rb_node **p = &self->syms.rb_node;
171 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000172 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300173 struct symbol *s;
174
175 while (*p != NULL) {
176 parent = *p;
177 s = rb_entry(parent, struct symbol, rb_node);
178 if (ip < s->start)
179 p = &(*p)->rb_left;
180 else
181 p = &(*p)->rb_right;
182 }
183 rb_link_node(&sym->rb_node, parent, p);
184 rb_insert_color(&sym->rb_node, &self->syms);
185}
186
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000187struct symbol *dso__find_symbol(struct dso *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300188{
189 struct rb_node *n;
190
191 if (self == NULL)
192 return NULL;
193
194 n = self->syms.rb_node;
195
196 while (n) {
197 struct symbol *s = rb_entry(n, struct symbol, rb_node);
198
199 if (ip < s->start)
200 n = n->rb_left;
201 else if (ip > s->end)
202 n = n->rb_right;
203 else
204 return s;
205 }
206
207 return NULL;
208}
209
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200210int build_id__sprintf(u8 *self, int len, char *bf)
211{
212 char *bid = bf;
213 u8 *raw = self;
214 int i;
215
216 for (i = 0; i < len; ++i) {
217 sprintf(bid, "%02x", *raw);
218 ++raw;
219 bid += 2;
220 }
221
222 return raw - self;
223}
224
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200225size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300226{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200227 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200228
229 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200230 return fprintf(fp, "%s", sbuild_id);
231}
232
233size_t dso__fprintf(struct dso *self, FILE *fp)
234{
235 struct rb_node *nd;
236 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
237
238 ret += dso__fprintf_buildid(self, fp);
239 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200240
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300241 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
242 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
243 ret += symbol__fprintf(pos, fp);
244 }
245
246 return ret;
247}
248
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300249/*
250 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
251 * so that we can in the next step set the symbol ->end address and then
252 * call kernel_maps__split_kallsyms.
253 */
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200254static int kernel_maps__load_all_kallsyms(void)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300255{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300256 char *line = NULL;
257 size_t n;
258 FILE *file = fopen("/proc/kallsyms", "r");
259
260 if (file == NULL)
261 goto out_failure;
262
263 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000264 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300265 struct symbol *sym;
266 int line_len, len;
267 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300268 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300269
270 line_len = getline(&line, &n, file);
271 if (line_len < 0)
272 break;
273
274 if (!line)
275 goto out_failure;
276
277 line[--line_len] = '\0'; /* \n */
278
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300279 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300280
281 len++;
282 if (len + 2 >= line_len)
283 continue;
284
285 symbol_type = toupper(line[len]);
286 /*
287 * We're interested only in code ('T'ext)
288 */
289 if (symbol_type != 'T' && symbol_type != 'W')
290 continue;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300291
292 symbol_name = line + len + 2;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300293 /*
294 * Will fix up the end later, when we have all symbols sorted.
295 */
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200296 sym = symbol__new(start, 0, symbol_name);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300297
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300298 if (sym == NULL)
299 goto out_delete_line;
300
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200301 /*
302 * We will pass the symbols to the filter later, in
303 * kernel_maps__split_kallsyms, when we have split the
304 * maps per module
305 */
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300306 dso__insert_symbol(kernel_map->dso, sym);
307 }
308
309 free(line);
310 fclose(file);
311
312 return 0;
313
314out_delete_line:
315 free(line);
316out_failure:
317 return -1;
318}
319
320/*
321 * Split the symbols into maps, making sure there are no overlaps, i.e. the
322 * kernel range is broken in several maps, named [kernel].N, as we don't have
323 * the original ELF section names vmlinux have.
324 */
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200325static int kernel_maps__split_kallsyms(symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300326{
327 struct map *map = kernel_map;
328 struct symbol *pos;
329 int count = 0;
330 struct rb_node *next = rb_first(&kernel_map->dso->syms);
331 int kernel_range = 0;
332
333 while (next) {
334 char *module;
335
336 pos = rb_entry(next, struct symbol, rb_node);
337 next = rb_next(&pos->rb_node);
338
339 module = strchr(pos->name, '\t');
340 if (module) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300341 *module++ = '\0';
342
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300343 if (strcmp(map->dso->name, module)) {
344 map = kernel_maps__find_by_dso_name(module);
345 if (!map) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200346 pr_err("/proc/{kallsyms,modules} "
347 "inconsistency!\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300348 return -1;
349 }
350 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300351 /*
352 * So that we look just like we get from .ko files,
353 * i.e. not prelinked, relative to map->start.
354 */
355 pos->start = map->map_ip(map, pos->start);
356 pos->end = map->map_ip(map, pos->end);
357 } else if (map != kernel_map) {
358 char dso_name[PATH_MAX];
359 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300360
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300361 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
362 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300363
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200364 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300365 if (dso == NULL)
366 return -1;
367
368 map = map__new2(pos->start, dso);
369 if (map == NULL) {
370 dso__delete(dso);
371 return -1;
372 }
373
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200374 map->map_ip = map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300375 kernel_maps__insert(map);
376 ++kernel_range;
377 }
378
379 if (filter && filter(map, pos)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300380 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200381 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300382 } else {
383 if (map != kernel_map) {
384 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
385 dso__insert_symbol(map->dso, pos);
386 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200387 count++;
388 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300389 }
390
Mike Galbraith9974f492009-07-02 08:05:58 +0200391 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300392}
393
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300394
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200395static int kernel_maps__load_kallsyms(symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300396{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200397 if (kernel_maps__load_all_kallsyms())
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300398 return -1;
399
400 dso__fixup_sym_end(kernel_map->dso);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200401 kernel_map->dso->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300402
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200403 return kernel_maps__split_kallsyms(filter);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300404}
405
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200406size_t kernel_maps__fprintf(FILE *fp)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300407{
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200408 size_t printed = fprintf(fp, "Kernel maps:\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300409 struct rb_node *nd;
410
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300411 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
412 struct map *pos = rb_entry(nd, struct map, rb_node);
413
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300414 printed += fprintf(fp, "Map:");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300415 printed += map__fprintf(pos, fp);
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200416 if (verbose > 1) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300417 printed += dso__fprintf(pos->dso, fp);
418 printed += fprintf(fp, "--\n");
419 }
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300420 }
421
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200422 return printed + fprintf(fp, "END kernel maps\n");
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300423}
424
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300425static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200426 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300427{
428 char *line = NULL;
429 size_t n;
430 FILE *file;
431 int nr_syms = 0;
432
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300433 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300434 if (file == NULL)
435 goto out_failure;
436
437 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000438 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300439 struct symbol *sym;
440 int line_len, len;
441
442 line_len = getline(&line, &n, file);
443 if (line_len < 0)
444 break;
445
446 if (!line)
447 goto out_failure;
448
449 line[--line_len] = '\0'; /* \n */
450
451 len = hex2u64(line, &start);
452
453 len++;
454 if (len + 2 >= line_len)
455 continue;
456
457 len += hex2u64(line + len, &size);
458
459 len++;
460 if (len + 2 >= line_len)
461 continue;
462
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200463 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300464
465 if (sym == NULL)
466 goto out_delete_line;
467
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300468 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200469 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300470 else {
471 dso__insert_symbol(self, sym);
472 nr_syms++;
473 }
474 }
475
476 free(line);
477 fclose(file);
478
479 return nr_syms;
480
481out_delete_line:
482 free(line);
483out_failure:
484 return -1;
485}
486
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300487/**
488 * elf_symtab__for_each_symbol - iterate thru all the symbols
489 *
490 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200491 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300492 * @sym: GElf_Sym iterator
493 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200494#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
495 for (idx = 0, gelf_getsym(syms, idx, &sym);\
496 idx < nr_syms; \
497 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300498
499static inline uint8_t elf_sym__type(const GElf_Sym *sym)
500{
501 return GELF_ST_TYPE(sym->st_info);
502}
503
504static inline int elf_sym__is_function(const GElf_Sym *sym)
505{
506 return elf_sym__type(sym) == STT_FUNC &&
507 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300508 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300509}
510
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200511static inline int elf_sym__is_label(const GElf_Sym *sym)
512{
513 return elf_sym__type(sym) == STT_NOTYPE &&
514 sym->st_name != 0 &&
515 sym->st_shndx != SHN_UNDEF &&
516 sym->st_shndx != SHN_ABS;
517}
518
519static inline const char *elf_sec__name(const GElf_Shdr *shdr,
520 const Elf_Data *secstrs)
521{
522 return secstrs->d_buf + shdr->sh_name;
523}
524
525static inline int elf_sec__is_text(const GElf_Shdr *shdr,
526 const Elf_Data *secstrs)
527{
528 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
529}
530
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300531static inline const char *elf_sym__name(const GElf_Sym *sym,
532 const Elf_Data *symstrs)
533{
534 return symstrs->d_buf + sym->st_name;
535}
536
537static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
538 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200539 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300540{
541 Elf_Scn *sec = NULL;
542 size_t cnt = 1;
543
544 while ((sec = elf_nextscn(elf, sec)) != NULL) {
545 char *str;
546
547 gelf_getshdr(sec, shp);
548 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
549 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200550 if (idx)
551 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300552 break;
553 }
554 ++cnt;
555 }
556
557 return sec;
558}
559
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300560#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
561 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
562 idx < nr_entries; \
563 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
564
565#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
566 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
567 idx < nr_entries; \
568 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
569
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300570/*
571 * We need to check if we have a .dynsym, so that we can handle the
572 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
573 * .dynsym or .symtab).
574 * And always look at the original dso, not at debuginfo packages, that
575 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
576 */
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200577static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
578 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300579{
580 uint32_t nr_rel_entries, idx;
581 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000582 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300583 GElf_Shdr shdr_plt;
584 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300585 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300586 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300587 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
588 size_t dynsym_idx;
589 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300590 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300591 Elf *elf;
592 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300593
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300594 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300595 if (fd < 0)
596 goto out;
597
Marti Raudsepp84087122009-10-24 19:10:36 +0300598 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300599 if (elf == NULL)
600 goto out_close;
601
602 if (gelf_getehdr(elf, &ehdr) == NULL)
603 goto out_elf_end;
604
605 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
606 ".dynsym", &dynsym_idx);
607 if (scn_dynsym == NULL)
608 goto out_elf_end;
609
610 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300611 ".rela.plt", NULL);
612 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300613 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300614 ".rel.plt", NULL);
615 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300616 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300617 }
618
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300619 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300620
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300621 if (shdr_rel_plt.sh_link != dynsym_idx)
622 goto out_elf_end;
623
624 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
625 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300626
627 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200628 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300629 * and the symbols in the .dynsym they refer to.
630 */
631 reldata = elf_getdata(scn_plt_rel, NULL);
632 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300633 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300634
635 syms = elf_getdata(scn_dynsym, NULL);
636 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300637 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300638
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300639 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300640 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300641 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300642
643 symstrs = elf_getdata(scn_symstrs, NULL);
644 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300645 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300646
647 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
648 plt_offset = shdr_plt.sh_offset;
649
650 if (shdr_rel_plt.sh_type == SHT_RELA) {
651 GElf_Rela pos_mem, *pos;
652
653 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
654 nr_rel_entries) {
655 symidx = GELF_R_SYM(pos->r_info);
656 plt_offset += shdr_plt.sh_entsize;
657 gelf_getsym(syms, symidx, &sym);
658 snprintf(sympltname, sizeof(sympltname),
659 "%s@plt", elf_sym__name(&sym, symstrs));
660
661 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200662 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300663 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300664 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300665
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200666 if (filter && filter(map, f))
667 symbol__delete(f);
668 else {
669 dso__insert_symbol(self, f);
670 ++nr;
671 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300672 }
673 } else if (shdr_rel_plt.sh_type == SHT_REL) {
674 GElf_Rel pos_mem, *pos;
675 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
676 nr_rel_entries) {
677 symidx = GELF_R_SYM(pos->r_info);
678 plt_offset += shdr_plt.sh_entsize;
679 gelf_getsym(syms, symidx, &sym);
680 snprintf(sympltname, sizeof(sympltname),
681 "%s@plt", elf_sym__name(&sym, symstrs));
682
683 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200684 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300685 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300686 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300687
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200688 if (filter && filter(map, f))
689 symbol__delete(f);
690 else {
691 dso__insert_symbol(self, f);
692 ++nr;
693 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300694 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300695 }
696
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300697 err = 0;
698out_elf_end:
699 elf_end(elf);
700out_close:
701 close(fd);
702
703 if (err == 0)
704 return nr;
705out:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200706 pr_warning("%s: problems reading %s PLT info.\n",
707 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300708 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300709}
710
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300711static int dso__load_sym(struct dso *self, struct map *map, const char *name,
712 int fd, symbol_filter_t filter, int kernel,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200713 int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300714{
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300715 struct map *curr_map = map;
716 struct dso *curr_dso = self;
717 size_t dso_name_len = strlen(self->short_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200718 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300719 uint32_t nr_syms;
720 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200721 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300722 GElf_Ehdr ehdr;
723 GElf_Shdr shdr;
724 Elf_Data *syms;
725 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300726 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300727 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300728 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300729
Marti Raudsepp84087122009-10-24 19:10:36 +0300730 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300731 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200732 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300733 goto out_close;
734 }
735
736 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200737 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300738 goto out_elf_end;
739 }
740
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300741 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
742 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300743 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
744 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300745 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300746 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300747
748 syms = elf_getdata(sec, NULL);
749 if (syms == NULL)
750 goto out_elf_end;
751
752 sec = elf_getscn(elf, shdr.sh_link);
753 if (sec == NULL)
754 goto out_elf_end;
755
756 symstrs = elf_getdata(sec, NULL);
757 if (symstrs == NULL)
758 goto out_elf_end;
759
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200760 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
761 if (sec_strndx == NULL)
762 goto out_elf_end;
763
764 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500765 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200766 goto out_elf_end;
767
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300768 nr_syms = shdr.sh_size / shdr.sh_entsize;
769
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200770 memset(&sym, 0, sizeof(sym));
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200771 if (!kernel) {
772 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300773 elf_section_by_name(elf, &ehdr, &shdr,
774 ".gnu.prelink_undo",
775 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200776 } else self->adjust_symbols = 0;
777
Ingo Molnar83a09442009-08-15 12:26:57 +0200778 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300779 struct symbol *f;
Ingo Molnar83a09442009-08-15 12:26:57 +0200780 const char *elf_name;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300781 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200782 int is_label = elf_sym__is_label(&sym);
783 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300784
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200785 if (!is_label && !elf_sym__is_function(&sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300786 continue;
787
788 sec = elf_getscn(elf, sym.st_shndx);
789 if (!sec)
790 goto out_elf_end;
791
792 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200793
794 if (is_label && !elf_sec__is_text(&shdr, secstrs))
795 continue;
796
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300797 elf_name = elf_sym__name(&sym, symstrs);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200798 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200799
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300800 if (kernel || kmodule) {
801 char dso_name[PATH_MAX];
802
803 if (strcmp(section_name,
804 curr_dso->short_name + dso_name_len) == 0)
805 goto new_symbol;
806
807 if (strcmp(section_name, ".text") == 0) {
808 curr_map = map;
809 curr_dso = self;
810 goto new_symbol;
811 }
812
813 snprintf(dso_name, sizeof(dso_name),
814 "%s%s", self->short_name, section_name);
815
816 curr_map = kernel_maps__find_by_dso_name(dso_name);
817 if (curr_map == NULL) {
818 u64 start = sym.st_value;
819
820 if (kmodule)
821 start += map->start + shdr.sh_offset;
822
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200823 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300824 if (curr_dso == NULL)
825 goto out_elf_end;
826 curr_map = map__new2(start, curr_dso);
827 if (curr_map == NULL) {
828 dso__delete(curr_dso);
829 goto out_elf_end;
830 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -0200831 curr_map->map_ip = identity__map_ip;
832 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300833 curr_dso->origin = DSO__ORIG_KERNEL;
834 kernel_maps__insert(curr_map);
835 dsos__add(curr_dso);
836 } else
837 curr_dso = curr_map->dso;
838
839 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300840 }
841
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300842 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200843 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
844 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
845 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300846 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300847 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300848 /*
849 * We need to figure out if the object was created from C++ sources
850 * DWARF DW_compile_unit has this, but we don't always have access
851 * to it...
852 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200853 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300854 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +0200855 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300856new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200857 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -0300858 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300859 if (!f)
860 goto out_elf_end;
861
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300862 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200863 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300864 else {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300865 dso__insert_symbol(curr_dso, f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300866 nr++;
867 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300868 }
869
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300870 /*
871 * For misannotated, zeroed, ASM function sizes.
872 */
873 if (nr > 0)
874 dso__fixup_sym_end(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300875 err = nr;
876out_elf_end:
877 elf_end(elf);
878out_close:
879 return err;
880}
881
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -0200882static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
883{
884 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
885}
886
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200887bool dsos__read_build_ids(void)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100888{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200889 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100890 struct dso *pos;
891
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200892 list_for_each_entry(pos, &dsos, node)
893 if (filename__read_build_id(pos->long_name, pos->build_id,
894 sizeof(pos->build_id)) > 0) {
895 have_build_id = true;
896 pos->has_build_id = true;
897 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100898
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -0200899 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +0100900}
901
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200902/*
903 * Align offset to 4 bytes as needed for note name and descriptor data.
904 */
905#define NOTE_ALIGN(n) (((n) + 3) & -4U)
906
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200907int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300908{
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200909 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300910 GElf_Ehdr ehdr;
911 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200912 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300913 Elf_Scn *sec;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200914 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300915 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300916
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200917 if (size < BUILD_ID_SIZE)
918 goto out;
919
920 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300921 if (fd < 0)
922 goto out;
923
Marti Raudsepp84087122009-10-24 19:10:36 +0300924 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300925 if (elf == NULL) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200926 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300927 goto out_close;
928 }
929
930 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200931 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300932 goto out_elf_end;
933 }
934
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200935 sec = elf_section_by_name(elf, &ehdr, &shdr,
936 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200937 if (sec == NULL) {
938 sec = elf_section_by_name(elf, &ehdr, &shdr,
939 ".notes", NULL);
940 if (sec == NULL)
941 goto out_elf_end;
942 }
943
944 data = elf_getdata(sec, NULL);
945 if (data == NULL)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -0300946 goto out_elf_end;
947
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200948 ptr = data->d_buf;
949 while (ptr < (data->d_buf + data->d_size)) {
950 GElf_Nhdr *nhdr = ptr;
951 int namesz = NOTE_ALIGN(nhdr->n_namesz),
952 descsz = NOTE_ALIGN(nhdr->n_descsz);
953 const char *name;
954
955 ptr += sizeof(*nhdr);
956 name = ptr;
957 ptr += namesz;
958 if (nhdr->n_type == NT_GNU_BUILD_ID &&
959 nhdr->n_namesz == sizeof("GNU")) {
960 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
961 memcpy(bf, ptr, BUILD_ID_SIZE);
962 err = BUILD_ID_SIZE;
963 break;
964 }
965 }
966 ptr += descsz;
967 }
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -0200968out_elf_end:
969 elf_end(elf);
970out_close:
971 close(fd);
972out:
973 return err;
974}
975
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -0200976int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
977{
978 int fd, err = -1;
979
980 if (size < BUILD_ID_SIZE)
981 goto out;
982
983 fd = open(filename, O_RDONLY);
984 if (fd < 0)
985 goto out;
986
987 while (1) {
988 char bf[BUFSIZ];
989 GElf_Nhdr nhdr;
990 int namesz, descsz;
991
992 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
993 break;
994
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -0200995 namesz = NOTE_ALIGN(nhdr.n_namesz);
996 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -0200997 if (nhdr.n_type == NT_GNU_BUILD_ID &&
998 nhdr.n_namesz == sizeof("GNU")) {
999 if (read(fd, bf, namesz) != namesz)
1000 break;
1001 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1002 if (read(fd, build_id,
1003 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1004 err = 0;
1005 break;
1006 }
1007 } else if (read(fd, bf, descsz) != descsz)
1008 break;
1009 } else {
1010 int n = namesz + descsz;
1011 if (read(fd, bf, n) != n)
1012 break;
1013 }
1014 }
1015 close(fd);
1016out:
1017 return err;
1018}
1019
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001020char dso__symtab_origin(const struct dso *self)
1021{
1022 static const char origin[] = {
1023 [DSO__ORIG_KERNEL] = 'k',
1024 [DSO__ORIG_JAVA_JIT] = 'j',
1025 [DSO__ORIG_FEDORA] = 'f',
1026 [DSO__ORIG_UBUNTU] = 'u',
1027 [DSO__ORIG_BUILDID] = 'b',
1028 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001029 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001030 };
1031
1032 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
1033 return '!';
1034 return origin[self->origin];
1035}
1036
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001037int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001038{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001039 int size = PATH_MAX;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001040 char *name;
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001041 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001042 int ret = -1;
1043 int fd;
1044
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001045 self->loaded = 1;
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001046
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001047 if (self->kernel)
1048 return dso__load_kernel_sym(self, map, filter);
1049
1050 name = malloc(size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001051 if (!name)
1052 return -1;
1053
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001054 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001055
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001056 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001057 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001058 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
1059 DSO__ORIG_NOT_FOUND;
1060 return ret;
1061 }
1062
1063 self->origin = DSO__ORIG_FEDORA - 1;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001064
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001065more:
1066 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001067 self->origin++;
1068 switch (self->origin) {
1069 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001070 snprintf(name, size, "/usr/lib/debug%s.debug",
1071 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001072 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001073 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001074 snprintf(name, size, "/usr/lib/debug%s",
1075 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001076 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001077 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001078 if (filename__read_build_id(self->long_name, build_id,
1079 sizeof(build_id))) {
1080 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1081
1082 build_id__sprintf(build_id, sizeof(build_id),
1083 build_id_hex);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001084 snprintf(name, size,
1085 "/usr/lib/debug/.build-id/%.2s/%s.debug",
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001086 build_id_hex, build_id_hex + 2);
1087 if (self->has_build_id)
1088 goto compare_build_id;
1089 break;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001090 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001091 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001092 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001093 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001094 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001095 break;
1096
1097 default:
1098 goto out;
1099 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001100
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001101 if (self->has_build_id) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001102 if (filename__read_build_id(name, build_id,
1103 sizeof(build_id)) < 0)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001104 goto more;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001105compare_build_id:
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001106 if (!dso__build_id_equal(self, build_id))
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001107 goto more;
1108 }
1109
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001110 fd = open(name, O_RDONLY);
1111 } while (fd < 0);
1112
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001113 ret = dso__load_sym(self, map, name, fd, filter, 0, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001114 close(fd);
1115
1116 /*
1117 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
1118 */
1119 if (!ret)
1120 goto more;
1121
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001122 if (ret > 0) {
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001123 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001124 if (nr_plt > 0)
1125 ret += nr_plt;
1126 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001127out:
1128 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001129 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1130 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001131 return ret;
1132}
1133
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001134struct map *kernel_map;
1135
1136static void kernel_maps__insert(struct map *map)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001137{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001138 maps__insert(&kernel_maps, map);
1139}
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001140
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001141struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp,
1142 symbol_filter_t filter)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001143{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001144 struct map *map = maps__find(&kernel_maps, ip);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001145
1146 if (mapp)
1147 *mapp = map;
1148
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001149 if (map) {
1150 ip = map->map_ip(map, ip);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001151 return map__find_symbol(map, ip, filter);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001152 }
1153
1154 return NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001155}
1156
1157struct map *kernel_maps__find_by_dso_name(const char *name)
1158{
1159 struct rb_node *nd;
1160
1161 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
1162 struct map *map = rb_entry(nd, struct map, rb_node);
1163
1164 if (map->dso && strcmp(map->dso->name, name) == 0)
1165 return map;
1166 }
1167
1168 return NULL;
1169}
1170
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001171static int dsos__set_modules_path_dir(char *dirname)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001172{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001173 struct dirent *dent;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001174 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001175
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001176 if (!dir) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001177 pr_err("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001178 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001179 }
1180
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001181 while ((dent = readdir(dir)) != NULL) {
1182 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001183
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001184 if (dent->d_type == DT_DIR) {
1185 if (!strcmp(dent->d_name, ".") ||
1186 !strcmp(dent->d_name, ".."))
1187 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001188
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001189 snprintf(path, sizeof(path), "%s/%s",
1190 dirname, dent->d_name);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001191 if (dsos__set_modules_path_dir(path) < 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001192 goto failure;
1193 } else {
1194 char *dot = strrchr(dent->d_name, '.'),
1195 dso_name[PATH_MAX];
1196 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001197 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001198
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001199 if (dot == NULL || strcmp(dot, ".ko"))
1200 continue;
1201 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1202 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001203
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001204 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001205 map = kernel_maps__find_by_dso_name(dso_name);
1206 if (map == NULL)
1207 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001208
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001209 snprintf(path, sizeof(path), "%s/%s",
1210 dirname, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001211
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001212 long_name = strdup(path);
1213 if (long_name == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001214 goto failure;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001215 dso__set_long_name(map->dso, long_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001216 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001217 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001218
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001219 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001220failure:
1221 closedir(dir);
1222 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001223}
1224
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001225static int dsos__set_modules_path(void)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001226{
1227 struct utsname uts;
1228 char modules_path[PATH_MAX];
1229
1230 if (uname(&uts) < 0)
1231 return -1;
1232
1233 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1234 uts.release);
1235
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001236 return dsos__set_modules_path_dir(modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001237}
1238
1239/*
1240 * Constructor variant for modules (where we know from /proc/modules where
1241 * they are loaded) and for vmlinux, where only after we load all the
1242 * symbols we'll know where it starts and ends.
1243 */
1244static struct map *map__new2(u64 start, struct dso *dso)
1245{
1246 struct map *self = malloc(sizeof(*self));
1247
1248 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001249 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001250 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001251 */
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001252 map__init(self, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001253 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001254
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001255 return self;
1256}
1257
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001258static int kernel_maps__create_module_maps(void)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001259{
1260 char *line = NULL;
1261 size_t n;
1262 FILE *file = fopen("/proc/modules", "r");
1263 struct map *map;
1264
1265 if (file == NULL)
1266 return -1;
1267
1268 while (!feof(file)) {
1269 char name[PATH_MAX];
1270 u64 start;
1271 struct dso *dso;
1272 char *sep;
1273 int line_len;
1274
1275 line_len = getline(&line, &n, file);
1276 if (line_len < 0)
1277 break;
1278
1279 if (!line)
1280 goto out_failure;
1281
1282 line[--line_len] = '\0'; /* \n */
1283
1284 sep = strrchr(line, 'x');
1285 if (sep == NULL)
1286 continue;
1287
1288 hex2u64(sep + 1, &start);
1289
1290 sep = strchr(line, ' ');
1291 if (sep == NULL)
1292 continue;
1293
1294 *sep = '\0';
1295
1296 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001297 dso = dso__new(name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001298
1299 if (dso == NULL)
1300 goto out_delete_line;
1301
1302 map = map__new2(start, dso);
1303 if (map == NULL) {
1304 dso__delete(dso);
1305 goto out_delete_line;
1306 }
1307
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001308 snprintf(name, sizeof(name),
1309 "/sys/module/%s/notes/.note.gnu.build-id", line);
1310 if (sysfs__read_build_id(name, dso->build_id,
1311 sizeof(dso->build_id)) == 0)
1312 dso->has_build_id = true;
1313
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001314 dso->origin = DSO__ORIG_KMODULE;
1315 kernel_maps__insert(map);
1316 dsos__add(dso);
1317 }
1318
1319 free(line);
1320 fclose(file);
1321
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001322 /*
1323 * Now that we have all sorted out, just set the ->end of all
1324 * maps:
1325 */
1326 kernel_maps__fixup_end();
1327
1328 return dsos__set_modules_path();
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001329
1330out_delete_line:
1331 free(line);
1332out_failure:
1333 return -1;
1334}
1335
1336static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001337 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001338{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001339 int err = -1, fd;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001340
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001341 if (self->has_build_id) {
1342 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001343
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001344 if (filename__read_build_id(vmlinux, build_id,
1345 sizeof(build_id)) < 0) {
1346 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1347 return -1;
1348 }
1349 if (!dso__build_id_equal(self, build_id)) {
1350 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1351 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1352
1353 build_id__sprintf(self->build_id,
1354 sizeof(self->build_id),
1355 expected_build_id);
1356 build_id__sprintf(build_id, sizeof(build_id),
1357 vmlinux_build_id);
1358 pr_debug("build_id in %s is %s while expected is %s, "
1359 "ignoring it\n", vmlinux, vmlinux_build_id,
1360 expected_build_id);
1361 return -1;
1362 }
1363 }
1364
1365 fd = open(vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001366 if (fd < 0)
1367 return -1;
1368
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001369 self->loaded = 1;
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001370 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001371
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001372 close(fd);
1373
1374 return err;
1375}
1376
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001377static int dso__load_kernel_sym(struct dso *self, struct map *map,
1378 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001379{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001380 int err = dso__load_vmlinux(self, map, self->name, filter);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001381
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001382 if (err <= 0) {
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001383 err = kernel_maps__load_kallsyms(filter);
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001384 if (err > 0)
1385 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1386 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001387
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001388 if (err > 0) {
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001389 map__fixup_start(map);
1390 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001391 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001392
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001393 return err;
1394}
1395
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001396LIST_HEAD(dsos);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001397struct dso *vdso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001398
Ingo Molnar83a09442009-08-15 12:26:57 +02001399const char *vmlinux_name = "vmlinux";
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001400
1401static void dsos__add(struct dso *dso)
1402{
1403 list_add_tail(&dso->node, &dsos);
1404}
1405
1406static struct dso *dsos__find(const char *name)
1407{
1408 struct dso *pos;
1409
1410 list_for_each_entry(pos, &dsos, node)
1411 if (strcmp(pos->name, name) == 0)
1412 return pos;
1413 return NULL;
1414}
1415
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001416struct dso *dsos__findnew(const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001417{
1418 struct dso *dso = dsos__find(name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001419
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001420 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001421 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001422 if (dso != NULL) {
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001423 dsos__add(dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001424 dso__set_basename(dso);
1425 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001426 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001427
1428 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001429}
1430
1431void dsos__fprintf(FILE *fp)
1432{
1433 struct dso *pos;
1434
1435 list_for_each_entry(pos, &dsos, node)
1436 dso__fprintf(pos, fp);
1437}
1438
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001439size_t dsos__fprintf_buildid(FILE *fp)
1440{
1441 struct dso *pos;
1442 size_t ret = 0;
1443
1444 list_for_each_entry(pos, &dsos, node) {
1445 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02001446 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001447 }
1448 return ret;
1449}
1450
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001451static int kernel_maps__create_kernel_map(void)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001452{
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001453 struct dso *kernel = dso__new(vmlinux_name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001454
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001455 if (kernel == NULL)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001456 return -1;
1457
1458 kernel_map = map__new2(0, kernel);
1459 if (kernel_map == NULL)
1460 goto out_delete_kernel_dso;
1461
1462 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001463
1464 kernel->short_name = "[kernel]";
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001465 kernel->kernel = 1;
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001466 vdso = dso__new("[vdso]");
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001467 if (vdso == NULL)
1468 goto out_delete_kernel_map;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001469
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001470 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1471 sizeof(kernel->build_id)) == 0)
1472 kernel->has_build_id = true;
1473
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001474 kernel_maps__insert(kernel_map);
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001475 dsos__add(kernel);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001476 dsos__add(vdso);
1477
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001478 return 0;
1479
1480out_delete_kernel_map:
1481 map__delete(kernel_map);
1482 kernel_map = NULL;
1483out_delete_kernel_dso:
1484 dso__delete(kernel);
1485 return -1;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001486}
1487
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001488int kernel_maps__init(bool use_modules)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001489{
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001490 if (kernel_maps__create_kernel_map() < 0)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001491 return -1;
1492
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001493 if (use_modules && kernel_maps__create_module_maps() < 0)
1494 pr_warning("Failed to load list of modules in use, "
1495 "continuing...\n");
Arnaldo Carvalho de Melo6671cb12009-11-20 20:51:24 -02001496
1497 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001498}
1499
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001500void symbol__init(unsigned int priv_size)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001501{
1502 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001503 symbol__priv_size = priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001504}