ef_obj.c revision 329247
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: stable/11/usr.sbin/kldxref/ef_obj.c 329247 2018-02-13 22:40:33Z emaste $ 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 52typedef struct { 53 void *addr; 54 Elf_Off size; 55 int flags; 56 int sec; /* Original section */ 57 char *name; 58} Elf_progent; 59 60typedef struct { 61 Elf_Rel *rel; 62 int nrel; 63 int sec; 64} Elf_relent; 65 66typedef struct { 67 Elf_Rela *rela; 68 int nrela; 69 int sec; 70} Elf_relaent; 71 72struct 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 102static int ef_obj_get_type(elf_file_t ef); 103static int ef_obj_close(elf_file_t ef); 104static int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 105static int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 106 void **ptr); 107static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, 108 void *dest); 109static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 110 void *dest); 111static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, 112 char *dest); 113static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 114 void **ptr); 115static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 116 void **ptr); 117static Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx); 118static int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, 119 long *stopp, long *countp); 120static int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 121 122static struct elf_file_ops ef_obj_file_ops = { 123 ef_obj_get_type, 124 ef_obj_close, 125 ef_obj_read, 126 ef_obj_read_entry, 127 ef_obj_seg_read, 128 ef_obj_seg_read_rel, 129 ef_obj_seg_read_string, 130 ef_obj_seg_read_entry, 131 ef_obj_seg_read_entry_rel, 132 ef_obj_symaddr, 133 ef_obj_lookup_set, 134 ef_obj_lookup_symbol 135}; 136 137static int 138ef_obj_get_type(elf_file_t __unused ef) 139{ 140 141 return (EFT_KLD); 142} 143 144static int 145ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 146{ 147 Elf_Sym *symp; 148 const char *strp; 149 int i; 150 151 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 152 strp = ef->ddbstrtab + symp->st_name; 153 if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { 154 *sym = symp; 155 return 0; 156 } 157 } 158 return ENOENT; 159} 160 161static int 162ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 163 long *countp) 164{ 165 int i; 166 167 for (i = 0; i < ef->nprogtab; i++) { 168 if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && 169 strcmp(ef->progtab[i].name + 4, name) == 0) { 170 *startp = (char *)ef->progtab[i].addr - ef->address; 171 *stopp = (char *)ef->progtab[i].addr + 172 ef->progtab[i].size - ef->address; 173 *countp = (*stopp - *startp) / sizeof(void *); 174 return (0); 175 } 176 } 177 return (ESRCH); 178} 179 180static Elf_Addr 181ef_obj_symaddr(elf_file_t ef, Elf_Size symidx) 182{ 183 const Elf_Sym *sym; 184 185 if (symidx >= (size_t) ef->ddbsymcnt) 186 return (0); 187 sym = ef->ddbsymtab + symidx; 188 189 if (sym->st_shndx != SHN_UNDEF) 190 return (sym->st_value - (Elf_Addr)ef->address); 191 return (0); 192} 193 194static int 195ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 196{ 197 ssize_t r; 198 199 if (offset != (Elf_Off)-1) { 200 if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 201 return EIO; 202 } 203 204 r = read(ef->ef_fd, dest, len); 205 if (r != -1 && (size_t)r == len) 206 return 0; 207 else 208 return EIO; 209} 210 211static int 212ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 213{ 214 int error; 215 216 *ptr = malloc(len); 217 if (*ptr == NULL) 218 return ENOMEM; 219 error = ef_obj_read(ef, offset, len, *ptr); 220 if (error) 221 free(*ptr); 222 return error; 223} 224 225static int 226ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 227{ 228 229 if (offset + len > ef->size) { 230 if (ef->ef_verbose) 231 warnx("ef_obj_seg_read(%s): bad offset/len (%lx:%ld)", 232 ef->ef_name, (long)offset, (long)len); 233 return (EFAULT); 234 } 235 bcopy(ef->address + offset, dest, len); 236 return (0); 237} 238 239static int 240ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 241{ 242 char *memaddr; 243 Elf_Rel *r; 244 Elf_Rela *a; 245 Elf_Off secbase, dataoff; 246 int error, i, sec; 247 248 if (offset + len > ef->size) { 249 if (ef->ef_verbose) 250 warnx("ef_obj_seg_read_rel(%s): bad offset/len (%lx:%ld)", 251 ef->ef_name, (long)offset, (long)len); 252 return (EFAULT); 253 } 254 bcopy(ef->address + offset, dest, len); 255 256 /* Find out which section contains the data. */ 257 memaddr = ef->address + offset; 258 sec = -1; 259 secbase = dataoff = 0; 260 for (i = 0; i < ef->nprogtab; i++) { 261 if (ef->progtab[i].addr == NULL) 262 continue; 263 if (memaddr < (char *)ef->progtab[i].addr || memaddr + len > 264 (char *)ef->progtab[i].addr + ef->progtab[i].size) 265 continue; 266 sec = ef->progtab[i].sec; 267 /* We relocate to address 0. */ 268 secbase = (char *)ef->progtab[i].addr - ef->address; 269 dataoff = memaddr - ef->address; 270 break; 271 } 272 273 if (sec == -1) 274 return (EFAULT); 275 276 /* Now do the relocations. */ 277 for (i = 0; i < ef->nrel; i++) { 278 if (ef->reltab[i].sec != sec) 279 continue; 280 for (r = ef->reltab[i].rel; 281 r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { 282 error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase, 283 dataoff, len, dest); 284 if (error != 0) 285 return (error); 286 } 287 } 288 for (i = 0; i < ef->nrela; i++) { 289 if (ef->relatab[i].sec != sec) 290 continue; 291 for (a = ef->relatab[i].rela; 292 a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { 293 error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 294 secbase, dataoff, len, dest); 295 if (error != 0) 296 return (error); 297 } 298 } 299 return (0); 300} 301 302static int 303ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest) 304{ 305 306 if (offset >= ef->size) { 307 if (ef->ef_verbose) 308 warnx("ef_obj_seg_read_string(%s): bad offset (%lx)", 309 ef->ef_name, (long)offset); 310 return (EFAULT); 311 } 312 313 if (ef->size - offset < len) 314 len = ef->size - offset; 315 316 if (strnlen(ef->address + offset, len) == len) 317 return (EFAULT); 318 319 memcpy(dest, ef->address + offset, len); 320 return (0); 321} 322 323static int 324ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 325{ 326 int error; 327 328 *ptr = malloc(len); 329 if (*ptr == NULL) 330 return ENOMEM; 331 error = ef_obj_seg_read(ef, offset, len, *ptr); 332 if (error) 333 free(*ptr); 334 return error; 335} 336 337static int 338ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 339 void **ptr) 340{ 341 int error; 342 343 *ptr = malloc(len); 344 if (*ptr == NULL) 345 return ENOMEM; 346 error = ef_obj_seg_read_rel(ef, offset, len, *ptr); 347 if (error) 348 free(*ptr); 349 return error; 350} 351 352int 353ef_obj_open(const char *filename, struct elf_file *efile, int verbose) 354{ 355 elf_file_t ef; 356 Elf_Ehdr *hdr; 357 Elf_Shdr *shdr; 358 Elf_Sym *es; 359 char *mapbase; 360 void *vtmp; 361 size_t mapsize, alignmask, max_addralign; 362 int error, fd, pb, ra, res, rl; 363 int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex; 364 365 if (filename == NULL) 366 return EFTYPE; 367 if ((fd = open(filename, O_RDONLY)) == -1) 368 return errno; 369 370 ef = calloc(1, sizeof(*ef)); 371 if (ef == NULL) { 372 close(fd); 373 return (ENOMEM); 374 } 375 376 efile->ef_ef = ef; 377 efile->ef_ops = &ef_obj_file_ops; 378 379 ef->ef_verbose = verbose; 380 ef->ef_fd = fd; 381 ef->ef_name = strdup(filename); 382 ef->ef_efile = efile; 383 hdr = (Elf_Ehdr *)&ef->ef_hdr; 384 385 res = read(fd, hdr, sizeof(*hdr)); 386 error = EFTYPE; 387 if (res != sizeof(*hdr)) 388 goto out; 389 if (!IS_ELF(*hdr)) 390 goto out; 391 if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 392 hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 393 hdr->e_ident[EI_VERSION] != EV_CURRENT || 394 hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || 395 hdr->e_type != ET_REL) 396 goto out; 397 398 nbytes = hdr->e_shnum * hdr->e_shentsize; 399 if (nbytes == 0 || hdr->e_shoff == 0 || 400 hdr->e_shentsize != sizeof(Elf_Shdr)) 401 goto out; 402 403 if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { 404 printf("ef_read_entry failed\n"); 405 goto out; 406 } 407 ef->e_shdr = shdr = vtmp; 408 409 /* Scan the section header for information and table sizing. */ 410 nsym = 0; 411 symtabindex = -1; 412 symstrindex = -1; 413 for (i = 0; i < hdr->e_shnum; i++) { 414 switch (shdr[i].sh_type) { 415 case SHT_PROGBITS: 416 case SHT_NOBITS: 417 ef->nprogtab++; 418 break; 419 case SHT_SYMTAB: 420 nsym++; 421 symtabindex = i; 422 symstrindex = shdr[i].sh_link; 423 break; 424 case SHT_REL: 425 ef->nrel++; 426 break; 427 case SHT_RELA: 428 ef->nrela++; 429 break; 430 case SHT_STRTAB: 431 break; 432 } 433 } 434 435 if (ef->nprogtab == 0) { 436 warnx("%s: file has no contents", filename); 437 goto out; 438 } 439 if (nsym != 1) { 440 warnx("%s: file has no valid symbol table", filename); 441 goto out; 442 } 443 if (symstrindex < 0 || symstrindex > hdr->e_shnum || 444 shdr[symstrindex].sh_type != SHT_STRTAB) { 445 warnx("%s: file has invalid symbol strings", filename); 446 goto out; 447 } 448 449 /* Allocate space for tracking the load chunks */ 450 if (ef->nprogtab != 0) 451 ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); 452 if (ef->nrel != 0) 453 ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); 454 if (ef->nrela != 0) 455 ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); 456 if ((ef->nprogtab != 0 && ef->progtab == NULL) || 457 (ef->nrel != 0 && ef->reltab == NULL) || 458 (ef->nrela != 0 && ef->relatab == NULL)) { 459 printf("malloc failed\n"); 460 error = ENOMEM; 461 goto out; 462 } 463 464 ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 465 if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, 466 shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { 467 printf("ef_read_entry failed\n"); 468 goto out; 469 } 470 471 ef->ddbstrcnt = shdr[symstrindex].sh_size; 472 if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, 473 shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { 474 printf("ef_read_entry failed\n"); 475 goto out; 476 } 477 478 /* Do we have a string table for the section names? */ 479 shstrindex = -1; 480 if (hdr->e_shstrndx != 0 && 481 shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 482 shstrindex = hdr->e_shstrndx; 483 ef->shstrcnt = shdr[shstrindex].sh_size; 484 if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, 485 shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { 486 printf("ef_read_entry failed\n"); 487 goto out; 488 } 489 } 490 491 /* Size up code/data(progbits) and bss(nobits). */ 492 alignmask = 0; 493 max_addralign = 0; 494 mapsize = 0; 495 for (i = 0; i < hdr->e_shnum; i++) { 496 switch (shdr[i].sh_type) { 497 case SHT_PROGBITS: 498 case SHT_NOBITS: 499 alignmask = shdr[i].sh_addralign - 1; 500 if (shdr[i].sh_addralign > max_addralign) 501 max_addralign = shdr[i].sh_addralign; 502 mapsize += alignmask; 503 mapsize &= ~alignmask; 504 mapsize += shdr[i].sh_size; 505 break; 506 } 507 } 508 509 /* We know how much space we need for the text/data/bss/etc. */ 510 ef->size = mapsize; 511 if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { 512 printf("posix_memalign failed\n"); 513 goto out; 514 } 515 mapbase = ef->address; 516 517 /* 518 * Now load code/data(progbits), zero bss(nobits), allocate 519 * space for and load relocs 520 */ 521 pb = 0; 522 rl = 0; 523 ra = 0; 524 alignmask = 0; 525 for (i = 0; i < hdr->e_shnum; i++) { 526 switch (shdr[i].sh_type) { 527 case SHT_PROGBITS: 528 case SHT_NOBITS: 529 alignmask = shdr[i].sh_addralign - 1; 530 mapbase += alignmask; 531 mapbase = (char *)((uintptr_t)mapbase & ~alignmask); 532 ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; 533 if (shdr[i].sh_type == SHT_PROGBITS) { 534 ef->progtab[pb].name = "<<PROGBITS>>"; 535 if (ef_obj_read(ef, shdr[i].sh_offset, 536 shdr[i].sh_size, 537 ef->progtab[pb].addr) != 0) { 538 printf("failed to read progbits\n"); 539 goto out; 540 } 541 } else { 542 ef->progtab[pb].name = "<<NOBITS>>"; 543 bzero(ef->progtab[pb].addr, shdr[i].sh_size); 544 } 545 ef->progtab[pb].size = shdr[i].sh_size; 546 ef->progtab[pb].sec = i; 547 if (ef->shstrtab && shdr[i].sh_name != 0) 548 ef->progtab[pb].name = 549 ef->shstrtab + shdr[i].sh_name; 550 551 /* Update all symbol values with the offset. */ 552 for (j = 0; j < ef->ddbsymcnt; j++) { 553 es = &ef->ddbsymtab[j]; 554 if (es->st_shndx != i) 555 continue; 556 es->st_value += (Elf_Addr)ef->progtab[pb].addr; 557 } 558 mapbase += shdr[i].sh_size; 559 pb++; 560 break; 561 case SHT_REL: 562 ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 563 ef->reltab[rl].sec = shdr[i].sh_info; 564 if (ef_obj_read_entry(ef, shdr[i].sh_offset, 565 shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 566 0) { 567 printf("ef_read_entry failed\n"); 568 goto out; 569 } 570 rl++; 571 break; 572 case SHT_RELA: 573 ef->relatab[ra].nrela = 574 shdr[i].sh_size / sizeof(Elf_Rela); 575 ef->relatab[ra].sec = shdr[i].sh_info; 576 if (ef_obj_read_entry(ef, shdr[i].sh_offset, 577 shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 578 0) { 579 printf("ef_read_entry failed\n"); 580 goto out; 581 } 582 ra++; 583 break; 584 } 585 } 586 error = 0; 587out: 588 if (error) 589 ef_obj_close(ef); 590 return error; 591} 592 593static int 594ef_obj_close(elf_file_t ef) 595{ 596 int i; 597 598 close(ef->ef_fd); 599 if (ef->ef_name) 600 free(ef->ef_name); 601 if (ef->e_shdr != NULL) 602 free(ef->e_shdr); 603 if (ef->size != 0) 604 free(ef->address); 605 if (ef->nprogtab != 0) 606 free(ef->progtab); 607 if (ef->nrel != 0) { 608 for (i = 0; i < ef->nrel; i++) 609 if (ef->reltab[i].rel != NULL) 610 free(ef->reltab[i].rel); 611 free(ef->reltab); 612 } 613 if (ef->nrela != 0) { 614 for (i = 0; i < ef->nrela; i++) 615 if (ef->relatab[i].rela != NULL) 616 free(ef->relatab[i].rela); 617 free(ef->relatab); 618 } 619 if (ef->ddbsymtab != NULL) 620 free(ef->ddbsymtab); 621 if (ef->ddbstrtab != NULL) 622 free(ef->ddbstrtab); 623 if (ef->shstrtab != NULL) 624 free(ef->shstrtab); 625 ef->ef_efile->ef_ops = NULL; 626 ef->ef_efile->ef_ef = NULL; 627 free(ef); 628 629 return 0; 630} 631