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