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

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