ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/usr.sbin/kldxref/ef_obj.c
Revision: 10729
Committed: Sat Jun 9 21:59:22 2018 UTC (5 years, 10 months ago) by laffer1
Content type: text/plain
File size: 15237 byte(s)
Log Message:
sync

File Contents

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

Properties

Name Value
svn:keywords MidnightBSD=%H