[BACK]Return to elf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ctfdump

Annotation of src/usr.bin/ctfdump/elf.c, Revision 1.6

1.6     ! mpi         1: /*     $OpenBSD: elf.c,v 1.5 2017/10/27 08:33:46 mpi Exp $ */
1.2       jasper      2:
1.1       mpi         3: /*
                      4:  * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
1.3       deraadt    19: #include <sys/types.h>
1.1       mpi        20:
                     21: #include <machine/reloc.h>
                     22:
                     23: #include <assert.h>
1.5       mpi        24: #include <elf.h>
1.1       mpi        25: #include <err.h>
                     26: #include <string.h>
                     27:
                     28: static int     elf_reloc_size(unsigned long);
1.4       jsg        29: static void    elf_reloc_apply(const char *, size_t, const char *, size_t,
                     30:                    ssize_t, char *, size_t);
1.1       mpi        31:
                     32: int
                     33: iself(const char *p, size_t filesize)
                     34: {
                     35:        Elf_Ehdr                *eh = (Elf_Ehdr *)p;
                     36:
                     37:        if (filesize < (off_t)sizeof(Elf_Ehdr)) {
                     38:                warnx("file too small to be ELF");
                     39:                return 0;
                     40:        }
                     41:
                     42:        if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
                     43:                return 0;
                     44:
                     45:        if (eh->e_ident[EI_CLASS] != ELFCLASS) {
                     46:                warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
                     47:                return 0;
                     48:        }
                     49:        if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
                     50:                warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
                     51:                return 0;
                     52:        }
                     53:        if (eh->e_ident[EI_DATA] >= ELFDATANUM) {
                     54:                warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
                     55:                return 0;
                     56:        }
                     57:        if (eh->e_shoff > filesize) {
                     58:                warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff);
                     59:                return 0;
                     60:        }
                     61:        if (eh->e_shentsize < sizeof(Elf_Shdr)) {
                     62:                warnx("bogus section header size %u", eh->e_shentsize);
                     63:                return 0;
                     64:        }
                     65:        if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
                     66:                warnx("bogus section header count %u", eh->e_shnum);
                     67:                return 0;
                     68:        }
                     69:        if (eh->e_shstrndx >= eh->e_shnum) {
                     70:                warnx("bogus string table index %u", eh->e_shstrndx);
                     71:                return 0;
                     72:        }
                     73:
                     74:        return 1;
                     75: }
                     76:
                     77: int
                     78: elf_getshstab(const char *p, size_t filesize, const char **shstab,
                     79:     size_t *shstabsize)
                     80: {
                     81:        Elf_Ehdr                *eh = (Elf_Ehdr *)p;
                     82:        Elf_Shdr                *sh;
                     83:
                     84:        sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
                     85:        if (sh->sh_type != SHT_STRTAB) {
                     86:                warnx("unexpected string table type");
                     87:                return -1;
                     88:        }
                     89:        if (sh->sh_offset > filesize) {
                     90:                warnx("bogus string table offset");
                     91:                return -1;
                     92:        }
                     93:        if (sh->sh_size > filesize - sh->sh_offset) {
                     94:                warnx("bogus string table size");
                     95:                return -1;
                     96:        }
                     97:        if (shstab != NULL)
                     98:                *shstab = p + sh->sh_offset;
                     99:        if (shstabsize != NULL)
                    100:                *shstabsize = sh->sh_size;
                    101:
                    102:        return 0;
                    103: }
                    104:
                    105: ssize_t
1.4       jsg       106: elf_getsymtab(const char *p, size_t filesize, const char *shstab,
                    107:     size_t shstabsz, const Elf_Sym **symtab, size_t *nsymb)
1.1       mpi       108: {
                    109:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    110:        Elf_Shdr        *sh;
                    111:        size_t           snlen;
                    112:        ssize_t          i;
                    113:
                    114:        snlen = strlen(ELF_SYMTAB);
                    115:
                    116:        for (i = 0; i < eh->e_shnum; i++) {
                    117:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    118:
                    119:                if (sh->sh_type != SHT_SYMTAB)
                    120:                        continue;
                    121:
                    122:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    123:                        continue;
                    124:
1.4       jsg       125:                if ((sh->sh_offset + sh->sh_size) > filesize)
                    126:                        continue;
                    127:
                    128:                if (sh->sh_entsize == 0)
                    129:                        continue;
                    130:
1.1       mpi       131:                if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
                    132:                        if (symtab != NULL)
                    133:                                *symtab = (Elf_Sym *)(p + sh->sh_offset);
                    134:                        if (nsymb != NULL)
                    135:                                *nsymb = (sh->sh_size / sh->sh_entsize);
                    136:
                    137:                        return i;
                    138:                }
                    139:        }
                    140:
                    141:        return -1;
                    142: }
                    143:
                    144: ssize_t
1.4       jsg       145: elf_getsection(char *p, size_t filesize, const char *sname, const char *shstab,
1.1       mpi       146:     size_t shstabsz, const char **psdata, size_t *pssz)
                    147: {
                    148:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    149:        Elf_Shdr        *sh;
                    150:        char            *sdata = NULL;
                    151:        size_t           snlen, ssz = 0;
                    152:        ssize_t          sidx, i;
                    153:
                    154:        snlen = strlen(sname);
                    155:        if (snlen == 0)
                    156:                return -1;
                    157:
                    158:        /* Find the given section. */
                    159:        for (i = 0; i < eh->e_shnum; i++) {
1.4       jsg       160:                if ((eh->e_shoff + i * eh->e_shentsize) > filesize)
                    161:                        continue;
                    162:
1.1       mpi       163:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    164:
                    165:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    166:                        continue;
                    167:
1.4       jsg       168:                if ((sh->sh_offset + sh->sh_size) > filesize)
                    169:                        continue;
                    170:
1.1       mpi       171:                if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
                    172:                        sidx = i;
                    173:                        sdata = p + sh->sh_offset;
                    174:                        ssz = sh->sh_size;
1.6     ! mpi       175: #ifdef needreloc
1.4       jsg       176:                        elf_reloc_apply(p, filesize, shstab, shstabsz, sidx,
                    177:                            sdata, ssz);
1.6     ! mpi       178: #endif
1.1       mpi       179:                        break;
                    180:                }
                    181:        }
                    182:
                    183:        if (sdata == NULL)
                    184:                return -1;
                    185:
                    186:        if (psdata != NULL)
                    187:                *psdata = sdata;
                    188:        if (pssz != NULL)
                    189:                *pssz = ssz;
                    190:
                    191:        return sidx;
                    192: }
                    193:
                    194: static int
                    195: elf_reloc_size(unsigned long type)
                    196: {
                    197:        switch (type) {
                    198: #ifdef R_X86_64_64
                    199:        case R_X86_64_64:
                    200:                return sizeof(uint64_t);
                    201: #endif
                    202: #ifdef R_X86_64_32
                    203:        case R_X86_64_32:
                    204:                return sizeof(uint32_t);
                    205: #endif
                    206: #ifdef RELOC_32
                    207:        case RELOC_32:
                    208:                return sizeof(uint32_t);
                    209: #endif
                    210:        default:
                    211:                break;
                    212:        }
                    213:
                    214:        return -1;
                    215: }
                    216:
                    217: #define ELF_WRITE_RELOC(buf, val, rsize)                               \
                    218: do {                                                                   \
                    219:        if (rsize == 4) {                                               \
                    220:                uint32_t v32 = val;                                     \
                    221:                memcpy(buf, &v32, sizeof(v32));                         \
                    222:        } else {                                                        \
                    223:                uint64_t v64 = val;                                     \
                    224:                memcpy(buf, &v64, sizeof(v64));                         \
                    225:        }                                                               \
                    226: } while (0)
                    227:
                    228: static void
