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: }