/* Some initializations for characters, including initial skills If mode == 0, then act as though the character was entering the game for the first time. Otherwise, act as though the character is being set to that level. */ void do_start(struct creature *ch, int mode) { void advance_level(struct creature *ch, int8_t keep_internal); int8_t new_player = 0; int i; struct obj_data *implant_save[NUM_WEARS]; struct obj_data *tattoo_save[NUM_WEARS]; // remove implant affects for (i = 0; i < NUM_WEARS; i++) { if (GET_IMPLANT(ch, i)) implant_save[i] = raw_unequip_char(ch, i, EQUIP_IMPLANT); else implant_save[i] = NULL; if (GET_TATTOO(ch, i)) tattoo_save[i] = raw_unequip_char(ch, i, EQUIP_TATTOO); else tattoo_save[i] = NULL; } if (GET_EXP(ch) == 0 && !IS_REMORT(ch) && !IS_VAMPIRE(ch)) new_player = true; GET_LEVEL(ch) = 1; GET_EXP(ch) = 1; if (mode) roll_real_abils(ch); for (i = 1; i <= MAX_SKILLS; i++) SET_SKILL(ch, i, 0); if (IS_VAMPIRE(ch)) GET_LIFE_POINTS(ch) = 1; else GET_LIFE_POINTS(ch) = 3 * (GET_WIS(ch) + GET_CON(ch)) / 40; ch->points.max_hit = 20; ch->points.max_mana = 100; ch->points.max_move = 82; if (IS_TABAXI(ch)) { SET_SKILL(ch, SKILL_CLAW, LEARNED(ch)); SET_SKILL(ch, SKILL_BITE, LEARNED(ch)); } if (IS_ELF(ch)) { SET_SKILL(ch, SKILL_ARCHERY, LEARNED(ch)); } switch (GET_CLASS(ch)) { case CLASS_MAGIC_USER: SET_SKILL(ch, SKILL_PUNCH, 10); break; case CLASS_CLERIC: SET_SKILL(ch, SKILL_PUNCH, 10); break; case CLASS_THIEF: SET_SKILL(ch, SKILL_PUNCH, 15); SET_SKILL(ch, SKILL_SNEAK, 10); SET_SKILL(ch, SKILL_HIDE, 5); SET_SKILL(ch, SKILL_STEAL, 15); break; case CLASS_WARRIOR: SET_SKILL(ch, SKILL_PUNCH, 20); break; case CLASS_BARB: SET_SKILL(ch, SKILL_PUNCH, 15); break; case CLASS_PSIONIC: SET_SKILL(ch, SKILL_PUNCH, 10); break; case CLASS_PHYSIC: SET_SKILL(ch, SKILL_PUNCH, 10); break; case CLASS_CYBORG: SET_SKILL(ch, SKILL_PUNCH, 10); break; case CLASS_KNIGHT: SET_SKILL(ch, SKILL_PUNCH, 20); break; case CLASS_RANGER: SET_SKILL(ch, SKILL_PUNCH, 15); GET_MAX_MOVE(ch) += dice(4, 9); break; case CLASS_MONK: SET_SKILL(ch, SKILL_PUNCH, 20); break; case CLASS_MERCENARY: SET_SKILL(ch, SKILL_PUNCH, 20); case CLASS_BARD: SET_SKILL(ch, SKILL_PUNCH, 25); SET_SKILL(ch, SKILL_ARCHERY, 25); break; } if (new_player) { if (PAST_CLASS(GET_CLASS(ch))) { deposit_past_bank(ch->desc->account, 8192 + number(256, 2048) + GET_INT(ch) + GET_WIS(ch)); ch->points.gold = 8192 + number(256, 2048) + GET_INT(ch) + GET_WIS(ch); } else if (FUTURE_CLASS(GET_CLASS(ch))) { deposit_future_bank(ch->desc->account, 8192 + number(256, 2048) + GET_INT(ch) + GET_WIS(ch)); ch->points.cash = 8192 + number(256, 2048) + GET_INT(ch) + GET_WIS(ch); } // New players do not start with the gown at this point // This has been left in for reference for generic newbie starting gear for the future. // New players start with a hospital gown and items most dear to them /* struct obj_data *gown = read_object(33800); if (gown != NULL) { equip_char(ch, gown, WEAR_ABOUT, EQUIP_WORN); } */ // Good clerics start with a holy symbol on neck if ((GET_CLASS(ch) == CLASS_CLERIC) && IS_GOOD(ch)) { struct obj_data *talisman = read_object(1280); if (talisman != NULL) { equip_char(ch, talisman, WEAR_NECK_1, EQUIP_WORN); } } // Evil clerics start with a holy symbol on hold if ((GET_CLASS(ch) == CLASS_CLERIC) && IS_EVIL(ch)) { struct obj_data *symbol = read_object(1260); if (symbol != NULL) { equip_char(ch, symbol, WEAR_HOLD, EQUIP_WORN); } } // Good knights start with a holy symbol on finger if ((GET_CLASS(ch) == CLASS_KNIGHT) && IS_GOOD(ch)) { struct obj_data *ring = read_object(1287); if (ring != NULL) { equip_char(ch, ring, WEAR_FINGER_L, EQUIP_WORN); } } // Evil knights start with a holy symbol on neck if ((GET_CLASS(ch) == CLASS_KNIGHT) && IS_EVIL(ch)) { struct obj_data *pendant = read_object(1270); if (pendant != NULL) { equip_char(ch, pendant, WEAR_NECK_1, EQUIP_WORN); } } // Bards start with a percussion instrument held, and stringed in inventory if (GET_CLASS(ch) == CLASS_BARD) { struct obj_data *lute = read_object(3218); if (lute != NULL) { obj_to_char(lute, ch); } } set_title(ch, "the complete newbie"); } advance_level(ch, 0); GET_MAX_MOVE(ch) += GET_CON(ch); GET_HIT(ch) = GET_MAX_HIT(ch); GET_MANA(ch) = GET_MAX_MANA(ch); GET_MOVE(ch) = GET_MAX_MOVE(ch); GET_COND(ch, THIRST) = 24; GET_COND(ch, FULL) = 24; GET_COND(ch, DRUNK) = 0; if (new_player) { ch->player.time.played = 0; ch->player.time.logon = time(NULL); } for (i = 0; i < NUM_WEARS; i++) { if (implant_save[i]) equip_char(ch, implant_save[i], i, EQUIP_IMPLANT); if (tattoo_save[i]) equip_char(ch, tattoo_save[i], i, EQUIP_TATTOO); } }
static void load(void) { union { struct exec ex; Elf32_Ehdr eh; } hdr; static Elf32_Phdr ep[2]; static Elf32_Shdr es[2]; caddr_t p; ufs_ino_t ino; uint32_t addr, x; int fmt, i, j; if (!(ino = lookup(kname))) { if (!ls) { printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, dsk.part); } return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (N_GETMAGIC(hdr.ex) == ZMAGIC) fmt = 0; else if (IS_ELF(hdr.eh)) fmt = 1; else { printf("Invalid %s\n", "format"); return; } if (fmt == 0) { addr = hdr.ex.a_entry & 0xffffff; p = PTOV(addr); fs_off = PAGE_SIZE; if (xfsread(ino, p, hdr.ex.a_text)) return; p += roundup2(hdr.ex.a_text, PAGE_SIZE); if (xfsread(ino, p, hdr.ex.a_data)) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) return; p += hdr.ex.a_syms; if (xfsread(ino, p, sizeof(int))) return; x = *(uint32_t *)p; p += sizeof(int); x -= sizeof(int); if (xfsread(ino, p, x)) return; p += x; } } else { fs_off = hdr.eh.e_phoff; for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = PTOV(ep[i].p_paddr & 0xffffff); fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; } p += roundup2(ep[1].p_memsz, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { fs_off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) return; p += es[i].sh_size; } } addr = hdr.eh.e_entry & 0xffffff; } bootinfo.bi_esymtab = VTOP(p); bootinfo.bi_kernelname = VTOP(kname); bootinfo.bi_bios_dev = dsk.drive; __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), 0, 0, 0, VTOP(&bootinfo)); }
/* * Attempt to load the file (file) as an ELF module. It will be stored at * (dest), and a pointer to a module structure describing the loaded object * will be saved in (result). */ int __elfN(obj_loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result) { struct preloaded_file *fp, *kfp; struct elf_file ef; Elf_Ehdr *hdr; int err; ssize_t bytes_read; fp = NULL; bzero(&ef, sizeof(struct elf_file)); /* * Open the image, read and validate the ELF header */ if (filename == NULL) /* can't handle nameless */ return(EFTYPE); if ((ef.fd = open(filename, O_RDONLY)) == -1) return(errno); hdr = &ef.hdr; bytes_read = read(ef.fd, hdr, sizeof(*hdr)); if (bytes_read != sizeof(*hdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; } /* Is it ELF? */ if (!IS_ELF(*hdr)) { err = EFTYPE; goto oerr; } if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ hdr->e_type != ET_REL) { err = EFTYPE; goto oerr; } if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { err = EFTYPE; goto oerr; } kfp = file_findfile(NULL, __elfN(obj_kerneltype)); if (kfp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadfile: can't load module before kernel\n"); err = EPERM; goto oerr; } if (archsw.arch_loadaddr != NULL) dest = archsw.arch_loadaddr(LOAD_ELF, hdr, dest); else dest = roundup(dest, PAGE_SIZE); /* * Ok, we think we should handle this. */ fp = file_alloc(); if (fp == NULL) { printf("elf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadfile: cannot allocate module info\n"); err = EPERM; goto out; } fp->f_name = strdup(filename); fp->f_type = strdup(__elfN(obj_moduletype)); printf("%s ", filename); fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); if (fp->f_size == 0 || fp->f_addr == 0) goto ioerr; /* save exec header as metadata */ file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); /* Load OK, return module pointer */ *result = (struct preloaded_file *)fp; err = 0; goto out; ioerr: err = EIO; oerr: file_discard(fp); out: close(ef.fd); if (ef.e_shdr != NULL) free(ef.e_shdr); return(err); }
static #endif void dump_file(const char *fname) { int fd; struct stat sb; caddr_t objbase; if (stat(fname, &sb) == -1) { warnx("cannot stat \"%s\"", fname); ++error_count; return; } if ((sb.st_mode & S_IFMT) != S_IFREG) { warnx("\"%s\" is not a regular file", fname); ++error_count; return; } if ((fd = open(fname, O_RDONLY, 0)) == -1) { warnx("cannot open \"%s\"", fname); ++error_count; return; } objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (objbase == (caddr_t) -1) { warnx("cannot mmap \"%s\"", fname); ++error_count; close(fd); return; } close(fd); file_base = (const char *) objbase; /* Makes address arithmetic easier */ if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) { warnx("%s: this is an ELF program; use objdump to examine", fname); ++error_count; munmap(objbase, sb.st_size); close(fd); return; } ex = (const struct exec *) align_struct(file_base); printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag); printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex), (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex)); if (N_BADMAG(*ex)) { warnx("%s: bad magic number", fname); ++error_count; munmap(objbase, sb.st_size); return; } printf(" a_text = 0x%lx\n", (long)ex->a_text); printf(" a_data = 0x%lx\n", (long)ex->a_data); printf(" a_bss = 0x%lx\n", (long)ex->a_bss); printf(" a_syms = 0x%lx\n", (long)ex->a_syms); printf(" a_entry = 0x%lx\n", (long)ex->a_entry); printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize); printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize); text_base = file_base + N_TXTOFF(*ex); data_base = file_base + N_DATOFF(*ex); rel_base = (const struct relocation_info *) align_struct(file_base + N_RELOFF(*ex)); sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex)); str_base = file_base + N_STROFF(*ex); rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); sym_count = ex->a_syms / sizeof sym_base[0]; assert(sym_count * sizeof sym_base[0] == ex->a_syms); if (sym_count != 0) { sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); assert(sym_used != NULL); } printf(" Entry = 0x%lx\n", (long)ex->a_entry); printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex), (long)N_TXTADDR(*ex)); printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex), (long)N_DATADDR(*ex)); /* * In an executable program file, everything is relocated relative to * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. * * In a shared library file, everything is relocated relative to the * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. * * The way to tell the difference is by looking at ex->a_entry. If it * is >= 0x1000, then we have an executable program. Otherwise, we * have a shared library. * * When a program is executed, the entire file is mapped into memory, * including the a.out header and so forth. But it is not mapped at * address 0; rather it is mapped at address 0x1000. The first page * of the user's address space is left unmapped in order to catch null * pointer dereferences. * * In this program, when we map in an executable program, we have to * simulate the empty page by decrementing our assumed base address by * a pagesize. */ text_addr = text_base; data_addr = data_base; origin = 0; if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ /* * The fields in the object have already been relocated on the * assumption that the object will be loaded at N_TXTADDR(*ex). * We have to compensate for that. */ text_addr -= PAGE_SIZE; data_addr -= PAGE_SIZE; origin = PAGE_SIZE; printf(" Program, origin = %lx\n", origin); } else if (N_GETFLAG(*ex) & EX_DYNAMIC) printf(" Shared library, origin = %lx\n", origin); else printf(" Object file, origin = %lx\n", origin); if (N_GETFLAG(*ex) & EX_DYNAMIC) { dyn = (const struct _dynamic *) align_struct(data_base); printf(" Dynamic version = %d\n", dyn->d_version); sdt = (const struct section_dispatch_table *) align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt); rtrel_base = (const struct relocation_info *) align_struct(text_addr + sdt->sdt_rel); rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; assert(rtrel_count * sizeof rtrel_base[0] == (size_t)(sdt->sdt_hash - sdt->sdt_rel)); rtsym_base = (const struct nzlist *) align_struct(text_addr + sdt->sdt_nzlist); rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / sizeof rtsym_base[0]; assert(rtsym_count * sizeof rtsym_base[0] == (size_t)(sdt->sdt_strings - sdt->sdt_nzlist)); if (rtsym_count != 0) { rtsym_used = (unsigned char *) calloc(rtsym_count, sizeof(unsigned char)); assert(rtsym_used != NULL); } rtstr_base = text_addr + sdt->sdt_strings; } dump_segs(); dump_sods(); dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); dump_syms(); dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, rtsym_used); dump_rtsyms(); if (rtsym_used != NULL) { free(rtsym_used); rtsym_used = NULL; } if (sym_used != NULL) { free(sym_used); sym_used = NULL; } munmap(objbase, sb.st_size); }
static int link_elf_obj_load_file(const char *filename, linker_file_t * result) { struct nlookupdata nd; struct thread *td = curthread; /* XXX */ struct proc *p = td->td_proc; char *pathname; struct vnode *vp; Elf_Ehdr *hdr; Elf_Shdr *shdr; Elf_Sym *es; int nbytes, i, j; vm_offset_t mapbase; size_t mapsize; int error = 0; int resid; elf_file_t ef; linker_file_t lf; int symtabindex; int symstrindex; int shstrindex; int nsym; int pb, rl, ra; int alignmask; /* XXX Hack for firmware loading where p == NULL */ if (p == NULL) { p = &proc0; } KKASSERT(p != NULL); if (p->p_ucred == NULL) { kprintf("link_elf_obj_load_file: cannot load '%s' from filesystem" " this early\n", filename); return ENOENT; } shdr = NULL; lf = NULL; mapsize = 0; hdr = NULL; pathname = linker_search_path(filename); if (pathname == NULL) return ENOENT; error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW | NLC_LOCKVP); if (error == 0) error = vn_open(&nd, NULL, FREAD, 0); kfree(pathname, M_LINKER); if (error) { nlookup_done(&nd); return error; } vp = nd.nl_open_vp; nd.nl_open_vp = NULL; nlookup_done(&nd); /* * Read the elf header from the file. */ hdr = kmalloc(sizeof(*hdr), M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, vp, (void *)hdr, sizeof(*hdr), 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = ENOEXEC; goto out; } if (!IS_ELF(*hdr)) { error = ENOEXEC; goto out; } if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { link_elf_obj_error(filename, "Unsupported file layout"); error = ENOEXEC; goto out; } if (hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT) { link_elf_obj_error(filename, "Unsupported file version"); error = ENOEXEC; goto out; } if (hdr->e_type != ET_REL) { error = ENOSYS; goto out; } if (hdr->e_machine != ELF_TARG_MACH) { link_elf_obj_error(filename, "Unsupported machine"); error = ENOEXEC; goto out; } ef = kmalloc(sizeof(struct elf_file), M_LINKER, M_WAITOK | M_ZERO); lf = linker_make_file(filename, ef, &link_elf_obj_file_ops); if (lf == NULL) { kfree(ef, M_LINKER); error = ENOMEM; goto out; } ef->nprogtab = 0; ef->e_shdr = 0; ef->nreltab = 0; ef->nrelatab = 0; /* Allocate and read in the section header */ nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { error = ENOEXEC; goto out; } shdr = kmalloc(nbytes, M_LINKER, M_WAITOK); ef->e_shdr = shdr; error = vn_rdwr(UIO_READ, vp, (caddr_t) shdr, nbytes, hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid) { error = ENOEXEC; goto out; } /* Scan the section header for information and table sizing. */ nsym = 0; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: ef->nprogtab++; break; case SHT_SYMTAB: nsym++; symtabindex = i; symstrindex = shdr[i].sh_link; break; case SHT_REL: ef->nreltab++; break; case SHT_RELA: ef->nrelatab++; break; case SHT_STRTAB: break; } } if (ef->nprogtab == 0) { link_elf_obj_error(filename, "file has no contents"); error = ENOEXEC; goto out; } if (nsym != 1) { /* Only allow one symbol table for now */ link_elf_obj_error(filename, "file has no valid symbol table"); error = ENOEXEC; goto out; } if (symstrindex < 0 || symstrindex > hdr->e_shnum || shdr[symstrindex].sh_type != SHT_STRTAB) { link_elf_obj_error(filename, "file has invalid symbol strings"); error = ENOEXEC; goto out; } /* Allocate space for tracking the load chunks */ if (ef->nprogtab != 0) ef->progtab = kmalloc(ef->nprogtab * sizeof(*ef->progtab), M_LINKER, M_WAITOK | M_ZERO); if (ef->nreltab != 0) ef->reltab = kmalloc(ef->nreltab * sizeof(*ef->reltab), M_LINKER, M_WAITOK | M_ZERO); if (ef->nrelatab != 0) ef->relatab = kmalloc(ef->nrelatab * sizeof(*ef->relatab), M_LINKER, M_WAITOK | M_ZERO); if ((ef->nprogtab != 0 && ef->progtab == NULL) || (ef->nreltab != 0 && ef->reltab == NULL) || (ef->nrelatab != 0 && ef->relatab == NULL)) { error = ENOMEM; goto out; } if (symtabindex == -1) panic("lost symbol table index"); /* Allocate space for and load the symbol table */ ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); ef->ddbsymtab = kmalloc(shdr[symtabindex].sh_size, M_LINKER, M_WAITOK); if (ef->ddbsymtab == NULL) { error = ENOMEM; goto out; } error = vn_rdwr(UIO_READ, vp, (void *)ef->ddbsymtab, shdr[symtabindex].sh_size, shdr[symtabindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } if (symstrindex == -1) panic("lost symbol string index"); /* Allocate space for and load the symbol strings */ ef->ddbstrcnt = shdr[symstrindex].sh_size; ef->ddbstrtab = kmalloc(shdr[symstrindex].sh_size, M_LINKER, M_WAITOK); if (ef->ddbstrtab == NULL) { error = ENOMEM; goto out; } error = vn_rdwr(UIO_READ, vp, ef->ddbstrtab, shdr[symstrindex].sh_size, shdr[symstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } /* Do we have a string table for the section names? */ shstrindex = -1; if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { shstrindex = hdr->e_shstrndx; ef->shstrcnt = shdr[shstrindex].sh_size; ef->shstrtab = kmalloc(shdr[shstrindex].sh_size, M_LINKER, M_WAITOK); if (ef->shstrtab == NULL) { error = ENOMEM; goto out; } error = vn_rdwr(UIO_READ, vp, ef->shstrtab, shdr[shstrindex].sh_size, shdr[shstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } } /* Size up code/data(progbits) and bss(nobits). */ alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapsize += alignmask; mapsize &= ~alignmask; mapsize += shdr[i].sh_size; break; } } /* * We know how much space we need for the text/data/bss/etc. This * stuff needs to be in a single chunk so that profiling etc can get * the bounds and gdb can associate offsets with modules */ ef->object = vm_object_allocate(OBJT_DEFAULT, round_page(mapsize) >> PAGE_SHIFT); if (ef->object == NULL) { error = ENOMEM; goto out; } vm_object_hold(ef->object); vm_object_reference_locked(ef->object); ef->address = (caddr_t) vm_map_min(&kernel_map); ef->bytes = 0; /* * In order to satisfy x86_64's architectural requirements on the * location of code and data in the kernel's address space, request a * mapping that is above the kernel. * * vkernel64's text+data is outside the managed VM space entirely. */ #if defined(__amd64__) && defined(_KERNEL_VIRTUAL) error = vkernel_module_memory_alloc(&mapbase, round_page(mapsize)); #else mapbase = KERNBASE; error = vm_map_find(&kernel_map, ef->object, 0, &mapbase, round_page(mapsize), PAGE_SIZE, TRUE, VM_MAPTYPE_NORMAL, VM_PROT_ALL, VM_PROT_ALL, FALSE); vm_object_drop(ef->object); if (error) { vm_object_deallocate(ef->object); ef->object = NULL; goto out; } /* Wire the pages */ error = vm_map_wire(&kernel_map, mapbase, mapbase + round_page(mapsize), 0); #endif if (error != KERN_SUCCESS) { error = ENOMEM; goto out; } /* Inform the kld system about the situation */ lf->address = ef->address = (caddr_t) mapbase; lf->size = round_page(mapsize); ef->bytes = mapsize; /* * Now load code/data(progbits), zero bss(nobits), allocate space for * and load relocs */ pb = 0; rl = 0; ra = 0; alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapbase += alignmask; mapbase &= ~alignmask; if (ef->shstrtab && shdr[i].sh_name != 0) ef->progtab[pb].name = ef->shstrtab + shdr[i].sh_name; else if (shdr[i].sh_type == SHT_PROGBITS) ef->progtab[pb].name = "<<PROGBITS>>"; else ef->progtab[pb].name = "<<NOBITS>>"; #if 0 if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, "set_pcpu")) ef->progtab[pb].addr = dpcpu_alloc(shdr[i].sh_size); #ifdef VIMAGE else if (ef->progtab[pb].name != NULL && !strcmp(ef->progtab[pb].name, VNET_SETNAME)) ef->progtab[pb].addr = vnet_data_alloc(shdr[i].sh_size); #endif else #endif ef->progtab[pb].addr = (void *)(uintptr_t) mapbase; if (ef->progtab[pb].addr == NULL) { error = ENOSPC; goto out; } ef->progtab[pb].size = shdr[i].sh_size; ef->progtab[pb].sec = i; if (shdr[i].sh_type == SHT_PROGBITS) { error = vn_rdwr(UIO_READ, vp, ef->progtab[pb].addr, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } #if 0 /* Initialize the per-cpu or vnet area. */ if (ef->progtab[pb].addr != (void *)mapbase && !strcmp(ef->progtab[pb].name, "set_pcpu")) dpcpu_copy(ef->progtab[pb].addr, shdr[i].sh_size); #ifdef VIMAGE else if (ef->progtab[pb].addr != (void *)mapbase && !strcmp(ef->progtab[pb].name, VNET_SETNAME)) vnet_data_copy(ef->progtab[pb].addr, shdr[i].sh_size); #endif #endif } else bzero(ef->progtab[pb].addr, shdr[i].sh_size); /* Update all symbol values with the offset. */ for (j = 0; j < ef->ddbsymcnt; j++) { es = &ef->ddbsymtab[j]; if (es->st_shndx != i) continue; es->st_value += (Elf_Addr) ef->progtab[pb].addr; } mapbase += shdr[i].sh_size; pb++; break; case SHT_REL: ef->reltab[rl].rel = kmalloc(shdr[i].sh_size, M_LINKER, M_WAITOK); ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); ef->reltab[rl].sec = shdr[i].sh_info; error = vn_rdwr(UIO_READ, vp, (void *)ef->reltab[rl].rel, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } rl++; break; case SHT_RELA: ef->relatab[ra].rela = kmalloc(shdr[i].sh_size, M_LINKER, M_WAITOK); ef->relatab[ra].nrela = shdr[i].sh_size / sizeof(Elf_Rela); ef->relatab[ra].sec = shdr[i].sh_info; error = vn_rdwr(UIO_READ, vp, (void *)ef->relatab[ra].rela, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; if (resid != 0) { error = EINVAL; goto out; } ra++; break; } } if (pb != ef->nprogtab) panic("lost progbits"); if (rl != ef->nreltab) panic("lost reltab"); if (ra != ef->nrelatab) panic("lost relatab"); if (mapbase != (vm_offset_t) ef->address + mapsize) panic("mapbase 0x%lx != address %p + mapsize 0x%lx (0x%lx)\n", mapbase, ef->address, mapsize, (vm_offset_t) ef->address + mapsize); /* Local intra-module relocations */ link_elf_obj_reloc_local(lf); /* Pull in dependencies */ error = linker_load_dependencies(lf); if (error) goto out; /* External relocations */ error = relocate_file(lf); if (error) goto out; *result = lf; out: if (error && lf) linker_file_unload(lf /*, LINKER_UNLOAD_FORCE */); if (hdr) kfree(hdr, M_LINKER); vn_unlock(vp); vn_close(vp, FREAD); return error; }
/* * Load the prototype boot sector (biosboot) into memory. */ static char * loadproto(char *fname, long *size) { int fd; size_t tdsize; /* text+data size */ char *bp; Elf_Ehdr eh; Elf_Word phsize; Elf_Phdr *ph; if ((fd = open(fname, O_RDONLY)) < 0) err(1, "%s", fname); if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) errx(1, "%s: read failed", fname); if (!IS_ELF(eh)) errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", fname, eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1], eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]); /* * We have to include the exec header in the beginning of * the buffer, and leave extra space at the end in case * the actual write to disk wants to skip the header. */ /* Program load header. */ if (eh.e_phnum != 1) errx(1, "%s: %u ELF load sections (only support 1)", fname, eh.e_phnum); phsize = eh.e_phnum * sizeof(Elf_Phdr); ph = malloc(phsize); if (ph == NULL) err(1, NULL); lseek(fd, eh.e_phoff, SEEK_SET); if (read(fd, ph, phsize) != phsize) errx(1, "%s: can't read header", fname); tdsize = ph->p_filesz; /* * Allocate extra space here because the caller may copy * the boot block starting at the end of the exec header. * This prevents reading beyond the end of the buffer. */ if ((bp = calloc(tdsize, 1)) == NULL) err(1, NULL); /* Read the rest of the file. */ lseek(fd, ph->p_offset, SEEK_SET); if (read(fd, bp, tdsize) != (ssize_t)tdsize) errx(1, "%s: read failed", fname); *size = tdsize; /* not aligned to DEV_BSIZE */ close(fd); return bp; }
core_obj_t* core_new(char* path) { struct stat sb; int fd; void* data; core_obj_t* ret; elfobj_t* luse; int i = 0; char* ptr; /* ** Map the core. */ if ((fd = open(path, O_RDONLY)) == -1) { return (NULL); } if (fstat(fd, &sb) == -1) { close(fd); return (NULL); } data = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); if (data == MAP_FAILED) return (NULL); /* ** Check if the core is really a elf. */ if (!IS_ELF(*((Elf_Ehdr*)data))) { errno = EFTRACE; ftrace_errstr = "File is not an elf file."; munmap(data, sb.st_size); return (NULL); } /* ** Fill the return */ ret = malloc(sizeof(core_obj_t)); if (ret == NULL) { munmap(data, sb.st_size); return (NULL); } ret->path = strdup(path); ret->map = data; ret->fd = -1; ret->size = sb.st_size; ret->luse = NULL; /* ** Fill luse. */ luse = malloc(sizeof(elfobj_t)); if (luse == NULL) return (ret); luse->base = 0; luse->header = data; luse->program_headers = NULL; luse->section_headers = NULL; luse->section_str = NULL; /* ** Program headers. */ luse->program_headers = malloc(sizeof(Elf_Phdr *) * (luse->header->e_phnum + 1)); if (luse->program_headers == NULL) goto luse_fill_failed; for (ptr = (char*) luse->header + luse->header->e_phoff, i = 0; i < luse->header->e_phnum; i++) { luse->program_headers[i] = (Elf_Phdr *) ptr; ptr += luse->header->e_phentsize; } luse->program_headers[i] = NULL; /* ** Section headers. */ luse->section_headers = malloc(sizeof(Elf_Shdr *) * (luse->header->e_shnum + 1)); if (luse->section_headers == NULL) goto luse_fill_failed; for (ptr = (char*) luse->header + luse->header->e_shoff, i = 0; i < luse->header->e_shnum; i++) { luse->section_headers[i] = (Elf_Shdr *) ptr; ptr += luse->header->e_shentsize; } luse->section_headers[i] = NULL; /* ** Section strng. */ if (luse->header->e_shstrndx != SHN_UNDEF) luse->section_str = data + luse->section_headers[luse->header->e_shstrndx]->sh_offset; else luse->section_str = NULL; ret->luse = luse; return (ret); luse_fill_failed: core_del(ret); if (luse->program_headers) free(luse->program_headers); if (luse->section_headers) free(luse->section_headers); free(luse); return (NULL); }
int load_elf_interp(const char *path, ulong load_addr) { char *data; Elf64_Ehdr *h; uint64_t map_top = 0; int fd; struct stat st; if ((fd = vkern_open(path, LINUX_O_RDONLY, 0)) < 0) { fprintf(stderr, "load_elf_interp, could not open file: %s\n", path); return -1; } fstat(fd, &st); data = mmap(0, st.st_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0); vkern_close(fd); h = (Elf64_Ehdr *)data; assert(IS_ELF(*h)); if (! (h->e_type == ET_EXEC || h->e_type == ET_DYN)) { return -LINUX_ENOEXEC; } if (h->e_machine != EM_X86_64) { return -LINUX_ENOEXEC; } Elf64_Phdr *p = (Elf64_Phdr *)(data + h->e_phoff); for (int i = 0; i < h->e_phnum; i++) { if (p[i].p_type != PT_LOAD) { continue; } ulong p_vaddr = p[i].p_vaddr + load_addr; ulong mask = PAGE_SIZEOF(PAGE_4KB) - 1; ulong vaddr = p_vaddr & ~mask; ulong offset = p_vaddr & mask; ulong size = roundup(p[i].p_memsz + offset, PAGE_SIZEOF(PAGE_4KB)); int prot = 0; if (p[i].p_flags & PF_X) prot |= LINUX_PROT_EXEC; if (p[i].p_flags & PF_W) prot |= LINUX_PROT_WRITE; if (p[i].p_flags & PF_R) prot |= LINUX_PROT_READ; assert(vaddr != 0); do_mmap(vaddr, size, PROT_READ | PROT_WRITE, prot, LINUX_MAP_PRIVATE | LINUX_MAP_FIXED | LINUX_MAP_ANONYMOUS, -1, 0); copy_to_user(vaddr + offset, data + p[i].p_offset, p[i].p_filesz); map_top = MAX(map_top, roundup(vaddr + size, PAGE_SIZEOF(PAGE_4KB))); } vmm_write_vmcs(VMCS_GUEST_RIP, load_addr + h->e_entry); proc.mm->start_brk = map_top; munmap(data, st.st_size); return 0; }
int main(int argc, char **argv) { struct exec exec; int ch, cnt, efd, fd, sflag; char *binfile, *corefile; char fname[MAXPATHLEN + 1]; sflag = 0; corefile = NULL; while ((ch = getopt(argc, argv, "c:s")) != -1) { switch (ch) { case 'c': corefile = optarg; break; case 's': sflag = 1; break; default: usage(); break; } } argv += optind; argc -= optind; /* XXX we should check that the pid argument is really a number */ switch (argc) { case 1: pid = atoi(argv[0]); asprintf(&binfile, "/proc/%d/file", pid); if (binfile == NULL) errx(1, "allocation failure"); break; case 2: pid = atoi(argv[1]); binfile = argv[0]; break; default: usage(); } efd = open(binfile, O_RDONLY, 0); if (efd < 0) err(1, "%s", binfile); cnt = read(efd, &exec, sizeof(exec)); if (cnt != sizeof(exec)) errx(1, "%s exec header: %s", binfile, cnt > 0 ? strerror(EIO) : strerror(errno)); if (IS_ELF(*(Elf_Ehdr *)&exec)) { close(efd); } else errx(1, "Invalid executable file"); if (corefile == NULL) { (void)snprintf(fname, sizeof(fname), "core.%d", pid); corefile = fname; } fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); if (fd < 0) err(1, "%s", corefile); if (sflag) { signal(SIGHUP, killed); signal(SIGINT, killed); signal(SIGTERM, killed); if (kill(pid, SIGSTOP) == -1) err(1, "%d: stop signal", pid); atexit(restart_target); } elf_coredump(fd, pid); (void)close(fd); exit(0); }
static int link_elf_load_file(const char* filename, linker_file_t* result) { struct nlookupdata nd; struct thread *td = curthread; /* XXX */ struct proc *p = td->td_proc; struct vnode *vp; Elf_Ehdr *hdr; caddr_t firstpage; int nbytes, i; Elf_Phdr *phdr; Elf_Phdr *phlimit; Elf_Phdr *segs[2]; int nsegs; Elf_Phdr *phdyn; Elf_Phdr *phphdr; caddr_t mapbase; size_t mapsize; Elf_Off base_offset; Elf_Addr base_vaddr; Elf_Addr base_vlimit; int error = 0; int resid; elf_file_t ef; linker_file_t lf; char *pathname; Elf_Shdr *shdr; int symtabindex; int symstrindex; int symcnt; int strcnt; /* XXX Hack for firmware loading where p == NULL */ if (p == NULL) { p = &proc0; } KKASSERT(p != NULL); if (p->p_ucred == NULL) { kprintf("link_elf_load_file: cannot load '%s' from filesystem" " this early\n", filename); return ENOENT; } shdr = NULL; lf = NULL; pathname = linker_search_path(filename); if (pathname == NULL) return ENOENT; error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP); if (error == 0) error = vn_open(&nd, NULL, FREAD, 0); kfree(pathname, M_LINKER); if (error) { nlookup_done(&nd); return error; } vp = nd.nl_open_vp; nd.nl_open_vp = NULL; nlookup_done(&nd); /* * Read the elf header from the file. */ firstpage = kmalloc(PAGE_SIZE, M_LINKER, M_WAITOK); hdr = (Elf_Ehdr *)firstpage; error = vn_rdwr(UIO_READ, vp, firstpage, PAGE_SIZE, 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); nbytes = PAGE_SIZE - resid; if (error) goto out; if (!IS_ELF(*hdr)) { error = ENOEXEC; goto out; } if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { link_elf_error("Unsupported file layout"); error = ENOEXEC; goto out; } if (hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT) { link_elf_error("Unsupported file version"); error = ENOEXEC; goto out; } if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { error = ENOSYS; goto out; } if (hdr->e_machine != ELF_TARG_MACH) { link_elf_error("Unsupported machine"); error = ENOEXEC; goto out; } /* * We rely on the program header being in the first page. This is * not strictly required by the ABI specification, but it seems to * always true in practice. And, it simplifies things considerably. */ if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) link_elf_error("Unreadable program headers"); /* * Scan the program header entries, and save key information. * * We rely on there being exactly two load segments, text and data, * in that order. */ phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); phlimit = phdr + hdr->e_phnum; nsegs = 0; phdyn = NULL; phphdr = NULL; while (phdr < phlimit) { switch (phdr->p_type) { case PT_LOAD: if (nsegs == 2) { link_elf_error("Too many sections"); error = ENOEXEC; goto out; } segs[nsegs] = phdr; ++nsegs; break; case PT_PHDR: phphdr = phdr; break; case PT_DYNAMIC: phdyn = phdr; break; case PT_INTERP: error = ENOSYS; goto out; } ++phdr; } if (phdyn == NULL) { link_elf_error("Object is not dynamically-linked"); error = ENOEXEC; goto out; } /* * Allocate the entire address space of the object, to stake out our * contiguous region, and to establish the base address for relocation. */ base_offset = trunc_page(segs[0]->p_offset); base_vaddr = trunc_page(segs[0]->p_vaddr); base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); mapsize = base_vlimit - base_vaddr; ef = kmalloc(sizeof(struct elf_file), M_LINKER, M_WAITOK | M_ZERO); #ifdef SPARSE_MAPPING ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); if (ef->object == NULL) { kfree(ef, M_LINKER); error = ENOMEM; goto out; } vm_object_hold(ef->object); vm_object_reference_locked(ef->object); ef->address = (caddr_t)vm_map_min(&kernel_map); error = vm_map_find(&kernel_map, ef->object, 0, (vm_offset_t *)&ef->address, mapsize, PAGE_SIZE, 1, VM_MAPTYPE_NORMAL, VM_PROT_ALL, VM_PROT_ALL, 0); vm_object_drop(ef->object); if (error) { vm_object_deallocate(ef->object); kfree(ef, M_LINKER); goto out; } #else ef->address = kmalloc(mapsize, M_LINKER, M_WAITOK); #endif mapbase = ef->address; /* * Read the text and data sections and zero the bss. */ for (i = 0; i < 2; i++) { caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; error = vn_rdwr(UIO_READ, vp, segbase, segs[i]->p_filesz, segs[i]->p_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) { #ifdef SPARSE_MAPPING vm_map_remove(&kernel_map, (vm_offset_t) ef->address, (vm_offset_t) ef->address + (ef->object->size << PAGE_SHIFT)); vm_object_deallocate(ef->object); #else kfree(ef->address, M_LINKER); #endif kfree(ef, M_LINKER); goto out; } bzero(segbase + segs[i]->p_filesz, segs[i]->p_memsz - segs[i]->p_filesz); #ifdef SPARSE_MAPPING /* * Wire down the pages */ vm_map_wire(&kernel_map, (vm_offset_t) segbase, (vm_offset_t) segbase + segs[i]->p_memsz, 0); #endif } ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); lf = linker_make_file(filename, ef, &link_elf_file_ops); if (lf == NULL) { #ifdef SPARSE_MAPPING vm_map_remove(&kernel_map, (vm_offset_t) ef->address, (vm_offset_t) ef->address + (ef->object->size << PAGE_SHIFT)); vm_object_deallocate(ef->object); #else kfree(ef->address, M_LINKER); #endif kfree(ef, M_LINKER); error = ENOMEM; goto out; } lf->address = ef->address; lf->size = mapsize; error = parse_dynamic(lf); if (error) goto out; link_elf_reloc_local(lf); error = linker_load_dependencies(lf); if (error) goto out; error = relocate_file(lf); if (error) goto out; /* Try and load the symbol table if it's present. (you can strip it!) */ nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0) goto nosyms; shdr = kmalloc(nbytes, M_LINKER, M_WAITOK | M_ZERO); error = vn_rdwr(UIO_READ, vp, (caddr_t)shdr, nbytes, hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { symtabindex = i; symstrindex = shdr[i].sh_link; } } if (symtabindex < 0 || symstrindex < 0) goto nosyms; symcnt = shdr[symtabindex].sh_size; ef->symbase = kmalloc(symcnt, M_LINKER, M_WAITOK); strcnt = shdr[symstrindex].sh_size; ef->strbase = kmalloc(strcnt, M_LINKER, M_WAITOK); error = vn_rdwr(UIO_READ, vp, ef->symbase, symcnt, shdr[symtabindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; error = vn_rdwr(UIO_READ, vp, ef->strbase, strcnt, shdr[symstrindex].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid); if (error) goto out; ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); ef->ddbsymtab = (const Elf_Sym *)ef->symbase; ef->ddbstrcnt = strcnt; ef->ddbstrtab = ef->strbase; nosyms: *result = lf; out: if (error && lf) linker_file_unload(lf); if (shdr) kfree(shdr, M_LINKER); if (firstpage) kfree(firstpage, M_LINKER); vn_unlock(vp); vn_close(vp, FREAD); return error; }
static int is_executable(const char *fname, int fd, int *is_shlib, int *type) { union { struct exec aout; #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) Elf32_Ehdr elf32; #endif Elf_Ehdr elf; } hdr; int n; *is_shlib = 0; *type = TYPE_UNKNOWN; if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { warn("%s: can't read program header", fname); return (0); } if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { /* a.out file */ if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC #if 1 /* Compatibility */ || hdr.aout.a_entry < __LDPGSZ #endif ) { warnx("%s: not a dynamic executable", fname); return (0); } *type = TYPE_AOUT; return (1); } #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { /* Handle 32 bit ELF objects */ Elf32_Phdr phdr; int dynamic, i; dynamic = 0; *type = TYPE_ELF32; if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { warnx("%s: header too short", fname); return (0); } for (i = 0; i < hdr.elf32.e_phnum; i++) { if (read(fd, &phdr, hdr.elf32.e_phentsize) != sizeof(phdr)) { warnx("%s: can't read program header", fname); return (0); } if (phdr.p_type == PT_DYNAMIC) { dynamic = 1; break; } } if (!dynamic) { warnx("%s: not a dynamic ELF executable", fname); return (0); } if (hdr.elf32.e_type == ET_DYN) { if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { *is_shlib = 1; return (1); } warnx("%s: not a FreeBSD ELF shared object", fname); return (0); } return (1); } #endif if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { /* Handle default ELF objects on this architecture */ Elf_Phdr phdr; int dynamic, i; dynamic = 0; *type = TYPE_ELF; if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { warnx("%s: header too short", fname); return (0); } for (i = 0; i < hdr.elf.e_phnum; i++) { if (read(fd, &phdr, hdr.elf.e_phentsize) != sizeof(phdr)) { warnx("%s: can't read program header", fname); return (0); } if (phdr.p_type == PT_DYNAMIC) { dynamic = 1; break; } } if (!dynamic) { warnx("%s: not a dynamic ELF executable", fname); return (0); } if (hdr.elf.e_type == ET_DYN) { if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { *is_shlib = 1; return (1); } warnx("%s: not a FreeBSD ELF shared object", fname); return (0); } return (1); } warnx("%s: not a dynamic executable", fname); return (0); }
/** * \brief Load ELF32 binary image into memory * * This function loads an ELF32 binary image, based at 'base' and of size * 'size' into the memory provided by 'allocate' * * \param em_machine ELF machine type. * \param allocate Memory allocation function. * \param state Pointer to state for allocation function. * \param base Base address of ELF32 binary image in memory. * \param size Size of ELF32 binary image in bytes. * \param retentry Used to return entry point address * \param ret_tlsbase Used to return TLS block base address * \param ret_tlsinitlen Used to return length of initialised TLS data block * \param ret_tlstotallen Used to return total length of TLS data */ errval_t elf32_load(uint16_t em_machine, elf_allocator_fn allocate_func, void *state, lvaddr_t base, size_t size, genvaddr_t *retentry, genvaddr_t *ret_tlsbase, size_t *ret_tlsinitlen, size_t *ret_tlstotallen) { struct Elf32_Ehdr *head = (struct Elf32_Ehdr *)base; errval_t err; int i; // Check for valid file size if (size < sizeof(struct Elf32_Ehdr)) { return ELF_ERR_FILESZ; } // Stage 1: Check for compatible ELF32 header: check endianess if(is_big_endian() && head->e_ident[EI_DATA] != ELFDATA2MSB){ return ELF_ERR_HEADER; } else if(!is_big_endian() && head->e_ident[EI_DATA] != ELFDATA2LSB){ return ELF_ERR_HEADER; } // Stage 2: Check for compatible ELF32 header if (!IS_ELF(*head) || head->e_ident[EI_CLASS] != ELFCLASS32 // || head->e_ident[EI_DATA] != ELFDATA2MSB //Enhanced with a function to check machine endianess || head->e_ident[EI_VERSION] != EV_CURRENT || head->e_ident[EI_OSABI] != ELFOSABI_SYSV || head->e_ident[EI_ABIVERSION] != 0 || (head->e_type != ET_EXEC && head->e_type != ET_DYN) || head->e_machine != em_machine || head->e_version != EV_CURRENT) { return ELF_ERR_HEADER; } // More sanity checks if (head->e_phoff + head->e_phentsize * head->e_phnum > size || head->e_phentsize != sizeof(struct Elf32_Phdr)) { return ELF_ERR_PROGHDR; } struct Elf32_Shdr *shead = (struct Elf32_Shdr *)(base + (uintptr_t)head->e_shoff); struct Elf32_Shdr *rela = elf32_find_section_header_type(shead, head->e_shnum, SHT_REL); struct Elf32_Shdr *symtab = elf32_find_section_header_type(shead, head->e_shnum, SHT_SYMTAB); size_t rela_size = rela ? rela->sh_size : 0, new_rela_size = 0; struct Elf32_Shdr *new_rela = NULL; // Find dynamic program header, if any struct Elf32_Phdr *phead = (struct Elf32_Phdr *)(base + (uintptr_t)head->e_phoff); for (i = 0; i < head->e_phnum; i++) { struct Elf32_Phdr *p = &phead[i]; if (p->p_type == PT_DYNAMIC) { struct Elf32_Dyn *dynamic = (void *)(base + (uintptr_t)p->p_offset); int n_dynamic = p->p_filesz / sizeof(struct Elf32_Dyn); for (int j = 0; j < n_dynamic; j++) { switch (dynamic[j].d_tag) { case DT_RELA: // virtual address of relocations, look for matching section new_rela = elf32_find_section_header_vaddr(shead, head->e_shnum, dynamic[j].d_un.d_val); break; case DT_RELASZ: // store size of relocations, as they may cover more than // one section new_rela_size = dynamic[j].d_un.d_val; break; case DT_SYMTAB: // virtual address of symtab, look for matching section symtab = elf32_find_section_header_vaddr(shead, head->e_shnum, dynamic[j].d_un.d_val); break; case DT_SYMENT: assert(dynamic[j].d_un.d_val == sizeof(struct Elf32_Sym)); break; } } if (new_rela != NULL) { assert(new_rela_size != 0); rela = new_rela; rela_size = new_rela_size; } break; } } genvaddr_t tls_base = 0; size_t tls_init_len = 0, tls_total_len = 0; // Process program headers to load file for (i = 0; i < head->e_phnum; i++) { struct Elf32_Phdr *p = &phead[i]; if (p->p_type == PT_LOAD) { // Map segment in user-space memory void *dest = NULL; err = allocate_func(state, p->p_vaddr, p->p_memsz, p->p_flags, &dest); if (err_is_fail(err)) { return err_push(err, ELF_ERR_ALLOCATE); } assert(dest != NULL); // Copy file segment into memory memcpy(dest, (void *)(base + (uintptr_t)p->p_offset), p->p_filesz); // Initialize rest of memory segment (ie. BSS) with all zeroes memset((char *)dest + p->p_filesz, 0, p->p_memsz - p->p_filesz); // Apply relocations if (rela != NULL && symtab != NULL) { elf32_relocate(p->p_vaddr, p->p_vaddr, (struct Elf32_Rel *) (base + (uintptr_t)rela->sh_offset), rela_size, (struct Elf32_Sym *) (base + (uintptr_t)symtab->sh_offset), symtab->sh_size, p->p_vaddr, dest); } } else if (p->p_type == PT_TLS) { assert(p->p_vaddr != 0); assert(tls_base == 0); // if not we have multiple TLS sections! tls_base = p->p_vaddr; tls_init_len = p->p_filesz; tls_total_len = p->p_memsz; } } if (retentry != NULL) { *retentry = head->e_entry; } if (ret_tlsbase != NULL) { *ret_tlsbase = tls_base; } if (ret_tlsinitlen != NULL) { *ret_tlsinitlen = tls_init_len; } if (ret_tlstotallen != NULL) { *ret_tlstotallen = tls_total_len; } return SYS_ERR_OK; }
uint32_t elf32_count_symbol_by_name(genvaddr_t elf_base, size_t elf_bytes, const char *name, uint8_t contains, uint8_t type, size_t *ret_bytes) { struct Elf32_Sym *sym = NULL; struct Elf32_Shdr *shead; struct Elf32_Shdr *symtab; const char *symname; lvaddr_t elfbase = (lvaddr_t)elf_base; struct Elf32_Ehdr *head = (struct Elf32_Ehdr *)elfbase; // just a sanity check if (!IS_ELF(*head) || head->e_ident[EI_CLASS] != ELFCLASS64) { return 0; } uint32_t count = 0; size_t bytes = 0; shead = (struct Elf32_Shdr *)(elfbase + (uintptr_t)head->e_shoff); symtab = elf32_find_section_header_type(shead, head->e_shnum, SHT_SYMTAB); uintptr_t symbase = elfbase + (uintptr_t)symtab->sh_offset; for (uintptr_t i = 0; i < symtab->sh_size; i += sizeof(struct Elf32_Sym)) { // getting the symbol sym = (struct Elf32_Sym *)(symbase + i); // check for matching type if ((sym->st_info & 0x0F) != type) { continue; } // find the section of the associacted string table struct Elf32_Shdr *strtab = shead+symtab->sh_link; // get the pointer to the symbol name from string table + string index symname = (const char *)elfbase + strtab->sh_offset + sym->st_name; if (!contains) { if (strcmp(symname, name)==0) { /* we have a match */ count++; bytes += strlen(symname)+1; } } else { if (strstr(symname,name) != 0) { count++; bytes += strlen(symname)+1; } } } if (ret_bytes) { *ret_bytes = bytes; } return count; }
int main(int argc, char **argv) { int ch, fd, n, xflag = 0, found = 0, phsize; u_int32_t *ip; Elf_Ehdr eh; Elf_Phdr *ph; while ((ch = getopt(argc, argv, "x")) != -1) { switch (ch) { case 'x': xflag = 1; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); file = argv[0]; fd = open(file, O_RDWR, 0644); if (fd < 0) { perror(file); exit(1); } n = read(fd, &eh, sizeof(eh)); if (n < sizeof(eh)) { printf("%s: reading header\n", file); exit(1); } if (!IS_ELF(eh)) { printf("%s: not elf\n", file); exit(1); } phsize = eh.e_phnum * sizeof(Elf_Phdr); ph = (Elf_Phdr *)malloc(phsize); lseek(fd, eh.e_phoff, SEEK_SET); if (read(fd, (char *)ph, phsize) != phsize) { printf("%s: can't read phdr area\n", file); exit(1); } for (n = 0; n < eh.e_phnum && !found; n++) { if (ph[n].p_type == PT_LOAD) found = find_rd_root_image(file, &eh, &ph[n], n); } if (!found) { printf("%s: can't locate space for rd_root_image!\n", file); exit(1); } /* * Map in the whole data segment. * The file offset needs to be page aligned. */ dataseg = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mmap_offs); if (dataseg == MAP_FAILED) { printf("%s: can not map data seg\n", file); perror(file); exit(1); } /* * Find value in the location: rd_root_size */ ip = (u_int32_t*) (dataseg + rd_root_size_off); rd_root_size_val = *ip; #ifdef DEBUG printf("rd_root_size val: 0x%08X (%d blocks)\n", (u_int32_t)rd_root_size_val, (u_int32_t)(rd_root_size_val >> 9)); #endif /* * Copy the symbol table and string table. */ #ifdef DEBUG printf("copying root image...\n"); #endif if (xflag) { n = write(STDOUT_FILENO, dataseg + rd_root_image_off, rd_root_size_val); if (n != rd_root_size_val) { perror("write"); exit(1); } } else { struct stat sstat; if (fstat(STDIN_FILENO, &sstat) == -1) { perror("fstat"); exit(1); } if (S_ISREG(sstat.st_mode) && sstat.st_size > rd_root_size_val) { fprintf(stderr, "ramdisk too small\n"); exit(1); } n = read(STDIN_FILENO, dataseg + rd_root_image_off, rd_root_size_val); if (n < 0) { perror("read"); exit(1); } msync(dataseg, mmap_size, 0); } #ifdef DEBUG printf("...copied %d bytes\n", n); #endif close(fd); exit(0); }
uintptr_t linkmap_addr(struct ps_prochandle *ph) { uintptr_t ehdr_addr, phdr_addr, dyn_addr, dmap_addr, lmap_addr; ELF_EHDR ehdr; ELF_PHDR *phdrs, *phdr; ELF_DYN *dyns, *dyn; struct r_debug dmap; unsigned long hdrs_size; unsigned int i; /* read ELF_EHDR at TEXT_START_ADDR and validate */ ehdr_addr = (uintptr_t)TEXT_START_ADDR; if (process_read_data(ph, ehdr_addr, (char *)&ehdr, sizeof(ehdr)) != true) { print_debug("process_read_data failed for ehdr_addr %p\n", ehdr_addr); return (0); } if (!IS_ELF(ehdr) || ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS || ehdr.e_ident[EI_DATA] != ELF_TARG_DATA || ehdr.e_ident[EI_VERSION] != EV_CURRENT || ehdr.e_phentsize != sizeof(ELF_PHDR) || ehdr.e_version != ELF_TARG_VER || ehdr.e_machine != ELF_TARG_MACH) { print_debug("not an ELF_EHDR at %p\n", ehdr_addr); return (0); } /* allocate space for all ELF_PHDR's and read */ phdr_addr = ehdr_addr + ehdr.e_phoff; hdrs_size = ehdr.e_phnum * sizeof(ELF_PHDR); if ((phdrs = malloc(hdrs_size)) == NULL) return (0); if (process_read_data(ph, phdr_addr, (char *)phdrs, hdrs_size) != true) { print_debug("process_read_data failed for phdr_addr %p\n", phdr_addr); return (0); } /* find PT_DYNAMIC section */ for (i = 0, phdr = phdrs; i < ehdr.e_phnum; i++, phdr++) { if (phdr->p_type == PT_DYNAMIC) break; } if (i >= ehdr.e_phnum) { print_debug("PT_DYNAMIC section not found!\n"); free(phdrs); return (0); } /* allocate space and read in ELF_DYN headers */ dyn_addr = phdr->p_vaddr; hdrs_size = phdr->p_memsz; free(phdrs); if ((dyns = malloc(hdrs_size)) == NULL) return (0); if (process_read_data(ph, dyn_addr, (char *)dyns, hdrs_size) != true) { print_debug("process_read_data failed for dyn_addr %p\n", dyn_addr); free(dyns); return (0); } /* find DT_DEBUG */ dyn = dyns; while (dyn->d_tag != DT_DEBUG && dyn->d_tag != DT_NULL) { dyn++; } if (dyn->d_tag != DT_DEBUG) { print_debug("failed to find DT_DEBUG\n"); free(dyns); return (0); } /* read struct r_debug into dmap */ dmap_addr = (uintptr_t)dyn->d_un.d_ptr; free(dyns); if (process_read_data(ph, dmap_addr, (char *)&dmap, sizeof(dmap)) != true) { print_debug("process_read_data failed for dmap_addr %p\n", dmap_addr); return (0); } lmap_addr = (uintptr_t)dmap.r_map; return (lmap_addr); }
/* * elf to a.out converter for freebsd/sparc64 bootblocks. */ int main(int ac, char **av) { Elf64_Half phentsize; Elf64_Half machine; Elf64_Half phnum; Elf64_Xword filesz; Elf64_Xword memsz; Elf64_Addr entry; Elf64_Off offset; Elf64_Off phoff; Elf64_Word type; unsigned char data; struct stat sb; struct exec a; Elf64_Phdr *p; Elf64_Ehdr *e; void *v; int efd; int fd; int c; int i; fd = STDIN_FILENO; while ((c = getopt(ac, av, "o:")) != -1) switch (c) { case 'o': if ((fd = open(optarg, O_CREAT|O_RDWR, 0644)) < 0) err(1, "%s", optarg); break; case '?': default: usage(); } ac -= optind; av += optind; if (ac == 0) usage(); if ((efd = open(*av, O_RDONLY)) < 0 || fstat(efd, &sb) < 0) err(1, NULL); v = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, efd, 0); if ((e = v) == MAP_FAILED) err(1, NULL); if (!IS_ELF(*e)) errx(1, "not an elf file"); if (e->e_ident[EI_CLASS] != ELFCLASS64) errx(1, "wrong class"); data = e->e_ident[EI_DATA]; if (data != ELFDATA2MSB && data != ELFDATA2LSB) errx(1, "wrong data format"); if (e->e_ident[EI_VERSION] != EV_CURRENT) errx(1, "wrong elf version"); machine = xe16toh(e->e_machine); if (machine != EM_SPARCV9 && machine != EM_ALPHA) errx(1, "wrong machine type"); phentsize = xe16toh(e->e_phentsize); if (phentsize != sizeof(*p)) errx(1, "phdr size mismatch"); entry = xe64toh(e->e_entry); phoff = xe64toh(e->e_phoff); phnum = xe16toh(e->e_phnum); p = (Elf64_Phdr *)((char *)e + phoff); bzero(&a, sizeof(a)); for (i = 0; i < phnum; i++) { type = xe32toh(p[i].p_type); switch (type) { case PT_LOAD: if (a.a_magic != 0) errx(1, "too many loadable segments"); filesz = xe64toh(p[i].p_filesz); memsz = xe64toh(p[i].p_memsz); offset = xe64toh(p[i].p_offset); a.a_magic = htoxe32(A_MAGIC); a.a_text = htoxe32(filesz); a.a_bss = htoxe32(memsz - filesz); a.a_entry = htoxe32(entry); if (write(fd, &a, sizeof(a)) != sizeof(a) || write(fd, (char *)e + offset, filesz) != (ssize_t)filesz) err(1, NULL); break; default: break; } } return (0); }
int main(int ac, char **av) { cap_rights_t rights; u_int64_t phoff; u_int64_t shoff; u_int64_t phentsize; u_int64_t phnum; u_int64_t shentsize; u_int64_t shnum; u_int64_t shstrndx; u_int64_t offset; u_int64_t name; u_int64_t type; struct stat sb; u_int flags; Elf32_Ehdr *e; void *p; void *sh; void *v; int fd; int ch; int i; out = stdout; flags = 0; while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1) switch (ch) { case 'a': flags = ED_ALL; break; case 'c': flags |= ED_SHDR; break; case 'd': flags |= ED_DYN; break; case 'e': flags |= ED_EHDR; break; case 'i': flags |= ED_INTERP; break; case 'G': flags |= ED_GOT; break; case 'h': flags |= ED_HASH; break; case 'n': flags |= ED_NOTE; break; case 'p': flags |= ED_PHDR; break; case 'r': flags |= ED_REL; break; case 's': flags |= ED_SYMTAB; break; case 'w': if ((out = fopen(optarg, "w")) == NULL) err(1, "%s", optarg); cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", optarg); break; case '?': default: usage(); } ac -= optind; av += optind; if (ac == 0 || flags == 0) usage(); if ((fd = open(*av, O_RDONLY)) < 0 || fstat(fd, &sb) < 0) err(1, "%s", *av); cap_rights_init(&rights, CAP_MMAP_R); if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) err(1, "unable to limit rights for %s", *av); cap_rights_init(&rights); if ((cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) || caph_limit_stdout() < 0 || caph_limit_stderr() < 0) { err(1, "unable to limit rights for stdio"); } if (cap_enter() < 0 && errno != ENOSYS) err(1, "unable to enter capability mode"); e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (e == MAP_FAILED) err(1, NULL); if (!IS_ELF(*(Elf32_Ehdr *)e)) errx(1, "not an elf file"); phoff = elf_get_off(e, e, E_PHOFF); shoff = elf_get_off(e, e, E_SHOFF); phentsize = elf_get_quarter(e, e, E_PHENTSIZE); phnum = elf_get_quarter(e, e, E_PHNUM); shentsize = elf_get_quarter(e, e, E_SHENTSIZE); p = (char *)e + phoff; if (shoff > 0) { sh = (char *)e + shoff; shnum = elf_get_shnum(e, sh); shstrndx = elf_get_shstrndx(e, sh); offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET); shstrtab = (char *)e + offset; } else { sh = NULL; shnum = 0; shstrndx = 0; shstrtab = NULL; } for (i = 0; (u_int64_t)i < shnum; i++) { name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME); offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET); if (strcmp(shstrtab + name, ".strtab") == 0) strtab = (char *)e + offset; if (strcmp(shstrtab + name, ".dynstr") == 0) dynstr = (char *)e + offset; } if (flags & ED_EHDR) elf_print_ehdr(e, sh); if (flags & ED_PHDR) elf_print_phdr(e, p); if (flags & ED_SHDR) elf_print_shdr(e, sh); for (i = 0; (u_int64_t)i < phnum; i++) { v = (char *)p + i * phentsize; type = elf_get_word(e, v, P_TYPE); switch (type) { case PT_INTERP: if (flags & ED_INTERP) elf_print_interp(e, v); break; case PT_NULL: case PT_LOAD: case PT_DYNAMIC: case PT_NOTE: case PT_SHLIB: case PT_PHDR: break; } } for (i = 0; (u_int64_t)i < shnum; i++) { v = (char *)sh + i * shentsize; type = elf_get_word(e, v, SH_TYPE); switch (type) { case SHT_SYMTAB: if (flags & ED_SYMTAB) elf_print_symtab(e, v, strtab); break; case SHT_DYNAMIC: if (flags & ED_DYN) elf_print_dynamic(e, v); break; case SHT_RELA: if (flags & ED_REL) elf_print_rela(e, v); break; case SHT_REL: if (flags & ED_REL) elf_print_rel(e, v); break; case SHT_NOTE: name = elf_get_word(e, v, SH_NAME); if (flags & ED_NOTE && strcmp(shstrtab + name, ".note.ABI-tag") == 0) elf_print_note(e, v); break; case SHT_DYNSYM: if (flags & ED_SYMTAB) elf_print_symtab(e, v, dynstr); break; case SHT_PROGBITS: name = elf_get_word(e, v, SH_NAME); if (flags & ED_GOT && strcmp(shstrtab + name, ".got") == 0) elf_print_got(e, v); break; case SHT_HASH: if (flags & ED_HASH) elf_print_hash(e, v); break; case SHT_NULL: case SHT_STRTAB: case SHT_NOBITS: case SHT_SHLIB: break; } } return 0; }
int load_elf(Elf64_Ehdr *ehdr, int argc, char *argv[], char **envp) { uint64_t map_top = 0; assert(IS_ELF(*ehdr)); if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { fprintf(stderr, "not an executable file"); fflush(stderr); return -LINUX_ENOEXEC; } if (ehdr->e_machine != EM_X86_64) { fprintf(stderr, "not an x64 executable"); fflush(stderr); return -LINUX_ENOEXEC; } Elf64_Phdr *p = (Elf64_Phdr *)((char *)ehdr + ehdr->e_phoff); uint64_t load_base = 0; bool load_base_set = false; ulong global_offset = 0; if (ehdr->e_type == ET_DYN) { /* NB: Program headers in elf files of ET_DYN can have 0 as their own p_vaddr. */ global_offset = 0x400000; /* default base address */ } for (int i = 0; i < ehdr->e_phnum; i++) { if (p[i].p_type != PT_LOAD) { continue; } ulong p_vaddr = p[i].p_vaddr + global_offset; ulong mask = PAGE_SIZEOF(PAGE_4KB) - 1; ulong vaddr = p_vaddr & ~mask; ulong offset = p_vaddr & mask; ulong size = roundup(p[i].p_memsz + offset, PAGE_SIZEOF(PAGE_4KB)); int prot = 0; if (p[i].p_flags & PF_X) prot |= LINUX_PROT_EXEC; if (p[i].p_flags & PF_W) prot |= LINUX_PROT_WRITE; if (p[i].p_flags & PF_R) prot |= LINUX_PROT_READ; assert(vaddr != 0); do_mmap(vaddr, size, PROT_READ | PROT_WRITE, prot, LINUX_MAP_PRIVATE | LINUX_MAP_FIXED | LINUX_MAP_ANONYMOUS, -1, 0); copy_to_user(vaddr + offset, (char *)ehdr + p[i].p_offset, p[i].p_filesz); if (! load_base_set) { load_base = p[i].p_vaddr - p[i].p_offset + global_offset; load_base_set = true; } map_top = MAX(map_top, roundup(vaddr + size, PAGE_SIZEOF(PAGE_4KB))); } assert(load_base_set); int i; bool interp = false; for (i = 0; i < ehdr->e_phnum; i++) { if (p[i].p_type == PT_INTERP) { interp = true; break; } } if (interp) { char interp_path[p[i].p_filesz + 1]; memcpy(interp_path, (char *)ehdr + p[i].p_offset, p[i].p_filesz); interp_path[p[i].p_filesz] = 0; if (load_elf_interp(interp_path, map_top) < 0) { return -1; } } else { vmm_write_vmcs(VMCS_GUEST_RIP, ehdr->e_entry + global_offset); proc.mm->start_brk = map_top; } init_userstack(argc, argv, envp, load_base, ehdr, global_offset, interp ? map_top : 0); return 1; }
int ELFNAMEEND(check)(int fd, const char *fn) { Elf_Ehdr eh; struct stat sb; unsigned char data; /* * Check the header to maek sure it's an ELF file (of the * appropriate size). */ if (fstat(fd, &sb) == -1) return 0; if (sb.st_size < (off_t)(sizeof eh)) return 0; if (read(fd, &eh, sizeof eh) != sizeof eh) return 0; if (IS_ELF(eh) == 0) return 0; data = eh.e_ident[EI_DATA]; switch (xe16toh(eh.e_machine)) { case EM_386: break; case EM_ALPHA: break; #ifndef EM_ARM #define EM_ARM 40 #endif case EM_ARM: break; #ifndef EM_MIPS #define EM_MIPS 8 #endif #ifndef EM_MIPS_RS4_BE /* same as EM_MIPS_RS3_LE */ #define EM_MIPS_RS4_BE 10 #endif case EM_MIPS: break; case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break; #ifndef EM_IA_64 #define EM_IA_64 50 #endif case EM_IA_64: break; #ifndef EM_PPC #define EM_PPC 20 #endif case EM_PPC: break; #ifndef EM_PPC64 #define EM_PPC64 21 #endif case EM_PPC64: break; #ifndef EM_SPARCV9 #define EM_SPARCV9 43 #endif case EM_SPARCV9: break; #ifndef EM_X86_64 #define EM_X86_64 62 #endif case EM_X86_64: break; /* ELFDEFNNAME(MACHDEP_ID_CASES) */ default: return 0; } return 1; }
static void boot_fromfs(void) { union { Elf64_Ehdr eh; } hdr; static Elf64_Phdr ep[2]; #if 0 static Elf64_Shdr es[2]; #endif caddr_t p; ufs_ino_t ino; uint64_t addr; int i, j; if (!(ino = lookup(kname))) { if (!ls) printf("No %s\n", kname); return; } if (xfsread(ino, &hdr, sizeof(hdr))) return; if (IS_ELF(hdr.eh)) { fs_off = hdr.eh.e_phoff; for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { if (xfsread(ino, ep + j, sizeof(ep[0]))) return; if (ep[j].p_type == PT_LOAD) j++; } for (i = 0; i < 2; i++) { p = (caddr_t)ep[i].p_paddr; fs_off = ep[i].p_offset; if (xfsread(ino, p, ep[i].p_filesz)) return; } p += roundup2(ep[1].p_memsz, PAGE_SIZE); #if 0 bootinfo.bi_symtab = VTOP(p); if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { fs_off = hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1); if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) return; p += es[i].sh_size; } } #endif addr = hdr.eh.e_entry; #if 0 bootinfo.bi_esymtab = VTOP(p); #endif } else { printf("Invalid %s\n", "format"); return; } boot((void *)addr, beri_argc, beri_argv, beri_envv); }
list_t* proc_get_depends_list(proc_obj_t* obj) { Elf_Ehdr ehdr; Elf_Phdr phdr; Elf_Dyn dyn; struct link_map lmap; unsigned long phdr_addr, dyn_addr, addr; struct r_debug rdebug; char buf[PATH_MAX + 1]; list_t* ret = NULL; depend_t* cur = NULL; /* ** Get elf header. */ if (proc_read(obj, 0x10000, sizeof(Elf32_Ehdr), (char*) &ehdr) == -1) return (NULL); if (!IS_ELF(ehdr)) { errno = EFTRACE; ftrace_errstr = "Not Elf ?!"; exit(1); return (NULL); } /* ** Get program Headers and find the Dynamic program header.. */ phdr_addr = 0x10000 + ehdr.e_phoff; if (proc_read(obj, phdr_addr, sizeof(Elf32_Phdr), (char*) &phdr) == -1) return (NULL); while (phdr.p_type != PT_DYNAMIC) { if (proc_read(obj, phdr_addr += sizeof(Elf32_Phdr), sizeof(Elf32_Phdr), (char*) &phdr) == -1) return (NULL); } if (phdr.p_type != PT_DYNAMIC) return (NULL); /* ** Browse evrey dyn and find {DT_PLTGOT|DT_DEBUG} */ if (proc_read(obj, phdr.p_vaddr, sizeof(Elf32_Dyn), (char*) &dyn) == -1) return (NULL); dyn_addr = phdr.p_vaddr; /* ** --------------------------- ** Retrieve with the DT_DEBUG */ while (dyn.d_tag != DT_DEBUG) { if (proc_read(obj, dyn_addr += sizeof(Elf32_Dyn), sizeof(Elf32_Dyn), (char*) &dyn) == -1) return (NULL); } if (dyn.d_tag != DT_DEBUG) return (NULL); /* printf("struct rdebug found @ 0x%x\n", dyn.d_un.d_ptr); */ /* ** Get addresse's struct rdebug */ if (proc_read(obj, dyn.d_un.d_ptr, sizeof(struct r_debug), (char*) &rdebug) == -1) return (NULL); /* ** Here we have the link_map addr. ** Create the depend list... */ for (addr = (unsigned long) rdebug.r_map; addr; addr = (unsigned long) lmap.l_next) { if (proc_read(obj, addr, sizeof(struct link_map), (char*) &lmap) == -1) goto proc_get_depends_list_failed; if (lmap.l_name == 0) continue; if (proc_read(obj, (long) lmap.l_name, PATH_MAX, (char*) buf) == -1) goto proc_get_depends_list_failed; cur = malloc(sizeof(depend_t)); if (cur == NULL) goto proc_get_depends_list_failed; cur->path = strdup(buf); cur->base_addr = (addr_t) lmap.l_addr; ret = list_add(ret, cur); if (ret == NULL) goto proc_get_depends_list_failed; } return (ret); /* ** If failed, free list And return NULL. */ proc_get_depends_list_failed: for (; ret; ) { cur = (depend_t*) ret->value; ret = list_del(ret, cur); if (cur && cur->path) free(cur->path); free(cur); } return (NULL); }
/* * Read information about /boot's inode, then put this and filesystem * parameters from the superblock into pbr_symbols. */ static int getbootparams(char *boot, int devfd, struct disklabel *dl) { int fd; struct stat dsb, fsb; struct statfs fssb; struct partition *pp; struct fs *fs; char *buf; u_int blk, *ap; struct ufs1_dinode *ip1; struct ufs2_dinode *ip2; int ndb; int mib[3]; size_t size; dev_t dev; int skew; /* * Open 2nd-level boot program and record enough details about * where it is on the filesystem represented by `devfd' * (inode block, offset within that block, and various filesystem * parameters essentially taken from the superblock) for biosboot * to be able to load it later. */ /* Make sure the (probably new) boot file is on disk. */ sync(); sleep(1); if ((fd = open(boot, O_RDONLY)) < 0) err(1, "open: %s", boot); if (fstatfs(fd, &fssb) != 0) err(1, "statfs: %s", boot); if (strncmp(fssb.f_fstypename, "ffs", MFSNAMELEN) && strncmp(fssb.f_fstypename, "ufs", MFSNAMELEN) ) errx(1, "%s: not on an FFS filesystem", boot); #if 0 if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) errx(1, "read: %s", boot); if (!IS_ELF(eh)) { errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", boot, eh.e_ident[EI_MAG0], eh.e_ident[EI_MAG1], eh.e_ident[EI_MAG2], eh.e_ident[EI_MAG3]); } #endif if (fsync(fd) != 0) err(1, "fsync: %s", boot); if (fstat(fd, &fsb) != 0) err(1, "fstat: %s", boot); if (fstat(devfd, &dsb) != 0) err(1, "fstat: %d", devfd); /* Check devices. */ mib[0] = CTL_MACHDEP; mib[1] = CPU_CHR2BLK; mib[2] = dsb.st_rdev; size = sizeof(dev); if (sysctl(mib, 3, &dev, &size, NULL, 0) >= 0) { if (fsb.st_dev / MAXPARTITIONS != dev / MAXPARTITIONS) errx(1, "cross-device install"); } pp = &dl->d_partitions[DISKPART(fsb.st_dev)]; close(fd); sbread(devfd, DL_SECTOBLK(dl, DL_GETPOFFSET(pp)), &fs); /* Read inode. */ if ((buf = malloc(fs->fs_bsize)) == NULL) err(1, NULL); blk = fsbtodb(fs, ino_to_fsba(fs, fsb.st_ino)); /* * Have the inode. Figure out how many filesystem blocks (not disk * sectors) there are for biosboot to load. */ devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset) + blk, fs->fs_bsize, "inode"); if (fs->fs_magic == FS_UFS2_MAGIC) { ip2 = (struct ufs2_dinode *)(buf) + ino_to_fsbo(fs, fsb.st_ino); ndb = howmany(ip2->di_size, fs->fs_bsize); ap = (u_int *)ip2->di_db; skew = sizeof(u_int32_t); } else { ip1 = (struct ufs1_dinode *)(buf) + ino_to_fsbo(fs, fsb.st_ino); ndb = howmany(ip1->di_size, fs->fs_bsize); ap = (u_int *)ip1->di_db; skew = 0; } if (ndb <= 0) errx(1, "No blocks to load"); /* * Now set the values that will need to go into biosboot * (the partition boot record, a.k.a. the PBR). */ sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16)); sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize / dl->d_secsize)); /* * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The * ino_to_fsba() return value is the number of fs_fsize units. * Calculate the shift to convert fs_fsize into physical sectors, * which are added to p_offset to get the sector address BIOS * will use. * * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize. */ sym_set_value(pbr_symbols, "_fsbtodb", ffs(fs->fs_fsize / dl->d_secsize) - 1); if (pp->p_offseth != 0) errx(1, "partition offset too high"); sym_set_value(pbr_symbols, "_p_offset", pp->p_offset); sym_set_value(pbr_symbols, "_inodeblk", ino_to_fsba(fs, fsb.st_ino)); sym_set_value(pbr_symbols, "_inodedbl", ((((char *)ap) - buf) + INODEOFF)); sym_set_value(pbr_symbols, "_nblocks", ndb); sym_set_value(pbr_symbols, "_blkskew", skew); if (verbose) { fprintf(stderr, "%s is %d blocks x %d bytes\n", boot, ndb, fs->fs_bsize); fprintf(stderr, "fs block shift %u; part offset %llu; " "inode block %lld, offset %u\n", ffs(fs->fs_fsize / dl->d_secsize) - 1, DL_GETPOFFSET(pp), ino_to_fsba(fs, fsb.st_ino), (unsigned int)((((char *)ap) - buf) + INODEOFF)); fprintf(stderr, "expecting %d-bit fs blocks (skew %d)\n", skew ? 64 : 32, skew); } return 0; }
TEE_Result elf_load_head(struct elf_load_state *state, size_t head_size, void **head, size_t *vasize) { TEE_Result res; size_t n; void *p; Elf32_Ehdr *ehdr; /* * The ELF resides in shared memory, to avoid attacks based on * modifying the ELF while we're parsing it here we only read each * byte from the ELF once. We're also hashing the ELF while reading * so we're limited to only read the ELF sequentially from start to * end. */ res = alloc_and_copy_to(&p, state, 0, sizeof(Elf32_Ehdr)); if (res != TEE_SUCCESS) return res; ehdr = p; state->ehdr = ehdr; if (!IS_ELF(*ehdr) || ehdr->e_ident[EI_VERSION] != EV_CURRENT || ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_ident[EI_DATA] != ELFDATA2LSB || ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE || ehdr->e_type != ET_DYN || ehdr->e_machine != EM_ARM || (ehdr->e_flags & EF_ARM_ABIMASK) != EF_ARM_ABI_VERSION || (ehdr->e_flags & EF_ARM_ABI_FLOAT_HARD) || ehdr->e_phentsize != sizeof(Elf32_Phdr) || ehdr->e_shentsize != sizeof(Elf32_Shdr)) return TEE_ERROR_BAD_FORMAT; /* * Program headers are supposed to be arranged as: * PT_LOAD [0] : .ta_head ... * ... * PT_LOAD [n] * * .ta_head must be located first in the first program header, * which also has to be of PT_LOAD type. * * A PT_DYNAMIC segment may appear, but is ignored. Any other * segment except PT_LOAD and PT_DYNAMIC will cause an error. All * sections not included by a PT_LOAD segment are ignored. */ if (ehdr->e_phnum < 1) return TEE_ERROR_BAD_FORMAT; res = alloc_and_copy_to(&p, state, ehdr->e_phoff, ehdr->e_phnum * sizeof(Elf32_Phdr)); if (res != TEE_SUCCESS) return res; state->phdr = p; /* * Check that the first program header is a PT_LOAD (not strictly * needed but our link script is supposed to arrange it that way) * and that it starts at virtual address 0. */ if (state->phdr[0].p_type != PT_LOAD || state->phdr[0].p_vaddr != 0) return TEE_ERROR_BAD_FORMAT; /* * Calculate amount of required virtual memory for TA. Find the max * address used by a PT_LOAD type. Note that last PT_LOAD type * dictates the total amount of needed memory. Eventual holes in * the memory will also be allocated. * * Note that this loop will terminate at n = 0 if not earlier * as we already know from above that state->phdr[0].p_type == PT_LOAD */ n = ehdr->e_phnum - 1; while (state->phdr[n].p_type != PT_LOAD) n--; state->vasize = state->phdr[n].p_vaddr + state->phdr[n].p_memsz; /* * Read .ta_head from first segment, make sure the segment is large * enough. We're only interested in seeing that the * TA_FLAG_EXEC_DDR flag is set. If that's true we set that flag in * the TA context to enable mapping the TA. Later when this * function has returned and the hash has been verified the flags * field will be updated with eventual other flags. */ if (state->phdr[0].p_filesz < head_size) return TEE_ERROR_BAD_FORMAT; res = alloc_and_copy_to(&p, state, state->phdr[0].p_offset, head_size); if (res != TEE_SUCCESS) return res; state->ta_head = p; state->ta_head_size = head_size; *head = state->ta_head; *vasize = state->vasize; return TEE_SUCCESS; }
int putfile(char *from_file, int to) { struct exec ex; register int n, total; char buf[2048]; int from, check_sum = 0; struct lif_load load; if ((from = open(from_file, O_RDONLY)) < 0) err(1, "%s", from_file); n = read(from, &ex, sizeof(ex)); if (n != sizeof(ex)) err(1, "%s: reading file header", from_file); entry = ex.a_entry; if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC) entry += sizeof(ex); else if (IS_ELF(*(Elf32_Ehdr *)&ex)) { Elf32_Ehdr elf_header; Elf32_Phdr *elf_segments; int i, header_count, memory_needed, elf_load_image_segment; (void) lseek(from, 0, SEEK_SET); n = read(from, &elf_header, sizeof(elf_header)); if (n != sizeof (elf_header)) err(1, "%s: reading ELF header", from_file); header_count = ntohs(elf_header.e_phnum); elf_segments = reallocarray(NULL, header_count, sizeof(*elf_segments)); if (elf_segments == NULL) err(1, "malloc"); memory_needed = header_count * sizeof(*elf_segments); (void) lseek(from, ntohl(elf_header.e_phoff), SEEK_SET); n = read(from, elf_segments, memory_needed); if (n != memory_needed) err(1, "%s: reading ELF segments", from_file); elf_load_image_segment = -1; for (i = 0; i < header_count; i++) { if (elf_segments[i].p_filesz && ntohl(elf_segments[i].p_flags) & PF_X) { if (elf_load_image_segment != -1) errx(1, "%s: more than one ELF program segment", from_file); elf_load_image_segment = i; } } if (elf_load_image_segment == -1) errx(1, "%s: no suitable ELF program segment", from_file); entry = ntohl(elf_header.e_entry) + ntohl(elf_segments[elf_load_image_segment].p_offset) - ntohl(elf_segments[elf_load_image_segment].p_vaddr); free(elf_segments); } else if (*(u_char *)&ex == 0x1f && ((u_char *)&ex)[1] == 0x8b) { entry = 0; } else errx(1, "%s: bad magic number", from_file); entry += sizeof(load); lseek(to, sizeof(load), SEEK_CUR); total = 0; n = sizeof(buf) - sizeof(load); /* copy the whole file */ for (lseek(from, 0, 0); ; n = sizeof(buf)) { bzero(buf, sizeof(buf)); if ((n = read(from, buf, n)) < 0) err(1, "%s", from_file); else if (n == 0) break; if (write(to, buf, n) != n) err(1, "%s", to_file); total += n; check_sum = cksum(check_sum, (int *)buf, n); } /* load header */ load.address = htobe32(loadpoint + sizeof(load)); load.count = htobe32(4 + total); check_sum = cksum(check_sum, (int *)&load, sizeof(load)); if (verbose) warnx("wrote %d bytes of file \'%s\'", total, from_file); total += sizeof(load); /* insert the header */ lseek(to, -total, SEEK_CUR); if (write(to, &load, sizeof(load)) != sizeof(load)) err(1, "%s", to_file); lseek(to, total - sizeof(load), SEEK_CUR); bzero(buf, sizeof(buf)); /* pad to int */ n = sizeof(int) - total % sizeof(int); if (total % sizeof(int)) { if (write(to, buf, n) != n) err(1, "%s", to_file); else total += n; } /* pad to the blocksize */ n = sizeof(buf) - total % sizeof(buf); if (n < sizeof(int)) { n += sizeof(buf); total += sizeof(buf); } else total += n; /* TODO should pad here to the 65k boundary for tape boot */ if (verbose) warnx("checksum is 0x%08x", -check_sum); check_sum = htobe32(-check_sum); if (write(to, &check_sum, sizeof(int)) != sizeof(int)) err(1, "%s", to_file); n -= sizeof(int); if (write(to, buf, n) != n) err(1, "%s", to_file); if (close(from) < 0 ) err(1, "%s", from_file); return total; }
static int link_elf_ctf_get(linker_file_t lf, linker_ctf_t *lc) { #ifdef DDB_CTF Elf_Ehdr *hdr = NULL; Elf_Shdr *shdr = NULL; caddr_t ctftab = NULL; caddr_t raw = NULL; caddr_t shstrtab = NULL; elf_file_t ef = (elf_file_t) lf; int flags; int i; int nbytes; int resid; int vfslocked; size_t sz; struct nameidata nd; struct thread *td = curthread; uint8_t ctf_hdr[CTF_HDR_SIZE]; #endif int error = 0; if (lf == NULL || lc == NULL) return (EINVAL); /* Set the defaults for no CTF present. That's not a crime! */ bzero(lc, sizeof(*lc)); #ifdef DDB_CTF /* * First check if we've tried to load CTF data previously and the * CTF ELF section wasn't found. We flag that condition by setting * ctfcnt to -1. See below. */ if (ef->ctfcnt < 0) return (0); /* Now check if we've already loaded the CTF data.. */ if (ef->ctfcnt > 0) { /* We only need to load once. */ lc->ctftab = ef->ctftab; lc->ctfcnt = ef->ctfcnt; lc->symtab = ef->ddbsymtab; lc->strtab = ef->ddbstrtab; lc->strcnt = ef->ddbstrcnt; lc->nsym = ef->ddbsymcnt; lc->ctfoffp = (uint32_t **) &ef->ctfoff; lc->typoffp = (uint32_t **) &ef->typoff; lc->typlenp = &ef->typlen; return (0); } /* * We need to try reading the CTF data. Flag no CTF data present * by default and if we actually succeed in reading it, we'll * update ctfcnt to the number of bytes read. */ ef->ctfcnt = -1; NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, lf->pathname, td); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error) return (error); vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); /* Allocate memory for the FLF header. */ if ((hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK)) == NULL) { error = ENOMEM; goto out; } /* Read the ELF header. */ if ((error = vn_rdwr(UIO_READ, nd.ni_vp, hdr, sizeof(*hdr), 0, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td)) != 0) goto out; /* Sanity check. */ if (!IS_ELF(*hdr)) { error = ENOEXEC; goto out; } nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { error = ENOEXEC; goto out; } /* Allocate memory for all the section headers */ if ((shdr = malloc(nbytes, M_LINKER, M_WAITOK)) == NULL) { error = ENOMEM; goto out; } /* Read all the section headers */ if ((error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)shdr, nbytes, hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td)) != 0) goto out; /* * We need to search for the CTF section by name, so if the * section names aren't present, then we can't locate the * .SUNW_ctf section containing the CTF data. */ if (hdr->e_shstrndx == 0 || shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { printf("%s(%d): module %s e_shstrndx is %d, sh_type is %d\n", __func__, __LINE__, lf->pathname, hdr->e_shstrndx, shdr[hdr->e_shstrndx].sh_type); error = EFTYPE; goto out; } /* Allocate memory to buffer the section header strings. */ if ((shstrtab = malloc(shdr[hdr->e_shstrndx].sh_size, M_LINKER, M_WAITOK)) == NULL) { error = ENOMEM; goto out; } /* Read the section header strings. */ if ((error = vn_rdwr(UIO_READ, nd.ni_vp, shstrtab, shdr[hdr->e_shstrndx].sh_size, shdr[hdr->e_shstrndx].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td)) != 0) goto out; /* Search for the section containing the CTF data. */ for (i = 0; i < hdr->e_shnum; i++) if (strcmp(".SUNW_ctf", shstrtab + shdr[i].sh_name) == 0) break; /* Check if the CTF section wasn't found. */ if (i >= hdr->e_shnum) { printf("%s(%d): module %s has no .SUNW_ctf section\n", __func__, __LINE__, lf->pathname); error = EFTYPE; goto out; } /* Read the CTF header. */ if ((error = vn_rdwr(UIO_READ, nd.ni_vp, ctf_hdr, sizeof(ctf_hdr), shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td)) != 0) goto out; /* Check the CTF magic number. (XXX check for big endian!) */ if (ctf_hdr[0] != 0xf1 || ctf_hdr[1] != 0xcf) { printf("%s(%d): module %s has invalid format\n", __func__, __LINE__, lf->pathname); error = EFTYPE; goto out; } /* Check if version 2. */ if (ctf_hdr[2] != 2) { printf("%s(%d): module %s CTF format version is %d " "(2 expected)\n", __func__, __LINE__, lf->pathname, ctf_hdr[2]); error = EFTYPE; goto out; } /* Check if the data is compressed. */ if ((ctf_hdr[3] & 0x1) != 0) { uint32_t *u32 = (uint32_t *) ctf_hdr; /* * The last two fields in the CTF header are the offset * from the end of the header to the start of the string * data and the length of that string data. se this * information to determine the decompressed CTF data * buffer required. */ sz = u32[CTF_HDR_STRTAB_U32] + u32[CTF_HDR_STRLEN_U32] + sizeof(ctf_hdr); /* * Allocate memory for the compressed CTF data, including * the header (which isn't compressed). */ if ((raw = malloc(shdr[i].sh_size, M_LINKER, M_WAITOK)) == NULL) { error = ENOMEM; goto out; } } else { /* * The CTF data is not compressed, so the ELF section * size is the same as the buffer size required. */ sz = shdr[i].sh_size; } /* * Allocate memory to buffer the CTF data in it's decompressed * form. */ if ((ctftab = malloc(sz, M_LINKER, M_WAITOK)) == NULL) { error = ENOMEM; goto out; } /* * Read the CTF data into the raw buffer if compressed, or * directly into the CTF buffer otherwise. */ if ((error = vn_rdwr(UIO_READ, nd.ni_vp, raw == NULL ? ctftab : raw, shdr[i].sh_size, shdr[i].sh_offset, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, td)) != 0) goto out; /* Check if decompression is required. */ if (raw != NULL) { z_stream zs; int ret; /* * The header isn't compressed, so copy that into the * CTF buffer first. */ bcopy(ctf_hdr, ctftab, sizeof(ctf_hdr)); /* Initialise the zlib structure. */ bzero(&zs, sizeof(zs)); zs.zalloc = z_alloc; zs.zfree = z_free; if (inflateInit(&zs) != Z_OK) { error = EIO; goto out; } zs.avail_in = shdr[i].sh_size - sizeof(ctf_hdr); zs.next_in = ((uint8_t *) raw) + sizeof(ctf_hdr); zs.avail_out = sz - sizeof(ctf_hdr); zs.next_out = ((uint8_t *) ctftab) + sizeof(ctf_hdr); if ((ret = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { printf("%s(%d): zlib inflate returned %d\n", __func__, __LINE__, ret); error = EIO; goto out; } } /* Got the CTF data! */ ef->ctftab = ctftab; ef->ctfcnt = shdr[i].sh_size; /* We'll retain the memory allocated for the CTF data. */ ctftab = NULL; /* Let the caller use the CTF data read. */ lc->ctftab = ef->ctftab; lc->ctfcnt = ef->ctfcnt; lc->symtab = ef->ddbsymtab; lc->strtab = ef->ddbstrtab; lc->strcnt = ef->ddbstrcnt; lc->nsym = ef->ddbsymcnt; lc->ctfoffp = (uint32_t **) &ef->ctfoff; lc->typoffp = (uint32_t **) &ef->typoff; lc->typlenp = &ef->typlen; out: VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); VFS_UNLOCK_GIANT(vfslocked); if (hdr != NULL) free(hdr, M_LINKER); if (shdr != NULL) free(shdr, M_LINKER); if (shstrtab != NULL) free(shstrtab, M_LINKER); if (ctftab != NULL) free(ctftab, M_LINKER); if (raw != NULL) free(raw, M_LINKER); #else error = EOPNOTSUPP; #endif return (error); }
int ef_obj_open(const char *filename, struct elf_file *efile, int verbose) { elf_file_t ef; Elf_Ehdr *hdr; Elf_Shdr *shdr; Elf_Sym *es; char *mapbase; void *vtmp; size_t mapsize, alignmask, max_addralign; int error, fd, pb, ra, res, rl; int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex; if (filename == NULL) return EFTYPE; if ((fd = open(filename, O_RDONLY)) == -1) return errno; ef = calloc(1, sizeof(*ef)); if (ef == NULL) { close(fd); return (ENOMEM); } efile->ef_ef = ef; efile->ef_ops = &ef_obj_file_ops; ef->ef_verbose = verbose; ef->ef_fd = fd; ef->ef_name = strdup(filename); ef->ef_efile = efile; hdr = (Elf_Ehdr *)&ef->ef_hdr; res = read(fd, hdr, sizeof(*hdr)); error = EFTYPE; if (res != sizeof(*hdr)) goto out; if (!IS_ELF(*hdr)) goto out; if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA || hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || hdr->e_type != ET_REL) goto out; nbytes = hdr->e_shnum * hdr->e_shentsize; if (nbytes == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) goto out; if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { printf("ef_read_entry failed\n"); goto out; } ef->e_shdr = shdr = vtmp; /* Scan the section header for information and table sizing. */ nsym = 0; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: ef->nprogtab++; break; case SHT_SYMTAB: nsym++; symtabindex = i; symstrindex = shdr[i].sh_link; break; case SHT_REL: ef->nrel++; break; case SHT_RELA: ef->nrela++; break; case SHT_STRTAB: break; } } if (ef->nprogtab == 0) { warnx("%s: file has no contents", filename); goto out; } if (nsym != 1) { warnx("%s: file has no valid symbol table", filename); goto out; } if (symstrindex < 0 || symstrindex > hdr->e_shnum || shdr[symstrindex].sh_type != SHT_STRTAB) { warnx("%s: file has invalid symbol strings", filename); goto out; } /* Allocate space for tracking the load chunks */ if (ef->nprogtab != 0) ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); if (ef->nrel != 0) ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); if (ef->nrela != 0) ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); if ((ef->nprogtab != 0 && ef->progtab == NULL) || (ef->nrel != 0 && ef->reltab == NULL) || (ef->nrela != 0 && ef->relatab == NULL)) { printf("malloc failed\n"); error = ENOMEM; goto out; } ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { printf("ef_read_entry failed\n"); goto out; } ef->ddbstrcnt = shdr[symstrindex].sh_size; if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { printf("ef_read_entry failed\n"); goto out; } /* Do we have a string table for the section names? */ shstrindex = -1; if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { shstrindex = hdr->e_shstrndx; ef->shstrcnt = shdr[shstrindex].sh_size; if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { printf("ef_read_entry failed\n"); goto out; } } /* Size up code/data(progbits) and bss(nobits). */ alignmask = 0; max_addralign = 0; mapsize = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; if (shdr[i].sh_addralign > max_addralign) max_addralign = shdr[i].sh_addralign; mapsize += alignmask; mapsize &= ~alignmask; mapsize += shdr[i].sh_size; break; } } /* We know how much space we need for the text/data/bss/etc. */ ef->size = mapsize; if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { printf("posix_memalign failed\n"); goto out; } mapbase = ef->address; /* * Now load code/data(progbits), zero bss(nobits), allocate * space for and load relocs */ pb = 0; rl = 0; ra = 0; alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; mapbase += alignmask; mapbase = (char *)((uintptr_t)mapbase & ~alignmask); ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; if (shdr[i].sh_type == SHT_PROGBITS) { ef->progtab[pb].name = "<<PROGBITS>>"; if (ef_obj_read(ef, shdr[i].sh_offset, shdr[i].sh_size, ef->progtab[pb].addr) != 0) { printf("failed to read progbits\n"); goto out; } } else { ef->progtab[pb].name = "<<NOBITS>>"; bzero(ef->progtab[pb].addr, shdr[i].sh_size); } ef->progtab[pb].size = shdr[i].sh_size; ef->progtab[pb].sec = i; if (ef->shstrtab && shdr[i].sh_name != 0) ef->progtab[pb].name = ef->shstrtab + shdr[i].sh_name; /* Update all symbol values with the offset. */ for (j = 0; j < ef->ddbsymcnt; j++) { es = &ef->ddbsymtab[j]; if (es->st_shndx != i) continue; es->st_value += (Elf_Addr)ef->progtab[pb].addr; } mapbase += shdr[i].sh_size; pb++; break; case SHT_REL: ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); ef->reltab[rl].sec = shdr[i].sh_info; if (ef_obj_read_entry(ef, shdr[i].sh_offset, shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 0) { printf("ef_read_entry failed\n"); goto out; } rl++; break; case SHT_RELA: ef->relatab[ra].nrela = shdr[i].sh_size / sizeof(Elf_Rela); ef->relatab[ra].sec = shdr[i].sh_info; if (ef_obj_read_entry(ef, shdr[i].sh_offset, shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 0) { printf("ef_read_entry failed\n"); goto out; } ra++; break; } } error = 0; out: if (error) ef_obj_close(ef); return error; }
int elf_getnfile(const char *filename, char ***defaultEs) { int fd; Elf_Ehdr h; struct stat s; void *mapbase; const char *base; const Elf_Shdr *shdrs; const Elf_Shdr *sh_symtab; const Elf_Shdr *sh_strtab; const char *strtab; const Elf_Sym *symtab; int symtabct; int i; if ((fd = open(filename, O_RDONLY)) == -1) err(1, "%s", filename); if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) { close(fd); return -1; } if (fstat(fd, &s) == -1) err(1, "cannot fstat %s", filename); if ((mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) err(1, "cannot mmap %s", filename); close(fd); base = (const char *)mapbase; shdrs = (const Elf_Shdr *)(base + h.e_shoff); /* Find the symbol table and associated string table section. */ for (i = 1; i < h.e_shnum; i++) if (shdrs[i].sh_type == SHT_SYMTAB) break; if (i == h.e_shnum) errx(1, "%s has no symbol table", filename); sh_symtab = &shdrs[i]; sh_strtab = &shdrs[sh_symtab->sh_link]; symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset); symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize; strtab = (const char *)(base + sh_strtab->sh_offset); /* Count the symbols that we're interested in. */ nname = 0; for (i = 1; i < symtabct; i++) if (wantsym(&symtab[i], strtab)) nname++; /* Allocate memory for them, plus a terminating entry. */ if ((nl = (nltype *)calloc(nname + 1, sizeof(nltype))) == NULL) errx(1, "insufficient memory for symbol table"); /* Read them in. */ npe = nl; for (i = 1; i < symtabct; i++) { const Elf_Sym *sym = &symtab[i]; if (wantsym(sym, strtab)) { npe->value = sym->st_value; npe->name = strtab + sym->st_name; npe++; } } npe->value = -1; *defaultEs = excludes; return 0; }