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