blob: 292f941555a8beb1efe34af8f33544c1871a7b4b [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 Melob0da9542009-11-27 16:29:14 -020021static void dsos__add(struct list_head *head, struct dso *dso);
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020022static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020023static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020024 symbol_filter_t filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020025static int vmlinux_path__nr_entries;
26static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030027
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020028struct symbol_conf symbol_conf = {
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -020029 .exclude_other = true,
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020030 .use_modules = true,
31 .try_vmlinux_path = true,
32};
33
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020034bool dso__loaded(const struct dso *self, enum map_type type)
35{
36 return self->loaded & (1 << type);
37}
38
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020039bool dso__sorted_by_name(const struct dso *self, enum map_type type)
40{
41 return self->sorted_by_name & (1 << type);
42}
43
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020044static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
45{
46 self->sorted_by_name |= (1 << type);
47}
48
Arnaldo Carvalho de Melo36a3e642010-01-04 16:19:27 -020049bool symbol_type__is_a(char symbol_type, enum map_type map_type)
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020050{
51 switch (map_type) {
52 case MAP__FUNCTION:
53 return symbol_type == 'T' || symbol_type == 'W';
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -020054 case MAP__VARIABLE:
55 return symbol_type == 'D' || symbol_type == 'd';
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020056 default:
57 return false;
58 }
59}
60
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020061static void symbols__fixup_end(struct rb_root *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030062{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020063 struct rb_node *nd, *prevnd = rb_first(self);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030064 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030065
66 if (prevnd == NULL)
67 return;
68
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030069 curr = rb_entry(prevnd, struct symbol, rb_node);
70
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030071 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030072 prev = curr;
73 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030074
75 if (prev->end == prev->start)
76 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030077 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030078
79 /* Last entry */
80 if (curr->end == curr->start)
81 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030082}
83
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -020084static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030085{
86 struct map *prev, *curr;
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -020087 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030088
89 if (prevnd == NULL)
90 return;
91
92 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030093
94 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
95 prev = curr;
96 curr = rb_entry(nd, struct map, rb_node);
97 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030098 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -020099
100 /*
101 * We still haven't the actual symbols, so guess the
102 * last map final address.
103 */
104 curr->end = ~0UL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300105}
106
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200107static void map_groups__fixup_end(struct map_groups *self)
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200108{
109 int i;
110 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200111 __map_groups__fixup_end(self, i);
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200112}
113
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200114static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300115{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300116 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200117 struct symbol *self = zalloc(symbol_conf.priv_size +
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200118 sizeof(*self) + namelen);
119 if (self == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200120 return NULL;
121
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200122 if (symbol_conf.priv_size)
123 self = ((void *)self) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200124
Ingo Molnar0b73da32009-06-06 15:48:52 +0200125 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200126 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200127
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -0200128 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200129
Ingo Molnar0b73da32009-06-06 15:48:52 +0200130 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300131
132 return self;
133}
134
Arnaldo Carvalho de Melo628ada02010-02-25 12:57:40 -0300135void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300136{
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200137 free(((void *)self) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300138}
139
140static size_t symbol__fprintf(struct symbol *self, FILE *fp)
141{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300142 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300143 self->start, self->end, self->name);
144}
145
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200146void dso__set_long_name(struct dso *self, char *name)
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200147{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200148 if (name == NULL)
149 return;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200150 self->long_name = name;
151 self->long_name_len = strlen(name);
152}
153
154static void dso__set_basename(struct dso *self)
155{
156 self->short_name = basename(self->long_name);
157}
158
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200159struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300160{
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200161 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300162
163 if (self != NULL) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200164 int i;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300165 strcpy(self->name, name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200166 dso__set_long_name(self, self->name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300167 self->short_name = self->name;
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200168 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200169 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300170 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300171 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200172 self->loaded = 0;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200173 self->sorted_by_name = 0;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200174 self->has_build_id = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300175 }
176
177 return self;
178}
179
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200180static void symbols__delete(struct rb_root *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300181{
182 struct symbol *pos;
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200183 struct rb_node *next = rb_first(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300184
185 while (next) {
186 pos = rb_entry(next, struct symbol, rb_node);
187 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200188 rb_erase(&pos->rb_node, self);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200189 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300190 }
191}
192
193void dso__delete(struct dso *self)
194{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200195 int i;
196 for (i = 0; i < MAP__NR_TYPES; ++i)
197 symbols__delete(&self->symbols[i]);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300198 if (self->long_name != self->name)
199 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300200 free(self);
201}
202
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200203void dso__set_build_id(struct dso *self, void *build_id)
204{
205 memcpy(self->build_id, build_id, sizeof(self->build_id));
206 self->has_build_id = 1;
207}
208
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200209static void symbols__insert(struct rb_root *self, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300210{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200211 struct rb_node **p = &self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300212 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000213 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300214 struct symbol *s;
215
216 while (*p != NULL) {
217 parent = *p;
218 s = rb_entry(parent, struct symbol, rb_node);
219 if (ip < s->start)
220 p = &(*p)->rb_left;
221 else
222 p = &(*p)->rb_right;
223 }
224 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200225 rb_insert_color(&sym->rb_node, self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300226}
227
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200228static struct symbol *symbols__find(struct rb_root *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300229{
230 struct rb_node *n;
231
232 if (self == NULL)
233 return NULL;
234
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200235 n = self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300236
237 while (n) {
238 struct symbol *s = rb_entry(n, struct symbol, rb_node);
239
240 if (ip < s->start)
241 n = n->rb_left;
242 else if (ip > s->end)
243 n = n->rb_right;
244 else
245 return s;
246 }
247
248 return NULL;
249}
250
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200251struct symbol_name_rb_node {
252 struct rb_node rb_node;
253 struct symbol sym;
254};
255
256static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
257{
258 struct rb_node **p = &self->rb_node;
259 struct rb_node *parent = NULL;
260 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
261
262 while (*p != NULL) {
263 parent = *p;
264 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
265 if (strcmp(sym->name, s->sym.name) < 0)
266 p = &(*p)->rb_left;
267 else
268 p = &(*p)->rb_right;
269 }
270 rb_link_node(&symn->rb_node, parent, p);
271 rb_insert_color(&symn->rb_node, self);
272}
273
274static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
275{
276 struct rb_node *nd;
277
278 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
279 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
280 symbols__insert_by_name(self, pos);
281 }
282}
283
284static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
285{
286 struct rb_node *n;
287
288 if (self == NULL)
289 return NULL;
290
291 n = self->rb_node;
292
293 while (n) {
294 struct symbol_name_rb_node *s;
295 int cmp;
296
297 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
298 cmp = strcmp(name, s->sym.name);
299
300 if (cmp < 0)
301 n = n->rb_left;
302 else if (cmp > 0)
303 n = n->rb_right;
304 else
305 return &s->sym;
306 }
307
308 return NULL;
309}
310
311struct symbol *dso__find_symbol(struct dso *self,
312 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200313{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200314 return symbols__find(&self->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200315}
316
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200317struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
318 const char *name)
319{
320 return symbols__find_by_name(&self->symbol_names[type], name);
321}
322
323void dso__sort_by_name(struct dso *self, enum map_type type)
324{
325 dso__set_sorted_by_name(self, type);
326 return symbols__sort_by_name(&self->symbol_names[type],
327 &self->symbols[type]);
328}
329
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200330int build_id__sprintf(const u8 *self, int len, char *bf)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200331{
332 char *bid = bf;
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200333 const u8 *raw = self;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200334 int i;
335
336 for (i = 0; i < len; ++i) {
337 sprintf(bid, "%02x", *raw);
338 ++raw;
339 bid += 2;
340 }
341
342 return raw - self;
343}
344
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200345size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300346{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200347 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200348
349 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200350 return fprintf(fp, "%s", sbuild_id);
351}
352
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200353size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200354{
355 struct rb_node *nd;
356 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
357
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -0300358 if (self->short_name != self->long_name)
359 ret += fprintf(fp, "%s, ", self->long_name);
360 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
361 self->loaded ? "" : "NOT ");
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200362 ret += dso__fprintf_buildid(self, fp);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200363 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200364 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
365 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
366 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300367 }
368
369 return ret;
370}
371
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200372int kallsyms__parse(const char *filename, void *arg,
373 int (*process_symbol)(void *arg, const char *name,
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200374 char type, u64 start))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300375{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300376 char *line = NULL;
377 size_t n;
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200378 int err = 0;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200379 FILE *file = fopen(filename, "r");
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300380
381 if (file == NULL)
382 goto out_failure;
383
384 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000385 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300386 int line_len, len;
387 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300388 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300389
390 line_len = getline(&line, &n, file);
391 if (line_len < 0)
392 break;
393
394 if (!line)
395 goto out_failure;
396
397 line[--line_len] = '\0'; /* \n */
398
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300399 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300400
401 len++;
402 if (len + 2 >= line_len)
403 continue;
404
405 symbol_type = toupper(line[len]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300406 symbol_name = line + len + 2;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300407
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200408 err = process_symbol(arg, symbol_name, symbol_type, start);
409 if (err)
410 break;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300411 }
412
413 free(line);
414 fclose(file);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200415 return err;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300416
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300417out_failure:
418 return -1;
419}
420
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200421struct process_kallsyms_args {
422 struct map *map;
423 struct dso *dso;
424};
425
426static int map__process_kallsym_symbol(void *arg, const char *name,
427 char type, u64 start)
428{
429 struct symbol *sym;
430 struct process_kallsyms_args *a = arg;
431 struct rb_root *root = &a->dso->symbols[a->map->type];
432
433 if (!symbol_type__is_a(type, a->map->type))
434 return 0;
435
436 /*
437 * Will fix up the end later, when we have all symbols sorted.
438 */
439 sym = symbol__new(start, 0, name);
440
441 if (sym == NULL)
442 return -ENOMEM;
443 /*
444 * We will pass the symbols to the filter later, in
445 * map__split_kallsyms, when we have split the maps per module
446 */
447 symbols__insert(root, sym);
448 return 0;
449}
450
451/*
452 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
453 * so that we can in the next step set the symbol ->end address and then
454 * call kernel_maps__split_kallsyms.
455 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200456static int dso__load_all_kallsyms(struct dso *self, const char *filename,
457 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200458{
459 struct process_kallsyms_args args = { .map = map, .dso = self, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200460 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200461}
462
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300463/*
464 * Split the symbols into maps, making sure there are no overlaps, i.e. the
465 * kernel range is broken in several maps, named [kernel].N, as we don't have
466 * the original ELF section names vmlinux have.
467 */
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200468static int dso__split_kallsyms(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200469 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300470{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200471 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200472 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300473 struct symbol *pos;
474 int count = 0;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200475 struct rb_root *root = &self->symbols[map->type];
476 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300477 int kernel_range = 0;
478
479 while (next) {
480 char *module;
481
482 pos = rb_entry(next, struct symbol, rb_node);
483 next = rb_next(&pos->rb_node);
484
485 module = strchr(pos->name, '\t');
486 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200487 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200488 goto discard_symbol;
489
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300490 *module++ = '\0';
491
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200492 if (strcmp(curr_map->dso->short_name, module)) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200493 curr_map = map_groups__find_by_name(kmaps, map->type, module);
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200494 if (curr_map == NULL) {
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200495 pr_debug("/proc/{kallsyms,modules} "
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200496 "inconsistency while looking "
497 "for \"%s\" module!\n", module);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300498 return -1;
499 }
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -0200500
501 if (curr_map->dso->loaded)
502 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300503 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300504 /*
505 * So that we look just like we get from .ko files,
506 * i.e. not prelinked, relative to map->start.
507 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200508 pos->start = curr_map->map_ip(curr_map, pos->start);
509 pos->end = curr_map->map_ip(curr_map, pos->end);
510 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300511 char dso_name[PATH_MAX];
512 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300513
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300514 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
515 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300516
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200517 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300518 if (dso == NULL)
519 return -1;
520
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200521 curr_map = map__new2(pos->start, dso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800522 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300523 dso__delete(dso);
524 return -1;
525 }
526
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200527 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200528 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300529 ++kernel_range;
530 }
531
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200532 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200533discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200534 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300535 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200536 if (curr_map != map) {
537 rb_erase(&pos->rb_node, root);
538 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300539 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200540 count++;
541 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300542 }
543
Mike Galbraith9974f492009-07-02 08:05:58 +0200544 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300545}
546
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200547int dso__load_kallsyms(struct dso *self, const char *filename,
548 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300549{
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200550 if (dso__load_all_kallsyms(self, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300551 return -1;
552
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200553 symbols__fixup_end(&self->symbols[map->type]);
554 self->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300555
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200556 return dso__split_kallsyms(self, map, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300557}
558
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300559static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200560 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300561{
562 char *line = NULL;
563 size_t n;
564 FILE *file;
565 int nr_syms = 0;
566
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300567 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300568 if (file == NULL)
569 goto out_failure;
570
571 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000572 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300573 struct symbol *sym;
574 int line_len, len;
575
576 line_len = getline(&line, &n, file);
577 if (line_len < 0)
578 break;
579
580 if (!line)
581 goto out_failure;
582
583 line[--line_len] = '\0'; /* \n */
584
585 len = hex2u64(line, &start);
586
587 len++;
588 if (len + 2 >= line_len)
589 continue;
590
591 len += hex2u64(line + len, &size);
592
593 len++;
594 if (len + 2 >= line_len)
595 continue;
596
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200597 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300598
599 if (sym == NULL)
600 goto out_delete_line;
601
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300602 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200603 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300604 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200605 symbols__insert(&self->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300606 nr_syms++;
607 }
608 }
609
610 free(line);
611 fclose(file);
612
613 return nr_syms;
614
615out_delete_line:
616 free(line);
617out_failure:
618 return -1;
619}
620
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300621/**
622 * elf_symtab__for_each_symbol - iterate thru all the symbols
623 *
624 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200625 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300626 * @sym: GElf_Sym iterator
627 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200628#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
629 for (idx = 0, gelf_getsym(syms, idx, &sym);\
630 idx < nr_syms; \
631 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300632
633static inline uint8_t elf_sym__type(const GElf_Sym *sym)
634{
635 return GELF_ST_TYPE(sym->st_info);
636}
637
638static inline int elf_sym__is_function(const GElf_Sym *sym)
639{
640 return elf_sym__type(sym) == STT_FUNC &&
641 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300642 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300643}
644
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200645static inline bool elf_sym__is_object(const GElf_Sym *sym)
646{
647 return elf_sym__type(sym) == STT_OBJECT &&
648 sym->st_name != 0 &&
649 sym->st_shndx != SHN_UNDEF;
650}
651
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200652static inline int elf_sym__is_label(const GElf_Sym *sym)
653{
654 return elf_sym__type(sym) == STT_NOTYPE &&
655 sym->st_name != 0 &&
656 sym->st_shndx != SHN_UNDEF &&
657 sym->st_shndx != SHN_ABS;
658}
659
660static inline const char *elf_sec__name(const GElf_Shdr *shdr,
661 const Elf_Data *secstrs)
662{
663 return secstrs->d_buf + shdr->sh_name;
664}
665
666static inline int elf_sec__is_text(const GElf_Shdr *shdr,
667 const Elf_Data *secstrs)
668{
669 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
670}
671
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200672static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
673 const Elf_Data *secstrs)
674{
675 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
676}
677
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300678static inline const char *elf_sym__name(const GElf_Sym *sym,
679 const Elf_Data *symstrs)
680{
681 return symstrs->d_buf + sym->st_name;
682}
683
684static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
685 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200686 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300687{
688 Elf_Scn *sec = NULL;
689 size_t cnt = 1;
690
691 while ((sec = elf_nextscn(elf, sec)) != NULL) {
692 char *str;
693
694 gelf_getshdr(sec, shp);
695 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
696 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200697 if (idx)
698 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300699 break;
700 }
701 ++cnt;
702 }
703
704 return sec;
705}
706
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300707#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
708 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
709 idx < nr_entries; \
710 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
711
712#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
713 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
714 idx < nr_entries; \
715 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
716
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300717/*
718 * We need to check if we have a .dynsym, so that we can handle the
719 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
720 * .dynsym or .symtab).
721 * And always look at the original dso, not at debuginfo packages, that
722 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
723 */
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200724static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
725 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300726{
727 uint32_t nr_rel_entries, idx;
728 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000729 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300730 GElf_Shdr shdr_plt;
731 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300732 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300733 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300734 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
735 size_t dynsym_idx;
736 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300737 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300738 Elf *elf;
739 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300740
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300741 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300742 if (fd < 0)
743 goto out;
744
Marti Raudsepp84087122009-10-24 19:10:36 +0300745 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300746 if (elf == NULL)
747 goto out_close;
748
749 if (gelf_getehdr(elf, &ehdr) == NULL)
750 goto out_elf_end;
751
752 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
753 ".dynsym", &dynsym_idx);
754 if (scn_dynsym == NULL)
755 goto out_elf_end;
756
757 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300758 ".rela.plt", NULL);
759 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300760 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300761 ".rel.plt", NULL);
762 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300763 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300764 }
765
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300766 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300767
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300768 if (shdr_rel_plt.sh_link != dynsym_idx)
769 goto out_elf_end;
770
771 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
772 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300773
774 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200775 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300776 * and the symbols in the .dynsym they refer to.
777 */
778 reldata = elf_getdata(scn_plt_rel, NULL);
779 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300780 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300781
782 syms = elf_getdata(scn_dynsym, NULL);
783 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300784 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300785
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300786 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300787 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300788 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300789
790 symstrs = elf_getdata(scn_symstrs, NULL);
791 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300792 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300793
794 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
795 plt_offset = shdr_plt.sh_offset;
796
797 if (shdr_rel_plt.sh_type == SHT_RELA) {
798 GElf_Rela pos_mem, *pos;
799
800 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
801 nr_rel_entries) {
802 symidx = GELF_R_SYM(pos->r_info);
803 plt_offset += shdr_plt.sh_entsize;
804 gelf_getsym(syms, symidx, &sym);
805 snprintf(sympltname, sizeof(sympltname),
806 "%s@plt", elf_sym__name(&sym, symstrs));
807
808 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200809 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300810 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300811 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300812
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200813 if (filter && filter(map, f))
814 symbol__delete(f);
815 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200816 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200817 ++nr;
818 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300819 }
820 } else if (shdr_rel_plt.sh_type == SHT_REL) {
821 GElf_Rel pos_mem, *pos;
822 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
823 nr_rel_entries) {
824 symidx = GELF_R_SYM(pos->r_info);
825 plt_offset += shdr_plt.sh_entsize;
826 gelf_getsym(syms, symidx, &sym);
827 snprintf(sympltname, sizeof(sympltname),
828 "%s@plt", elf_sym__name(&sym, symstrs));
829
830 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200831 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300832 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300833 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300834
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200835 if (filter && filter(map, f))
836 symbol__delete(f);
837 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200838 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200839 ++nr;
840 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300841 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300842 }
843
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300844 err = 0;
845out_elf_end:
846 elf_end(elf);
847out_close:
848 close(fd);
849
850 if (err == 0)
851 return nr;
852out:
Arnaldo Carvalho de Melofe2197b2010-03-11 20:12:40 -0300853 pr_debug("%s: problems reading %s PLT info.\n",
854 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300855 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300856}
857
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200858static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
859{
860 switch (type) {
861 case MAP__FUNCTION:
862 return elf_sym__is_function(self);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200863 case MAP__VARIABLE:
864 return elf_sym__is_object(self);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200865 default:
866 return false;
867 }
868}
869
870static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
871{
872 switch (type) {
873 case MAP__FUNCTION:
874 return elf_sec__is_text(self, secstrs);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200875 case MAP__VARIABLE:
876 return elf_sec__is_data(self, secstrs);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200877 default:
878 return false;
879 }
880}
881
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200882static int dso__load_sym(struct dso *self, struct map *map, const char *name,
883 int fd, symbol_filter_t filter, int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300884{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200885 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300886 struct map *curr_map = map;
887 struct dso *curr_dso = self;
888 size_t dso_name_len = strlen(self->short_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200889 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300890 uint32_t nr_syms;
891 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200892 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300893 GElf_Ehdr ehdr;
894 GElf_Shdr shdr;
895 Elf_Data *syms;
896 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300897 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300898 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300899 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300900
Marti Raudsepp84087122009-10-24 19:10:36 +0300901 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300902 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200903 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300904 goto out_close;
905 }
906
907 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200908 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300909 goto out_elf_end;
910 }
911
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300912 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
913 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300914 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
915 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300916 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300917 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300918
919 syms = elf_getdata(sec, NULL);
920 if (syms == NULL)
921 goto out_elf_end;
922
923 sec = elf_getscn(elf, shdr.sh_link);
924 if (sec == NULL)
925 goto out_elf_end;
926
927 symstrs = elf_getdata(sec, NULL);
928 if (symstrs == NULL)
929 goto out_elf_end;
930
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200931 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
932 if (sec_strndx == NULL)
933 goto out_elf_end;
934
935 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500936 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200937 goto out_elf_end;
938
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300939 nr_syms = shdr.sh_size / shdr.sh_entsize;
940
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200941 memset(&sym, 0, sizeof(sym));
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200942 if (!self->kernel) {
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200943 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300944 elf_section_by_name(elf, &ehdr, &shdr,
945 ".gnu.prelink_undo",
946 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200947 } else self->adjust_symbols = 0;
948
Ingo Molnar83a09442009-08-15 12:26:57 +0200949 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300950 struct symbol *f;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200951 const char *elf_name = elf_sym__name(&sym, symstrs);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300952 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200953 int is_label = elf_sym__is_label(&sym);
954 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300955
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200956 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
957 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
958 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200959
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200960 if (!is_label && !elf_sym__is_a(&sym, map->type))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300961 continue;
962
963 sec = elf_getscn(elf, sym.st_shndx);
964 if (!sec)
965 goto out_elf_end;
966
967 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200968
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200969 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200970 continue;
971
972 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200973
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200974 if (self->kernel || kmodule) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300975 char dso_name[PATH_MAX];
976
977 if (strcmp(section_name,
978 curr_dso->short_name + dso_name_len) == 0)
979 goto new_symbol;
980
981 if (strcmp(section_name, ".text") == 0) {
982 curr_map = map;
983 curr_dso = self;
984 goto new_symbol;
985 }
986
987 snprintf(dso_name, sizeof(dso_name),
988 "%s%s", self->short_name, section_name);
989
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200990 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300991 if (curr_map == NULL) {
992 u64 start = sym.st_value;
993
994 if (kmodule)
995 start += map->start + shdr.sh_offset;
996
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200997 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300998 if (curr_dso == NULL)
999 goto out_elf_end;
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001000 curr_map = map__new2(start, curr_dso,
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001001 map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001002 if (curr_map == NULL) {
1003 dso__delete(curr_dso);
1004 goto out_elf_end;
1005 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001006 curr_map->map_ip = identity__map_ip;
1007 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001008 curr_dso->origin = self->origin;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001009 map_groups__insert(kmap->kmaps, curr_map);
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001010 dsos__add(&dsos__kernel, curr_dso);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001011 dso__set_loaded(curr_dso, map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001012 } else
1013 curr_dso = curr_map->dso;
1014
1015 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001016 }
1017
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001018 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -02001019 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1020 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1021 (u64)sym.st_value, (u64)shdr.sh_addr,
1022 (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001023 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001024 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001025 /*
1026 * We need to figure out if the object was created from C++ sources
1027 * DWARF DW_compile_unit has this, but we don't always have access
1028 * to it...
1029 */
Ingo Molnar83a09442009-08-15 12:26:57 +02001030 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001031 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +02001032 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001033new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001034 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001035 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001036 if (!f)
1037 goto out_elf_end;
1038
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001039 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001040 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001041 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001042 symbols__insert(&curr_dso->symbols[curr_map->type], f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001043 nr++;
1044 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001045 }
1046
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001047 /*
1048 * For misannotated, zeroed, ASM function sizes.
1049 */
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001050 if (nr > 0) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001051 symbols__fixup_end(&self->symbols[map->type]);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001052 if (kmap) {
1053 /*
1054 * We need to fixup this here too because we create new
1055 * maps here, for things like vsyscall sections.
1056 */
1057 __map_groups__fixup_end(kmap->kmaps, map->type);
1058 }
1059 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001060 err = nr;
1061out_elf_end:
1062 elf_end(elf);
1063out_close:
1064 return err;
1065}
1066
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001067static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1068{
1069 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1070}
1071
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001072static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001073{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001074 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001075 struct dso *pos;
1076
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001077 list_for_each_entry(pos, head, node) {
1078 if (with_hits && !pos->hit)
1079 continue;
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001080 if (filename__read_build_id(pos->long_name, pos->build_id,
1081 sizeof(pos->build_id)) > 0) {
1082 have_build_id = true;
1083 pos->has_build_id = true;
1084 }
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001085 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001086
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001087 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001088}
1089
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001090bool dsos__read_build_ids(bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001091{
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001092 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1093 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
Arnaldo Carvalho de Melo8b4825b2009-12-09 20:09:37 -02001094 return kbuildids || ubuildids;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001095}
1096
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001097/*
1098 * Align offset to 4 bytes as needed for note name and descriptor data.
1099 */
1100#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1101
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -02001102int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001103{
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -02001104 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001105 GElf_Ehdr ehdr;
1106 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001107 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001108 Elf_Scn *sec;
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001109 Elf_Kind ek;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001110 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001111 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001112
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -02001113 if (size < BUILD_ID_SIZE)
1114 goto out;
1115
1116 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001117 if (fd < 0)
1118 goto out;
1119
Marti Raudsepp84087122009-10-24 19:10:36 +03001120 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001121 if (elf == NULL) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001122 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001123 goto out_close;
1124 }
1125
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001126 ek = elf_kind(elf);
1127 if (ek != ELF_K_ELF)
1128 goto out_elf_end;
1129
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001130 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001131 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001132 goto out_elf_end;
1133 }
1134
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -02001135 sec = elf_section_by_name(elf, &ehdr, &shdr,
1136 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001137 if (sec == NULL) {
1138 sec = elf_section_by_name(elf, &ehdr, &shdr,
1139 ".notes", NULL);
1140 if (sec == NULL)
1141 goto out_elf_end;
1142 }
1143
1144 data = elf_getdata(sec, NULL);
1145 if (data == NULL)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001146 goto out_elf_end;
1147
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001148 ptr = data->d_buf;
1149 while (ptr < (data->d_buf + data->d_size)) {
1150 GElf_Nhdr *nhdr = ptr;
1151 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1152 descsz = NOTE_ALIGN(nhdr->n_descsz);
1153 const char *name;
1154
1155 ptr += sizeof(*nhdr);
1156 name = ptr;
1157 ptr += namesz;
1158 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1159 nhdr->n_namesz == sizeof("GNU")) {
1160 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1161 memcpy(bf, ptr, BUILD_ID_SIZE);
1162 err = BUILD_ID_SIZE;
1163 break;
1164 }
1165 }
1166 ptr += descsz;
1167 }
Arnaldo Carvalho de Melo2643ce1142009-11-03 21:46:10 -02001168out_elf_end:
1169 elf_end(elf);
1170out_close:
1171 close(fd);
1172out:
1173 return err;
1174}
1175
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001176int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1177{
1178 int fd, err = -1;
1179
1180 if (size < BUILD_ID_SIZE)
1181 goto out;
1182
1183 fd = open(filename, O_RDONLY);
1184 if (fd < 0)
1185 goto out;
1186
1187 while (1) {
1188 char bf[BUFSIZ];
1189 GElf_Nhdr nhdr;
1190 int namesz, descsz;
1191
1192 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1193 break;
1194
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001195 namesz = NOTE_ALIGN(nhdr.n_namesz);
1196 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001197 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1198 nhdr.n_namesz == sizeof("GNU")) {
1199 if (read(fd, bf, namesz) != namesz)
1200 break;
1201 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1202 if (read(fd, build_id,
1203 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1204 err = 0;
1205 break;
1206 }
1207 } else if (read(fd, bf, descsz) != descsz)
1208 break;
1209 } else {
1210 int n = namesz + descsz;
1211 if (read(fd, bf, n) != n)
1212 break;
1213 }
1214 }
1215 close(fd);
1216out:
1217 return err;
1218}
1219
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001220char dso__symtab_origin(const struct dso *self)
1221{
1222 static const char origin[] = {
1223 [DSO__ORIG_KERNEL] = 'k',
1224 [DSO__ORIG_JAVA_JIT] = 'j',
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001225 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001226 [DSO__ORIG_FEDORA] = 'f',
1227 [DSO__ORIG_UBUNTU] = 'u',
1228 [DSO__ORIG_BUILDID] = 'b',
1229 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001230 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001231 };
1232
1233 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
1234 return '!';
1235 return origin[self->origin];
1236}
1237
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001238int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001239{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001240 int size = PATH_MAX;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001241 char *name;
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001242 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001243 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001244 int ret = -1;
1245 int fd;
1246
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001247 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001248
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001249 if (self->kernel)
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001250 return dso__load_kernel_sym(self, map, filter);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001251
1252 name = malloc(size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001253 if (!name)
1254 return -1;
1255
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001256 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001257
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001258 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001259 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001260 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
1261 DSO__ORIG_NOT_FOUND;
1262 return ret;
1263 }
1264
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001265 self->origin = DSO__ORIG_BUILD_ID_CACHE;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001266
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001267 if (self->has_build_id) {
1268 build_id__sprintf(self->build_id, sizeof(self->build_id),
1269 build_id_hex);
1270 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1271 getenv("HOME"), DEBUG_CACHE_DIR,
1272 build_id_hex, build_id_hex + 2);
1273 goto open_file;
1274 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001275more:
1276 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001277 self->origin++;
1278 switch (self->origin) {
1279 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001280 snprintf(name, size, "/usr/lib/debug%s.debug",
1281 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001282 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001283 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001284 snprintf(name, size, "/usr/lib/debug%s",
1285 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001286 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001287 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001288 if (filename__read_build_id(self->long_name, build_id,
1289 sizeof(build_id))) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001290 build_id__sprintf(build_id, sizeof(build_id),
1291 build_id_hex);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001292 snprintf(name, size,
1293 "/usr/lib/debug/.build-id/%.2s/%s.debug",
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001294 build_id_hex, build_id_hex + 2);
1295 if (self->has_build_id)
1296 goto compare_build_id;
1297 break;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001298 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001299 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001300 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001301 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001302 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001303 break;
1304
1305 default:
1306 goto out;
1307 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001308
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001309 if (self->has_build_id) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001310 if (filename__read_build_id(name, build_id,
1311 sizeof(build_id)) < 0)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001312 goto more;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001313compare_build_id:
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001314 if (!dso__build_id_equal(self, build_id))
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001315 goto more;
1316 }
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001317open_file:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001318 fd = open(name, O_RDONLY);
1319 } while (fd < 0);
1320
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001321 ret = dso__load_sym(self, map, name, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001322 close(fd);
1323
1324 /*
1325 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
1326 */
1327 if (!ret)
1328 goto more;
1329
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001330 if (ret > 0) {
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001331 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001332 if (nr_plt > 0)
1333 ret += nr_plt;
1334 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001335out:
1336 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001337 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1338 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001339 return ret;
1340}
1341
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001342struct map *map_groups__find_by_name(struct map_groups *self,
1343 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001344{
1345 struct rb_node *nd;
1346
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001347 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001348 struct map *map = rb_entry(nd, struct map, rb_node);
1349
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001350 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001351 return map;
1352 }
1353
1354 return NULL;
1355}
1356
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001357static int dso__kernel_module_get_build_id(struct dso *self)
1358{
1359 char filename[PATH_MAX];
1360 /*
1361 * kernel module short names are of the form "[module]" and
1362 * we need just "module" here.
1363 */
1364 const char *name = self->short_name + 1;
1365
1366 snprintf(filename, sizeof(filename),
1367 "/sys/module/%.*s/notes/.note.gnu.build-id",
1368 (int)strlen(name - 1), name);
1369
1370 if (sysfs__read_build_id(filename, self->build_id,
1371 sizeof(self->build_id)) == 0)
1372 self->has_build_id = true;
1373
1374 return 0;
1375}
1376
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001377static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001378{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001379 struct dirent *dent;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001380 DIR *dir = opendir(dirname);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001381
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001382 if (!dir) {
Arnaldo Carvalho de Melo87f8ea42009-11-22 13:21:41 -02001383 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001384 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001385 }
1386
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001387 while ((dent = readdir(dir)) != NULL) {
1388 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001389
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001390 if (dent->d_type == DT_DIR) {
1391 if (!strcmp(dent->d_name, ".") ||
1392 !strcmp(dent->d_name, ".."))
1393 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001394
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001395 snprintf(path, sizeof(path), "%s/%s",
1396 dirname, dent->d_name);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001397 if (map_groups__set_modules_path_dir(self, path) < 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001398 goto failure;
1399 } else {
1400 char *dot = strrchr(dent->d_name, '.'),
1401 dso_name[PATH_MAX];
1402 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001403 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001404
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001405 if (dot == NULL || strcmp(dot, ".ko"))
1406 continue;
1407 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1408 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001409
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001410 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001411 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001412 if (map == NULL)
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);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001417
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001418 long_name = strdup(path);
1419 if (long_name == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001420 goto failure;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001421 dso__set_long_name(map->dso, long_name);
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001422 dso__kernel_module_get_build_id(map->dso);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001423 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001424 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001425
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001426 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001427failure:
1428 closedir(dir);
1429 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001430}
1431
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001432static int map_groups__set_modules_path(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001433{
1434 struct utsname uts;
1435 char modules_path[PATH_MAX];
1436
1437 if (uname(&uts) < 0)
1438 return -1;
1439
1440 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1441 uts.release);
1442
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001443 return map_groups__set_modules_path_dir(self, modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001444}
1445
1446/*
1447 * Constructor variant for modules (where we know from /proc/modules where
1448 * they are loaded) and for vmlinux, where only after we load all the
1449 * symbols we'll know where it starts and ends.
1450 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001451static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001452{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001453 struct map *self = zalloc(sizeof(*self) +
1454 (dso->kernel ? sizeof(struct kmap) : 0));
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001455 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001456 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001457 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001458 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001459 map__init(self, type, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001460 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001461
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001462 return self;
1463}
1464
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001465struct map *map_groups__new_module(struct map_groups *self, u64 start,
1466 const char *filename)
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001467{
1468 struct map *map;
1469 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1470
1471 if (dso == NULL)
1472 return NULL;
1473
1474 map = map__new2(start, dso, MAP__FUNCTION);
1475 if (map == NULL)
1476 return NULL;
1477
1478 dso->origin = DSO__ORIG_KMODULE;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001479 map_groups__insert(self, map);
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001480 return map;
1481}
1482
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001483static int map_groups__create_modules(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001484{
1485 char *line = NULL;
1486 size_t n;
1487 FILE *file = fopen("/proc/modules", "r");
1488 struct map *map;
1489
1490 if (file == NULL)
1491 return -1;
1492
1493 while (!feof(file)) {
1494 char name[PATH_MAX];
1495 u64 start;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001496 char *sep;
1497 int line_len;
1498
1499 line_len = getline(&line, &n, file);
1500 if (line_len < 0)
1501 break;
1502
1503 if (!line)
1504 goto out_failure;
1505
1506 line[--line_len] = '\0'; /* \n */
1507
1508 sep = strrchr(line, 'x');
1509 if (sep == NULL)
1510 continue;
1511
1512 hex2u64(sep + 1, &start);
1513
1514 sep = strchr(line, ' ');
1515 if (sep == NULL)
1516 continue;
1517
1518 *sep = '\0';
1519
1520 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001521 map = map_groups__new_module(self, start, name);
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001522 if (map == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001523 goto out_delete_line;
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001524 dso__kernel_module_get_build_id(map->dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001525 }
1526
1527 free(line);
1528 fclose(file);
1529
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001530 return map_groups__set_modules_path(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001531
1532out_delete_line:
1533 free(line);
1534out_failure:
1535 return -1;
1536}
1537
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -02001538static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001539 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001540{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001541 int err = -1, fd;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001542
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001543 if (self->has_build_id) {
1544 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001545
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001546 if (filename__read_build_id(vmlinux, build_id,
1547 sizeof(build_id)) < 0) {
1548 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1549 return -1;
1550 }
1551 if (!dso__build_id_equal(self, build_id)) {
1552 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1553 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1554
1555 build_id__sprintf(self->build_id,
1556 sizeof(self->build_id),
1557 expected_build_id);
1558 build_id__sprintf(build_id, sizeof(build_id),
1559 vmlinux_build_id);
1560 pr_debug("build_id in %s is %s while expected is %s, "
1561 "ignoring it\n", vmlinux, vmlinux_build_id,
1562 expected_build_id);
1563 return -1;
1564 }
1565 }
1566
1567 fd = open(vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001568 if (fd < 0)
1569 return -1;
1570
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001571 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001572 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001573 close(fd);
1574
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001575 if (err > 0)
1576 pr_debug("Using %s for symbols\n", vmlinux);
1577
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001578 return err;
1579}
1580
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001581int dso__load_vmlinux_path(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001582 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001583{
1584 int i, err = 0;
1585
1586 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1587 vmlinux_path__nr_entries);
1588
1589 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001590 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001591 if (err > 0) {
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001592 dso__set_long_name(self, strdup(vmlinux_path[i]));
1593 break;
1594 }
1595 }
1596
1597 return err;
1598}
1599
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001600static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001601 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001602{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001603 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001604 const char *kallsyms_filename = NULL;
1605 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001606 /*
1607 * Step 1: if the user specified a vmlinux filename, use it and only
1608 * it, reporting errors to the user if it cannot be used.
1609 *
1610 * For instance, try to analyse an ARM perf.data file _without_ a
1611 * build-id, or if the user specifies the wrong path to the right
1612 * vmlinux file, obviously we can't fallback to another vmlinux (a
1613 * x86_86 one, on the machine where analysis is being performed, say),
1614 * or worse, /proc/kallsyms.
1615 *
1616 * If the specified file _has_ a build-id and there is a build-id
1617 * section in the perf.data file, we will still do the expected
1618 * validation in dso__load_vmlinux and will bail out if they don't
1619 * match.
1620 */
1621 if (symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001622 err = dso__load_vmlinux(self, map,
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001623 symbol_conf.vmlinux_name, filter);
1624 goto out_try_fixup;
1625 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001626
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001627 if (vmlinux_path != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001628 err = dso__load_vmlinux_path(self, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001629 if (err > 0)
1630 goto out_fixup;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001631 }
1632
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001633 /*
1634 * Say the kernel DSO was created when processing the build-id header table,
1635 * we have a build-id, so check if it is the same as the running kernel,
1636 * using it if it is.
1637 */
1638 if (self->has_build_id) {
1639 u8 kallsyms_build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001640 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001641
1642 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
Arnaldo Carvalho de Melo8d0591f62010-01-14 18:30:05 -02001643 sizeof(kallsyms_build_id)) == 0) {
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001644 if (dso__build_id_equal(self, kallsyms_build_id)) {
1645 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Melo8d0591f62010-01-14 18:30:05 -02001646 goto do_kallsyms;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001647 }
Arnaldo Carvalho de Melo8d0591f62010-01-14 18:30:05 -02001648 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001649 /*
1650 * Now look if we have it on the build-id cache in
1651 * $HOME/.debug/[kernel.kallsyms].
1652 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001653 build_id__sprintf(self->build_id, sizeof(self->build_id),
1654 sbuild_id);
1655
1656 if (asprintf(&kallsyms_allocated_filename,
1657 "%s/.debug/[kernel.kallsyms]/%s",
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001658 getenv("HOME"), sbuild_id) == -1) {
1659 pr_err("Not enough memory for kallsyms file lookup\n");
Arnaldo Carvalho de Melo8d0591f62010-01-14 18:30:05 -02001660 return -1;
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001661 }
Arnaldo Carvalho de Melo8d0591f62010-01-14 18:30:05 -02001662
Arnaldo Carvalho de Melo19fc2de2010-01-22 14:35:02 -02001663 kallsyms_filename = kallsyms_allocated_filename;
1664
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001665 if (access(kallsyms_filename, F_OK)) {
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001666 pr_err("No kallsyms or vmlinux with build-id %s "
1667 "was found\n", sbuild_id);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001668 free(kallsyms_allocated_filename);
1669 return -1;
1670 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001671 } else {
1672 /*
1673 * Last resort, if we don't have a build-id and couldn't find
1674 * any vmlinux file, try the running kernel kallsyms table.
1675 */
1676 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001677 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001678
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001679do_kallsyms:
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001680 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001681 if (err > 0)
1682 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001683 free(kallsyms_allocated_filename);
1684
1685out_try_fixup:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001686 if (err > 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001687out_fixup:
Arnaldo Carvalho de Meloe1c7c6a2010-01-22 14:35:01 -02001688 if (kallsyms_filename != NULL)
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001689 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001690 map__fixup_start(map);
1691 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001692 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001693
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001694 return err;
1695}
1696
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001697LIST_HEAD(dsos__user);
1698LIST_HEAD(dsos__kernel);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001699
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001700static void dsos__add(struct list_head *head, struct dso *dso)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001701{
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001702 list_add_tail(&dso->node, head);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001703}
1704
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001705static struct dso *dsos__find(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001706{
1707 struct dso *pos;
1708
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001709 list_for_each_entry(pos, head, node)
Arnaldo Carvalho de Melocf4e5b02010-01-14 23:45:27 -02001710 if (strcmp(pos->long_name, name) == 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001711 return pos;
1712 return NULL;
1713}
1714
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001715struct dso *__dsos__findnew(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001716{
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001717 struct dso *dso = dsos__find(head, name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001718
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001719 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001720 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001721 if (dso != NULL) {
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001722 dsos__add(head, dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001723 dso__set_basename(dso);
1724 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001725 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001726
1727 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001728}
1729
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001730static void __dsos__fprintf(struct list_head *head, FILE *fp)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001731{
1732 struct dso *pos;
1733
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001734 list_for_each_entry(pos, head, node) {
1735 int i;
1736 for (i = 0; i < MAP__NR_TYPES; ++i)
1737 dso__fprintf(pos, i, fp);
1738 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001739}
1740
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001741void dsos__fprintf(FILE *fp)
1742{
1743 __dsos__fprintf(&dsos__kernel, fp);
1744 __dsos__fprintf(&dsos__user, fp);
1745}
1746
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001747static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1748 bool with_hits)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001749{
1750 struct dso *pos;
1751 size_t ret = 0;
1752
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001753 list_for_each_entry(pos, head, node) {
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001754 if (with_hits && !pos->hit)
1755 continue;
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001756 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02001757 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001758 }
1759 return ret;
1760}
1761
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001762size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001763{
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001764 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1765 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001766}
1767
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001768struct dso *dso__new_kernel(const char *name)
1769{
1770 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1771
1772 if (self != NULL) {
1773 self->short_name = "[kernel]";
1774 self->kernel = 1;
1775 }
1776
1777 return self;
1778}
1779
1780void dso__read_running_kernel_build_id(struct dso *self)
1781{
1782 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1783 sizeof(self->build_id)) == 0)
1784 self->has_build_id = true;
1785}
1786
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001787static struct dso *dsos__create_kernel(const char *vmlinux)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001788{
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001789 struct dso *kernel = dso__new_kernel(vmlinux);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001790
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -02001791 if (kernel != NULL) {
1792 dso__read_running_kernel_build_id(kernel);
1793 dsos__add(&dsos__kernel, kernel);
1794 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001795
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001796 return kernel;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001797}
1798
Arnaldo Carvalho de Melob7cece762010-01-13 13:22:17 -02001799int __map_groups__create_kernel_maps(struct map_groups *self,
1800 struct map *vmlinux_maps[MAP__NR_TYPES],
1801 struct dso *kernel)
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001802{
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001803 enum map_type type;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001804
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001805 for (type = 0; type < MAP__NR_TYPES; ++type) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001806 struct kmap *kmap;
1807
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001808 vmlinux_maps[type] = map__new2(0, kernel, type);
1809 if (vmlinux_maps[type] == NULL)
1810 return -1;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001811
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001812 vmlinux_maps[type]->map_ip =
1813 vmlinux_maps[type]->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001814
1815 kmap = map__kmap(vmlinux_maps[type]);
1816 kmap->kmaps = self;
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001817 map_groups__insert(self, vmlinux_maps[type]);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001818 }
1819
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001820 return 0;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001821}
1822
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001823static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001824{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001825 while (--vmlinux_path__nr_entries >= 0) {
1826 free(vmlinux_path[vmlinux_path__nr_entries]);
1827 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1828 }
1829
1830 free(vmlinux_path);
1831 vmlinux_path = NULL;
1832}
1833
1834static int vmlinux_path__init(void)
1835{
1836 struct utsname uts;
1837 char bf[PATH_MAX];
1838
1839 if (uname(&uts) < 0)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001840 return -1;
1841
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001842 vmlinux_path = malloc(sizeof(char *) * 5);
1843 if (vmlinux_path == NULL)
1844 return -1;
1845
1846 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1847 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1848 goto out_fail;
1849 ++vmlinux_path__nr_entries;
1850 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1851 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1852 goto out_fail;
1853 ++vmlinux_path__nr_entries;
1854 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1855 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1856 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1857 goto out_fail;
1858 ++vmlinux_path__nr_entries;
1859 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1860 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1861 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1862 goto out_fail;
1863 ++vmlinux_path__nr_entries;
1864 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1865 uts.release);
1866 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1867 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1868 goto out_fail;
1869 ++vmlinux_path__nr_entries;
1870
1871 return 0;
1872
1873out_fail:
1874 vmlinux_path__exit();
1875 return -1;
1876}
1877
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001878size_t vmlinux_path__fprintf(FILE *fp)
1879{
1880 int i;
1881 size_t printed = 0;
1882
1883 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1884 printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
1885
1886 return printed;
1887}
1888
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001889static int setup_list(struct strlist **list, const char *list_str,
1890 const char *list_name)
1891{
1892 if (list_str == NULL)
1893 return 0;
1894
1895 *list = strlist__new(true, list_str);
1896 if (!*list) {
1897 pr_err("problems parsing %s list\n", list_name);
1898 return -1;
1899 }
1900 return 0;
1901}
1902
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001903int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001904{
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001905 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001906 if (symbol_conf.sort_by_name)
1907 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1908 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001909
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001910 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001911 return -1;
1912
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001913 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1914 pr_err("'.' is the only non valid --field-separator argument\n");
1915 return -1;
1916 }
1917
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001918 if (setup_list(&symbol_conf.dso_list,
1919 symbol_conf.dso_list_str, "dso") < 0)
1920 return -1;
1921
1922 if (setup_list(&symbol_conf.comm_list,
1923 symbol_conf.comm_list_str, "comm") < 0)
1924 goto out_free_dso_list;
1925
1926 if (setup_list(&symbol_conf.sym_list,
1927 symbol_conf.sym_list_str, "symbol") < 0)
1928 goto out_free_comm_list;
1929
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001930 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001931
1932out_free_dso_list:
1933 strlist__delete(symbol_conf.dso_list);
1934out_free_comm_list:
1935 strlist__delete(symbol_conf.comm_list);
1936 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001937}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001938
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001939int map_groups__create_kernel_maps(struct map_groups *self,
1940 struct map *vmlinux_maps[MAP__NR_TYPES])
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001941{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001942 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1943
1944 if (kernel == NULL)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001945 return -1;
1946
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001947 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1948 return -1;
1949
1950 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
Arnaldo Carvalho de Melo10fe12e2010-02-20 19:53:13 -02001951 pr_debug("Problems creating module maps, continuing anyway...\n");
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -02001952 /*
1953 * Now that we have all the maps created, just set the ->end of them:
1954 */
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001955 map_groups__fixup_end(self);
Arnaldo Carvalho de Melo6671cb12009-11-20 20:51:24 -02001956 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001957}