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 #include <link.h> 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 = malloc(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 bzero(ef, sizeof(*ef)); 357 ef->ef_verbose = verbose; 358 ef->ef_fd = fd; 359 ef->ef_name = strdup(filename); 360 ef->ef_efile = efile; 361 hdr = (Elf_Ehdr *)&ef->ef_hdr; 362 363 res = read(fd, hdr, sizeof(*hdr)); 364 error = EFTYPE; 365 if (res != sizeof(*hdr)) 366 goto out; 367 if (!IS_ELF(*hdr)) 368 goto out; 369 if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 370 hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 371 hdr->e_ident[EI_VERSION] != EV_CURRENT || 372 hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || 373 hdr->e_type != ET_REL) 374 goto out; 375 376 nbytes = hdr->e_shnum * hdr->e_shentsize; 377 if (nbytes == 0 || hdr->e_shoff == 0 || 378 hdr->e_shentsize != sizeof(Elf_Shdr)) 379 goto out; 380 381 if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { 382 printf("ef_read_entry failed\n"); 383 goto out; 384 } 385 ef->e_shdr = shdr = vtmp; 386 387 /* Scan the section header for information and table sizing. */ 388 nsym = 0; 389 symtabindex = -1; 390 symstrindex = -1; 391 for (i = 0; i < hdr->e_shnum; i++) { 392 switch (shdr[i].sh_type) { 393 case SHT_PROGBITS: 394 case SHT_NOBITS: 395 ef->nprogtab++; 396 break; 397 case SHT_SYMTAB: 398 nsym++; 399 symtabindex = i; 400 symstrindex = shdr[i].sh_link; 401 break; 402 case SHT_REL: 403 ef->nrel++; 404 break; 405 case SHT_RELA: 406 ef->nrela++; 407 break; 408 case SHT_STRTAB: 409 break; 410 } 411 } 412 413 if (ef->nprogtab == 0) { 414 warnx("%s: file has no contents", filename); 415 goto out; 416 } 417 if (nsym != 1) { 418 warnx("%s: file has no valid symbol table", filename); 419 goto out; 420 } 421 if (symstrindex < 0 || symstrindex > hdr->e_shnum || 422 shdr[symstrindex].sh_type != SHT_STRTAB) { 423 warnx("%s: file has invalid symbol strings", filename); 424 goto out; 425 } 426 427 /* Allocate space for tracking the load chunks */ 428 if (ef->nprogtab != 0) 429 ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); 430 if (ef->nrel != 0) 431 ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); 432 if (ef->nrela != 0) 433 ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); 434 if ((ef->nprogtab != 0 && ef->progtab == NULL) || 435 (ef->nrel != 0 && ef->reltab == NULL) || 436 (ef->nrela != 0 && ef->relatab == NULL)) { 437 printf("malloc failed\n"); 438 error = ENOMEM; 439 goto out; 440 } 441 442 ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 443 if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, 444 shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { 445 printf("ef_read_entry failed\n"); 446 goto out; 447 } 448 449 ef->ddbstrcnt = shdr[symstrindex].sh_size; 450 if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, 451 shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { 452 printf("ef_read_entry failed\n"); 453 goto out; 454 } 455 456 /* Do we have a string table for the section names? */ 457 shstrindex = -1; 458 if (hdr->e_shstrndx != 0 && 459 shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 460 shstrindex = hdr->e_shstrndx; 461 ef->shstrcnt = shdr[shstrindex].sh_size; 462 if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, 463 shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { 464 printf("ef_read_entry failed\n"); 465 goto out; 466 } 467 } 468 469 /* Size up code/data(progbits) and bss(nobits). */ 470 alignmask = 0; 471 max_addralign = 0; 472 mapsize = 0; 473 for (i = 0; i < hdr->e_shnum; i++) { 474 switch (shdr[i].sh_type) { 475 case SHT_PROGBITS: 476 case SHT_NOBITS: 477 alignmask = shdr[i].sh_addralign - 1; 478 if (shdr[i].sh_addralign > max_addralign) 479 max_addralign = shdr[i].sh_addralign; 480 mapsize += alignmask; 481 mapsize &= ~alignmask; 482 mapsize += shdr[i].sh_size; 483 break; 484 } 485 } 486 487 /* We know how much space we need for the text/data/bss/etc. */ 488 ef->size = mapsize; 489 if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { 490 printf("posix_memalign failed\n"); 491 goto out; 492 } 493 mapbase = ef->address; 494 495 /* 496 * Now load code/data(progbits), zero bss(nobits), allocate 497 * space for and load relocs 498 */ 499 pb = 0; 500 rl = 0; 501 ra = 0; 502 alignmask = 0; 503 for (i = 0; i < hdr->e_shnum; i++) { 504 switch (shdr[i].sh_type) { 505 case SHT_PROGBITS: 506 case SHT_NOBITS: 507 alignmask = shdr[i].sh_addralign - 1; 508 mapbase += alignmask; 509 mapbase = (char *)((uintptr_t)mapbase & ~alignmask); 510 ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; 511 if (shdr[i].sh_type == SHT_PROGBITS) { 512 ef->progtab[pb].name = "<<PROGBITS>>"; 513 if (ef_obj_read(ef, shdr[i].sh_offset, 514 shdr[i].sh_size, 515 ef->progtab[pb].addr) != 0) { 516 printf("failed to read progbits\n"); 517 goto out; 518 } 519 } else { 520 ef->progtab[pb].name = "<<NOBITS>>"; 521 bzero(ef->progtab[pb].addr, shdr[i].sh_size); 522 } 523 ef->progtab[pb].size = shdr[i].sh_size; 524 ef->progtab[pb].sec = i; 525 if (ef->shstrtab && shdr[i].sh_name != 0) 526 ef->progtab[pb].name = 527 ef->shstrtab + shdr[i].sh_name; 528 529 /* Update all symbol values with the offset. */ 530 for (j = 0; j < ef->ddbsymcnt; j++) { 531 es = &ef->ddbsymtab[j]; 532 if (es->st_shndx != i) 533 continue; 534 es->st_value += (Elf_Addr)ef->progtab[pb].addr; 535 } 536 mapbase += shdr[i].sh_size; 537 pb++; 538 break; 539 case SHT_REL: 540 ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 541 ef->reltab[rl].sec = shdr[i].sh_info; 542 if (ef_obj_read_entry(ef, shdr[i].sh_offset, 543 shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 544 0) { 545 printf("ef_read_entry failed\n"); 546 goto out; 547 } 548 rl++; 549 break; 550 case SHT_RELA: 551 ef->relatab[ra].nrela = 552 shdr[i].sh_size / sizeof(Elf_Rela); 553 ef->relatab[ra].sec = shdr[i].sh_info; 554 if (ef_obj_read_entry(ef, shdr[i].sh_offset, 555 shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 556 0) { 557 printf("ef_read_entry failed\n"); 558 goto out; 559 } 560 ra++; 561 break; 562 } 563 } 564 error = 0; 565 out: 566 if (error) 567 ef_obj_close(ef); 568 return error; 569 } 570 571 static int 572 ef_obj_close(elf_file_t ef) 573 { 574 int i; 575 576 close(ef->ef_fd); 577 if (ef->ef_name) 578 free(ef->ef_name); 579 if (ef->e_shdr != NULL) 580 free(ef->e_shdr); 581 if (ef->size != 0) 582 free(ef->address); 583 if (ef->nprogtab != 0) 584 free(ef->progtab); 585 if (ef->nrel != 0) { 586 for (i = 0; i < ef->nrel; i++) 587 if (ef->reltab[i].rel != NULL) 588 free(ef->reltab[i].rel); 589 free(ef->reltab); 590 } 591 if (ef->nrela != 0) { 592 for (i = 0; i < ef->nrela; i++) 593 if (ef->relatab[i].rela != NULL) 594 free(ef->relatab[i].rela); 595 free(ef->relatab); 596 } 597 if (ef->ddbsymtab != NULL) 598 free(ef->ddbsymtab); 599 if (ef->ddbstrtab != NULL) 600 free(ef->ddbstrtab); 601 if (ef->shstrtab != NULL) 602 free(ef->shstrtab); 603 ef->ef_efile->ef_ops = NULL; 604 ef->ef_efile->ef_ef = NULL; 605 free(ef); 606 607 return 0; 608 } 609