xref: /linux/tools/perf/util/symbol.c (revision 2277ab4a1df50e05bc732fe9488d4e902bb8399a)
1 #include "util.h"
2 #include "../perf.h"
3 #include "string.h"
4 #include "symbol.h"
5 
6 #include <libelf.h>
7 #include <gelf.h>
8 #include <elf.h>
9 
10 const char *sym_hist_filter;
11 
12 static struct symbol *symbol__new(u64 start, u64 len,
13 				  const char *name, unsigned int priv_size,
14 				  u64 obj_start, int verbose)
15 {
16 	size_t namelen = strlen(name) + 1;
17 	struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
18 
19 	if (!self)
20 		return NULL;
21 
22 	if (verbose >= 2)
23 		printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24 			(u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25 
26 	self->obj_start= obj_start;
27 	self->hist = NULL;
28 	self->hist_sum = 0;
29 
30 	if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31 		self->hist = calloc(sizeof(u64), len);
32 
33 	if (priv_size) {
34 		memset(self, 0, priv_size);
35 		self = ((void *)self) + priv_size;
36 	}
37 	self->start = start;
38 	self->end   = len ? start + len - 1 : start;
39 	memcpy(self->name, name, namelen);
40 
41 	return self;
42 }
43 
44 static void symbol__delete(struct symbol *self, unsigned int priv_size)
45 {
46 	free(((void *)self) - priv_size);
47 }
48 
49 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50 {
51 	if (!self->module)
52 		return fprintf(fp, " %llx-%llx %s\n",
53 		       self->start, self->end, self->name);
54 	else
55 		return fprintf(fp, " %llx-%llx %s \t[%s]\n",
56 		       self->start, self->end, self->name, self->module->name);
57 }
58 
59 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
60 {
61 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
62 
63 	if (self != NULL) {
64 		strcpy(self->name, name);
65 		self->syms = RB_ROOT;
66 		self->sym_priv_size = sym_priv_size;
67 		self->find_symbol = dso__find_symbol;
68 	}
69 
70 	return self;
71 }
72 
73 static void dso__delete_symbols(struct dso *self)
74 {
75 	struct symbol *pos;
76 	struct rb_node *next = rb_first(&self->syms);
77 
78 	while (next) {
79 		pos = rb_entry(next, struct symbol, rb_node);
80 		next = rb_next(&pos->rb_node);
81 		rb_erase(&pos->rb_node, &self->syms);
82 		symbol__delete(pos, self->sym_priv_size);
83 	}
84 }
85 
86 void dso__delete(struct dso *self)
87 {
88 	dso__delete_symbols(self);
89 	free(self);
90 }
91 
92 static void dso__insert_symbol(struct dso *self, struct symbol *sym)
93 {
94 	struct rb_node **p = &self->syms.rb_node;
95 	struct rb_node *parent = NULL;
96 	const u64 ip = sym->start;
97 	struct symbol *s;
98 
99 	while (*p != NULL) {
100 		parent = *p;
101 		s = rb_entry(parent, struct symbol, rb_node);
102 		if (ip < s->start)
103 			p = &(*p)->rb_left;
104 		else
105 			p = &(*p)->rb_right;
106 	}
107 	rb_link_node(&sym->rb_node, parent, p);
108 	rb_insert_color(&sym->rb_node, &self->syms);
109 }
110 
111 struct symbol *dso__find_symbol(struct dso *self, u64 ip)
112 {
113 	struct rb_node *n;
114 
115 	if (self == NULL)
116 		return NULL;
117 
118 	n = self->syms.rb_node;
119 
120 	while (n) {
121 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
122 
123 		if (ip < s->start)
124 			n = n->rb_left;
125 		else if (ip > s->end)
126 			n = n->rb_right;
127 		else
128 			return s;
129 	}
130 
131 	return NULL;
132 }
133 
134 size_t dso__fprintf(struct dso *self, FILE *fp)
135 {
136 	size_t ret = fprintf(fp, "dso: %s\n", self->name);
137 
138 	struct rb_node *nd;
139 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
140 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
141 		ret += symbol__fprintf(pos, fp);
142 	}
143 
144 	return ret;
145 }
146 
147 static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
148 {
149 	struct rb_node *nd, *prevnd;
150 	char *line = NULL;
151 	size_t n;
152 	FILE *file = fopen("/proc/kallsyms", "r");
153 	int count = 0;
154 
155 	if (file == NULL)
156 		goto out_failure;
157 
158 	while (!feof(file)) {
159 		u64 start;
160 		struct symbol *sym;
161 		int line_len, len;
162 		char symbol_type;
163 
164 		line_len = getline(&line, &n, file);
165 		if (line_len < 0)
166 			break;
167 
168 		if (!line)
169 			goto out_failure;
170 
171 		line[--line_len] = '\0'; /* \n */
172 
173 		len = hex2u64(line, &start);
174 
175 		len++;
176 		if (len + 2 >= line_len)
177 			continue;
178 
179 		symbol_type = toupper(line[len]);
180 		/*
181 		 * We're interested only in code ('T'ext)
182 		 */
183 		if (symbol_type != 'T' && symbol_type != 'W')
184 			continue;
185 		/*
186 		 * Well fix up the end later, when we have all sorted.
187 		 */
188 		sym = symbol__new(start, 0xdead, line + len + 2,
189 				  self->sym_priv_size, 0, verbose);
190 
191 		if (sym == NULL)
192 			goto out_delete_line;
193 
194 		if (filter && filter(self, sym))
195 			symbol__delete(sym, self->sym_priv_size);
196 		else {
197 			dso__insert_symbol(self, sym);
198 			count++;
199 		}
200 	}
201 
202 	/*
203 	 * Now that we have all sorted out, just set the ->end of all
204 	 * symbols
205 	 */
206 	prevnd = rb_first(&self->syms);
207 
208 	if (prevnd == NULL)
209 		goto out_delete_line;
210 
211 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
212 		struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
213 			      *curr = rb_entry(nd, struct symbol, rb_node);
214 
215 		prev->end = curr->start - 1;
216 		prevnd = nd;
217 	}
218 
219 	free(line);
220 	fclose(file);
221 
222 	return count;
223 
224 out_delete_line:
225 	free(line);
226 out_failure:
227 	return -1;
228 }
229 
230 static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
231 {
232 	char *line = NULL;
233 	size_t n;
234 	FILE *file;
235 	int nr_syms = 0;
236 
237 	file = fopen(self->name, "r");
238 	if (file == NULL)
239 		goto out_failure;
240 
241 	while (!feof(file)) {
242 		u64 start, size;
243 		struct symbol *sym;
244 		int line_len, len;
245 
246 		line_len = getline(&line, &n, file);
247 		if (line_len < 0)
248 			break;
249 
250 		if (!line)
251 			goto out_failure;
252 
253 		line[--line_len] = '\0'; /* \n */
254 
255 		len = hex2u64(line, &start);
256 
257 		len++;
258 		if (len + 2 >= line_len)
259 			continue;
260 
261 		len += hex2u64(line + len, &size);
262 
263 		len++;
264 		if (len + 2 >= line_len)
265 			continue;
266 
267 		sym = symbol__new(start, size, line + len,
268 				  self->sym_priv_size, start, verbose);
269 
270 		if (sym == NULL)
271 			goto out_delete_line;
272 
273 		if (filter && filter(self, sym))
274 			symbol__delete(sym, self->sym_priv_size);
275 		else {
276 			dso__insert_symbol(self, sym);
277 			nr_syms++;
278 		}
279 	}
280 
281 	free(line);
282 	fclose(file);
283 
284 	return nr_syms;
285 
286 out_delete_line:
287 	free(line);
288 out_failure:
289 	return -1;
290 }
291 
292 /**
293  * elf_symtab__for_each_symbol - iterate thru all the symbols
294  *
295  * @self: struct elf_symtab instance to iterate
296  * @index: uint32_t index
297  * @sym: GElf_Sym iterator
298  */
299 #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
300 	for (index = 0, gelf_getsym(syms, index, &sym);\
301 	     index < nr_syms; \
302 	     index++, gelf_getsym(syms, index, &sym))
303 
304 static inline uint8_t elf_sym__type(const GElf_Sym *sym)
305 {
306 	return GELF_ST_TYPE(sym->st_info);
307 }
308 
309 static inline int elf_sym__is_function(const GElf_Sym *sym)
310 {
311 	return elf_sym__type(sym) == STT_FUNC &&
312 	       sym->st_name != 0 &&
313 	       sym->st_shndx != SHN_UNDEF &&
314 	       sym->st_size != 0;
315 }
316 
317 static inline int elf_sym__is_label(const GElf_Sym *sym)
318 {
319 	return elf_sym__type(sym) == STT_NOTYPE &&
320 		sym->st_name != 0 &&
321 		sym->st_shndx != SHN_UNDEF &&
322 		sym->st_shndx != SHN_ABS;
323 }
324 
325 static inline const char *elf_sec__name(const GElf_Shdr *shdr,
326 					const Elf_Data *secstrs)
327 {
328 	return secstrs->d_buf + shdr->sh_name;
329 }
330 
331 static inline int elf_sec__is_text(const GElf_Shdr *shdr,
332 					const Elf_Data *secstrs)
333 {
334 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
335 }
336 
337 static inline const char *elf_sym__name(const GElf_Sym *sym,
338 					const Elf_Data *symstrs)
339 {
340 	return symstrs->d_buf + sym->st_name;
341 }
342 
343 static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
344 				    GElf_Shdr *shp, const char *name,
345 				    size_t *index)
346 {
347 	Elf_Scn *sec = NULL;
348 	size_t cnt = 1;
349 
350 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
351 		char *str;
352 
353 		gelf_getshdr(sec, shp);
354 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
355 		if (!strcmp(name, str)) {
356 			if (index)
357 				*index = cnt;
358 			break;
359 		}
360 		++cnt;
361 	}
362 
363 	return sec;
364 }
365 
366 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
367 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
368 	     idx < nr_entries; \
369 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
370 
371 #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
372 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
373 	     idx < nr_entries; \
374 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 
376 static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
377 				       GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
378 				       GElf_Shdr *shdr_dynsym,
379 				       size_t dynsym_idx, int verbose)
380 {
381 	uint32_t nr_rel_entries, idx;
382 	GElf_Sym sym;
383 	u64 plt_offset;
384 	GElf_Shdr shdr_plt;
385 	struct symbol *f;
386 	GElf_Shdr shdr_rel_plt;
387 	Elf_Data *reldata, *syms, *symstrs;
388 	Elf_Scn *scn_plt_rel, *scn_symstrs;
389 	char sympltname[1024];
390 	int nr = 0, symidx;
391 
392 	scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
393 					  ".rela.plt", NULL);
394 	if (scn_plt_rel == NULL) {
395 		scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
396 						  ".rel.plt", NULL);
397 		if (scn_plt_rel == NULL)
398 			return 0;
399 	}
400 
401 	if (shdr_rel_plt.sh_link != dynsym_idx)
402 		return 0;
403 
404 	if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 		return 0;
406 
407 	/*
408 	 * Fetch the relocation section to find the indexes to the GOT
409 	 * and the symbols in the .dynsym they refer to.
410 	 */
411 	reldata = elf_getdata(scn_plt_rel, NULL);
412 	if (reldata == NULL)
413 		return -1;
414 
415 	syms = elf_getdata(scn_dynsym, NULL);
416 	if (syms == NULL)
417 		return -1;
418 
419 	scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
420 	if (scn_symstrs == NULL)
421 		return -1;
422 
423 	symstrs = elf_getdata(scn_symstrs, NULL);
424 	if (symstrs == NULL)
425 		return -1;
426 
427 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 	plt_offset = shdr_plt.sh_offset;
429 
430 	if (shdr_rel_plt.sh_type == SHT_RELA) {
431 		GElf_Rela pos_mem, *pos;
432 
433 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
434 					   nr_rel_entries) {
435 			symidx = GELF_R_SYM(pos->r_info);
436 			plt_offset += shdr_plt.sh_entsize;
437 			gelf_getsym(syms, symidx, &sym);
438 			snprintf(sympltname, sizeof(sympltname),
439 				 "%s@plt", elf_sym__name(&sym, symstrs));
440 
441 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 					sympltname, self->sym_priv_size, 0, verbose);
443 			if (!f)
444 				return -1;
445 
446 			dso__insert_symbol(self, f);
447 			++nr;
448 		}
449 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
450 		GElf_Rel pos_mem, *pos;
451 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
452 					  nr_rel_entries) {
453 			symidx = GELF_R_SYM(pos->r_info);
454 			plt_offset += shdr_plt.sh_entsize;
455 			gelf_getsym(syms, symidx, &sym);
456 			snprintf(sympltname, sizeof(sympltname),
457 				 "%s@plt", elf_sym__name(&sym, symstrs));
458 
459 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 					sympltname, self->sym_priv_size, 0, verbose);
461 			if (!f)
462 				return -1;
463 
464 			dso__insert_symbol(self, f);
465 			++nr;
466 		}
467 	} else {
468 		/*
469 		 * TODO: There are still one more shdr_rel_plt.sh_type
470 		 * I have to investigate, but probably should be ignored.
471 		 */
472 	}
473 
474 	return nr;
475 }
476 
477 static int dso__load_sym(struct dso *self, int fd, const char *name,
478 			 symbol_filter_t filter, int verbose, struct module *mod)
479 {
480 	Elf_Data *symstrs, *secstrs;
481 	uint32_t nr_syms;
482 	int err = -1;
483 	uint32_t index;
484 	GElf_Ehdr ehdr;
485 	GElf_Shdr shdr;
486 	Elf_Data *syms;
487 	GElf_Sym sym;
488 	Elf_Scn *sec, *sec_dynsym, *sec_strndx;
489 	Elf *elf;
490 	size_t dynsym_idx;
491 	int nr = 0;
492 
493 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 	if (elf == NULL) {
495 		if (verbose)
496 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
497 				__func__, name);
498 		goto out_close;
499 	}
500 
501 	if (gelf_getehdr(elf, &ehdr) == NULL) {
502 		if (verbose)
503 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
504 		goto out_elf_end;
505 	}
506 
507 	/*
508 	 * We need to check if we have a .dynsym, so that we can handle the
509 	 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
510 	 * .dynsym or .symtab)
511 	 */
512 	sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
513 					 ".dynsym", &dynsym_idx);
514 	if (sec_dynsym != NULL) {
515 		nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
516 						 sec_dynsym, &shdr,
517 						 dynsym_idx, verbose);
518 		if (nr < 0)
519 			goto out_elf_end;
520 	}
521 
522 	/*
523 	 * But if we have a full .symtab (that is a superset of .dynsym) we
524 	 * should add the symbols not in the .dynsyn
525 	 */
526 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 	if (sec == NULL) {
528 		if (sec_dynsym == NULL)
529 			goto out_elf_end;
530 
531 		sec = sec_dynsym;
532 		gelf_getshdr(sec, &shdr);
533 	}
534 
535 	syms = elf_getdata(sec, NULL);
536 	if (syms == NULL)
537 		goto out_elf_end;
538 
539 	sec = elf_getscn(elf, shdr.sh_link);
540 	if (sec == NULL)
541 		goto out_elf_end;
542 
543 	symstrs = elf_getdata(sec, NULL);
544 	if (symstrs == NULL)
545 		goto out_elf_end;
546 
547 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
548 	if (sec_strndx == NULL)
549 		goto out_elf_end;
550 
551 	secstrs = elf_getdata(sec_strndx, NULL);
552 	if (symstrs == NULL)
553 		goto out_elf_end;
554 
555 	nr_syms = shdr.sh_size / shdr.sh_entsize;
556 
557 	memset(&sym, 0, sizeof(sym));
558 	self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 				elf_section_by_name(elf, &ehdr, &shdr,
560 						     ".gnu.prelink_undo",
561 						     NULL) != NULL);
562 	elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 		struct symbol *f;
564 		u64 obj_start;
565 		struct section *section = NULL;
566 		int is_label = elf_sym__is_label(&sym);
567 		const char *section_name;
568 
569 		if (!is_label && !elf_sym__is_function(&sym))
570 			continue;
571 
572 		sec = elf_getscn(elf, sym.st_shndx);
573 		if (!sec)
574 			goto out_elf_end;
575 
576 		gelf_getshdr(sec, &shdr);
577 
578 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
579 			continue;
580 
581 		section_name = elf_sec__name(&shdr, secstrs);
582 		obj_start = sym.st_value;
583 
584 		if (self->adjust_symbols) {
585 			if (verbose >= 2)
586 				printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
587 					(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
588 
589 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
590 		}
591 
592 		if (mod) {
593 			section = mod->sections->find_section(mod->sections, section_name);
594 			if (section)
595 				sym.st_value += section->vma;
596 			else {
597 				fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
598 					mod->name, section_name);
599 				goto out_elf_end;
600 			}
601 		}
602 
603 		f = symbol__new(sym.st_value, sym.st_size,
604 				elf_sym__name(&sym, symstrs),
605 				self->sym_priv_size, obj_start, verbose);
606 		if (!f)
607 			goto out_elf_end;
608 
609 		if (filter && filter(self, f))
610 			symbol__delete(f, self->sym_priv_size);
611 		else {
612 			f->module = mod;
613 			dso__insert_symbol(self, f);
614 			nr++;
615 		}
616 	}
617 
618 	err = nr;
619 out_elf_end:
620 	elf_end(elf);
621 out_close:
622 	return err;
623 }
624 
625 int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
626 {
627 	int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
628 	char *name = malloc(size);
629 	int variant = 0;
630 	int ret = -1;
631 	int fd;
632 
633 	if (!name)
634 		return -1;
635 
636 	self->adjust_symbols = 0;
637 
638 	if (strncmp(self->name, "/tmp/perf-", 10) == 0)
639 		return dso__load_perf_map(self, filter, verbose);
640 
641 more:
642 	do {
643 		switch (variant) {
644 		case 0: /* Fedora */
645 			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
646 			break;
647 		case 1: /* Ubuntu */
648 			snprintf(name, size, "/usr/lib/debug%s", self->name);
649 			break;
650 		case 2: /* Sane people */
651 			snprintf(name, size, "%s", self->name);
652 			break;
653 
654 		default:
655 			goto out;
656 		}
657 		variant++;
658 
659 		fd = open(name, O_RDONLY);
660 	} while (fd < 0);
661 
662 	ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
663 	close(fd);
664 
665 	/*
666 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
667 	 */
668 	if (!ret)
669 		goto more;
670 
671 out:
672 	free(name);
673 	return ret;
674 }
675 
676 static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
677 			     symbol_filter_t filter, int verbose)
678 {
679 	struct module *mod = mod_dso__find_module(mods, name);
680 	int err = 0, fd;
681 
682 	if (mod == NULL || !mod->active)
683 		return err;
684 
685 	fd = open(mod->path, O_RDONLY);
686 
687 	if (fd < 0)
688 		return err;
689 
690 	err = dso__load_sym(self, fd, name, filter, verbose, mod);
691 	close(fd);
692 
693 	return err;
694 }
695 
696 int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
697 {
698 	struct mod_dso *mods = mod_dso__new_dso("modules");
699 	struct module *pos;
700 	struct rb_node *next;
701 	int err;
702 
703 	err = mod_dso__load_modules(mods);
704 
705 	if (err <= 0)
706 		return err;
707 
708 	/*
709 	 * Iterate over modules, and load active symbols.
710 	 */
711 	next = rb_first(&mods->mods);
712 	while (next) {
713 		pos = rb_entry(next, struct module, rb_node);
714 		err = dso__load_module(self, mods, pos->name, filter, verbose);
715 
716 		if (err < 0)
717 			break;
718 
719 		next = rb_next(&pos->rb_node);
720 	}
721 
722 	if (err < 0) {
723 		mod_dso__delete_modules(mods);
724 		mod_dso__delete_self(mods);
725 	}
726 
727 	return err;
728 }
729 
730 static inline void dso__fill_symbol_holes(struct dso *self)
731 {
732 	struct symbol *prev = NULL;
733 	struct rb_node *nd;
734 
735 	for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
736 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
737 
738 		if (prev) {
739 			u64 hole = 0;
740 			int alias = pos->start == prev->start;
741 
742 			if (!alias)
743 				hole = prev->start - pos->end - 1;
744 
745 			if (hole || alias) {
746 				if (alias)
747 					pos->end = prev->end;
748 				else if (hole)
749 					pos->end = prev->start - 1;
750 			}
751 		}
752 		prev = pos;
753 	}
754 }
755 
756 static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
757 			     symbol_filter_t filter, int verbose)
758 {
759 	int err, fd = open(vmlinux, O_RDONLY);
760 
761 	if (fd < 0)
762 		return -1;
763 
764 	err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
765 
766 	if (err > 0)
767 		dso__fill_symbol_holes(self);
768 
769 	close(fd);
770 
771 	return err;
772 }
773 
774 int dso__load_kernel(struct dso *self, const char *vmlinux,
775 		     symbol_filter_t filter, int verbose, int modules)
776 {
777 	int err = -1;
778 
779 	if (vmlinux) {
780 		err = dso__load_vmlinux(self, vmlinux, filter, verbose);
781 		if (err > 0 && modules)
782 			err = dso__load_modules(self, filter, verbose);
783 	}
784 
785 	if (err <= 0)
786 		err = dso__load_kallsyms(self, filter, verbose);
787 
788 	return err;
789 }
790 
791 void symbol__init(void)
792 {
793 	elf_version(EV_CURRENT);
794 }
795