blob: f3d4151e46a1e865a2135c4e56cda70c67c7474b [file] [log] [blame]
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001#define _GNU_SOURCE
2#include <ctype.h>
3#include <dirent.h>
4#include <errno.h>
5#include <libgen.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <string.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <sys/param.h>
12#include <fcntl.h>
13#include <unistd.h>
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030014#include "symbol.h"
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -030015#include "strlist.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030016
17#include <libelf.h>
18#include <gelf.h>
19#include <elf.h>
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -020020#include <limits.h>
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030021#include <sys/utsname.h>
Peter Zijlstra2cdbc462009-08-05 14:05:16 +020022
Arnaldo Carvalho de Meloc12e15e2009-11-21 14:31:25 -020023#ifndef NT_GNU_BUILD_ID
24#define NT_GNU_BUILD_ID 3
25#endif
26
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -020027static void dsos__add(struct list_head *head, struct dso *dso);
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020028static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020029static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -020030 symbol_filter_t filter);
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -020031static int vmlinux_path__nr_entries;
32static char **vmlinux_path;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -030033
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -020034struct symbol_conf symbol_conf = {
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -020035 .exclude_other = true,
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -020036 .use_modules = true,
37 .try_vmlinux_path = true,
38};
39
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020040bool dso__loaded(const struct dso *self, enum map_type type)
41{
42 return self->loaded & (1 << type);
43}
44
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020045bool dso__sorted_by_name(const struct dso *self, enum map_type type)
46{
47 return self->sorted_by_name & (1 << type);
48}
49
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -020050static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
51{
52 self->sorted_by_name |= (1 << type);
53}
54
Arnaldo Carvalho de Melo36a3e642010-01-04 16:19:27 -020055bool symbol_type__is_a(char symbol_type, enum map_type map_type)
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020056{
57 switch (map_type) {
58 case MAP__FUNCTION:
59 return symbol_type == 'T' || symbol_type == 'W';
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -020060 case MAP__VARIABLE:
61 return symbol_type == 'D' || symbol_type == 'd';
Arnaldo Carvalho de Melo6893d4e2009-12-11 14:50:37 -020062 default:
63 return false;
64 }
65}
66
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020067static void symbols__fixup_end(struct rb_root *self)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030068{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020069 struct rb_node *nd, *prevnd = rb_first(self);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030070 struct symbol *curr, *prev;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030071
72 if (prevnd == NULL)
73 return;
74
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030075 curr = rb_entry(prevnd, struct symbol, rb_node);
76
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030077 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030078 prev = curr;
79 curr = rb_entry(nd, struct symbol, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030080
81 if (prev->end == prev->start)
82 prev->end = curr->start - 1;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030083 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -030084
85 /* Last entry */
86 if (curr->end == curr->start)
87 curr->end = roundup(curr->start, 4096);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030088}
89
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -020090static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030091{
92 struct map *prev, *curr;
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -020093 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030094
95 if (prevnd == NULL)
96 return;
97
98 curr = rb_entry(prevnd, struct map, rb_node);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -030099
100 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
101 prev = curr;
102 curr = rb_entry(nd, struct map, rb_node);
103 prev->end = curr->start - 1;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300104 }
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -0200105
106 /*
107 * We still haven't the actual symbols, so guess the
108 * last map final address.
109 */
110 curr->end = ~0UL;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300111}
112
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200113static void map_groups__fixup_end(struct map_groups *self)
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200114{
115 int i;
116 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200117 __map_groups__fixup_end(self, i);
Arnaldo Carvalho de Melo23ea4a32009-11-27 16:29:19 -0200118}
119
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200120static struct symbol *symbol__new(u64 start, u64 len, const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300121{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300122 size_t namelen = strlen(name) + 1;
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -0300123 struct symbol *self = calloc(1, (symbol_conf.priv_size +
124 sizeof(*self) + namelen));
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200125 if (self == NULL)
Ingo Molnar0b73da32009-06-06 15:48:52 +0200126 return NULL;
127
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200128 if (symbol_conf.priv_size)
129 self = ((void *)self) + symbol_conf.priv_size;
Arnaldo Carvalho de Melo36479482009-11-24 12:05:16 -0200130
Ingo Molnar0b73da32009-06-06 15:48:52 +0200131 self->start = start;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200132 self->end = len ? start + len - 1 : start;
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200133
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -0200134 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200135
Ingo Molnar0b73da32009-06-06 15:48:52 +0200136 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300137
138 return self;
139}
140
Arnaldo Carvalho de Melo628ada02010-02-25 12:57:40 -0300141void symbol__delete(struct symbol *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300142{
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200143 free(((void *)self) - symbol_conf.priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300144}
145
146static size_t symbol__fprintf(struct symbol *self, FILE *fp)
147{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300148 return fprintf(fp, " %llx-%llx %s\n",
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300149 self->start, self->end, self->name);
150}
151
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200152void dso__set_long_name(struct dso *self, char *name)
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200153{
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -0200154 if (name == NULL)
155 return;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200156 self->long_name = name;
157 self->long_name_len = strlen(name);
158}
159
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300160static void dso__set_short_name(struct dso *self, const char *name)
161{
162 if (name == NULL)
163 return;
164 self->short_name = name;
165 self->short_name_len = strlen(name);
166}
167
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200168static void dso__set_basename(struct dso *self)
169{
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300170 dso__set_short_name(self, basename(self->long_name));
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200171}
172
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200173struct dso *dso__new(const char *name)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300174{
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -0300175 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300176
177 if (self != NULL) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200178 int i;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300179 strcpy(self->name, name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -0200180 dso__set_long_name(self, self->name);
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300181 dso__set_short_name(self, self->name);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200182 for (i = 0; i < MAP__NR_TYPES; ++i)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200183 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300184 self->slen_calculated = 0;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300185 self->origin = DSO__ORIG_NOT_FOUND;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200186 self->loaded = 0;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200187 self->sorted_by_name = 0;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200188 self->has_build_id = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300189 }
190
191 return self;
192}
193
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200194static void symbols__delete(struct rb_root *self)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300195{
196 struct symbol *pos;
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200197 struct rb_node *next = rb_first(self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300198
199 while (next) {
200 pos = rb_entry(next, struct symbol, rb_node);
201 next = rb_next(&pos->rb_node);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200202 rb_erase(&pos->rb_node, self);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200203 symbol__delete(pos);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300204 }
205}
206
207void dso__delete(struct dso *self)
208{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200209 int i;
210 for (i = 0; i < MAP__NR_TYPES; ++i)
211 symbols__delete(&self->symbols[i]);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300212 if (self->long_name != self->name)
213 free(self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300214 free(self);
215}
216
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200217void dso__set_build_id(struct dso *self, void *build_id)
218{
219 memcpy(self->build_id, build_id, sizeof(self->build_id));
220 self->has_build_id = 1;
221}
222
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200223static void symbols__insert(struct rb_root *self, struct symbol *sym)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300224{
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200225 struct rb_node **p = &self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300226 struct rb_node *parent = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000227 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300228 struct symbol *s;
229
230 while (*p != NULL) {
231 parent = *p;
232 s = rb_entry(parent, struct symbol, rb_node);
233 if (ip < s->start)
234 p = &(*p)->rb_left;
235 else
236 p = &(*p)->rb_right;
237 }
238 rb_link_node(&sym->rb_node, parent, p);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200239 rb_insert_color(&sym->rb_node, self);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300240}
241
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200242static struct symbol *symbols__find(struct rb_root *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300243{
244 struct rb_node *n;
245
246 if (self == NULL)
247 return NULL;
248
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200249 n = self->rb_node;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300250
251 while (n) {
252 struct symbol *s = rb_entry(n, struct symbol, rb_node);
253
254 if (ip < s->start)
255 n = n->rb_left;
256 else if (ip > s->end)
257 n = n->rb_right;
258 else
259 return s;
260 }
261
262 return NULL;
263}
264
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200265struct symbol_name_rb_node {
266 struct rb_node rb_node;
267 struct symbol sym;
268};
269
270static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
271{
272 struct rb_node **p = &self->rb_node;
273 struct rb_node *parent = NULL;
274 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
275
276 while (*p != NULL) {
277 parent = *p;
278 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
279 if (strcmp(sym->name, s->sym.name) < 0)
280 p = &(*p)->rb_left;
281 else
282 p = &(*p)->rb_right;
283 }
284 rb_link_node(&symn->rb_node, parent, p);
285 rb_insert_color(&symn->rb_node, self);
286}
287
288static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
289{
290 struct rb_node *nd;
291
292 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
293 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
294 symbols__insert_by_name(self, pos);
295 }
296}
297
298static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
299{
300 struct rb_node *n;
301
302 if (self == NULL)
303 return NULL;
304
305 n = self->rb_node;
306
307 while (n) {
308 struct symbol_name_rb_node *s;
309 int cmp;
310
311 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
312 cmp = strcmp(name, s->sym.name);
313
314 if (cmp < 0)
315 n = n->rb_left;
316 else if (cmp > 0)
317 n = n->rb_right;
318 else
319 return &s->sym;
320 }
321
322 return NULL;
323}
324
325struct symbol *dso__find_symbol(struct dso *self,
326 enum map_type type, u64 addr)
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200327{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200328 return symbols__find(&self->symbols[type], addr);
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200329}
330
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200331struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
332 const char *name)
333{
334 return symbols__find_by_name(&self->symbol_names[type], name);
335}
336
337void dso__sort_by_name(struct dso *self, enum map_type type)
338{
339 dso__set_sorted_by_name(self, type);
340 return symbols__sort_by_name(&self->symbol_names[type],
341 &self->symbols[type]);
342}
343
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200344int build_id__sprintf(const u8 *self, int len, char *bf)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200345{
346 char *bid = bf;
Arnaldo Carvalho de Meloef12a142010-01-20 15:28:45 -0200347 const u8 *raw = self;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200348 int i;
349
350 for (i = 0; i < len; ++i) {
351 sprintf(bid, "%02x", *raw);
352 ++raw;
353 bid += 2;
354 }
355
356 return raw - self;
357}
358
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200359size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300360{
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200361 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -0200362
363 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200364 return fprintf(fp, "%s", sbuild_id);
365}
366
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200367size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200368{
369 struct rb_node *nd;
370 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
371
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -0300372 if (self->short_name != self->long_name)
373 ret += fprintf(fp, "%s, ", self->long_name);
374 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
375 self->loaded ? "" : "NOT ");
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -0200376 ret += dso__fprintf_buildid(self, fp);
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200377 ret += fprintf(fp, ")\n");
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200378 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
379 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
380 ret += symbol__fprintf(pos, fp);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300381 }
382
383 return ret;
384}
385
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200386int kallsyms__parse(const char *filename, void *arg,
387 int (*process_symbol)(void *arg, const char *name,
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200388 char type, u64 start))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300389{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300390 char *line = NULL;
391 size_t n;
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200392 int err = 0;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200393 FILE *file = fopen(filename, "r");
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300394
395 if (file == NULL)
396 goto out_failure;
397
398 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000399 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300400 int line_len, len;
401 char symbol_type;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300402 char *symbol_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300403
404 line_len = getline(&line, &n, file);
405 if (line_len < 0)
406 break;
407
408 if (!line)
409 goto out_failure;
410
411 line[--line_len] = '\0'; /* \n */
412
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300413 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300414
415 len++;
416 if (len + 2 >= line_len)
417 continue;
418
419 symbol_type = toupper(line[len]);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300420 symbol_name = line + len + 2;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300421
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200422 err = process_symbol(arg, symbol_name, symbol_type, start);
423 if (err)
424 break;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300425 }
426
427 free(line);
428 fclose(file);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200429 return err;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300430
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300431out_failure:
432 return -1;
433}
434
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200435struct process_kallsyms_args {
436 struct map *map;
437 struct dso *dso;
438};
439
440static int map__process_kallsym_symbol(void *arg, const char *name,
441 char type, u64 start)
442{
443 struct symbol *sym;
444 struct process_kallsyms_args *a = arg;
445 struct rb_root *root = &a->dso->symbols[a->map->type];
446
447 if (!symbol_type__is_a(type, a->map->type))
448 return 0;
449
450 /*
451 * Will fix up the end later, when we have all symbols sorted.
452 */
453 sym = symbol__new(start, 0, name);
454
455 if (sym == NULL)
456 return -ENOMEM;
457 /*
458 * We will pass the symbols to the filter later, in
459 * map__split_kallsyms, when we have split the maps per module
460 */
461 symbols__insert(root, sym);
462 return 0;
463}
464
465/*
466 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
467 * so that we can in the next step set the symbol ->end address and then
468 * call kernel_maps__split_kallsyms.
469 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200470static int dso__load_all_kallsyms(struct dso *self, const char *filename,
471 struct map *map)
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200472{
473 struct process_kallsyms_args args = { .map = map, .dso = self, };
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200474 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
Arnaldo Carvalho de Melo682b3352010-01-04 16:19:26 -0200475}
476
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300477/*
478 * Split the symbols into maps, making sure there are no overlaps, i.e. the
479 * kernel range is broken in several maps, named [kernel].N, as we don't have
480 * the original ELF section names vmlinux have.
481 */
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -0200482static int dso__split_kallsyms(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200483 symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300484{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200485 struct map_groups *kmaps = map__kmap(map)->kmaps;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200486 struct map *curr_map = map;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300487 struct symbol *pos;
488 int count = 0;
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200489 struct rb_root *root = &self->symbols[map->type];
490 struct rb_node *next = rb_first(root);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300491 int kernel_range = 0;
492
493 while (next) {
494 char *module;
495
496 pos = rb_entry(next, struct symbol, rb_node);
497 next = rb_next(&pos->rb_node);
498
499 module = strchr(pos->name, '\t');
500 if (module) {
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -0200501 if (!symbol_conf.use_modules)
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200502 goto discard_symbol;
503
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300504 *module++ = '\0';
505
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200506 if (strcmp(curr_map->dso->short_name, module)) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200507 curr_map = map_groups__find_by_name(kmaps, map->type, module);
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200508 if (curr_map == NULL) {
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -0200509 pr_debug("/proc/{kallsyms,modules} "
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200510 "inconsistency while looking "
511 "for \"%s\" module!\n", module);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300512 return -1;
513 }
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -0200514
515 if (curr_map->dso->loaded)
516 goto discard_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300517 }
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300518 /*
519 * So that we look just like we get from .ko files,
520 * i.e. not prelinked, relative to map->start.
521 */
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200522 pos->start = curr_map->map_ip(curr_map, pos->start);
523 pos->end = curr_map->map_ip(curr_map, pos->end);
524 } else if (curr_map != map) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300525 char dso_name[PATH_MAX];
526 struct dso *dso;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300527
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300528 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
529 kernel_range++);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300530
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200531 dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300532 if (dso == NULL)
533 return -1;
534
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200535 curr_map = map__new2(pos->start, dso, map->type);
Zhang, Yanmin37fe5fc2010-02-25 11:00:51 +0800536 if (curr_map == NULL) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300537 dso__delete(dso);
538 return -1;
539 }
540
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200541 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200542 map_groups__insert(kmaps, curr_map);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300543 ++kernel_range;
544 }
545
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200546 if (filter && filter(curr_map, pos)) {
Arnaldo Carvalho de Melo1de8e242009-11-27 16:29:21 -0200547discard_symbol: rb_erase(&pos->rb_node, root);
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200548 symbol__delete(pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300549 } else {
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200550 if (curr_map != map) {
551 rb_erase(&pos->rb_node, root);
552 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300553 }
Mike Galbraith9974f492009-07-02 08:05:58 +0200554 count++;
555 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300556 }
557
Mike Galbraith9974f492009-07-02 08:05:58 +0200558 return count;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300559}
560
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200561int dso__load_kallsyms(struct dso *self, const char *filename,
562 struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300563{
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -0200564 if (dso__load_all_kallsyms(self, filename, map) < 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300565 return -1;
566
Arnaldo Carvalho de Melo4e062552009-11-27 16:29:18 -0200567 symbols__fixup_end(&self->symbols[map->type]);
568 self->origin = DSO__ORIG_KERNEL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300569
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200570 return dso__split_kallsyms(self, map, filter);
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -0300571}
572
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300573static int dso__load_perf_map(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200574 symbol_filter_t filter)
Pekka Enberg80d496b2009-06-08 21:12:48 +0300575{
576 char *line = NULL;
577 size_t n;
578 FILE *file;
579 int nr_syms = 0;
580
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300581 file = fopen(self->long_name, "r");
Pekka Enberg80d496b2009-06-08 21:12:48 +0300582 if (file == NULL)
583 goto out_failure;
584
585 while (!feof(file)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000586 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300587 struct symbol *sym;
588 int line_len, len;
589
590 line_len = getline(&line, &n, file);
591 if (line_len < 0)
592 break;
593
594 if (!line)
595 goto out_failure;
596
597 line[--line_len] = '\0'; /* \n */
598
599 len = hex2u64(line, &start);
600
601 len++;
602 if (len + 2 >= line_len)
603 continue;
604
605 len += hex2u64(line + len, &size);
606
607 len++;
608 if (len + 2 >= line_len)
609 continue;
610
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200611 sym = symbol__new(start, size, line + len);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300612
613 if (sym == NULL)
614 goto out_delete_line;
615
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300616 if (filter && filter(map, sym))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200617 symbol__delete(sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300618 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200619 symbols__insert(&self->symbols[map->type], sym);
Pekka Enberg80d496b2009-06-08 21:12:48 +0300620 nr_syms++;
621 }
622 }
623
624 free(line);
625 fclose(file);
626
627 return nr_syms;
628
629out_delete_line:
630 free(line);
631out_failure:
632 return -1;
633}
634
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300635/**
636 * elf_symtab__for_each_symbol - iterate thru all the symbols
637 *
638 * @self: struct elf_symtab instance to iterate
Ingo Molnar83a09442009-08-15 12:26:57 +0200639 * @idx: uint32_t idx
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300640 * @sym: GElf_Sym iterator
641 */
Ingo Molnar83a09442009-08-15 12:26:57 +0200642#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
643 for (idx = 0, gelf_getsym(syms, idx, &sym);\
644 idx < nr_syms; \
645 idx++, gelf_getsym(syms, idx, &sym))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300646
647static inline uint8_t elf_sym__type(const GElf_Sym *sym)
648{
649 return GELF_ST_TYPE(sym->st_info);
650}
651
652static inline int elf_sym__is_function(const GElf_Sym *sym)
653{
654 return elf_sym__type(sym) == STT_FUNC &&
655 sym->st_name != 0 &&
Arnaldo Carvalho de Melo81833132009-10-05 23:35:03 -0300656 sym->st_shndx != SHN_UNDEF;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300657}
658
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200659static inline bool elf_sym__is_object(const GElf_Sym *sym)
660{
661 return elf_sym__type(sym) == STT_OBJECT &&
662 sym->st_name != 0 &&
663 sym->st_shndx != SHN_UNDEF;
664}
665
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200666static inline int elf_sym__is_label(const GElf_Sym *sym)
667{
668 return elf_sym__type(sym) == STT_NOTYPE &&
669 sym->st_name != 0 &&
670 sym->st_shndx != SHN_UNDEF &&
671 sym->st_shndx != SHN_ABS;
672}
673
674static inline const char *elf_sec__name(const GElf_Shdr *shdr,
675 const Elf_Data *secstrs)
676{
677 return secstrs->d_buf + shdr->sh_name;
678}
679
680static inline int elf_sec__is_text(const GElf_Shdr *shdr,
681 const Elf_Data *secstrs)
682{
683 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
684}
685
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200686static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
687 const Elf_Data *secstrs)
688{
689 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
690}
691
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300692static inline const char *elf_sym__name(const GElf_Sym *sym,
693 const Elf_Data *symstrs)
694{
695 return symstrs->d_buf + sym->st_name;
696}
697
698static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
699 GElf_Shdr *shp, const char *name,
Ingo Molnar83a09442009-08-15 12:26:57 +0200700 size_t *idx)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300701{
702 Elf_Scn *sec = NULL;
703 size_t cnt = 1;
704
705 while ((sec = elf_nextscn(elf, sec)) != NULL) {
706 char *str;
707
708 gelf_getshdr(sec, shp);
709 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
710 if (!strcmp(name, str)) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200711 if (idx)
712 *idx = cnt;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300713 break;
714 }
715 ++cnt;
716 }
717
718 return sec;
719}
720
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300721#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
722 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
723 idx < nr_entries; \
724 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
725
726#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
727 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
728 idx < nr_entries; \
729 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
730
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300731/*
732 * We need to check if we have a .dynsym, so that we can handle the
733 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
734 * .dynsym or .symtab).
735 * And always look at the original dso, not at debuginfo packages, that
736 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
737 */
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200738static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
739 symbol_filter_t filter)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300740{
741 uint32_t nr_rel_entries, idx;
742 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000743 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300744 GElf_Shdr shdr_plt;
745 struct symbol *f;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300746 GElf_Shdr shdr_rel_plt, shdr_dynsym;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300747 Elf_Data *reldata, *syms, *symstrs;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300748 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
749 size_t dynsym_idx;
750 GElf_Ehdr ehdr;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300751 char sympltname[1024];
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300752 Elf *elf;
753 int nr = 0, symidx, fd, err = 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300754
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300755 fd = open(self->long_name, O_RDONLY);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300756 if (fd < 0)
757 goto out;
758
Marti Raudsepp84087122009-10-24 19:10:36 +0300759 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300760 if (elf == NULL)
761 goto out_close;
762
763 if (gelf_getehdr(elf, &ehdr) == NULL)
764 goto out_elf_end;
765
766 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
767 ".dynsym", &dynsym_idx);
768 if (scn_dynsym == NULL)
769 goto out_elf_end;
770
771 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300772 ".rela.plt", NULL);
773 if (scn_plt_rel == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300774 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300775 ".rel.plt", NULL);
776 if (scn_plt_rel == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300777 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300778 }
779
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300780 err = -1;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300781
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300782 if (shdr_rel_plt.sh_link != dynsym_idx)
783 goto out_elf_end;
784
785 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
786 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300787
788 /*
Ingo Molnar83a09442009-08-15 12:26:57 +0200789 * Fetch the relocation section to find the idxes to the GOT
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300790 * and the symbols in the .dynsym they refer to.
791 */
792 reldata = elf_getdata(scn_plt_rel, NULL);
793 if (reldata == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300794 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300795
796 syms = elf_getdata(scn_dynsym, NULL);
797 if (syms == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300798 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300799
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300800 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300801 if (scn_symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300802 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300803
804 symstrs = elf_getdata(scn_symstrs, NULL);
805 if (symstrs == NULL)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300806 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300807
808 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
809 plt_offset = shdr_plt.sh_offset;
810
811 if (shdr_rel_plt.sh_type == SHT_RELA) {
812 GElf_Rela pos_mem, *pos;
813
814 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
815 nr_rel_entries) {
816 symidx = GELF_R_SYM(pos->r_info);
817 plt_offset += shdr_plt.sh_entsize;
818 gelf_getsym(syms, symidx, &sym);
819 snprintf(sympltname, sizeof(sympltname),
820 "%s@plt", elf_sym__name(&sym, symstrs));
821
822 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200823 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300824 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300825 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300826
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200827 if (filter && filter(map, f))
828 symbol__delete(f);
829 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200830 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200831 ++nr;
832 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300833 }
834 } else if (shdr_rel_plt.sh_type == SHT_REL) {
835 GElf_Rel pos_mem, *pos;
836 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
837 nr_rel_entries) {
838 symidx = GELF_R_SYM(pos->r_info);
839 plt_offset += shdr_plt.sh_entsize;
840 gelf_getsym(syms, symidx, &sym);
841 snprintf(sympltname, sizeof(sympltname),
842 "%s@plt", elf_sym__name(&sym, symstrs));
843
844 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -0200845 sympltname);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300846 if (!f)
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300847 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300848
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200849 if (filter && filter(map, f))
850 symbol__delete(f);
851 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200852 symbols__insert(&self->symbols[map->type], f);
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -0200853 ++nr;
854 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300855 }
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300856 }
857
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300858 err = 0;
859out_elf_end:
860 elf_end(elf);
861out_close:
862 close(fd);
863
864 if (err == 0)
865 return nr;
866out:
Arnaldo Carvalho de Melofe2197b2010-03-11 20:12:40 -0300867 pr_debug("%s: problems reading %s PLT info.\n",
868 __func__, self->long_name);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300869 return 0;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300870}
871
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200872static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
873{
874 switch (type) {
875 case MAP__FUNCTION:
876 return elf_sym__is_function(self);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200877 case MAP__VARIABLE:
878 return elf_sym__is_object(self);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200879 default:
880 return false;
881 }
882}
883
884static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
885{
886 switch (type) {
887 case MAP__FUNCTION:
888 return elf_sec__is_text(self, secstrs);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -0200889 case MAP__VARIABLE:
890 return elf_sec__is_data(self, secstrs);
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200891 default:
892 return false;
893 }
894}
895
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200896static int dso__load_sym(struct dso *self, struct map *map, const char *name,
897 int fd, symbol_filter_t filter, int kmodule)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300898{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200899 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300900 struct map *curr_map = map;
901 struct dso *curr_dso = self;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200902 Elf_Data *symstrs, *secstrs;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300903 uint32_t nr_syms;
904 int err = -1;
Ingo Molnar83a09442009-08-15 12:26:57 +0200905 uint32_t idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300906 GElf_Ehdr ehdr;
907 GElf_Shdr shdr;
908 Elf_Data *syms;
909 GElf_Sym sym;
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300910 Elf_Scn *sec, *sec_strndx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300911 Elf *elf;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300912 int nr = 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300913
Marti Raudsepp84087122009-10-24 19:10:36 +0300914 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300915 if (elf == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200916 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300917 goto out_close;
918 }
919
920 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -0200921 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300922 goto out_elf_end;
923 }
924
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300925 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
926 if (sec == NULL) {
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -0300927 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
928 if (sec == NULL)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300929 goto out_elf_end;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300930 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300931
932 syms = elf_getdata(sec, NULL);
933 if (syms == NULL)
934 goto out_elf_end;
935
936 sec = elf_getscn(elf, shdr.sh_link);
937 if (sec == NULL)
938 goto out_elf_end;
939
940 symstrs = elf_getdata(sec, NULL);
941 if (symstrs == NULL)
942 goto out_elf_end;
943
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200944 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
945 if (sec_strndx == NULL)
946 goto out_elf_end;
947
948 secstrs = elf_getdata(sec_strndx, NULL);
Stoyan Gaydarov9b30a262009-07-30 05:25:29 -0500949 if (secstrs == NULL)
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200950 goto out_elf_end;
951
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300952 nr_syms = shdr.sh_size / shdr.sh_entsize;
953
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200954 memset(&sym, 0, sizeof(sym));
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200955 if (!self->kernel) {
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200956 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -0300957 elf_section_by_name(elf, &ehdr, &shdr,
958 ".gnu.prelink_undo",
959 NULL) != NULL);
Mike Galbraithd20ff6b2009-07-20 14:01:38 +0200960 } else self->adjust_symbols = 0;
961
Ingo Molnar83a09442009-08-15 12:26:57 +0200962 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300963 struct symbol *f;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200964 const char *elf_name = elf_sym__name(&sym, symstrs);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300965 char *demangled = NULL;
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200966 int is_label = elf_sym__is_label(&sym);
967 const char *section_name;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300968
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200969 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
970 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
971 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
Arnaldo Carvalho de Melo56b03f32010-01-05 16:50:31 -0200972
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200973 if (!is_label && !elf_sym__is_a(&sym, map->type))
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300974 continue;
975
976 sec = elf_getscn(elf, sym.st_shndx);
977 if (!sec)
978 goto out_elf_end;
979
980 gelf_getshdr(sec, &shdr);
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200981
Arnaldo Carvalho de Melod45868d2009-12-11 14:50:38 -0200982 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
Mike Galbraith6cfcc532009-07-02 08:08:36 +0200983 continue;
984
985 section_name = elf_sec__name(&shdr, secstrs);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200986
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200987 if (self->kernel || kmodule) {
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300988 char dso_name[PATH_MAX];
989
990 if (strcmp(section_name,
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -0300991 (curr_dso->short_name +
992 self->short_name_len)) == 0)
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -0300993 goto new_symbol;
994
995 if (strcmp(section_name, ".text") == 0) {
996 curr_map = map;
997 curr_dso = self;
998 goto new_symbol;
999 }
1000
1001 snprintf(dso_name, sizeof(dso_name),
1002 "%s%s", self->short_name, section_name);
1003
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001004 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001005 if (curr_map == NULL) {
1006 u64 start = sym.st_value;
1007
1008 if (kmodule)
1009 start += map->start + shdr.sh_offset;
1010
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001011 curr_dso = dso__new(dso_name);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001012 if (curr_dso == NULL)
1013 goto out_elf_end;
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001014 curr_map = map__new2(start, curr_dso,
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001015 map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001016 if (curr_map == NULL) {
1017 dso__delete(curr_dso);
1018 goto out_elf_end;
1019 }
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -02001020 curr_map->map_ip = identity__map_ip;
1021 curr_map->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001022 curr_dso->origin = self->origin;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001023 map_groups__insert(kmap->kmaps, curr_map);
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001024 dsos__add(&dsos__kernel, curr_dso);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001025 dso__set_loaded(curr_dso, map->type);
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001026 } else
1027 curr_dso = curr_map->dso;
1028
1029 goto new_symbol;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001030 }
1031
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001032 if (curr_dso->adjust_symbols) {
Arnaldo Carvalho de Melo29a9f662010-02-03 16:52:06 -02001033 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1034 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1035 (u64)sym.st_value, (u64)shdr.sh_addr,
1036 (u64)shdr.sh_offset);
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001037 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
Arnaldo Carvalho de Meloaf427bf2009-10-05 14:26:17 -03001038 }
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001039 /*
1040 * We need to figure out if the object was created from C++ sources
1041 * DWARF DW_compile_unit has this, but we don't always have access
1042 * to it...
1043 */
Ingo Molnar83a09442009-08-15 12:26:57 +02001044 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001045 if (demangled != NULL)
Ingo Molnar83a09442009-08-15 12:26:57 +02001046 elf_name = demangled;
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001047new_symbol:
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001048 f = symbol__new(sym.st_value, sym.st_size, elf_name);
Arnaldo Carvalho de Melo28ac9092009-07-20 14:14:12 -03001049 free(demangled);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001050 if (!f)
1051 goto out_elf_end;
1052
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001053 if (filter && filter(curr_map, f))
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001054 symbol__delete(f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001055 else {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001056 symbols__insert(&curr_dso->symbols[curr_map->type], f);
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -03001057 nr++;
1058 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001059 }
1060
Arnaldo Carvalho de Melo2e538c42009-10-07 13:48:56 -03001061 /*
1062 * For misannotated, zeroed, ASM function sizes.
1063 */
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001064 if (nr > 0) {
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001065 symbols__fixup_end(&self->symbols[map->type]);
Arnaldo Carvalho de Melo6275ce22010-02-03 16:52:01 -02001066 if (kmap) {
1067 /*
1068 * We need to fixup this here too because we create new
1069 * maps here, for things like vsyscall sections.
1070 */
1071 __map_groups__fixup_end(kmap->kmaps, map->type);
1072 }
1073 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001074 err = nr;
1075out_elf_end:
1076 elf_end(elf);
1077out_close:
1078 return err;
1079}
1080
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001081static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1082{
1083 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1084}
1085
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001086static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001087{
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001088 bool have_build_id = false;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001089 struct dso *pos;
1090
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001091 list_for_each_entry(pos, head, node) {
1092 if (with_hits && !pos->hit)
1093 continue;
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001094 if (filename__read_build_id(pos->long_name, pos->build_id,
1095 sizeof(pos->build_id)) > 0) {
1096 have_build_id = true;
1097 pos->has_build_id = true;
1098 }
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001099 }
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001100
Arnaldo Carvalho de Meloe30a3d12009-11-18 20:20:51 -02001101 return have_build_id;
Frederic Weisbecker57f395a2009-11-11 04:51:04 +01001102}
1103
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001104bool dsos__read_build_ids(bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001105{
Arnaldo Carvalho de Melo6122e4e2010-02-03 16:52:05 -02001106 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1107 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
Arnaldo Carvalho de Melo8b4825b2009-12-09 20:09:37 -02001108 return kbuildids || ubuildids;
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001109}
1110
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001111/*
1112 * Align offset to 4 bytes as needed for note name and descriptor data.
1113 */
1114#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1115
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001116int filename__read_build_id(const char *filename, void *bf, size_t size)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001117{
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001118 int fd, err = -1;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001119 GElf_Ehdr ehdr;
1120 GElf_Shdr shdr;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001121 Elf_Data *data;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001122 Elf_Scn *sec;
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001123 Elf_Kind ek;
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001124 void *ptr;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001125 Elf *elf;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001126
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001127 if (size < BUILD_ID_SIZE)
1128 goto out;
1129
1130 fd = open(filename, O_RDONLY);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001131 if (fd < 0)
1132 goto out;
1133
Marti Raudsepp84087122009-10-24 19:10:36 +03001134 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001135 if (elf == NULL) {
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001136 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001137 goto out_close;
1138 }
1139
Pekka Enberge57cfcd2009-11-22 12:29:44 +02001140 ek = elf_kind(elf);
1141 if (ek != ELF_K_ELF)
1142 goto out_elf_end;
1143
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001144 if (gelf_getehdr(elf, &ehdr) == NULL) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001145 pr_err("%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001146 goto out_elf_end;
1147 }
1148
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001149 sec = elf_section_by_name(elf, &ehdr, &shdr,
1150 ".note.gnu.build-id", NULL);
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001151 if (sec == NULL) {
1152 sec = elf_section_by_name(elf, &ehdr, &shdr,
1153 ".notes", NULL);
1154 if (sec == NULL)
1155 goto out_elf_end;
1156 }
1157
1158 data = elf_getdata(sec, NULL);
1159 if (data == NULL)
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001160 goto out_elf_end;
1161
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001162 ptr = data->d_buf;
1163 while (ptr < (data->d_buf + data->d_size)) {
1164 GElf_Nhdr *nhdr = ptr;
1165 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1166 descsz = NOTE_ALIGN(nhdr->n_descsz);
1167 const char *name;
1168
1169 ptr += sizeof(*nhdr);
1170 name = ptr;
1171 ptr += namesz;
1172 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1173 nhdr->n_namesz == sizeof("GNU")) {
1174 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1175 memcpy(bf, ptr, BUILD_ID_SIZE);
1176 err = BUILD_ID_SIZE;
1177 break;
1178 }
1179 }
1180 ptr += descsz;
1181 }
Arnaldo Carvalho de Melo2643ce12009-11-03 21:46:10 -02001182out_elf_end:
1183 elf_end(elf);
1184out_close:
1185 close(fd);
1186out:
1187 return err;
1188}
1189
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001190int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1191{
1192 int fd, err = -1;
1193
1194 if (size < BUILD_ID_SIZE)
1195 goto out;
1196
1197 fd = open(filename, O_RDONLY);
1198 if (fd < 0)
1199 goto out;
1200
1201 while (1) {
1202 char bf[BUFSIZ];
1203 GElf_Nhdr nhdr;
1204 int namesz, descsz;
1205
1206 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1207 break;
1208
Arnaldo Carvalho de Melofd7a3462009-11-20 20:51:25 -02001209 namesz = NOTE_ALIGN(nhdr.n_namesz);
1210 descsz = NOTE_ALIGN(nhdr.n_descsz);
Arnaldo Carvalho de Melof1617b42009-11-18 20:20:52 -02001211 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1212 nhdr.n_namesz == sizeof("GNU")) {
1213 if (read(fd, bf, namesz) != namesz)
1214 break;
1215 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1216 if (read(fd, build_id,
1217 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1218 err = 0;
1219 break;
1220 }
1221 } else if (read(fd, bf, descsz) != descsz)
1222 break;
1223 } else {
1224 int n = namesz + descsz;
1225 if (read(fd, bf, n) != n)
1226 break;
1227 }
1228 }
1229 close(fd);
1230out:
1231 return err;
1232}
1233
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001234char dso__symtab_origin(const struct dso *self)
1235{
1236 static const char origin[] = {
1237 [DSO__ORIG_KERNEL] = 'k',
1238 [DSO__ORIG_JAVA_JIT] = 'j',
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001239 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001240 [DSO__ORIG_FEDORA] = 'f',
1241 [DSO__ORIG_UBUNTU] = 'u',
1242 [DSO__ORIG_BUILDID] = 'b',
1243 [DSO__ORIG_DSO] = 'd',
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001244 [DSO__ORIG_KMODULE] = 'K',
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001245 };
1246
1247 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
1248 return '!';
1249 return origin[self->origin];
1250}
1251
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001252int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001253{
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001254 int size = PATH_MAX;
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001255 char *name;
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001256 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001257 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001258 int ret = -1;
1259 int fd;
1260
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001261 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001262
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001263 if (self->kernel)
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001264 return dso__load_kernel_sym(self, map, filter);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001265
1266 name = malloc(size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001267 if (!name)
1268 return -1;
1269
Arnaldo Carvalho de Melo30d7a772009-07-02 21:24:14 -03001270 self->adjust_symbols = 0;
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -03001271
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001272 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001273 ret = dso__load_perf_map(self, map, filter);
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001274 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
1275 DSO__ORIG_NOT_FOUND;
1276 return ret;
1277 }
1278
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001279 self->origin = DSO__ORIG_BUILD_ID_CACHE;
Pekka Enberg80d496b2009-06-08 21:12:48 +03001280
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001281 if (self->has_build_id) {
1282 build_id__sprintf(self->build_id, sizeof(self->build_id),
1283 build_id_hex);
1284 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1285 getenv("HOME"), DEBUG_CACHE_DIR,
1286 build_id_hex, build_id_hex + 2);
1287 goto open_file;
1288 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001289more:
1290 do {
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001291 self->origin++;
1292 switch (self->origin) {
1293 case DSO__ORIG_FEDORA:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001294 snprintf(name, size, "/usr/lib/debug%s.debug",
1295 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001296 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001297 case DSO__ORIG_UBUNTU:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001298 snprintf(name, size, "/usr/lib/debug%s",
1299 self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001300 break;
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001301 case DSO__ORIG_BUILDID:
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001302 if (filename__read_build_id(self->long_name, build_id,
1303 sizeof(build_id))) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001304 build_id__sprintf(build_id, sizeof(build_id),
1305 build_id_hex);
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001306 snprintf(name, size,
1307 "/usr/lib/debug/.build-id/%.2s/%s.debug",
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001308 build_id_hex, build_id_hex + 2);
1309 if (self->has_build_id)
1310 goto compare_build_id;
1311 break;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001312 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001313 self->origin++;
Arnaldo Carvalho de Melo4d1e00a2009-08-05 19:02:49 -03001314 /* Fall thru */
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001315 case DSO__ORIG_DSO:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001316 snprintf(name, size, "%s", self->long_name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001317 break;
1318
1319 default:
1320 goto out;
1321 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001322
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001323 if (self->has_build_id) {
Arnaldo Carvalho de Melod3379ab2009-11-18 20:20:50 -02001324 if (filename__read_build_id(name, build_id,
1325 sizeof(build_id)) < 0)
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001326 goto more;
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001327compare_build_id:
Arnaldo Carvalho de Melo78075ca2009-11-20 20:51:26 -02001328 if (!dso__build_id_equal(self, build_id))
Arnaldo Carvalho de Melo8d063672009-11-04 18:50:43 -02001329 goto more;
1330 }
Arnaldo Carvalho de Melo4cf40132009-12-27 21:37:06 -02001331open_file:
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001332 fd = open(name, O_RDONLY);
1333 } while (fd < 0);
1334
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001335 ret = dso__load_sym(self, map, name, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001336 close(fd);
1337
1338 /*
1339 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
1340 */
1341 if (!ret)
1342 goto more;
1343
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001344 if (ret > 0) {
Arnaldo Carvalho de Melo82164162009-11-16 13:48:11 -02001345 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
Arnaldo Carvalho de Meloa25e46c2009-07-11 12:18:36 -03001346 if (nr_plt > 0)
1347 ret += nr_plt;
1348 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001349out:
1350 free(name);
Arnaldo Carvalho de Melo1340e6b2009-08-11 17:04:36 -03001351 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1352 return 0;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001353 return ret;
1354}
1355
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001356struct map *map_groups__find_by_name(struct map_groups *self,
1357 enum map_type type, const char *name)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001358{
1359 struct rb_node *nd;
1360
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -02001361 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001362 struct map *map = rb_entry(nd, struct map, rb_node);
1363
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001364 if (map->dso && strcmp(map->dso->short_name, name) == 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001365 return map;
1366 }
1367
1368 return NULL;
1369}
1370
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001371static int dso__kernel_module_get_build_id(struct dso *self)
1372{
1373 char filename[PATH_MAX];
1374 /*
1375 * kernel module short names are of the form "[module]" and
1376 * we need just "module" here.
1377 */
1378 const char *name = self->short_name + 1;
1379
1380 snprintf(filename, sizeof(filename),
1381 "/sys/module/%.*s/notes/.note.gnu.build-id",
1382 (int)strlen(name - 1), name);
1383
1384 if (sysfs__read_build_id(filename, self->build_id,
1385 sizeof(self->build_id)) == 0)
1386 self->has_build_id = true;
1387
1388 return 0;
1389}
1390
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001391static int map_groups__set_modules_path_dir(struct map_groups *self, char *dir_name)
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001392{
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001393 struct dirent *dent;
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001394 DIR *dir = opendir(dir_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001395
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001396 if (!dir) {
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001397 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001398 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001399 }
1400
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001401 while ((dent = readdir(dir)) != NULL) {
1402 char path[PATH_MAX];
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001403
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001404 if (dent->d_type == DT_DIR) {
1405 if (!strcmp(dent->d_name, ".") ||
1406 !strcmp(dent->d_name, ".."))
1407 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001408
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001409 snprintf(path, sizeof(path), "%s/%s",
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001410 dir_name, dent->d_name);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001411 if (map_groups__set_modules_path_dir(self, path) < 0)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001412 goto failure;
1413 } else {
1414 char *dot = strrchr(dent->d_name, '.'),
1415 dso_name[PATH_MAX];
1416 struct map *map;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001417 char *long_name;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001418
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001419 if (dot == NULL || strcmp(dot, ".ko"))
1420 continue;
1421 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1422 (int)(dot - dent->d_name), dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001423
Arnaldo Carvalho de Meloa2a99e82009-10-05 14:26:18 -03001424 strxfrchar(dso_name, '-', '_');
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001425 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001426 if (map == NULL)
1427 continue;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001428
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001429 snprintf(path, sizeof(path), "%s/%s",
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001430 dir_name, dent->d_name);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001431
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001432 long_name = strdup(path);
1433 if (long_name == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001434 goto failure;
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001435 dso__set_long_name(map->dso, long_name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001436 dso__kernel_module_get_build_id(map->dso);
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001437 }
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001438 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001439
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001440 return 0;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001441failure:
1442 closedir(dir);
1443 return -1;
Mike Galbraith6cfcc532009-07-02 08:08:36 +02001444}
1445
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001446static int map_groups__set_modules_path(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001447{
1448 struct utsname uts;
1449 char modules_path[PATH_MAX];
1450
1451 if (uname(&uts) < 0)
1452 return -1;
1453
1454 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1455 uts.release);
1456
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001457 return map_groups__set_modules_path_dir(self, modules_path);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001458}
1459
1460/*
1461 * Constructor variant for modules (where we know from /proc/modules where
1462 * they are loaded) and for vmlinux, where only after we load all the
1463 * symbols we'll know where it starts and ends.
1464 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001465static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001466{
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001467 struct map *self = calloc(1, (sizeof(*self) +
1468 (dso->kernel ? sizeof(struct kmap) : 0)));
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001469 if (self != NULL) {
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001470 /*
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001471 * ->end will be filled after we load all the symbols
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001472 */
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001473 map__init(self, type, start, 0, 0, dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001474 }
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -02001475
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001476 return self;
1477}
1478
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001479struct map *map_groups__new_module(struct map_groups *self, u64 start,
1480 const char *filename)
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001481{
1482 struct map *map;
1483 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1484
1485 if (dso == NULL)
1486 return NULL;
1487
1488 map = map__new2(start, dso, MAP__FUNCTION);
1489 if (map == NULL)
1490 return NULL;
1491
1492 dso->origin = DSO__ORIG_KMODULE;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001493 map_groups__insert(self, map);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001494 return map;
1495}
1496
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001497static int map_groups__create_modules(struct map_groups *self)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001498{
1499 char *line = NULL;
1500 size_t n;
1501 FILE *file = fopen("/proc/modules", "r");
1502 struct map *map;
1503
1504 if (file == NULL)
1505 return -1;
1506
1507 while (!feof(file)) {
1508 char name[PATH_MAX];
1509 u64 start;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001510 char *sep;
1511 int line_len;
1512
1513 line_len = getline(&line, &n, file);
1514 if (line_len < 0)
1515 break;
1516
1517 if (!line)
1518 goto out_failure;
1519
1520 line[--line_len] = '\0'; /* \n */
1521
1522 sep = strrchr(line, 'x');
1523 if (sep == NULL)
1524 continue;
1525
1526 hex2u64(sep + 1, &start);
1527
1528 sep = strchr(line, ' ');
1529 if (sep == NULL)
1530 continue;
1531
1532 *sep = '\0';
1533
1534 snprintf(name, sizeof(name), "[%s]", line);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001535 map = map_groups__new_module(self, start, name);
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001536 if (map == NULL)
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001537 goto out_delete_line;
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001538 dso__kernel_module_get_build_id(map->dso);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001539 }
1540
1541 free(line);
1542 fclose(file);
1543
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001544 return map_groups__set_modules_path(self);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001545
1546out_delete_line:
1547 free(line);
1548out_failure:
1549 return -1;
1550}
1551
Arnaldo Carvalho de Melo9958e1f2009-12-11 14:50:36 -02001552static int dso__load_vmlinux(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo6beba7a2009-10-21 17:34:06 -02001553 const char *vmlinux, symbol_filter_t filter)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001554{
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001555 int err = -1, fd;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001556
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001557 if (self->has_build_id) {
1558 u8 build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001559
Arnaldo Carvalho de Melofbd733b2009-11-20 20:51:28 -02001560 if (filename__read_build_id(vmlinux, build_id,
1561 sizeof(build_id)) < 0) {
1562 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1563 return -1;
1564 }
1565 if (!dso__build_id_equal(self, build_id)) {
1566 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1567 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1568
1569 build_id__sprintf(self->build_id,
1570 sizeof(self->build_id),
1571 expected_build_id);
1572 build_id__sprintf(build_id, sizeof(build_id),
1573 vmlinux_build_id);
1574 pr_debug("build_id in %s is %s while expected is %s, "
1575 "ignoring it\n", vmlinux, vmlinux_build_id,
1576 expected_build_id);
1577 return -1;
1578 }
1579 }
1580
1581 fd = open(vmlinux, O_RDONLY);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001582 if (fd < 0)
1583 return -1;
1584
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -02001585 dso__set_loaded(self, map->type);
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001586 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001587 close(fd);
1588
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001589 if (err > 0)
1590 pr_debug("Using %s for symbols\n", vmlinux);
1591
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001592 return err;
1593}
1594
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001595int dso__load_vmlinux_path(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001596 symbol_filter_t filter)
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001597{
1598 int i, err = 0;
1599
1600 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1601 vmlinux_path__nr_entries);
1602
1603 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001604 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001605 if (err > 0) {
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001606 dso__set_long_name(self, strdup(vmlinux_path[i]));
1607 break;
1608 }
1609 }
1610
1611 return err;
1612}
1613
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -02001614static int dso__load_kernel_sym(struct dso *self, struct map *map,
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001615 symbol_filter_t filter)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001616{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001617 int err;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001618 const char *kallsyms_filename = NULL;
1619 char *kallsyms_allocated_filename = NULL;
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001620 /*
1621 * Step 1: if the user specified a vmlinux filename, use it and only
1622 * it, reporting errors to the user if it cannot be used.
1623 *
1624 * For instance, try to analyse an ARM perf.data file _without_ a
1625 * build-id, or if the user specifies the wrong path to the right
1626 * vmlinux file, obviously we can't fallback to another vmlinux (a
1627 * x86_86 one, on the machine where analysis is being performed, say),
1628 * or worse, /proc/kallsyms.
1629 *
1630 * If the specified file _has_ a build-id and there is a build-id
1631 * section in the perf.data file, we will still do the expected
1632 * validation in dso__load_vmlinux and will bail out if they don't
1633 * match.
1634 */
1635 if (symbol_conf.vmlinux_name != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001636 err = dso__load_vmlinux(self, map,
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001637 symbol_conf.vmlinux_name, filter);
1638 goto out_try_fixup;
1639 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001640
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001641 if (vmlinux_path != NULL) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001642 err = dso__load_vmlinux_path(self, map, filter);
Arnaldo Carvalho de Meloa19afe42010-01-27 21:05:50 -02001643 if (err > 0)
1644 goto out_fixup;
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001645 }
1646
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001647 /*
1648 * Say the kernel DSO was created when processing the build-id header table,
1649 * we have a build-id, so check if it is the same as the running kernel,
1650 * using it if it is.
1651 */
1652 if (self->has_build_id) {
1653 u8 kallsyms_build_id[BUILD_ID_SIZE];
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001654 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001655
1656 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001657 sizeof(kallsyms_build_id)) == 0) {
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001658 if (dso__build_id_equal(self, kallsyms_build_id)) {
1659 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001660 goto do_kallsyms;
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001661 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001662 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001663 /*
1664 * Now look if we have it on the build-id cache in
1665 * $HOME/.debug/[kernel.kallsyms].
1666 */
Arnaldo Carvalho de Melo9e201442010-01-14 18:30:06 -02001667 build_id__sprintf(self->build_id, sizeof(self->build_id),
1668 sbuild_id);
1669
1670 if (asprintf(&kallsyms_allocated_filename,
1671 "%s/.debug/[kernel.kallsyms]/%s",
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001672 getenv("HOME"), sbuild_id) == -1) {
1673 pr_err("Not enough memory for kallsyms file lookup\n");
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001674 return -1;
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001675 }
Arnaldo Carvalho de Melo8d0591f2010-01-14 18:30:05 -02001676
Arnaldo Carvalho de Melo19fc2de2010-01-22 14:35:02 -02001677 kallsyms_filename = kallsyms_allocated_filename;
1678
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001679 if (access(kallsyms_filename, F_OK)) {
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001680 pr_err("No kallsyms or vmlinux with build-id %s "
1681 "was found\n", sbuild_id);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001682 free(kallsyms_allocated_filename);
1683 return -1;
1684 }
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001685 } else {
1686 /*
1687 * Last resort, if we don't have a build-id and couldn't find
1688 * any vmlinux file, try the running kernel kallsyms table.
1689 */
1690 kallsyms_filename = "/proc/kallsyms";
Arnaldo Carvalho de Meloef6ae722009-11-20 20:51:29 -02001691 }
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001692
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001693do_kallsyms:
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001694 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03001695 if (err > 0)
1696 pr_debug("Using %s for symbols\n", kallsyms_filename);
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001697 free(kallsyms_allocated_filename);
1698
1699out_try_fixup:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001700 if (err > 0) {
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001701out_fixup:
Arnaldo Carvalho de Meloe1c7c6a2010-01-22 14:35:01 -02001702 if (kallsyms_filename != NULL)
Arnaldo Carvalho de Melodc8d6ab2010-01-19 10:36:14 -02001703 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -02001704 map__fixup_start(map);
1705 map__fixup_end(map);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -03001706 }
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -03001707
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -03001708 return err;
1709}
1710
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001711LIST_HEAD(dsos__user);
1712LIST_HEAD(dsos__kernel);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001713
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001714static void dsos__add(struct list_head *head, struct dso *dso)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001715{
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001716 list_add_tail(&dso->node, head);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001717}
1718
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001719static struct dso *dsos__find(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001720{
1721 struct dso *pos;
1722
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001723 list_for_each_entry(pos, head, node)
Arnaldo Carvalho de Melocf4e5b02010-01-14 23:45:27 -02001724 if (strcmp(pos->long_name, name) == 0)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001725 return pos;
1726 return NULL;
1727}
1728
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001729struct dso *__dsos__findnew(struct list_head *head, const char *name)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001730{
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001731 struct dso *dso = dsos__find(head, name);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001732
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02001733 if (!dso) {
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -02001734 dso = dso__new(name);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001735 if (dso != NULL) {
Arnaldo Carvalho de Meloa89e5abe2010-01-07 19:59:39 -02001736 dsos__add(head, dso);
Arnaldo Carvalho de Melocfc10d32009-11-17 15:40:53 -02001737 dso__set_basename(dso);
1738 }
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -02001739 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001740
1741 return dso;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001742}
1743
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001744static void __dsos__fprintf(struct list_head *head, FILE *fp)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001745{
1746 struct dso *pos;
1747
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001748 list_for_each_entry(pos, head, node) {
1749 int i;
1750 for (i = 0; i < MAP__NR_TYPES; ++i)
1751 dso__fprintf(pos, i, fp);
1752 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001753}
1754
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001755void dsos__fprintf(FILE *fp)
1756{
1757 __dsos__fprintf(&dsos__kernel, fp);
1758 __dsos__fprintf(&dsos__user, fp);
1759}
1760
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001761static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1762 bool with_hits)
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001763{
1764 struct dso *pos;
1765 size_t ret = 0;
1766
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001767 list_for_each_entry(pos, head, node) {
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001768 if (with_hits && !pos->hit)
1769 continue;
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001770 ret += dso__fprintf_buildid(pos, fp);
Arnaldo Carvalho de Melo1124ba72009-11-16 21:45:25 -02001771 ret += fprintf(fp, " %s\n", pos->long_name);
Arnaldo Carvalho de Melo9e03eb22009-11-16 16:32:44 -02001772 }
1773 return ret;
1774}
1775
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001776size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001777{
Arnaldo Carvalho de Melo88d3d9b72010-01-14 23:45:30 -02001778 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1779 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
Arnaldo Carvalho de Melob0da9542009-11-27 16:29:14 -02001780}
1781
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001782struct dso *dso__new_kernel(const char *name)
1783{
1784 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1785
1786 if (self != NULL) {
Arnaldo Carvalho de Melob63be8d2010-03-15 15:03:50 -03001787 dso__set_short_name(self, "[kernel]");
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001788 self->kernel = 1;
1789 }
1790
1791 return self;
1792}
1793
1794void dso__read_running_kernel_build_id(struct dso *self)
1795{
1796 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1797 sizeof(self->build_id)) == 0)
1798 self->has_build_id = true;
1799}
1800
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001801static struct dso *dsos__create_kernel(const char *vmlinux)
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001802{
Arnaldo Carvalho de Melofd1d9082010-01-27 21:05:51 -02001803 struct dso *kernel = dso__new_kernel(vmlinux);
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001804
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -02001805 if (kernel != NULL) {
1806 dso__read_running_kernel_build_id(kernel);
1807 dsos__add(&dsos__kernel, kernel);
1808 }
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001809
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001810 return kernel;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001811}
1812
Arnaldo Carvalho de Melob7cece72010-01-13 13:22:17 -02001813int __map_groups__create_kernel_maps(struct map_groups *self,
1814 struct map *vmlinux_maps[MAP__NR_TYPES],
1815 struct dso *kernel)
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001816{
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001817 enum map_type type;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001818
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001819 for (type = 0; type < MAP__NR_TYPES; ++type) {
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001820 struct kmap *kmap;
1821
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001822 vmlinux_maps[type] = map__new2(0, kernel, type);
1823 if (vmlinux_maps[type] == NULL)
1824 return -1;
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001825
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001826 vmlinux_maps[type]->map_ip =
1827 vmlinux_maps[type]->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001828
1829 kmap = map__kmap(vmlinux_maps[type]);
1830 kmap->kmaps = self;
Arnaldo Carvalho de Melode176482010-01-04 16:19:29 -02001831 map_groups__insert(self, vmlinux_maps[type]);
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001832 }
1833
Arnaldo Carvalho de Melof1dfa0b2009-12-11 14:50:39 -02001834 return 0;
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001835}
1836
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001837static void vmlinux_path__exit(void)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001838{
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001839 while (--vmlinux_path__nr_entries >= 0) {
1840 free(vmlinux_path[vmlinux_path__nr_entries]);
1841 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1842 }
1843
1844 free(vmlinux_path);
1845 vmlinux_path = NULL;
1846}
1847
1848static int vmlinux_path__init(void)
1849{
1850 struct utsname uts;
1851 char bf[PATH_MAX];
1852
1853 if (uname(&uts) < 0)
Arnaldo Carvalho de Melo24460422009-11-18 20:20:53 -02001854 return -1;
1855
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001856 vmlinux_path = malloc(sizeof(char *) * 5);
1857 if (vmlinux_path == NULL)
1858 return -1;
1859
1860 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1861 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1862 goto out_fail;
1863 ++vmlinux_path__nr_entries;
1864 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1865 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1866 goto out_fail;
1867 ++vmlinux_path__nr_entries;
1868 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1869 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1870 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1871 goto out_fail;
1872 ++vmlinux_path__nr_entries;
1873 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1874 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1875 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1876 goto out_fail;
1877 ++vmlinux_path__nr_entries;
1878 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1879 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
1885 return 0;
1886
1887out_fail:
1888 vmlinux_path__exit();
1889 return -1;
1890}
1891
Arnaldo Carvalho de Melob0a9ab62010-03-15 11:46:58 -03001892size_t vmlinux_path__fprintf(FILE *fp)
1893{
1894 int i;
1895 size_t printed = 0;
1896
1897 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1898 printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
1899
1900 return printed;
1901}
1902
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001903static int setup_list(struct strlist **list, const char *list_str,
1904 const char *list_name)
1905{
1906 if (list_str == NULL)
1907 return 0;
1908
1909 *list = strlist__new(true, list_str);
1910 if (!*list) {
1911 pr_err("problems parsing %s list\n", list_name);
1912 return -1;
1913 }
1914 return 0;
1915}
1916
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001917int symbol__init(void)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001918{
Arnaldo Carvalho de Melo95011c62009-11-27 16:29:20 -02001919 elf_version(EV_CURRENT);
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001920 if (symbol_conf.sort_by_name)
1921 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1922 sizeof(struct symbol));
Arnaldo Carvalho de Melob32d1332009-11-24 12:05:15 -02001923
Arnaldo Carvalho de Melo75be6cf2009-12-15 20:04:39 -02001924 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001925 return -1;
1926
Arnaldo Carvalho de Meloc410a332009-12-15 20:04:41 -02001927 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1928 pr_err("'.' is the only non valid --field-separator argument\n");
1929 return -1;
1930 }
1931
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001932 if (setup_list(&symbol_conf.dso_list,
1933 symbol_conf.dso_list_str, "dso") < 0)
1934 return -1;
1935
1936 if (setup_list(&symbol_conf.comm_list,
1937 symbol_conf.comm_list_str, "comm") < 0)
1938 goto out_free_dso_list;
1939
1940 if (setup_list(&symbol_conf.sym_list,
1941 symbol_conf.sym_list_str, "symbol") < 0)
1942 goto out_free_comm_list;
1943
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001944 return 0;
Arnaldo Carvalho de Melo655000e2009-12-15 20:04:40 -02001945
1946out_free_dso_list:
1947 strlist__delete(symbol_conf.dso_list);
1948out_free_comm_list:
1949 strlist__delete(symbol_conf.comm_list);
1950 return -1;
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001951}
Arnaldo Carvalho de Melocc612d82009-11-23 16:39:10 -02001952
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001953int map_groups__create_kernel_maps(struct map_groups *self,
1954 struct map *vmlinux_maps[MAP__NR_TYPES])
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001955{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001956 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1957
1958 if (kernel == NULL)
Arnaldo Carvalho de Melo4aa65632009-12-13 19:50:29 -02001959 return -1;
1960
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001961 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1962 return -1;
1963
1964 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
Arnaldo Carvalho de Melo10fe12e2010-02-20 19:53:13 -02001965 pr_debug("Problems creating module maps, continuing anyway...\n");
Arnaldo Carvalho de Melo90c83212009-11-21 14:31:24 -02001966 /*
1967 * Now that we have all the maps created, just set the ->end of them:
1968 */
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -02001969 map_groups__fixup_end(self);
Arnaldo Carvalho de Melo6671cb12009-11-20 20:51:24 -02001970 return 0;
Frederic Weisbeckercd84c2a2009-08-12 10:03:49 +02001971}
Arnaldo Carvalho de Melo5aab6212010-03-25 19:59:00 -03001972
1973static int hex(char ch)
1974{
1975 if ((ch >= '0') && (ch <= '9'))
1976 return ch - '0';
1977 if ((ch >= 'a') && (ch <= 'f'))
1978 return ch - 'a' + 10;
1979 if ((ch >= 'A') && (ch <= 'F'))
1980 return ch - 'A' + 10;
1981 return -1;
1982}
1983
1984/*
1985 * While we find nice hex chars, build a long_val.
1986 * Return number of chars processed.
1987 */
1988int hex2u64(const char *ptr, u64 *long_val)
1989{
1990 const char *p = ptr;
1991 *long_val = 0;
1992
1993 while (*p) {
1994 const int hex_val = hex(*p);
1995
1996 if (hex_val < 0)
1997 break;
1998
1999 *long_val = (*long_val << 4) | hex_val;
2000 p++;
2001 }
2002
2003 return p - ptr;
2004}
2005
2006char *strxfrchar(char *s, char from, char to)
2007{
2008 char *p = s;
2009
2010 while ((p = strchr(p, from)) != NULL)
2011 *p++ = to;
2012
2013 return s;
2014}