blob: c458c4a371d11ea11715f3937111843234739462 [file] [log] [blame]
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001#include "util.h"
2#include "../perf.h"
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02003#include "sort.h"
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -03004#include "string.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03005#include "symbol.h"
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03006#include "thread.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03007
Frederic Weisbecker8f288272009-08-16 22:05:48 +02008#include "debug.h"
9
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020010#include <asm/bug.h>
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030011#include <libelf.h>
12#include <gelf.h>
13#include <elf.h>
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -020014#include <limits.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030015#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020016
Arnaldo Carvalho de Meloc12e15e2009-11-21 14:31:25 -020017#ifndef NT_GNU_BUILD_ID
18#define NT_GNU_BUILD_ID 3
19#endif
20
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030021enum dso_origin {
22 DSO__ORIG_KERNEL = 0,
23 DSO__ORIG_JAVA_JIT,
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -020024 DSO__ORIG_BUILD_ID_CACHE,
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030025 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID,
28 DSO__ORIG_DSO,
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030029 DSO__ORIG_KMODULE,
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -030030 DSO__ORIG_NOT_FOUND,
31};
32
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -020033static void dsos__add(struct list_head *head, struct dso *dso);
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020034static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020035static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020036 symbol_filter_t filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020037static int vmlinux_path__nr_entries;
38static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030039
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020040struct symbol_conf symbol_conf = {
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -020041 .exclude_other = true,
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020042 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020046bool dso__loaded(const struct dso *self, enum map_type type)
47{
48 return self->loaded & (1 << type);
49}
50
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020051bool dso__sorted_by_name(const struct dso *self, enum map_type type)
52{
53 return self->sorted_by_name & (1 << type);
54}
55
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020056static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
57{
58 self->sorted_by_name |= (1 << type);
59}
60
Arnaldo Carvalho de Melo36a3e642010-01-04 16:19:27 -020061bool symbol_type__is_a(char symbol_type, enum map_type map_type)
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020062{
63 switch (map_type) {
64 case MAP__FUNCTION:
65 return symbol_type == 'T' || symbol_type == 'W';
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -020066 case MAP__VARIABLE:
67 return symbol_type == 'D' || symbol_type == 'd';
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020068 default:
69 return false;
70 }
71}
72
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020073static void symbols__fixup_end(struct rb_root *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030074{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020075 struct rb_node *nd, *prevnd = rb_first(self);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030076 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030077
78 if (prevnd == NULL)
79 return;
80
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030081 curr = rb_entry(prevnd, struct symbol, rb_node);
82
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030083 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030084 prev = curr;
85 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030086
87 if (prev->end == prev->start)
88 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030089 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030090
91 /* Last entry */
92 if (curr->end == curr->start)
93 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030094}
95
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -020096static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030097{
98 struct map *prev, *curr;
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -020099 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300100
101 if (prevnd == NULL)
102 return;
103
104 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300105
106 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
107 prev = curr;
108 curr = rb_entry(nd, struct map, rb_node);
109 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300110 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -0200111
112 /*
113 * We still haven't the actual symbols, so guess the
114 * last map final address.
115 */
116 curr->end = ~0UL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300117}
118
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200119static void map_groups__fixup_end(struct map_groups *self)
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200120{
121 int i;
122 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200123 __map_groups__fixup_end(self, i);
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200124}
125
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200126static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300127{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300128 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200129 struct symbol *self = zalloc(symbol_conf.priv_size +
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200130 sizeof(*self) + namelen);
131 if (self == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200132 return NULL;
133
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200134 if (symbol_conf.priv_size)
135 self = ((void *)self) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200136
Ingo Molnar0b73da32009-06-06 15:48:52 +0200137 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200138 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200139
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -0200140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200141
Ingo Molnar0b73da32009-06-06 15:48:52 +0200142 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300143
144 return self;
145}
146
Arnaldo Carvalho de Melo628ada02010-02-25 12:57:40 -0300147void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300148{
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200149 free(((void *)self) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300150}
151
152static size_t symbol__fprintf(struct symbol *self, FILE *fp)
153{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300154 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300155 self->start, self->end, self->name);
156}
157
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200158void dso__set_long_name(struct dso *self, char *name)
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200159{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200160 if (name == NULL)
161 return;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200162 self->long_name = name;
163 self->long_name_len = strlen(name);
164}
165
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300166static void dso__set_short_name(struct dso *self, const char *name)
167{
168 if (name == NULL)
169 return;
170 self->short_name = name;
171 self->short_name_len = strlen(name);
172}
173
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200174static void dso__set_basename(struct dso *self)
175{
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300176 dso__set_short_name(self, basename(self->long_name));
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200177}
178
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200179struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300180{
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200181 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300182
183 if (self != NULL) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200184 int i;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300185 strcpy(self->name, name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200186 dso__set_long_name(self, self->name);
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300187 dso__set_short_name(self, self->name);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200188 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200189 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300190 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300191 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200192 self->loaded = 0;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200193 self->sorted_by_name = 0;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200194 self->has_build_id = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300195 }
196
197 return self;
198}
199
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200200static void symbols__delete(struct rb_root *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300201{
202 struct symbol *pos;
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200203 struct rb_node *next = rb_first(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300204
205 while (next) {
206 pos = rb_entry(next, struct symbol, rb_node);
207 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200208 rb_erase(&pos->rb_node, self);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200209 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300210 }
211}
212
213void dso__delete(struct dso *self)
214{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200215 int i;
216 for (i = 0; i < MAP__NR_TYPES; ++i)
217 symbols__delete(&self->symbols[i]);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300218 if (self->long_name != self->name)
219 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300220 free(self);
221}
222
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200223void dso__set_build_id(struct dso *self, void *build_id)
224{
225 memcpy(self->build_id, build_id, sizeof(self->build_id));
226 self->has_build_id = 1;
227}
228
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200229static void symbols__insert(struct rb_root *self, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300230{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200231 struct rb_node **p = &self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300232 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000233 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300234 struct symbol *s;
235
236 while (*p != NULL) {
237 parent = *p;
238 s = rb_entry(parent, struct symbol, rb_node);
239 if (ip < s->start)
240 p = &(*p)->rb_left;
241 else
242 p = &(*p)->rb_right;
243 }
244 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200245 rb_insert_color(&sym->rb_node, self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300246}
247
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200248static struct symbol *symbols__find(struct rb_root *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300249{
250 struct rb_node *n;
251
252 if (self == NULL)
253 return NULL;
254
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200255 n = self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300256
257 while (n) {
258 struct symbol *s = rb_entry(n, struct symbol, rb_node);
259
260 if (ip < s->start)
261 n = n->rb_left;
262 else if (ip > s->end)
263 n = n->rb_right;
264 else
265 return s;
266 }
267
268 return NULL;
269}
270
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200271struct symbol_name_rb_node {
272 struct rb_node rb_node;
273 struct symbol sym;
274};
275
276static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
277{
278 struct rb_node **p = &self->rb_node;
279 struct rb_node *parent = NULL;
280 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
281
282 while (*p != NULL) {
283 parent = *p;
284 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
285 if (strcmp(sym->name, s->sym.name) < 0)
286 p = &(*p)->rb_left;
287 else
288 p = &(*p)->rb_right;
289 }
290 rb_link_node(&symn->rb_node, parent, p);
291 rb_insert_color(&symn->rb_node, self);
292}
293
294static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
295{
296 struct rb_node *nd;
297
298 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
299 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
300 symbols__insert_by_name(self, pos);
301 }
302}
303
304static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
305{
306 struct rb_node *n;
307
308 if (self == NULL)
309 return NULL;
310
311 n = self->rb_node;
312
313 while (n) {
314 struct symbol_name_rb_node *s;
315 int cmp;
316
317 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
318 cmp = strcmp(name, s->sym.name);
319
320 if (cmp < 0)
321 n = n->rb_left;
322 else if (cmp > 0)
323 n = n->rb_right;
324 else
325 return &s->sym;
326 }
327
328 return NULL;
329}
330
331struct symbol *dso__find_symbol(struct dso *self,
332 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200333{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200334 return symbols__find(&self->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200335}
336
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200337struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
338 const char *name)
339{
340 return symbols__find_by_name(&self->symbol_names[type], name);
341}
342
343void dso__sort_by_name(struct dso *self, enum map_type type)
344{
345 dso__set_sorted_by_name(self, type);
346 return symbols__sort_by_name(&self->symbol_names[type],
347 &self->symbols[type]);
348}
349
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200350int build_id__sprintf(const u8 *self, int len, char *bf)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200351{
352 char *bid = bf;
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200353 const u8 *raw = self;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200354 int i;
355
356 for (i = 0; i < len; ++i) {
357 sprintf(bid, "%02x", *raw);
358 ++raw;
359 bid += 2;
360 }
361
362 return raw - self;
363}
364
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200365size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300366{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200367 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200368
369 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200370 return fprintf(fp, "%s", sbuild_id);
371}
372
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200373size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200374{
375 struct rb_node *nd;
376 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
377
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -0300378 if (self->short_name != self->long_name)
379 ret += fprintf(fp, "%s, ", self->long_name);
380 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
381 self->loaded ? "" : "NOT ");
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200382 ret += dso__fprintf_buildid(self, fp);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200383 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200384 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
385 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
386 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300387 }
388
389 return ret;
390}
391
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200392int kallsyms__parse(const char *filename, void *arg,
393 int (*process_symbol)(void *arg, const char *name,
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200394 char type, u64 start))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300395{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300396 char *line = NULL;
397 size_t n;
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200398 int err = 0;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200399 FILE *file = fopen(filename, "r");
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300400
401 if (file == NULL)
402 goto out_failure;
403
404 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000405 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300406 int line_len, len;
407 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300408 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300409
410 line_len = getline(&line, &n, file);
411 if (line_len < 0)
412 break;
413
414 if (!line)
415 goto out_failure;
416
417 line[--line_len] = '\0'; /* \n */
418
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300419 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300420
421 len++;
422 if (len + 2 >= line_len)
423 continue;
424
425 symbol_type = toupper(line[len]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300426 symbol_name = line + len + 2;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300427
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200428 err = process_symbol(arg, symbol_name, symbol_type, start);
429 if (err)
430 break;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300431 }
432
433 free(line);
434 fclose(file);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200435 return err;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300436
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300437out_failure:
438 return -1;
439}
440
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200441struct process_kallsyms_args {
442 struct map *map;
443 struct dso *dso;
444};
445
446static int map__process_kallsym_symbol(void *arg, const char *name,
447 char type, u64 start)
448{
449 struct symbol *sym;
450 struct process_kallsyms_args *a = arg;
451 struct rb_root *root = &a->dso->symbols[a->map->type];
452
453 if (!symbol_type__is_a(type, a->map->type))
454 return 0;
455
456 /*
457 * Will fix up the end later, when we have all symbols sorted.
458 */
459 sym = symbol__new(start, 0, name);
460
461 if (sym == NULL)
462 return -ENOMEM;
463 /*
464 * We will pass the symbols to the filter later, in
465 * map__split_kallsyms, when we have split the maps per module
466 */
467 symbols__insert(root, sym);
468 return 0;
469}
470
471/*
472 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
473 * so that we can in the next step set the symbol ->end address and then
474 * call kernel_maps__split_kallsyms.
475 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200476static int dso__load_all_kallsyms(struct dso *self, const char *filename,
477 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200478{
479 struct process_kallsyms_args args = { .map = map, .dso = self, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200480 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200481}
482
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300483/*
484 * Split the symbols into maps, making sure there are no overlaps, i.e. the
485 * kernel range is broken in several maps, named [kernel].N, as we don't have
486 * the original ELF section names vmlinux have.
487 */
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200488static int dso__split_kallsyms(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200489 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300490{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200491 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200492 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300493 struct symbol *pos;
494 int count = 0;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200495 struct rb_root *root = &self->symbols[map->type];
496 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300497 int kernel_range = 0;
498
499 while (next) {
500 char *module;
501
502 pos = rb_entry(next, struct symbol, rb_node);
503 next = rb_next(&pos->rb_node);
504
505 module = strchr(pos->name, '\t');
506 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200507 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200508 goto discard_symbol;
509
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300510 *module++ = '\0';
511
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200512 if (strcmp(curr_map->dso->short_name, module)) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200513 curr_map = map_groups__find_by_name(kmaps, map->type, module);
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200514 if (curr_map == NULL) {
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200515 pr_debug("/proc/{kallsyms,modules} "
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200516 "inconsistency while looking "
517 "for \"%s\" module!\n", module);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300518 return -1;
519 }
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200520
521 if (curr_map->dso->loaded)
522 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300523 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300524 /*
525 * So that we look just like we get from .ko files,
526 * i.e. not prelinked, relative to map->start.
527 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200528 pos->start = curr_map->map_ip(curr_map, pos->start);
529 pos->end = curr_map->map_ip(curr_map, pos->end);
530 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300531 char dso_name[PATH_MAX];
532 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300533
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300534 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
535 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300536
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200537 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300538 if (dso == NULL)
539 return -1;
540
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200541 curr_map = map__new2(pos->start, dso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800542 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300543 dso__delete(dso);
544 return -1;
545 }
546
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200547 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200548 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300549 ++kernel_range;
550 }
551
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200552 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200553discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200554 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300555 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200556 if (curr_map != map) {
557 rb_erase(&pos->rb_node, root);
558 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300559 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200560 count++;
561 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300562 }
563
Mike Galbraith9974f492009-07-02 08:05:58 +0200564 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300565}
566
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200567int dso__load_kallsyms(struct dso *self, const char *filename,
568 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300569{
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200570 if (dso__load_all_kallsyms(self, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300571 return -1;
572
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200573 symbols__fixup_end(&self->symbols[map->type]);
574 self->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300575
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200576 return dso__split_kallsyms(self, map, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300577}
578
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300579static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200580 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300581{
582 char *line = NULL;
583 size_t n;
584 FILE *file;
585 int nr_syms = 0;
586
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300587 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300588 if (file == NULL)
589 goto out_failure;
590
591 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000592 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300593 struct symbol *sym;
594 int line_len, len;
595
596 line_len = getline(&line, &n, file);
597 if (line_len < 0)
598 break;
599
600 if (!line)
601 goto out_failure;
602
603 line[--line_len] = '\0'; /* \n */
604
605 len = hex2u64(line, &start);
606
607 len++;
608 if (len + 2 >= line_len)
609 continue;
610
611 len += hex2u64(line + len, &size);
612
613 len++;
614 if (len + 2 >= line_len)
615 continue;
616
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200617 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300618
619 if (sym == NULL)
620 goto out_delete_line;
621
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300622 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200623 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300624 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200625 symbols__insert(&self->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300626 nr_syms++;
627 }
628 }
629
630 free(line);
631 fclose(file);
632
633 return nr_syms;
634
635out_delete_line:
636 free(line);
637out_failure:
638 return -1;
639}
640
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300641/**
642 * elf_symtab__for_each_symbol - iterate thru all the symbols
643 *
644 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200645 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300646 * @sym: GElf_Sym iterator
647 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200648#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
649 for (idx = 0, gelf_getsym(syms, idx, &sym);\
650 idx < nr_syms; \
651 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300652
653static inline uint8_t elf_sym__type(const GElf_Sym *sym)
654{
655 return GELF_ST_TYPE(sym->st_info);
656}
657
658static inline int elf_sym__is_function(const GElf_Sym *sym)
659{
660 return elf_sym__type(sym) == STT_FUNC &&
661 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300662 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300663}
664
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200665static inline bool elf_sym__is_object(const GElf_Sym *sym)
666{
667 return elf_sym__type(sym) == STT_OBJECT &&
668 sym->st_name != 0 &&
669 sym->st_shndx != SHN_UNDEF;
670}
671
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200672static inline int elf_sym__is_label(const GElf_Sym *sym)
673{
674 return elf_sym__type(sym) == STT_NOTYPE &&
675 sym->st_name != 0 &&
676 sym->st_shndx != SHN_UNDEF &&
677 sym->st_shndx != SHN_ABS;
678}
679
680static inline const char *elf_sec__name(const GElf_Shdr *shdr,
681 const Elf_Data *secstrs)
682{
683 return secstrs->d_buf + shdr->sh_name;
684}
685
686static inline int elf_sec__is_text(const GElf_Shdr *shdr,
687 const Elf_Data *secstrs)
688{
689 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
690}
691
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200692static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
693 const Elf_Data *secstrs)
694{
695 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
696}
697
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300698static inline const char *elf_sym__name(const GElf_Sym *sym,
699 const Elf_Data *symstrs)
700{
701 return symstrs->d_buf + sym->st_name;
702}
703
704static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
705 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200706 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300707{
708 Elf_Scn *sec = NULL;
709 size_t cnt = 1;
710
711 while ((sec = elf_nextscn(elf, sec)) != NULL) {
712 char *str;
713
714 gelf_getshdr(sec, shp);
715 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
716 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200717 if (idx)
718 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300719 break;
720 }
721 ++cnt;
722 }
723
724 return sec;
725}
726
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300727#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
728 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
729 idx < nr_entries; \
730 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
731
732#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
733 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
734 idx < nr_entries; \
735 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
736
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300737/*
738 * We need to check if we have a .dynsym, so that we can handle the
739 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
740 * .dynsym or .symtab).
741 * And always look at the original dso, not at debuginfo packages, that
742 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
743 */
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200744static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
745 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300746{
747 uint32_t nr_rel_entries, idx;
748 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000749 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300750 GElf_Shdr shdr_plt;
751 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300752 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300753 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300754 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
755 size_t dynsym_idx;
756 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300757 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300758 Elf *elf;
759 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300760
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300761 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300762 if (fd < 0)
763 goto out;
764
Marti Raudsepp84087122009-10-24 19:10:36 +0300765 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300766 if (elf == NULL)
767 goto out_close;
768
769 if (gelf_getehdr(elf, &ehdr) == NULL)
770 goto out_elf_end;
771
772 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
773 ".dynsym", &dynsym_idx);
774 if (scn_dynsym == NULL)
775 goto out_elf_end;
776
777 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300778 ".rela.plt", NULL);
779 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300780 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300781 ".rel.plt", NULL);
782 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300783 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300784 }
785
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300786 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300787
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300788 if (shdr_rel_plt.sh_link != dynsym_idx)
789 goto out_elf_end;
790
791 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
792 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300793
794 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200795 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300796 * and the symbols in the .dynsym they refer to.
797 */
798 reldata = elf_getdata(scn_plt_rel, NULL);
799 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300800 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300801
802 syms = elf_getdata(scn_dynsym, NULL);
803 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300804 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300805
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300806 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300807 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300808 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300809
810 symstrs = elf_getdata(scn_symstrs, NULL);
811 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300812 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300813
814 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
815 plt_offset = shdr_plt.sh_offset;
816
817 if (shdr_rel_plt.sh_type == SHT_RELA) {
818 GElf_Rela pos_mem, *pos;
819
820 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
821 nr_rel_entries) {
822 symidx = GELF_R_SYM(pos->r_info);
823 plt_offset += shdr_plt.sh_entsize;
824 gelf_getsym(syms, symidx, &sym);
825 snprintf(sympltname, sizeof(sympltname),
826 "%s@plt", elf_sym__name(&sym, symstrs));
827
828 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200829 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300830 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300831 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300832
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200833 if (filter && filter(map, f))
834 symbol__delete(f);
835 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200836 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200837 ++nr;
838 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300839 }
840 } else if (shdr_rel_plt.sh_type == SHT_REL) {
841 GElf_Rel pos_mem, *pos;
842 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
843 nr_rel_entries) {
844 symidx = GELF_R_SYM(pos->r_info);
845 plt_offset += shdr_plt.sh_entsize;
846 gelf_getsym(syms, symidx, &sym);
847 snprintf(sympltname, sizeof(sympltname),
848 "%s@plt", elf_sym__name(&sym, symstrs));
849
850 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200851 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300852 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300853 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300854
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200855 if (filter && filter(map, f))
856 symbol__delete(f);
857 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200858 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200859 ++nr;
860 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300861 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300862 }
863
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300864 err = 0;
865out_elf_end:
866 elf_end(elf);
867out_close:
868 close(fd);
869
870 if (err == 0)
871 return nr;
872out:
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200873 pr_warning("%s: problems reading %s PLT info.\n",
874 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300875 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300876}
877
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200878static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
879{
880 switch (type) {
881 case MAP__FUNCTION:
882 return elf_sym__is_function(self);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200883 case MAP__VARIABLE:
884 return elf_sym__is_object(self);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200885 default:
886 return false;
887 }
888}
889
890static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
891{
892 switch (type) {
893 case MAP__FUNCTION:
894 return elf_sec__is_text(self, secstrs);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200895 case MAP__VARIABLE:
896 return elf_sec__is_data(self, secstrs);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200897 default:
898 return false;
899 }
900}
901
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200902static int dso__load_sym(struct dso *self, struct map *map, const char *name,
903 int fd, symbol_filter_t filter, int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300904{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200905 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300906 struct map *curr_map = map;
907 struct dso *curr_dso = self;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200908 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300909 uint32_t nr_syms;
910 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200911 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300912 GElf_Ehdr ehdr;
913 GElf_Shdr shdr;
914 Elf_Data *syms;
915 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300916 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300917 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300918 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300919
Marti Raudsepp84087122009-10-24 19:10:36 +0300920 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300921 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200922 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300923 goto out_close;
924 }
925
926 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200927 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300928 goto out_elf_end;
929 }
930
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300931 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
932 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300933 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
934 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300935 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300936 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300937
938 syms = elf_getdata(sec, NULL);
939 if (syms == NULL)
940 goto out_elf_end;
941
942 sec = elf_getscn(elf, shdr.sh_link);
943 if (sec == NULL)
944 goto out_elf_end;
945
946 symstrs = elf_getdata(sec, NULL);
947 if (symstrs == NULL)
948 goto out_elf_end;
949
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200950 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
951 if (sec_strndx == NULL)
952 goto out_elf_end;
953
954 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500955 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200956 goto out_elf_end;
957
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300958 nr_syms = shdr.sh_size / shdr.sh_entsize;
959
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200960 memset(&sym, 0, sizeof(sym));
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200961 if (!self->kernel) {
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200962 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300963 elf_section_by_name(elf, &ehdr, &shdr,
964 ".gnu.prelink_undo",
965 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200966 } else self->adjust_symbols = 0;
967
Ingo Molnar83a09442009-08-15 12:26:57 +0200968 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300969 struct symbol *f;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200970 const char *elf_name = elf_sym__name(&sym, symstrs);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300971 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200972 int is_label = elf_sym__is_label(&sym);
973 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300974
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200975 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
976 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
977 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200978
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200979 if (!is_label && !elf_sym__is_a(&sym, map->type))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300980 continue;
981
982 sec = elf_getscn(elf, sym.st_shndx);
983 if (!sec)
984 goto out_elf_end;
985
986 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200987
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200988 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200989 continue;
990
991 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200992
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200993 if (self->kernel || kmodule) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300994 char dso_name[PATH_MAX];
995
996 if (strcmp(section_name,
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300997 (curr_dso->short_name +
998 self->short_name_len)) == 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300999 goto new_symbol;
1000
1001 if (strcmp(section_name, ".text") == 0) {
1002 curr_map = map;
1003 curr_dso = self;
1004 goto new_symbol;
1005 }
1006
1007 snprintf(dso_name, sizeof(dso_name),
1008 "%s%s", self->short_name, section_name);
1009
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001010 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001011 if (curr_map == NULL) {
1012 u64 start = sym.st_value;
1013
1014 if (kmodule)
1015 start += map->start + shdr.sh_offset;
1016
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001017 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001018 if (curr_dso == NULL)
1019 goto out_elf_end;
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001020 curr_map = map__new2(start, curr_dso,
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001021 map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001022 if (curr_map == NULL) {
1023 dso__delete(curr_dso);
1024 goto out_elf_end;
1025 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001026 curr_map->map_ip = identity__map_ip;
1027 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001028 curr_dso->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001029 map_groups__insert(kmap->kmaps, curr_map);
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001030 dsos__add(&dsos__kernel, curr_dso);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001031 dso__set_loaded(curr_dso, map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001032 } else
1033 curr_dso = curr_map->dso;
1034
1035 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001036 }
1037
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001038 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -02001039 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1040 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1041 (u64)sym.st_value, (u64)shdr.sh_addr,
1042 (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001043 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001044 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001045 /*
1046 * We need to figure out if the object was created from C++ sources
1047 * DWARF DW_compile_unit has this, but we don't always have access
1048 * to it...
1049 */
Ingo Molnar83a09442009-08-15 12:26:57 +02001050 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001051 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +02001052 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001053new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001054 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001055 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001056 if (!f)
1057 goto out_elf_end;
1058
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001059 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001060 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001061 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001062 symbols__insert(&curr_dso->symbols[curr_map->type], f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001063 nr++;
1064 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001065 }
1066
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001067 /*
1068 * For misannotated, zeroed, ASM function sizes.
1069 */
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001070 if (nr > 0) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001071 symbols__fixup_end(&self->symbols[map->type]);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001072 if (kmap) {
1073 /*
1074 * We need to fixup this here too because we create new
1075 * maps here, for things like vsyscall sections.
1076 */
1077 __map_groups__fixup_end(kmap->kmaps, map->type);
1078 }
1079 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001080 err = nr;
1081out_elf_end:
1082 elf_end(elf);
1083out_close:
1084 return err;
1085}
1086
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001087static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1088{
1089 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1090}
1091
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001092static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001093{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001094 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001095 struct dso *pos;
1096
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001097 list_for_each_entry(pos, head, node) {
1098 if (with_hits && !pos->hit)
1099 continue;
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001100 if (filename__read_build_id(pos->long_name, pos->build_id,
1101 sizeof(pos->build_id)) > 0) {
1102 have_build_id = true;
1103 pos->has_build_id = true;
1104 }
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001105 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001106
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001107 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001108}
1109
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001110bool dsos__read_build_ids(bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001111{
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001112 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1113 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
Arnaldo Carvalho de Melo8b4825b2009-12-09 20:09:37 -02001114 return kbuildids || ubuildids;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001115}
1116
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001117/*
1118 * Align offset to 4 bytes as needed for note name and descriptor data.
1119 */
1120#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1121
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001122int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001123{
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001124 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001125 GElf_Ehdr ehdr;
1126 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001127 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001128 Elf_Scn *sec;
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001129 Elf_Kind ek;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001130 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001131 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001132
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001133 if (size < BUILD_ID_SIZE)
1134 goto out;
1135
1136 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001137 if (fd < 0)
1138 goto out;
1139
Marti Raudsepp84087122009-10-24 19:10:36 +03001140 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001141 if (elf == NULL) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001142 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001143 goto out_close;
1144 }
1145
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001146 ek = elf_kind(elf);
1147 if (ek != ELF_K_ELF)
1148 goto out_elf_end;
1149
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001150 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001151 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001152 goto out_elf_end;
1153 }
1154
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001155 sec = elf_section_by_name(elf, &ehdr, &shdr,
1156 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001157 if (sec == NULL) {
1158 sec = elf_section_by_name(elf, &ehdr, &shdr,
1159 ".notes", NULL);
1160 if (sec == NULL)
1161 goto out_elf_end;
1162 }
1163
1164 data = elf_getdata(sec, NULL);
1165 if (data == NULL)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001166 goto out_elf_end;
1167
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001168 ptr = data->d_buf;
1169 while (ptr < (data->d_buf + data->d_size)) {
1170 GElf_Nhdr *nhdr = ptr;
1171 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1172 descsz = NOTE_ALIGN(nhdr->n_descsz);
1173 const char *name;
1174
1175 ptr += sizeof(*nhdr);
1176 name = ptr;
1177 ptr += namesz;
1178 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1179 nhdr->n_namesz == sizeof("GNU")) {
1180 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1181 memcpy(bf, ptr, BUILD_ID_SIZE);
1182 err = BUILD_ID_SIZE;
1183 break;
1184 }
1185 }
1186 ptr += descsz;
1187 }
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001188out_elf_end:
1189 elf_end(elf);
1190out_close:
1191 close(fd);
1192out:
1193 return err;
1194}
1195
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001196int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1197{
1198 int fd, err = -1;
1199
1200 if (size < BUILD_ID_SIZE)
1201 goto out;
1202
1203 fd = open(filename, O_RDONLY);
1204 if (fd < 0)
1205 goto out;
1206
1207 while (1) {
1208 char bf[BUFSIZ];
1209 GElf_Nhdr nhdr;
1210 int namesz, descsz;
1211
1212 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1213 break;
1214
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001215 namesz = NOTE_ALIGN(nhdr.n_namesz);
1216 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001217 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1218 nhdr.n_namesz == sizeof("GNU")) {
1219 if (read(fd, bf, namesz) != namesz)
1220 break;
1221 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1222 if (read(fd, build_id,
1223 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1224 err = 0;
1225 break;
1226 }
1227 } else if (read(fd, bf, descsz) != descsz)
1228 break;
1229 } else {
1230 int n = namesz + descsz;
1231 if (read(fd, bf, n) != n)
1232 break;
1233 }
1234 }
1235 close(fd);
1236out:
1237 return err;
1238}
1239
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001240char dso__symtab_origin(const struct dso *self)
1241{
1242 static const char origin[] = {
1243 [DSO__ORIG_KERNEL] = 'k',
1244 [DSO__ORIG_JAVA_JIT] = 'j',
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001245 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001246 [DSO__ORIG_FEDORA] = 'f',
1247 [DSO__ORIG_UBUNTU] = 'u',
1248 [DSO__ORIG_BUILDID] = 'b',
1249 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001250 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001251 };
1252
1253 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
1254 return '!';
1255 return origin[self->origin];
1256}
1257
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001258int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001259{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001260 int size = PATH_MAX;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001261 char *name;
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001262 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001263 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001264 int ret = -1;
1265 int fd;
1266
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001267 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001268
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001269 if (self->kernel)
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001270 return dso__load_kernel_sym(self, map, filter);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001271
1272 name = malloc(size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001273 if (!name)
1274 return -1;
1275
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001276 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001277
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001278 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001279 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001280 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
1281 DSO__ORIG_NOT_FOUND;
1282 return ret;
1283 }
1284
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001285 self->origin = DSO__ORIG_BUILD_ID_CACHE;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001286
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001287 if (self->has_build_id) {
1288 build_id__sprintf(self->build_id, sizeof(self->build_id),
1289 build_id_hex);
1290 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1291 getenv("HOME"), DEBUG_CACHE_DIR,
1292 build_id_hex, build_id_hex + 2);
1293 goto open_file;
1294 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001295more:
1296 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001297 self->origin++;
1298 switch (self->origin) {
1299 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001300 snprintf(name, size, "/usr/lib/debug%s.debug",
1301 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001302 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001303 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001304 snprintf(name, size, "/usr/lib/debug%s",
1305 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001306 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001307 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001308 if (filename__read_build_id(self->long_name, build_id,
1309 sizeof(build_id))) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001310 build_id__sprintf(build_id, sizeof(build_id),
1311 build_id_hex);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001312 snprintf(name, size,
1313 "/usr/lib/debug/.build-id/%.2s/%s.debug",
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001314 build_id_hex, build_id_hex + 2);
1315 if (self->has_build_id)
1316 goto compare_build_id;
1317 break;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001318 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001319 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001320 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001321 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001322 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001323 break;
1324
1325 default:
1326 goto out;
1327 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001328
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001329 if (self->has_build_id) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001330 if (filename__read_build_id(name, build_id,
1331 sizeof(build_id)) < 0)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001332 goto more;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001333compare_build_id:
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001334 if (!dso__build_id_equal(self, build_id))
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001335 goto more;
1336 }
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001337open_file:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001338 fd = open(name, O_RDONLY);
1339 } while (fd < 0);
1340
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001341 ret = dso__load_sym(self, map, name, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001342 close(fd);
1343
1344 /*
1345 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
1346 */
1347 if (!ret)
1348 goto more;
1349
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001350 if (ret > 0) {
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001351 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001352 if (nr_plt > 0)
1353 ret += nr_plt;
1354 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001355out:
1356 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001357 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1358 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001359 return ret;
1360}
1361
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001362struct map *map_groups__find_by_name(struct map_groups *self,
1363 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001364{
1365 struct rb_node *nd;
1366
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001367 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001368 struct map *map = rb_entry(nd, struct map, rb_node);
1369
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001370 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001371 return map;
1372 }
1373
1374 return NULL;
1375}
1376
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001377static int dso__kernel_module_get_build_id(struct dso *self)
1378{
1379 char filename[PATH_MAX];
1380 /*
1381 * kernel module short names are of the form "[module]" and
1382 * we need just "module" here.
1383 */
1384 const char *name = self->short_name + 1;
1385
1386 snprintf(filename, sizeof(filename),
1387 "/sys/module/%.*s/notes/.note.gnu.build-id",
1388 (int)strlen(name - 1), name);
1389
1390 if (sysfs__read_build_id(filename, self->build_id,
1391 sizeof(self->build_id)) == 0)
1392 self->has_build_id = true;
1393
1394 return 0;
1395}
1396
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001397static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001398{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001399 struct dirent *dent;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001400 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001401
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001402 if (!dir) {
Arnaldo Carvalho de Melo87f8ea42009-11-22 13:21:41 -02001403 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001404 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001405 }
1406
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001407 while ((dent = readdir(dir)) != NULL) {
1408 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001409
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001410 if (dent->d_type == DT_DIR) {
1411 if (!strcmp(dent->d_name, ".") ||
1412 !strcmp(dent->d_name, ".."))
1413 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001414
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001415 snprintf(path, sizeof(path), "%s/%s",
1416 dirname, dent->d_name);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001417 if (map_groups__set_modules_path_dir(self, path) < 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001418 goto failure;
1419 } else {
1420 char *dot = strrchr(dent->d_name, '.'),
1421 dso_name[PATH_MAX];
1422 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001423 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001424
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001425 if (dot == NULL || strcmp(dot, ".ko"))
1426 continue;
1427 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1428 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001429
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001430 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001431 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001432 if (map == NULL)
1433 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001434
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001435 snprintf(path, sizeof(path), "%s/%s",
1436 dirname, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001437
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001438 long_name = strdup(path);
1439 if (long_name == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001440 goto failure;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001441 dso__set_long_name(map->dso, long_name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001442 dso__kernel_module_get_build_id(map->dso);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001443 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001444 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001445
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001446 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001447failure:
1448 closedir(dir);
1449 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001450}
1451
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001452static int map_groups__set_modules_path(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001453{
1454 struct utsname uts;
1455 char modules_path[PATH_MAX];
1456
1457 if (uname(&uts) < 0)
1458 return -1;
1459
1460 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1461 uts.release);
1462
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001463 return map_groups__set_modules_path_dir(self, modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001464}
1465
1466/*
1467 * Constructor variant for modules (where we know from /proc/modules where
1468 * they are loaded) and for vmlinux, where only after we load all the
1469 * symbols we'll know where it starts and ends.
1470 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001471static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001472{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001473 struct map *self = zalloc(sizeof(*self) +
1474 (dso->kernel ? sizeof(struct kmap) : 0));
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001475 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001476 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001477 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001478 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001479 map__init(self, type, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001480 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001481
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001482 return self;
1483}
1484
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001485struct map *map_groups__new_module(struct map_groups *self, u64 start,
1486 const char *filename)
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001487{
1488 struct map *map;
1489 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1490
1491 if (dso == NULL)
1492 return NULL;
1493
1494 map = map__new2(start, dso, MAP__FUNCTION);
1495 if (map == NULL)
1496 return NULL;
1497
1498 dso->origin = DSO__ORIG_KMODULE;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001499 map_groups__insert(self, map);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001500 return map;
1501}
1502
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001503static int map_groups__create_modules(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001504{
1505 char *line = NULL;
1506 size_t n;
1507 FILE *file = fopen("/proc/modules", "r");
1508 struct map *map;
1509
1510 if (file == NULL)
1511 return -1;
1512
1513 while (!feof(file)) {
1514 char name[PATH_MAX];
1515 u64 start;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001516 char *sep;
1517 int line_len;
1518
1519 line_len = getline(&line, &n, file);
1520 if (line_len < 0)
1521 break;
1522
1523 if (!line)
1524 goto out_failure;
1525
1526 line[--line_len] = '\0'; /* \n */
1527
1528 sep = strrchr(line, 'x');
1529 if (sep == NULL)
1530 continue;
1531
1532 hex2u64(sep + 1, &start);
1533
1534 sep = strchr(line, ' ');
1535 if (sep == NULL)
1536 continue;
1537
1538 *sep = '\0';
1539
1540 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001541 map = map_groups__new_module(self, start, name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001542 if (map == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001543 goto out_delete_line;
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001544 dso__kernel_module_get_build_id(map->dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001545 }
1546
1547 free(line);
1548 fclose(file);
1549
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001550 return map_groups__set_modules_path(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001551
1552out_delete_line:
1553 free(line);
1554out_failure:
1555 return -1;
1556}
1557
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -02001558static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001559 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001560{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001561 int err = -1, fd;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001562
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001563 if (self->has_build_id) {
1564 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001565
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001566 if (filename__read_build_id(vmlinux, build_id,
1567 sizeof(build_id)) < 0) {
1568 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1569 return -1;
1570 }
1571 if (!dso__build_id_equal(self, build_id)) {
1572 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1573 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1574
1575 build_id__sprintf(self->build_id,
1576 sizeof(self->build_id),
1577 expected_build_id);
1578 build_id__sprintf(build_id, sizeof(build_id),
1579 vmlinux_build_id);
1580 pr_debug("build_id in %s is %s while expected is %s, "
1581 "ignoring it\n", vmlinux, vmlinux_build_id,
1582 expected_build_id);
1583 return -1;
1584 }
1585 }
1586
1587 fd = open(vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001588 if (fd < 0)
1589 return -1;
1590
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001591 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001592 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001593 close(fd);
1594
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001595 if (err > 0)
1596 pr_debug("Using %s for symbols\n", vmlinux);
1597
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001598 return err;
1599}
1600
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001601int dso__load_vmlinux_path(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001602 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001603{
1604 int i, err = 0;
1605
1606 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1607 vmlinux_path__nr_entries);
1608
1609 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001610 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001611 if (err > 0) {
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001612 dso__set_long_name(self, strdup(vmlinux_path[i]));
1613 break;
1614 }
1615 }
1616
1617 return err;
1618}
1619
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001620static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001621 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001622{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001623 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001624 const char *kallsyms_filename = NULL;
1625 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001626 /*
1627 * Step 1: if the user specified a vmlinux filename, use it and only
1628 * it, reporting errors to the user if it cannot be used.
1629 *
1630 * For instance, try to analyse an ARM perf.data file _without_ a
1631 * build-id, or if the user specifies the wrong path to the right
1632 * vmlinux file, obviously we can't fallback to another vmlinux (a
1633 * x86_86 one, on the machine where analysis is being performed, say),
1634 * or worse, /proc/kallsyms.
1635 *
1636 * If the specified file _has_ a build-id and there is a build-id
1637 * section in the perf.data file, we will still do the expected
1638 * validation in dso__load_vmlinux and will bail out if they don't
1639 * match.
1640 */
1641 if (symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001642 err = dso__load_vmlinux(self, map,
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001643 symbol_conf.vmlinux_name, filter);
1644 goto out_try_fixup;
1645 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001646
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001647 if (vmlinux_path != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001648 err = dso__load_vmlinux_path(self, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001649 if (err > 0)
1650 goto out_fixup;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001651 }
1652
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001653 /*
1654 * Say the kernel DSO was created when processing the build-id header table,
1655 * we have a build-id, so check if it is the same as the running kernel,
1656 * using it if it is.
1657 */
1658 if (self->has_build_id) {
1659 u8 kallsyms_build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001660 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001661
1662 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001663 sizeof(kallsyms_build_id)) == 0) {
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001664 if (dso__build_id_equal(self, kallsyms_build_id)) {
1665 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001666 goto do_kallsyms;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001667 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001668 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001669 /*
1670 * Now look if we have it on the build-id cache in
1671 * $HOME/.debug/[kernel.kallsyms].
1672 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001673 build_id__sprintf(self->build_id, sizeof(self->build_id),
1674 sbuild_id);
1675
1676 if (asprintf(&kallsyms_allocated_filename,
1677 "%s/.debug/[kernel.kallsyms]/%s",
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001678 getenv("HOME"), sbuild_id) == -1) {
1679 pr_err("Not enough memory for kallsyms file lookup\n");
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001680 return -1;
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001681 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001682
Arnaldo Carvalho de Melo19fc2de2010-01-22 14:35:02 -02001683 kallsyms_filename = kallsyms_allocated_filename;
1684
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001685 if (access(kallsyms_filename, F_OK)) {
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001686 pr_err("No kallsyms or vmlinux with build-id %s "
1687 "was found\n", sbuild_id);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001688 free(kallsyms_allocated_filename);
1689 return -1;
1690 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001691 } else {
1692 /*
1693 * Last resort, if we don't have a build-id and couldn't find
1694 * any vmlinux file, try the running kernel kallsyms table.
1695 */
1696 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001697 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001698
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001699do_kallsyms:
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001700 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001701 if (err > 0)
1702 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001703 free(kallsyms_allocated_filename);
1704
1705out_try_fixup:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001706 if (err > 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001707out_fixup:
Arnaldo Carvalho de Meloe1c7c6a2010-01-22 14:35:01 -02001708 if (kallsyms_filename != NULL)
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001709 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001710 map__fixup_start(map);
1711 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001712 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001713
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001714 return err;
1715}
1716
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001717LIST_HEAD(dsos__user);
1718LIST_HEAD(dsos__kernel);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001719
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001720static void dsos__add(struct list_head *head, struct dso *dso)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001721{
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001722 list_add_tail(&dso->node, head);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001723}
1724
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001725static struct dso *dsos__find(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001726{
1727 struct dso *pos;
1728
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001729 list_for_each_entry(pos, head, node)
Arnaldo Carvalho de Melocf4e5b02010-01-14 23:45:27 -02001730 if (strcmp(pos->long_name, name) == 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001731 return pos;
1732 return NULL;
1733}
1734
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001735struct dso *__dsos__findnew(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001736{
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001737 struct dso *dso = dsos__find(head, name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001738
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001739 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001740 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001741 if (dso != NULL) {
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001742 dsos__add(head, dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001743 dso__set_basename(dso);
1744 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001745 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001746
1747 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001748}
1749
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001750static void __dsos__fprintf(struct list_head *head, FILE *fp)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001751{
1752 struct dso *pos;
1753
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001754 list_for_each_entry(pos, head, node) {
1755 int i;
1756 for (i = 0; i < MAP__NR_TYPES; ++i)
1757 dso__fprintf(pos, i, fp);
1758 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001759}
1760
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001761void dsos__fprintf(FILE *fp)
1762{
1763 __dsos__fprintf(&dsos__kernel, fp);
1764 __dsos__fprintf(&dsos__user, fp);
1765}
1766
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001767static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1768 bool with_hits)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001769{
1770 struct dso *pos;
1771 size_t ret = 0;
1772
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001773 list_for_each_entry(pos, head, node) {
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001774 if (with_hits && !pos->hit)
1775 continue;
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001776 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02001777 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001778 }
1779 return ret;
1780}
1781
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001782size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001783{
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001784 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1785 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001786}
1787
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001788struct dso *dso__new_kernel(const char *name)
1789{
1790 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1791
1792 if (self != NULL) {
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -03001793 dso__set_short_name(self, "[kernel]");
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001794 self->kernel = 1;
1795 }
1796
1797 return self;
1798}
1799
1800void dso__read_running_kernel_build_id(struct dso *self)
1801{
1802 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1803 sizeof(self->build_id)) == 0)
1804 self->has_build_id = true;
1805}
1806
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001807static struct dso *dsos__create_kernel(const char *vmlinux)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001808{
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001809 struct dso *kernel = dso__new_kernel(vmlinux);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001810
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -02001811 if (kernel != NULL) {
1812 dso__read_running_kernel_build_id(kernel);
1813 dsos__add(&dsos__kernel, kernel);
1814 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001815
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001816 return kernel;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001817}
1818
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001819int __map_groups__create_kernel_maps(struct map_groups *self,
1820 struct map *vmlinux_maps[MAP__NR_TYPES],
1821 struct dso *kernel)
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001822{
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001823 enum map_type type;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001824
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001825 for (type = 0; type < MAP__NR_TYPES; ++type) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001826 struct kmap *kmap;
1827
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001828 vmlinux_maps[type] = map__new2(0, kernel, type);
1829 if (vmlinux_maps[type] == NULL)
1830 return -1;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001831
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001832 vmlinux_maps[type]->map_ip =
1833 vmlinux_maps[type]->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001834
1835 kmap = map__kmap(vmlinux_maps[type]);
1836 kmap->kmaps = self;
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001837 map_groups__insert(self, vmlinux_maps[type]);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001838 }
1839
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001840 return 0;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001841}
1842
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001843static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001844{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001845 while (--vmlinux_path__nr_entries >= 0) {
1846 free(vmlinux_path[vmlinux_path__nr_entries]);
1847 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1848 }
1849
1850 free(vmlinux_path);
1851 vmlinux_path = NULL;
1852}
1853
1854static int vmlinux_path__init(void)
1855{
1856 struct utsname uts;
1857 char bf[PATH_MAX];
1858
1859 if (uname(&uts) < 0)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001860 return -1;
1861
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001862 vmlinux_path = malloc(sizeof(char *) * 5);
1863 if (vmlinux_path == NULL)
1864 return -1;
1865
1866 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1867 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1868 goto out_fail;
1869 ++vmlinux_path__nr_entries;
1870 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1871 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1872 goto out_fail;
1873 ++vmlinux_path__nr_entries;
1874 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1875 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1876 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1877 goto out_fail;
1878 ++vmlinux_path__nr_entries;
1879 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1880 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1881 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1882 goto out_fail;
1883 ++vmlinux_path__nr_entries;
1884 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1885 uts.release);
1886 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1887 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1888 goto out_fail;
1889 ++vmlinux_path__nr_entries;
1890
1891 return 0;
1892
1893out_fail:
1894 vmlinux_path__exit();
1895 return -1;
1896}
1897
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001898static int setup_list(struct strlist **list, const char *list_str,
1899 const char *list_name)
1900{
1901 if (list_str == NULL)
1902 return 0;
1903
1904 *list = strlist__new(true, list_str);
1905 if (!*list) {
1906 pr_err("problems parsing %s list\n", list_name);
1907 return -1;
1908 }
1909 return 0;
1910}
1911
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001912int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001913{
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001914 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001915 if (symbol_conf.sort_by_name)
1916 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1917 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001918
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001919 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001920 return -1;
1921
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001922 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1923 pr_err("'.' is the only non valid --field-separator argument\n");
1924 return -1;
1925 }
1926
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001927 if (setup_list(&symbol_conf.dso_list,
1928 symbol_conf.dso_list_str, "dso") < 0)
1929 return -1;
1930
1931 if (setup_list(&symbol_conf.comm_list,
1932 symbol_conf.comm_list_str, "comm") < 0)
1933 goto out_free_dso_list;
1934
1935 if (setup_list(&symbol_conf.sym_list,
1936 symbol_conf.sym_list_str, "symbol") < 0)
1937 goto out_free_comm_list;
1938
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001939 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001940
1941out_free_dso_list:
1942 strlist__delete(symbol_conf.dso_list);
1943out_free_comm_list:
1944 strlist__delete(symbol_conf.comm_list);
1945 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001946}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001947
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001948int map_groups__create_kernel_maps(struct map_groups *self,
1949 struct map *vmlinux_maps[MAP__NR_TYPES])
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001950{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001951 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1952
1953 if (kernel == NULL)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001954 return -1;
1955
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001956 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1957 return -1;
1958
1959 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
Arnaldo Carvalho de Melo10fe12e2010-02-20 19:53:13 -02001960 pr_debug("Problems creating module maps, continuing anyway...\n");
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -02001961 /*
1962 * Now that we have all the maps created, just set the ->end of them:
1963 */
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001964 map_groups__fixup_end(self);
Arnaldo Carvalho de Melo6671cb12009-11-20 20:51:24 -02001965 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001966}