1968bcca2SKa Ho Ng /*- 2968bcca2SKa Ho Ng * SPDX-License-Identifier: BSD-4-Clause 3968bcca2SKa Ho Ng * 4968bcca2SKa Ho Ng * Copyright (c) 2000, Boris Popov 5968bcca2SKa Ho Ng * Copyright (c) 1998-2000 Doug Rabson 6968bcca2SKa Ho Ng * Copyright (c) 2004 Peter Wemm 7968bcca2SKa Ho Ng * All rights reserved. 8968bcca2SKa Ho Ng * 9968bcca2SKa Ho Ng * Redistribution and use in source and binary forms, with or without 10968bcca2SKa Ho Ng * modification, are permitted provided that the following conditions 11968bcca2SKa Ho Ng * are met: 12968bcca2SKa Ho Ng * 1. Redistributions of source code must retain the above copyright 13968bcca2SKa Ho Ng * notice, this list of conditions and the following disclaimer. 14968bcca2SKa Ho Ng * 2. Redistributions in binary form must reproduce the above copyright 15968bcca2SKa Ho Ng * notice, this list of conditions and the following disclaimer in the 16968bcca2SKa Ho Ng * documentation and/or other materials provided with the distribution. 17968bcca2SKa Ho Ng * 3. All advertising materials mentioning features or use of this software 18968bcca2SKa Ho Ng * must display the following acknowledgement: 19968bcca2SKa Ho Ng * This product includes software developed by Boris Popov. 20968bcca2SKa Ho Ng * 4. Neither the name of the author nor the names of any co-contributors 21968bcca2SKa Ho Ng * may be used to endorse or promote products derived from this software 22968bcca2SKa Ho Ng * without specific prior written permission. 23968bcca2SKa Ho Ng * 24968bcca2SKa Ho Ng * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25968bcca2SKa Ho Ng * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26968bcca2SKa Ho Ng * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27968bcca2SKa Ho Ng * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28968bcca2SKa Ho Ng * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29968bcca2SKa Ho Ng * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30968bcca2SKa Ho Ng * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31968bcca2SKa Ho Ng * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32968bcca2SKa Ho Ng * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33968bcca2SKa Ho Ng * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34968bcca2SKa Ho Ng * SUCH DAMAGE. 35968bcca2SKa Ho Ng */ 36968bcca2SKa Ho Ng 37968bcca2SKa Ho Ng #include <sys/param.h> 38968bcca2SKa Ho Ng 39968bcca2SKa Ho Ng #include <err.h> 40968bcca2SKa Ho Ng #include <errno.h> 41968bcca2SKa Ho Ng #include <gelf.h> 42968bcca2SKa Ho Ng #include <stdio.h> 43968bcca2SKa Ho Ng #include <stdlib.h> 44968bcca2SKa Ho Ng #include <string.h> 45968bcca2SKa Ho Ng 46968bcca2SKa Ho Ng #include "kldelf.h" 47968bcca2SKa Ho Ng 48968bcca2SKa Ho Ng typedef struct { 49968bcca2SKa Ho Ng GElf_Addr addr; 50968bcca2SKa Ho Ng GElf_Off offset; 51968bcca2SKa Ho Ng GElf_Off size; 52968bcca2SKa Ho Ng int flags; 53968bcca2SKa Ho Ng int sec; /* Original section */ 54968bcca2SKa Ho Ng char *name; 55968bcca2SKa Ho Ng } Elf_progent; 56968bcca2SKa Ho Ng 57968bcca2SKa Ho Ng typedef struct { 58968bcca2SKa Ho Ng GElf_Rel *rel; 59968bcca2SKa Ho Ng long nrel; 60968bcca2SKa Ho Ng int sec; 61968bcca2SKa Ho Ng } Elf_relent; 62968bcca2SKa Ho Ng 63968bcca2SKa Ho Ng typedef struct { 64968bcca2SKa Ho Ng GElf_Rela *rela; 65968bcca2SKa Ho Ng long nrela; 66968bcca2SKa Ho Ng int sec; 67968bcca2SKa Ho Ng } Elf_relaent; 68968bcca2SKa Ho Ng 69968bcca2SKa Ho Ng struct ef_file { 70968bcca2SKa Ho Ng char *ef_name; 71968bcca2SKa Ho Ng struct elf_file *ef_efile; 72968bcca2SKa Ho Ng 73968bcca2SKa Ho Ng Elf_progent *progtab; 74968bcca2SKa Ho Ng int nprogtab; 75968bcca2SKa Ho Ng 76968bcca2SKa Ho Ng Elf_relaent *relatab; 77968bcca2SKa Ho Ng int nrela; 78968bcca2SKa Ho Ng 79968bcca2SKa Ho Ng Elf_relent *reltab; 80968bcca2SKa Ho Ng int nrel; 81968bcca2SKa Ho Ng 82968bcca2SKa Ho Ng GElf_Sym *ddbsymtab; /* The symbol table we are using */ 83968bcca2SKa Ho Ng size_t ddbsymcnt; /* Number of symbols */ 84968bcca2SKa Ho Ng caddr_t ddbstrtab; /* String table */ 85968bcca2SKa Ho Ng long ddbstrcnt; /* number of bytes in string table */ 86968bcca2SKa Ho Ng 87968bcca2SKa Ho Ng caddr_t shstrtab; /* Section name string table */ 88968bcca2SKa Ho Ng long shstrcnt; /* number of bytes in string table */ 89968bcca2SKa Ho Ng 90968bcca2SKa Ho Ng int ef_verbose; 91968bcca2SKa Ho Ng }; 92968bcca2SKa Ho Ng 93968bcca2SKa Ho Ng static void ef_obj_close(elf_file_t ef); 94968bcca2SKa Ho Ng 95968bcca2SKa Ho Ng static int ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, 96968bcca2SKa Ho Ng size_t len, void *dest); 97968bcca2SKa Ho Ng static int ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address, 98968bcca2SKa Ho Ng size_t len, char *dest); 99968bcca2SKa Ho Ng 100968bcca2SKa Ho Ng static GElf_Addr ef_obj_symaddr(elf_file_t ef, GElf_Size symidx); 101968bcca2SKa Ho Ng static int ef_obj_lookup_set(elf_file_t ef, const char *name, 102968bcca2SKa Ho Ng GElf_Addr *startp, GElf_Addr *stopp, long *countp); 103968bcca2SKa Ho Ng static int ef_obj_lookup_symbol(elf_file_t ef, const char *name, 104*72e15f76SKa Ho Ng GElf_Sym **sym, bool see_local); 105968bcca2SKa Ho Ng 106968bcca2SKa Ho Ng static struct elf_file_ops ef_obj_file_ops = { 107968bcca2SKa Ho Ng .close = ef_obj_close, 108968bcca2SKa Ho Ng .seg_read_rel = ef_obj_seg_read_rel, 109968bcca2SKa Ho Ng .seg_read_string = ef_obj_seg_read_string, 110968bcca2SKa Ho Ng .symaddr = ef_obj_symaddr, 111968bcca2SKa Ho Ng .lookup_set = ef_obj_lookup_set, 11243628a31SKa Ho Ng .lookup_symbol = ef_obj_lookup_symbol, 113968bcca2SKa Ho Ng }; 114968bcca2SKa Ho Ng 115968bcca2SKa Ho Ng static GElf_Off 116968bcca2SKa Ho Ng ef_obj_get_offset(elf_file_t ef, GElf_Addr addr) 117968bcca2SKa Ho Ng { 118968bcca2SKa Ho Ng Elf_progent *pt; 119968bcca2SKa Ho Ng int i; 120968bcca2SKa Ho Ng 121968bcca2SKa Ho Ng for (i = 0; i < ef->nprogtab; i++) { 122968bcca2SKa Ho Ng pt = &ef->progtab[i]; 123968bcca2SKa Ho Ng if (pt->offset == (GElf_Off)-1) 124968bcca2SKa Ho Ng continue; 125968bcca2SKa Ho Ng if (addr >= pt->addr && addr < pt->addr + pt->size) 126968bcca2SKa Ho Ng return (pt->offset + (addr - pt->addr)); 127968bcca2SKa Ho Ng } 128968bcca2SKa Ho Ng return (0); 129968bcca2SKa Ho Ng } 130968bcca2SKa Ho Ng 131968bcca2SKa Ho Ng static int 132*72e15f76SKa Ho Ng ef_obj_lookup_symbol(elf_file_t ef, const char *name, GElf_Sym **sym, 133*72e15f76SKa Ho Ng bool see_local) 134968bcca2SKa Ho Ng { 135968bcca2SKa Ho Ng GElf_Sym *symp; 136968bcca2SKa Ho Ng const char *strp; 137968bcca2SKa Ho Ng int i; 138968bcca2SKa Ho Ng 139968bcca2SKa Ho Ng for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 140968bcca2SKa Ho Ng strp = ef->ddbstrtab + symp->st_name; 141968bcca2SKa Ho Ng if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { 142*72e15f76SKa Ho Ng if (see_local || 143*72e15f76SKa Ho Ng GELF_ST_BIND(symp->st_info) != STB_LOCAL) { 144968bcca2SKa Ho Ng *sym = symp; 145968bcca2SKa Ho Ng return (0); 146968bcca2SKa Ho Ng } 147968bcca2SKa Ho Ng } 148*72e15f76SKa Ho Ng } 149968bcca2SKa Ho Ng return (ENOENT); 150968bcca2SKa Ho Ng } 151968bcca2SKa Ho Ng 152968bcca2SKa Ho Ng static int 153968bcca2SKa Ho Ng ef_obj_lookup_set(elf_file_t ef, const char *name, GElf_Addr *startp, 154968bcca2SKa Ho Ng GElf_Addr *stopp, long *countp) 155968bcca2SKa Ho Ng { 156968bcca2SKa Ho Ng int i; 157968bcca2SKa Ho Ng 158968bcca2SKa Ho Ng for (i = 0; i < ef->nprogtab; i++) { 159968bcca2SKa Ho Ng if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && 160968bcca2SKa Ho Ng strcmp(ef->progtab[i].name + 4, name) == 0) { 161968bcca2SKa Ho Ng *startp = ef->progtab[i].addr; 162968bcca2SKa Ho Ng *stopp = ef->progtab[i].addr + ef->progtab[i].size; 163968bcca2SKa Ho Ng *countp = (*stopp - *startp) / 164968bcca2SKa Ho Ng elf_pointer_size(ef->ef_efile); 165968bcca2SKa Ho Ng return (0); 166968bcca2SKa Ho Ng } 167968bcca2SKa Ho Ng } 168968bcca2SKa Ho Ng return (ESRCH); 169968bcca2SKa Ho Ng } 170968bcca2SKa Ho Ng 171968bcca2SKa Ho Ng static GElf_Addr 172968bcca2SKa Ho Ng ef_obj_symaddr(elf_file_t ef, GElf_Size symidx) 173968bcca2SKa Ho Ng { 174968bcca2SKa Ho Ng const GElf_Sym *sym; 175968bcca2SKa Ho Ng 176968bcca2SKa Ho Ng if (symidx >= ef->ddbsymcnt) 177968bcca2SKa Ho Ng return (0); 178968bcca2SKa Ho Ng sym = ef->ddbsymtab + symidx; 179968bcca2SKa Ho Ng 180968bcca2SKa Ho Ng if (sym->st_shndx != SHN_UNDEF) 181968bcca2SKa Ho Ng return (sym->st_value); 182968bcca2SKa Ho Ng return (0); 183968bcca2SKa Ho Ng } 184968bcca2SKa Ho Ng 185968bcca2SKa Ho Ng static int 186968bcca2SKa Ho Ng ef_obj_seg_read_rel(elf_file_t ef, GElf_Addr address, size_t len, void *dest) 187968bcca2SKa Ho Ng { 188968bcca2SKa Ho Ng GElf_Off secofs; 189968bcca2SKa Ho Ng GElf_Rel *r; 190968bcca2SKa Ho Ng GElf_Rela *a; 191968bcca2SKa Ho Ng GElf_Addr secbase, dataoff; 192968bcca2SKa Ho Ng int error, i, sec; 193968bcca2SKa Ho Ng 194968bcca2SKa Ho Ng /* Find out which section contains the data. */ 195968bcca2SKa Ho Ng sec = -1; 196968bcca2SKa Ho Ng for (i = 0; i < ef->nprogtab; i++) { 197968bcca2SKa Ho Ng if (address < ef->progtab[i].addr) 198968bcca2SKa Ho Ng continue; 199968bcca2SKa Ho Ng 200968bcca2SKa Ho Ng dataoff = address - ef->progtab[i].addr; 201968bcca2SKa Ho Ng if (dataoff + len > ef->progtab[i].size) 202968bcca2SKa Ho Ng continue; 203968bcca2SKa Ho Ng 204968bcca2SKa Ho Ng sec = ef->progtab[i].sec; 205968bcca2SKa Ho Ng secbase = ef->progtab[i].addr; 206968bcca2SKa Ho Ng secofs = ef->progtab[i].offset; 207968bcca2SKa Ho Ng break; 208968bcca2SKa Ho Ng } 209968bcca2SKa Ho Ng 210968bcca2SKa Ho Ng if (sec == -1) { 211968bcca2SKa Ho Ng if (ef->ef_verbose) 212968bcca2SKa Ho Ng warnx("ef_obj_seg_read_rel(%s): bad address (%jx)", 213968bcca2SKa Ho Ng ef->ef_name, (uintmax_t)address); 214968bcca2SKa Ho Ng return (EFAULT); 215968bcca2SKa Ho Ng } 216968bcca2SKa Ho Ng 217968bcca2SKa Ho Ng if (secofs == (GElf_Off)-1) { 218968bcca2SKa Ho Ng memset(dest, 0, len); 219968bcca2SKa Ho Ng } else { 220968bcca2SKa Ho Ng error = elf_read_raw_data(ef->ef_efile, secofs + dataoff, dest, 221968bcca2SKa Ho Ng len); 222968bcca2SKa Ho Ng if (error != 0) 223968bcca2SKa Ho Ng return (error); 224968bcca2SKa Ho Ng } 225968bcca2SKa Ho Ng 226968bcca2SKa Ho Ng /* Now do the relocations. */ 227968bcca2SKa Ho Ng for (i = 0; i < ef->nrel; i++) { 228968bcca2SKa Ho Ng if (ef->reltab[i].sec != sec) 229968bcca2SKa Ho Ng continue; 230968bcca2SKa Ho Ng for (r = ef->reltab[i].rel; 231968bcca2SKa Ho Ng r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { 232968bcca2SKa Ho Ng error = elf_reloc(ef->ef_efile, r, ELF_T_REL, secbase, 233968bcca2SKa Ho Ng address, len, dest); 234968bcca2SKa Ho Ng if (error != 0) 235968bcca2SKa Ho Ng return (error); 236968bcca2SKa Ho Ng } 237968bcca2SKa Ho Ng } 238968bcca2SKa Ho Ng for (i = 0; i < ef->nrela; i++) { 239968bcca2SKa Ho Ng if (ef->relatab[i].sec != sec) 240968bcca2SKa Ho Ng continue; 241968bcca2SKa Ho Ng for (a = ef->relatab[i].rela; 242968bcca2SKa Ho Ng a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { 243968bcca2SKa Ho Ng error = elf_reloc(ef->ef_efile, a, ELF_T_RELA, secbase, 244968bcca2SKa Ho Ng address, len, dest); 245968bcca2SKa Ho Ng if (error != 0) 246968bcca2SKa Ho Ng return (error); 247968bcca2SKa Ho Ng } 248968bcca2SKa Ho Ng } 249968bcca2SKa Ho Ng return (0); 250968bcca2SKa Ho Ng } 251968bcca2SKa Ho Ng 252968bcca2SKa Ho Ng static int 253968bcca2SKa Ho Ng ef_obj_seg_read_string(elf_file_t ef, GElf_Addr address, size_t len, char *dest) 254968bcca2SKa Ho Ng { 255968bcca2SKa Ho Ng GElf_Off ofs; 256968bcca2SKa Ho Ng 257968bcca2SKa Ho Ng ofs = ef_obj_get_offset(ef, address); 258968bcca2SKa Ho Ng if (ofs == 0) { 259968bcca2SKa Ho Ng if (ef->ef_verbose) 260968bcca2SKa Ho Ng warnx("ef_obj_seg_read_string(%s): bad address (%jx)", 261968bcca2SKa Ho Ng ef->ef_name, (uintmax_t)address); 262968bcca2SKa Ho Ng return (EFAULT); 263968bcca2SKa Ho Ng } 264968bcca2SKa Ho Ng 265968bcca2SKa Ho Ng return (elf_read_raw_string(ef->ef_efile, ofs, dest, len)); 266968bcca2SKa Ho Ng } 267968bcca2SKa Ho Ng 268968bcca2SKa Ho Ng int 269968bcca2SKa Ho Ng ef_obj_open(struct elf_file *efile, int verbose) 270968bcca2SKa Ho Ng { 271968bcca2SKa Ho Ng elf_file_t ef; 272968bcca2SKa Ho Ng GElf_Ehdr *hdr; 273968bcca2SKa Ho Ng GElf_Shdr *shdr; 274968bcca2SKa Ho Ng GElf_Sym *es; 275968bcca2SKa Ho Ng GElf_Addr mapbase; 276968bcca2SKa Ho Ng size_t i, nshdr; 277968bcca2SKa Ho Ng int error, pb, ra, rl; 278968bcca2SKa Ho Ng int j, nsym, symstrindex, symtabindex; 279968bcca2SKa Ho Ng 280968bcca2SKa Ho Ng hdr = &efile->ef_hdr; 281968bcca2SKa Ho Ng if (hdr->e_type != ET_REL || hdr->e_shnum == 0 || hdr->e_shoff == 0 || 282968bcca2SKa Ho Ng hdr->e_shentsize != elf_object_size(efile, ELF_T_SHDR)) 283968bcca2SKa Ho Ng return (EFTYPE); 284968bcca2SKa Ho Ng 285968bcca2SKa Ho Ng ef = calloc(1, sizeof(*ef)); 286968bcca2SKa Ho Ng if (ef == NULL) 287968bcca2SKa Ho Ng return (errno); 288968bcca2SKa Ho Ng 289968bcca2SKa Ho Ng efile->ef_ef = ef; 290968bcca2SKa Ho Ng efile->ef_ops = &ef_obj_file_ops; 291968bcca2SKa Ho Ng 292968bcca2SKa Ho Ng ef->ef_verbose = verbose; 293968bcca2SKa Ho Ng ef->ef_name = strdup(efile->ef_filename); 294968bcca2SKa Ho Ng ef->ef_efile = efile; 295968bcca2SKa Ho Ng 296968bcca2SKa Ho Ng error = elf_read_shdrs(efile, &nshdr, &shdr); 297968bcca2SKa Ho Ng if (error != 0) { 298968bcca2SKa Ho Ng shdr = NULL; 299968bcca2SKa Ho Ng goto out; 300968bcca2SKa Ho Ng } 301968bcca2SKa Ho Ng 302968bcca2SKa Ho Ng /* Scan the section headers for information and table sizing. */ 303968bcca2SKa Ho Ng nsym = 0; 304968bcca2SKa Ho Ng symtabindex = -1; 305968bcca2SKa Ho Ng symstrindex = -1; 306968bcca2SKa Ho Ng for (i = 0; i < nshdr; i++) { 307968bcca2SKa Ho Ng switch (shdr[i].sh_type) { 308968bcca2SKa Ho Ng case SHT_PROGBITS: 309968bcca2SKa Ho Ng case SHT_NOBITS: 310968bcca2SKa Ho Ng ef->nprogtab++; 311968bcca2SKa Ho Ng break; 312968bcca2SKa Ho Ng case SHT_SYMTAB: 313968bcca2SKa Ho Ng nsym++; 314968bcca2SKa Ho Ng symtabindex = i; 315968bcca2SKa Ho Ng symstrindex = shdr[i].sh_link; 316968bcca2SKa Ho Ng break; 317968bcca2SKa Ho Ng case SHT_REL: 318968bcca2SKa Ho Ng ef->nrel++; 319968bcca2SKa Ho Ng break; 320968bcca2SKa Ho Ng case SHT_RELA: 321968bcca2SKa Ho Ng ef->nrela++; 322968bcca2SKa Ho Ng break; 323968bcca2SKa Ho Ng case SHT_STRTAB: 324968bcca2SKa Ho Ng break; 325968bcca2SKa Ho Ng } 326968bcca2SKa Ho Ng } 327968bcca2SKa Ho Ng 328968bcca2SKa Ho Ng if (ef->nprogtab == 0) { 329968bcca2SKa Ho Ng warnx("%s: file has no contents", ef->ef_name); 330968bcca2SKa Ho Ng goto out; 331968bcca2SKa Ho Ng } 332968bcca2SKa Ho Ng if (nsym != 1) { 333968bcca2SKa Ho Ng warnx("%s: file has no valid symbol table", ef->ef_name); 334968bcca2SKa Ho Ng goto out; 335968bcca2SKa Ho Ng } 336968bcca2SKa Ho Ng if (symstrindex < 0 || symstrindex > nshdr || 337968bcca2SKa Ho Ng shdr[symstrindex].sh_type != SHT_STRTAB) { 338968bcca2SKa Ho Ng warnx("%s: file has invalid symbol strings", ef->ef_name); 339968bcca2SKa Ho Ng goto out; 340968bcca2SKa Ho Ng } 341968bcca2SKa Ho Ng 342968bcca2SKa Ho Ng /* Allocate space for tracking the load chunks */ 343968bcca2SKa Ho Ng if (ef->nprogtab != 0) 344968bcca2SKa Ho Ng ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); 345968bcca2SKa Ho Ng if (ef->nrel != 0) 346968bcca2SKa Ho Ng ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); 347968bcca2SKa Ho Ng if (ef->nrela != 0) 348968bcca2SKa Ho Ng ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); 349968bcca2SKa Ho Ng if ((ef->nprogtab != 0 && ef->progtab == NULL) || 350968bcca2SKa Ho Ng (ef->nrel != 0 && ef->reltab == NULL) || 351968bcca2SKa Ho Ng (ef->nrela != 0 && ef->relatab == NULL)) { 352599c4399SKa Ho Ng warnx("malloc failed"); 353968bcca2SKa Ho Ng error = ENOMEM; 354968bcca2SKa Ho Ng goto out; 355968bcca2SKa Ho Ng } 356968bcca2SKa Ho Ng 357968bcca2SKa Ho Ng if (elf_read_symbols(efile, symtabindex, &ef->ddbsymcnt, 358968bcca2SKa Ho Ng &ef->ddbsymtab) != 0) { 359599c4399SKa Ho Ng warnx("elf_read_symbols failed"); 360968bcca2SKa Ho Ng goto out; 361968bcca2SKa Ho Ng } 362968bcca2SKa Ho Ng 363968bcca2SKa Ho Ng if (elf_read_string_table(efile, &shdr[symstrindex], &ef->ddbstrcnt, 364968bcca2SKa Ho Ng &ef->ddbstrtab) != 0) { 365599c4399SKa Ho Ng warnx("elf_read_string_table failed"); 366968bcca2SKa Ho Ng goto out; 367968bcca2SKa Ho Ng } 368968bcca2SKa Ho Ng 369968bcca2SKa Ho Ng /* Do we have a string table for the section names? */ 370968bcca2SKa Ho Ng if (hdr->e_shstrndx != 0 && 371968bcca2SKa Ho Ng shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 372968bcca2SKa Ho Ng if (elf_read_string_table(efile, &shdr[hdr->e_shstrndx], 373968bcca2SKa Ho Ng &ef->shstrcnt, &ef->shstrtab) != 0) { 374599c4399SKa Ho Ng warnx("elf_read_string_table failed"); 375968bcca2SKa Ho Ng goto out; 376968bcca2SKa Ho Ng } 377968bcca2SKa Ho Ng } 378968bcca2SKa Ho Ng 379968bcca2SKa Ho Ng /* 380968bcca2SKa Ho Ng * Now allocate address space for code/data(progbits) and 381968bcca2SKa Ho Ng * bss(nobits) and allocate space for and load relocs. 382968bcca2SKa Ho Ng */ 383968bcca2SKa Ho Ng pb = 0; 384968bcca2SKa Ho Ng rl = 0; 385968bcca2SKa Ho Ng ra = 0; 386968bcca2SKa Ho Ng mapbase = 0; 387968bcca2SKa Ho Ng for (i = 0; i < nshdr; i++) { 388968bcca2SKa Ho Ng switch (shdr[i].sh_type) { 389968bcca2SKa Ho Ng case SHT_PROGBITS: 390968bcca2SKa Ho Ng case SHT_NOBITS: 391968bcca2SKa Ho Ng mapbase = roundup2(mapbase, shdr[i].sh_addralign); 392968bcca2SKa Ho Ng ef->progtab[pb].addr = mapbase; 393968bcca2SKa Ho Ng if (shdr[i].sh_type == SHT_PROGBITS) { 394968bcca2SKa Ho Ng ef->progtab[pb].name = "<<PROGBITS>>"; 395968bcca2SKa Ho Ng ef->progtab[pb].offset = shdr[i].sh_offset; 396968bcca2SKa Ho Ng } else { 397968bcca2SKa Ho Ng ef->progtab[pb].name = "<<NOBITS>>"; 398968bcca2SKa Ho Ng ef->progtab[pb].offset = (GElf_Off)-1; 399968bcca2SKa Ho Ng } 400968bcca2SKa Ho Ng ef->progtab[pb].size = shdr[i].sh_size; 401968bcca2SKa Ho Ng ef->progtab[pb].sec = i; 402968bcca2SKa Ho Ng if (ef->shstrtab && shdr[i].sh_name != 0) 403968bcca2SKa Ho Ng ef->progtab[pb].name = 404968bcca2SKa Ho Ng ef->shstrtab + shdr[i].sh_name; 405968bcca2SKa Ho Ng 406968bcca2SKa Ho Ng /* Update all symbol values with the offset. */ 407968bcca2SKa Ho Ng for (j = 0; j < ef->ddbsymcnt; j++) { 408968bcca2SKa Ho Ng es = &ef->ddbsymtab[j]; 409968bcca2SKa Ho Ng if (es->st_shndx != i) 410968bcca2SKa Ho Ng continue; 411968bcca2SKa Ho Ng es->st_value += ef->progtab[pb].addr; 412968bcca2SKa Ho Ng } 413968bcca2SKa Ho Ng mapbase += shdr[i].sh_size; 414968bcca2SKa Ho Ng pb++; 415968bcca2SKa Ho Ng break; 416968bcca2SKa Ho Ng case SHT_REL: 417968bcca2SKa Ho Ng ef->reltab[rl].sec = shdr[i].sh_info; 418968bcca2SKa Ho Ng if (elf_read_rel(efile, i, &ef->reltab[rl].nrel, 419968bcca2SKa Ho Ng &ef->reltab[rl].rel) != 0) { 420599c4399SKa Ho Ng warnx("elf_read_rel failed"); 421968bcca2SKa Ho Ng goto out; 422968bcca2SKa Ho Ng } 423968bcca2SKa Ho Ng rl++; 424968bcca2SKa Ho Ng break; 425968bcca2SKa Ho Ng case SHT_RELA: 426968bcca2SKa Ho Ng ef->relatab[ra].sec = shdr[i].sh_info; 427968bcca2SKa Ho Ng if (elf_read_rela(efile, i, &ef->relatab[ra].nrela, 428968bcca2SKa Ho Ng &ef->relatab[ra].rela) != 0) { 429599c4399SKa Ho Ng warnx("elf_read_rela failed"); 430968bcca2SKa Ho Ng goto out; 431968bcca2SKa Ho Ng } 432968bcca2SKa Ho Ng ra++; 433968bcca2SKa Ho Ng break; 434968bcca2SKa Ho Ng } 435968bcca2SKa Ho Ng } 436968bcca2SKa Ho Ng error = 0; 437968bcca2SKa Ho Ng out: 438968bcca2SKa Ho Ng free(shdr); 439968bcca2SKa Ho Ng if (error != 0) 440968bcca2SKa Ho Ng ef_obj_close(ef); 441968bcca2SKa Ho Ng return (error); 442968bcca2SKa Ho Ng } 443968bcca2SKa Ho Ng 444968bcca2SKa Ho Ng static void 445968bcca2SKa Ho Ng ef_obj_close(elf_file_t ef) 446968bcca2SKa Ho Ng { 447968bcca2SKa Ho Ng int i; 448968bcca2SKa Ho Ng 449968bcca2SKa Ho Ng if (ef->ef_name) 450968bcca2SKa Ho Ng free(ef->ef_name); 451968bcca2SKa Ho Ng if (ef->nprogtab != 0) 452968bcca2SKa Ho Ng free(ef->progtab); 453968bcca2SKa Ho Ng if (ef->nrel != 0) { 454968bcca2SKa Ho Ng for (i = 0; i < ef->nrel; i++) 455968bcca2SKa Ho Ng if (ef->reltab[i].rel != NULL) 456968bcca2SKa Ho Ng free(ef->reltab[i].rel); 457968bcca2SKa Ho Ng free(ef->reltab); 458968bcca2SKa Ho Ng } 459968bcca2SKa Ho Ng if (ef->nrela != 0) { 460968bcca2SKa Ho Ng for (i = 0; i < ef->nrela; i++) 461968bcca2SKa Ho Ng if (ef->relatab[i].rela != NULL) 462968bcca2SKa Ho Ng free(ef->relatab[i].rela); 463968bcca2SKa Ho Ng free(ef->relatab); 464968bcca2SKa Ho Ng } 465968bcca2SKa Ho Ng if (ef->ddbsymtab != NULL) 466968bcca2SKa Ho Ng free(ef->ddbsymtab); 467968bcca2SKa Ho Ng if (ef->ddbstrtab != NULL) 468968bcca2SKa Ho Ng free(ef->ddbstrtab); 469968bcca2SKa Ho Ng if (ef->shstrtab != NULL) 470968bcca2SKa Ho Ng free(ef->shstrtab); 471968bcca2SKa Ho Ng ef->ef_efile->ef_ops = NULL; 472968bcca2SKa Ho Ng ef->ef_efile->ef_ef = NULL; 473968bcca2SKa Ho Ng free(ef); 474968bcca2SKa Ho Ng } 475