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