xref: /freebsd/usr.sbin/kldxref/ef_obj.c (revision a0ee8cc6)
1 /*
2  * Copyright (c) 2000, Boris Popov
3  * Copyright (c) 1998-2000 Doug Rabson
4  * Copyright (c) 2004 Peter Wemm
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Boris Popov.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $FreeBSD$
35  */
36 
37 #include <sys/param.h>
38 #include <sys/linker.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <machine/elf.h>
46 #define FREEBSD_ELF
47 
48 #include <err.h>
49 
50 #include "ef.h"
51 
52 typedef struct {
53 	void		*addr;
54 	Elf_Off		size;
55 	int		flags;
56 	int		sec;	/* Original section */
57 	char		*name;
58 } Elf_progent;
59 
60 typedef struct {
61 	Elf_Rel		*rel;
62 	int		nrel;
63 	int		sec;
64 } Elf_relent;
65 
66 typedef struct {
67 	Elf_Rela	*rela;
68 	int		nrela;
69 	int		sec;
70 } Elf_relaent;
71 
72 struct ef_file {
73 	char		*ef_name;
74 	int		ef_fd;
75 	Elf_Ehdr	ef_hdr;
76 	struct elf_file *ef_efile;
77 
78 	caddr_t		address;
79 	Elf_Off		size;
80 	Elf_Shdr	*e_shdr;
81 
82 	Elf_progent	*progtab;
83 	int		nprogtab;
84 
85 	Elf_relaent	*relatab;
86 	int		nrela;
87 
88 	Elf_relent	*reltab;
89 	int		nrel;
90 
91 	Elf_Sym		*ddbsymtab;	/* The symbol table we are using */
92 	long		ddbsymcnt;	/* Number of symbols */
93 	caddr_t		ddbstrtab;	/* String table */
94 	long		ddbstrcnt;	/* number of bytes in string table */
95 
96 	caddr_t		shstrtab;	/* Section name string table */
97 	long		shstrcnt;	/* number of bytes in string table */
98 
99 	int		ef_verbose;
100 };
101 
102 static int ef_obj_get_type(elf_file_t ef);
103 static int ef_obj_close(elf_file_t ef);
104 static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest);
105 static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
106     void **ptr);
107 static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
108     void *dest);
109 static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
110     void *dest);
111 static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
112     void **ptr);
113 static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
114     void **ptr);
115 static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx);
116 static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp,
117     long *stopp, long *countp);
118 static int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym);
119 
120 static struct elf_file_ops ef_obj_file_ops = {
121 	ef_obj_get_type,
122 	ef_obj_close,
123 	ef_obj_read,
124 	ef_obj_read_entry,
125 	ef_obj_seg_read,
126 	ef_obj_seg_read_rel,
127 	ef_obj_seg_read_entry,
128 	ef_obj_seg_read_entry_rel,
129 	ef_obj_symaddr,
130 	ef_obj_lookup_set,
131 	ef_obj_lookup_symbol
132 };
133 
134 static int
135 ef_obj_get_type(elf_file_t __unused ef)
136 {
137 
138 	return (EFT_KLD);
139 }
140 
141 static int
142 ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym)
143 {
144 	Elf_Sym *symp;
145 	const char *strp;
146 	int i;
147 
148 	for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
149 		strp = ef->ddbstrtab + symp->st_name;
150 		if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) {
151 			*sym = symp;
152 			return 0;
153 		}
154 	}
155 	return ENOENT;
156 }
157 
158 static int
159 ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp,
160     long *countp)
161 {
162 	int i;
163 
164 	for (i = 0; i < ef->nprogtab; i++) {
165 		if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) &&
166 		    strcmp(ef->progtab[i].name + 4, name) == 0) {
167 			*startp = (char *)ef->progtab[i].addr - ef->address;
168 			*stopp = (char *)ef->progtab[i].addr +
169 			    ef->progtab[i].size - ef->address;
170 			*countp = (*stopp - *startp) / sizeof(void *);
171 			return (0);
172 		}
173 	}
174 	return (ESRCH);
175 }
176 
177 static Elf_Addr
178 ef_obj_symaddr(elf_file_t ef, Elf_Size symidx)
179 {
180 	const Elf_Sym *sym;
181 
182 	if (symidx >= (size_t) ef->ddbsymcnt)
183 		return (0);
184 	sym = ef->ddbsymtab + symidx;
185 
186 	if (sym->st_shndx != SHN_UNDEF)
187 		return (sym->st_value - (Elf_Addr)ef->address);
188 	return (0);
189 }
190 
191 static int
192 ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
193 {
194 	ssize_t r;
195 
196 	if (offset != (Elf_Off)-1) {
197 		if (lseek(ef->ef_fd, offset, SEEK_SET) == -1)
198 			return EIO;
199 	}
200 
201 	r = read(ef->ef_fd, dest, len);
202 	if (r != -1 && (size_t)r == len)
203 		return 0;
204 	else
205 		return EIO;
206 }
207 
208 static int
209 ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
210 {
211 	int error;
212 
213 	*ptr = malloc(len);
214 	if (*ptr == NULL)
215 		return ENOMEM;
216 	error = ef_obj_read(ef, offset, len, *ptr);
217 	if (error)
218 		free(*ptr);
219 	return error;
220 }
221 
222 static int
223 ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
224 {
225 
226 	if (offset + len > ef->size) {
227 		if (ef->ef_verbose)
228 			warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
229 			    ef->ef_name, (long)offset, (long)len);
230 		return (EFAULT);
231 	}
232 	bcopy(ef->address + offset, dest, len);
233 	return (0);
234 }
235 
236 static int
237 ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
238 {
239 	char *memaddr;
240 	Elf_Rel *r;
241 	Elf_Rela *a;
242 	Elf_Off secbase, dataoff;
243 	int error, i, sec;
244 
245 	if (offset + len > ef->size) {
246 		if (ef->ef_verbose)
247 			warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
248 			    ef->ef_name, (long)offset, (long)len);
249 		return (EFAULT);
250 	}
251 	bcopy(ef->address + offset, dest, len);
252 
253 	/* Find out which section contains the data. */
254 	memaddr = ef->address + offset;
255 	sec = -1;
256 	secbase = dataoff = 0;
257 	for (i = 0; i < ef->nprogtab; i++) {
258 		if (ef->progtab[i].addr == NULL)
259 			continue;
260 		if (memaddr < (char *)ef->progtab[i].addr || memaddr + len >
261 		     (char *)ef->progtab[i].addr + ef->progtab[i].size)
262 			continue;
263 		sec = ef->progtab[i].sec;
264 		/* We relocate to address 0. */
265 		secbase = (char *)ef->progtab[i].addr - ef->address;
266 		dataoff = memaddr - ef->address;
267 		break;
268 	}
269 
270 	if (sec == -1)
271 		return (EFAULT);
272 
273 	/* Now do the relocations. */
274 	for (i = 0; i < ef->nrel; i++) {
275 		if (ef->reltab[i].sec != sec)
276 			continue;
277 		for (r = ef->reltab[i].rel;
278 		     r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) {
279 			error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase,
280 			    dataoff, len, dest);
281 			if (error != 0)
282 				return (error);
283 		}
284 	}
285 	for (i = 0; i < ef->nrela; i++) {
286 		if (ef->relatab[i].sec != sec)
287 			continue;
288 		for (a = ef->relatab[i].rela;
289 		     a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) {
290 			error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA,
291 			    secbase, dataoff, len, dest);
292 			if (error != 0)
293 				return (error);
294 		}
295 	}
296 	return (0);
297 }
298 
299 static int
300 ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
301 {
302 	int error;
303 
304 	*ptr = malloc(len);
305 	if (*ptr == NULL)
306 		return ENOMEM;
307 	error = ef_obj_seg_read(ef, offset, len, *ptr);
308 	if (error)
309 		free(*ptr);
310 	return error;
311 }
312 
313 static int
314 ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
315     void **ptr)
316 {
317 	int error;
318 
319 	*ptr = malloc(len);
320 	if (*ptr == NULL)
321 		return ENOMEM;
322 	error = ef_obj_seg_read_rel(ef, offset, len, *ptr);
323 	if (error)
324 		free(*ptr);
325 	return error;
326 }
327 
328 int
329 ef_obj_open(const char *filename, struct elf_file *efile, int verbose)
330 {
331 	elf_file_t ef;
332 	Elf_Ehdr *hdr;
333 	Elf_Shdr *shdr;
334 	Elf_Sym *es;
335 	char *mapbase;
336 	void *vtmp;
337 	size_t mapsize, alignmask, max_addralign;
338 	int error, fd, pb, ra, res, rl;
339 	int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex;
340 
341 	if (filename == NULL)
342 		return EFTYPE;
343 	if ((fd = open(filename, O_RDONLY)) == -1)
344 		return errno;
345 
346 	ef = calloc(1, sizeof(*ef));
347 	if (ef == NULL) {
348 		close(fd);
349 		return (ENOMEM);
350 	}
351 
352 	efile->ef_ef = ef;
353 	efile->ef_ops = &ef_obj_file_ops;
354 
355 	ef->ef_verbose = verbose;
356 	ef->ef_fd = fd;
357 	ef->ef_name = strdup(filename);
358 	ef->ef_efile = efile;
359 	hdr = (Elf_Ehdr *)&ef->ef_hdr;
360 
361 	res = read(fd, hdr, sizeof(*hdr));
362 	error = EFTYPE;
363 	if (res != sizeof(*hdr))
364 		goto out;
365 	if (!IS_ELF(*hdr))
366 		goto out;
367 	if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
368 	    hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
369 	    hdr->e_ident[EI_VERSION] != EV_CURRENT ||
370 	    hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH ||
371 	    hdr->e_type != ET_REL)
372 		goto out;
373 
374 	nbytes = hdr->e_shnum * hdr->e_shentsize;
375 	if (nbytes == 0 || hdr->e_shoff == 0 ||
376 	    hdr->e_shentsize != sizeof(Elf_Shdr))
377 		goto out;
378 
379 	if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) {
380 		printf("ef_read_entry failed\n");
381 		goto out;
382 	}
383 	ef->e_shdr = shdr = vtmp;
384 
385 	/* Scan the section header for information and table sizing. */
386 	nsym = 0;
387 	symtabindex = -1;
388 	symstrindex = -1;
389 	for (i = 0; i < hdr->e_shnum; i++) {
390 		switch (shdr[i].sh_type) {
391 		case SHT_PROGBITS:
392 		case SHT_NOBITS:
393 			ef->nprogtab++;
394 			break;
395 		case SHT_SYMTAB:
396 			nsym++;
397 			symtabindex = i;
398 			symstrindex = shdr[i].sh_link;
399 			break;
400 		case SHT_REL:
401 			ef->nrel++;
402 			break;
403 		case SHT_RELA:
404 			ef->nrela++;
405 			break;
406 		case SHT_STRTAB:
407 			break;
408 		}
409 	}
410 
411 	if (ef->nprogtab == 0) {
412 		warnx("%s: file has no contents", filename);
413 		goto out;
414 	}
415 	if (nsym != 1) {
416 		warnx("%s: file has no valid symbol table", filename);
417 		goto out;
418 	}
419 	if (symstrindex < 0 || symstrindex > hdr->e_shnum ||
420 	    shdr[symstrindex].sh_type != SHT_STRTAB) {
421 		warnx("%s: file has invalid symbol strings", filename);
422 		goto out;
423 	}
424 
425 	/* Allocate space for tracking the load chunks */
426 	if (ef->nprogtab != 0)
427 		ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab));
428 	if (ef->nrel != 0)
429 		ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab));
430 	if (ef->nrela != 0)
431 		ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab));
432 	if ((ef->nprogtab != 0 && ef->progtab == NULL) ||
433 	    (ef->nrel != 0 && ef->reltab == NULL) ||
434 	    (ef->nrela != 0 && ef->relatab == NULL)) {
435 		printf("malloc failed\n");
436 		error = ENOMEM;
437 		goto out;
438 	}
439 
440 	ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
441 	if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset,
442 	    shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) {
443 		printf("ef_read_entry failed\n");
444 		goto out;
445 	}
446 
447 	ef->ddbstrcnt = shdr[symstrindex].sh_size;
448 	if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset,
449 	    shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) {
450 		printf("ef_read_entry failed\n");
451 		goto out;
452 	}
453 
454 	/* Do we have a string table for the section names?  */
455 	shstrindex = -1;
456 	if (hdr->e_shstrndx != 0 &&
457 	    shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) {
458 		shstrindex = hdr->e_shstrndx;
459 		ef->shstrcnt = shdr[shstrindex].sh_size;
460 		if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset,
461 		    shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) {
462 			printf("ef_read_entry failed\n");
463 			goto out;
464 		}
465 	}
466 
467 	/* Size up code/data(progbits) and bss(nobits). */
468 	alignmask = 0;
469 	max_addralign = 0;
470 	mapsize = 0;
471 	for (i = 0; i < hdr->e_shnum; i++) {
472 		switch (shdr[i].sh_type) {
473 		case SHT_PROGBITS:
474 		case SHT_NOBITS:
475 			alignmask = shdr[i].sh_addralign - 1;
476 			if (shdr[i].sh_addralign > max_addralign)
477 				max_addralign = shdr[i].sh_addralign;
478 			mapsize += alignmask;
479 			mapsize &= ~alignmask;
480 			mapsize += shdr[i].sh_size;
481 			break;
482 		}
483 	}
484 
485 	/* We know how much space we need for the text/data/bss/etc. */
486 	ef->size = mapsize;
487 	if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) {
488 		printf("posix_memalign failed\n");
489 		goto out;
490 	}
491 	mapbase = ef->address;
492 
493 	/*
494 	 * Now load code/data(progbits), zero bss(nobits), allocate
495 	 * space for and load relocs
496 	 */
497 	pb = 0;
498 	rl = 0;
499 	ra = 0;
500 	alignmask = 0;
501 	for (i = 0; i < hdr->e_shnum; i++) {
502 		switch (shdr[i].sh_type) {
503 		case SHT_PROGBITS:
504 		case SHT_NOBITS:
505 			alignmask = shdr[i].sh_addralign - 1;
506 			mapbase += alignmask;
507 			mapbase  = (char *)((uintptr_t)mapbase & ~alignmask);
508 			ef->progtab[pb].addr = (void *)(uintptr_t)mapbase;
509 			if (shdr[i].sh_type == SHT_PROGBITS) {
510 				ef->progtab[pb].name = "<<PROGBITS>>";
511 				if (ef_obj_read(ef, shdr[i].sh_offset,
512 				    shdr[i].sh_size,
513 				    ef->progtab[pb].addr) != 0) {
514 					printf("failed to read progbits\n");
515 					goto out;
516 				}
517 			} else {
518 				ef->progtab[pb].name = "<<NOBITS>>";
519 				bzero(ef->progtab[pb].addr, shdr[i].sh_size);
520 			}
521 			ef->progtab[pb].size = shdr[i].sh_size;
522 			ef->progtab[pb].sec = i;
523 			if (ef->shstrtab && shdr[i].sh_name != 0)
524 				ef->progtab[pb].name =
525 				    ef->shstrtab + shdr[i].sh_name;
526 
527 			/* Update all symbol values with the offset. */
528 			for (j = 0; j < ef->ddbsymcnt; j++) {
529 				es = &ef->ddbsymtab[j];
530 				if (es->st_shndx != i)
531 					continue;
532 				es->st_value += (Elf_Addr)ef->progtab[pb].addr;
533 			}
534 			mapbase += shdr[i].sh_size;
535 			pb++;
536 			break;
537 		case SHT_REL:
538 			ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel);
539 			ef->reltab[rl].sec = shdr[i].sh_info;
540 			if (ef_obj_read_entry(ef, shdr[i].sh_offset,
541 			    shdr[i].sh_size, (void**)&ef->reltab[rl].rel) !=
542 			    0) {
543 				printf("ef_read_entry failed\n");
544 				goto out;
545 			}
546 			rl++;
547 			break;
548 		case SHT_RELA:
549 			ef->relatab[ra].nrela =
550 			    shdr[i].sh_size / sizeof(Elf_Rela);
551 			ef->relatab[ra].sec = shdr[i].sh_info;
552 			if (ef_obj_read_entry(ef, shdr[i].sh_offset,
553 			    shdr[i].sh_size, (void**)&ef->relatab[ra].rela) !=
554 			    0) {
555 				printf("ef_read_entry failed\n");
556 				goto out;
557 			}
558 			ra++;
559 			break;
560 		}
561 	}
562 	error = 0;
563 out:
564 	if (error)
565 		ef_obj_close(ef);
566 	return error;
567 }
568 
569 static int
570 ef_obj_close(elf_file_t ef)
571 {
572 	int i;
573 
574 	close(ef->ef_fd);
575 	if (ef->ef_name)
576 		free(ef->ef_name);
577 	if (ef->e_shdr != NULL)
578 		free(ef->e_shdr);
579 	if (ef->size != 0)
580 		free(ef->address);
581 	if (ef->nprogtab != 0)
582 		free(ef->progtab);
583 	if (ef->nrel != 0) {
584 		for (i = 0; i < ef->nrel; i++)
585 			if (ef->reltab[i].rel != NULL)
586 				free(ef->reltab[i].rel);
587 		free(ef->reltab);
588 	}
589 	if (ef->nrela != 0) {
590 		for (i = 0; i < ef->nrela; i++)
591 			if (ef->relatab[i].rela != NULL)
592 				free(ef->relatab[i].rela);
593 		free(ef->relatab);
594 	}
595 	if (ef->ddbsymtab != NULL)
596 		free(ef->ddbsymtab);
597 	if (ef->ddbstrtab != NULL)
598 		free(ef->ddbstrtab);
599 	if (ef->shstrtab != NULL)
600 		free(ef->shstrtab);
601 	ef->ef_efile->ef_ops = NULL;
602 	ef->ef_efile->ef_ef = NULL;
603 	free(ef);
604 
605 	return 0;
606 }
607