1.4       jsg       229: elf_reloc_apply(const char *p, size_t filesize, const char *shstab,
                    230:     size_t shstabsz, ssize_t sidx, char *sdata, size_t ssz)
1.1       mpi       231: {
                    232:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    233:        Elf_Shdr        *sh;
                    234:        Elf_Rel         *rel = NULL;
                    235:        Elf_RelA        *rela = NULL;
                    236:        const Elf_Sym   *symtab, *sym;
                    237:        ssize_t          symtabidx;
                    238:        size_t           nsymb, rsym, rtyp, roff;
                    239:        size_t           i, j;
                    240:        uint64_t         value;
                    241:        int              rsize;
                    242:
                    243:        /* Find symbol table location and number of symbols. */
1.4       jsg       244:        symtabidx = elf_getsymtab(p, filesize, shstab, shstabsz, &symtab,
                    245:            &nsymb);
1.1       mpi       246:        if (symtabidx == -1) {
                    247:                warnx("symbol table not found");
                    248:                return;
                    249:        }
                    250:
                    251:        /* Apply possible relocation. */
                    252:        for (i = 0; i < eh->e_shnum; i++) {
1.4       jsg       253:                if ((eh->e_shoff + i * eh->e_shentsize) > filesize)
                    254:                        continue;
                    255:
1.1       mpi       256:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    257:
                    258:                if (sh->sh_size == 0)
                    259:                        continue;
                    260:
                    261:                if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
                    262:                        continue;
                    263:
1.4       jsg       264:                if ((sh->sh_offset + sh->sh_size) > filesize)
                    265:                        continue;
                    266:
1.1       mpi       267:                switch (sh->sh_type) {
                    268:                case SHT_RELA:
                    269:                        rela = (Elf_RelA *)(p + sh->sh_offset);
                    270:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
                    271:                                rsym = ELF_R_SYM(rela[j].r_info);
                    272:                                rtyp = ELF_R_TYPE(rela[j].r_info);
                    273:                                roff = rela[j].r_offset;
                    274:                                if (rsym >= nsymb)
                    275:                                        continue;
1.4       jsg       276:                                if (roff >= filesize)
                    277:                                        continue;
1.1       mpi       278:                                sym = &symtab[rsym];
                    279:                                value = sym->st_value + rela[j].r_addend;
                    280:
                    281:                                rsize = elf_reloc_size(rtyp);
                    282:                                if (rsize == -1 || roff + rsize >= ssz)
                    283:                                        continue;
                    284:
                    285:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    286:                        }
                    287:                        break;
                    288:                case SHT_REL:
                    289:                        rel = (Elf_Rel *)(p + sh->sh_offset);
                    290:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
                    291:                                rsym = ELF_R_SYM(rel[j].r_info);
                    292:                                rtyp = ELF_R_TYPE(rel[j].r_info);
                    293:                                roff = rel[j].r_offset;
                    294:                                if (rsym >= nsymb)
1.4       jsg       295:                                        continue;
                    296:                                if (roff >= filesize)
1.1       mpi       297:                                        continue;
                    298:                                sym = &symtab[rsym];
                    299:                                value = sym->st_value;
                    300:
                    301:                                rsize = elf_reloc_size(rtyp);
                    302:                                if (rsize == -1 || roff + rsize >= ssz)
                    303:                                        continue;
                    304:
                    305:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    306:                        }
                    307:                        break;
                    308:                default:
                    309:                        continue;
                    310:                }
                    311:        }
                    312: }