[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.3

1.3     ! deraadt     1: /*     $OpenBSD: elf.c,v 1.2 2017/08/11 15:00:00 jasper 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: #include <sys/exec_elf.h>
                     21:
                     22: #include <machine/reloc.h>
                     23:
                     24: #include <assert.h>
                     25: #include <err.h>
                     26: #include <string.h>
                     27:
                     28: static int     elf_reloc_size(unsigned long);
                     29: static void    elf_reloc_apply(const char *, const char *, size_t, ssize_t,
                     30:                    char *, size_t);
                     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
                    106: elf_getsymtab(const char *p, const char *shstab, size_t shstabsz,
                    107:     const Elf_Sym **symtab, size_t *nsymb)
                    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:
                    125:                if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
                    126:                        if (symtab != NULL)
                    127:                                *symtab = (Elf_Sym *)(p + sh->sh_offset);
                    128:                        if (nsymb != NULL)
                    129:                                *nsymb = (sh->sh_size / sh->sh_entsize);
                    130:
                    131:                        return i;
                    132:                }
                    133:        }
                    134:
                    135:        return -1;
                    136: }
                    137:
                    138: ssize_t
                    139: elf_getsection(char *p, const char *sname, const char *shstab,
                    140:     size_t shstabsz, const char **psdata, size_t *pssz)
                    141: {
                    142:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    143:        Elf_Shdr        *sh;
                    144:        char            *sdata = NULL;
                    145:        size_t           snlen, ssz = 0;
                    146:        ssize_t          sidx, i;
                    147:
                    148:        snlen = strlen(sname);
                    149:        if (snlen == 0)
                    150:                return -1;
                    151:
                    152:        /* Find the given section. */
                    153:        for (i = 0; i < eh->e_shnum; i++) {
                    154:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    155:
                    156:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    157:                        continue;
                    158:
                    159:                if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
                    160:                        sidx = i;
                    161:                        sdata = p + sh->sh_offset;
                    162:                        ssz = sh->sh_size;
                    163:                        elf_reloc_apply(p, shstab, shstabsz, sidx, sdata, ssz);
                    164:                        break;
                    165:                }
                    166:        }
                    167:
                    168:        if (sdata == NULL)
                    169:                return -1;
                    170:
                    171:        if (psdata != NULL)
                    172:                *psdata = sdata;
                    173:        if (pssz != NULL)
                    174:                *pssz = ssz;
                    175:
                    176:        return sidx;
                    177: }
                    178:
                    179: static int
                    180: elf_reloc_size(unsigned long type)
                    181: {
                    182:        switch (type) {
                    183: #ifdef R_X86_64_64
                    184:        case R_X86_64_64:
                    185:                return sizeof(uint64_t);
                    186: #endif
                    187: #ifdef R_X86_64_32
                    188:        case R_X86_64_32:
                    189:                return sizeof(uint32_t);
                    190: #endif
                    191: #ifdef RELOC_32
                    192:        case RELOC_32:
                    193:                return sizeof(uint32_t);
                    194: #endif
                    195:        default:
                    196:                break;
                    197:        }
                    198:
                    199:        return -1;
                    200: }
                    201:
                    202: #define ELF_WRITE_RELOC(buf, val, rsize)                               \
                    203: do {                                                                   \
                    204:        if (rsize == 4) {                                               \
                    205:                uint32_t v32 = val;                                     \
                    206:                memcpy(buf, &v32, sizeof(v32));                         \
                    207:        } else {                                                        \
                    208:                uint64_t v64 = val;                                     \
                    209:                memcpy(buf, &v64, sizeof(v64));                         \
                    210:        }                                                               \
                    211: } while (0)
                    212:
                    213: static void
                    214: elf_reloc_apply(const char *p, const char *shstab, size_t shstabsz,
                    215:     ssize_t sidx, char *sdata, size_t ssz)
                    216: {
                    217:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    218:        Elf_Shdr        *sh;
                    219:        Elf_Rel         *rel = NULL;
                    220:        Elf_RelA        *rela = NULL;
                    221:        const Elf_Sym   *symtab, *sym;
                    222:        ssize_t          symtabidx;
                    223:        size_t           nsymb, rsym, rtyp, roff;
                    224:        size_t           i, j;
                    225:        uint64_t         value;
                    226:        int              rsize;
                    227:
                    228:        /* Find symbol table location and number of symbols. */
                    229:        symtabidx = elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb);
                    230:        if (symtabidx == -1) {
                    231:                warnx("symbol table not found");
                    232:                return;
                    233:        }
                    234:
                    235:        /* Apply possible relocation. */
                    236:        for (i = 0; i < eh->e_shnum; i++) {
                    237:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    238:
                    239:                if (sh->sh_size == 0)
                    240:                        continue;
                    241:
                    242:                if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
                    243:                        continue;
                    244:
                    245:                switch (sh->sh_type) {
                    246:                case SHT_RELA:
                    247:                        rela = (Elf_RelA *)(p + sh->sh_offset);
                    248:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
                    249:                                rsym = ELF_R_SYM(rela[j].r_info);
                    250:                                rtyp = ELF_R_TYPE(rela[j].r_info);
                    251:                                roff = rela[j].r_offset;
                    252:                                if (rsym >= nsymb)
                    253:                                        continue;
                    254:                                sym = &symtab[rsym];
                    255:                                value = sym->st_value + rela[j].r_addend;
                    256:
                    257:                                rsize = elf_reloc_size(rtyp);
                    258:                                if (rsize == -1 || roff + rsize >= ssz)
                    259:                                        continue;
                    260:
                    261:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    262:                        }
                    263:                        break;
                    264:                case SHT_REL:
                    265:                        rel = (Elf_Rel *)(p + sh->sh_offset);
                    266:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
                    267:                                rsym = ELF_R_SYM(rel[j].r_info);
                    268:                                rtyp = ELF_R_TYPE(rel[j].r_info);
                    269:                                roff = rel[j].r_offset;
                    270:                                if (rsym >= nsymb)
                    271:                                        continue;
                    272:                                sym = &symtab[rsym];
                    273:                                value = sym->st_value;
                    274:
                    275:                                rsize = elf_reloc_size(rtyp);
                    276:                                if (rsize == -1 || roff + rsize >= ssz)
                    277:                                        continue;
                    278:
                    279:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    280:                        }
                    281:                        break;
                    282:                default:
                    283:                        continue;
                    284:                }
                    285:        }
                    286: }