Blob


1 /*
2 * Parse 32-bit ELF files.
3 * Copyright (c) 2004 Russ Cox. See LICENSE.
4 */
6 #include <u.h>
7 #include <libc.h>
8 #include <mach.h>
9 #include "elf.h"
11 typedef struct ElfHdrBytes ElfHdrBytes;
12 typedef struct ElfSectBytes ElfSectBytes;
13 typedef struct ElfProgBytes ElfProgBytes;
14 typedef struct ElfSymBytes ElfSymBytes;
16 typedef struct ElfHdrBytes64 ElfHdrBytes64;
17 typedef struct ElfSectBytes64 ElfSectBytes64;
18 typedef struct ElfProgBytes64 ElfProgBytes64;
19 typedef struct ElfSymBytes64 ElfSymBytes64;
21 struct ElfHdrBytes
22 {
23 uchar ident[16];
24 uchar type[2];
25 uchar machine[2];
26 uchar version[4];
27 uchar entry[4];
28 uchar phoff[4];
29 uchar shoff[4];
30 uchar flags[4];
31 uchar ehsize[2];
32 uchar phentsize[2];
33 uchar phnum[2];
34 uchar shentsize[2];
35 uchar shnum[2];
36 uchar shstrndx[2];
37 };
39 struct ElfHdrBytes64
40 {
41 uchar ident[16];
42 uchar type[2];
43 uchar machine[2];
44 uchar version[4];
45 uchar entry[8];
46 uchar phoff[8];
47 uchar shoff[8];
48 uchar flags[4];
49 uchar ehsize[2];
50 uchar phentsize[2];
51 uchar phnum[2];
52 uchar shentsize[2];
53 uchar shnum[2];
54 uchar shstrndx[2];
55 };
57 struct ElfSectBytes
58 {
59 uchar name[4];
60 uchar type[4];
61 uchar flags[4];
62 uchar addr[4];
63 uchar offset[4];
64 uchar size[4];
65 uchar link[4];
66 uchar info[4];
67 uchar align[4];
68 uchar entsize[4];
69 };
71 struct ElfSectBytes64
72 {
73 uchar name[4];
74 uchar type[4];
75 uchar flags[8];
76 uchar addr[8];
77 uchar offset[8];
78 uchar size[8];
79 uchar link[4];
80 uchar info[4];
81 uchar align[8];
82 uchar entsize[8];
83 };
85 struct ElfSymBytes
86 {
87 uchar name[4];
88 uchar value[4];
89 uchar size[4];
90 uchar info; /* top4: bind, bottom4: type */
91 uchar other;
92 uchar shndx[2];
93 };
95 struct ElfSymBytes64
96 {
97 uchar name[4];
98 uchar info;
99 uchar other;
100 uchar shndx[2];
101 uchar value[8];
102 uchar size[8];
103 };
105 struct ElfProgBytes
107 uchar type[4];
108 uchar offset[4];
109 uchar vaddr[4];
110 uchar paddr[4];
111 uchar filesz[4];
112 uchar memsz[4];
113 uchar flags[4];
114 uchar align[4];
115 };
117 struct ElfProgBytes64
119 uchar type[4];
120 uchar flags[4];
121 uchar offset[8];
122 uchar vaddr[8];
123 uchar paddr[8];
124 uchar filesz[8];
125 uchar memsz[8];
126 uchar align[8];
127 };
129 uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
131 static void unpackhdr(ElfHdr*, void*);
132 static void unpackprog(ElfHdr*, ElfProg*, void*);
133 static void unpacksect(ElfHdr*, ElfSect*, void*);
135 static char *elftypes[] = {
136 "none",
137 "relocatable",
138 "executable",
139 "shared object",
140 "core",
141 };
143 char*
144 elftype(int t)
146 if(t < 0 || t >= nelem(elftypes))
147 return "unknown";
148 return elftypes[t];
151 static char *elfmachs[] = {
152 "none",
153 "32100",
154 "sparc",
155 "386",
156 "68000",
157 "88000",
158 "486",
159 "860",
160 "MIPS",
161 };
163 char*
164 elfmachine(int t)
166 if(t < 0 || t >= nelem(elfmachs))
167 return "unknown";
168 return elfmachs[t];
171 Elf*
172 elfopen(char *name)
174 int fd;
175 Elf *e;
177 if((fd = open(name, OREAD)) < 0)
178 return nil;
179 if((e = elfinit(fd)) == nil)
180 close(fd);
181 return e;
184 Elf*
185 elfinit(int fd)
187 int i;
188 Elf *e;
189 ElfHdr *h;
190 union {
191 ElfHdrBytes h32;
192 ElfHdrBytes64 h64;
193 } hdrb;
194 void *p = nil;
195 ElfSect *s;
197 e = mallocz(sizeof(Elf), 1);
198 if(e == nil)
199 return nil;
200 e->fd = fd;
202 /*
203 * parse header
204 */
205 seek(fd, 0, 0);
206 if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
207 goto err;
208 h = &e->hdr;
209 unpackhdr(h, &hdrb);
210 if(h->class != ElfClass32 && h->class != ElfClass64){
211 werrstr("bad ELF class - not 32-bit, 64-bit");
212 goto err;
214 if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
215 werrstr("bad ELF encoding - not LSB, MSB");
216 goto err;
218 if(hdrb.h32.ident[6] != h->version){
219 werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
220 (uint)hdrb.h32.ident[6], (uint)h->version);
221 goto err;
224 /*
225 * the prog+section info is almost always small - just load it into memory.
226 */
227 e->nprog = h->phnum;
228 e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
229 p = mallocz(h->phentsize, 1);
230 for(i=0; i<e->nprog; i++){
231 if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
232 || readn(fd, p, h->phentsize) != h->phentsize)
233 goto err;
234 unpackprog(h, &e->prog[i], p);
236 free(p);
237 p = nil;
239 e->nsect = h->shnum;
240 if(e->nsect == 0)
241 goto nosects;
242 e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
243 p = mallocz(h->shentsize, 1);
244 for(i=0; i<e->nsect; i++){
245 if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
246 || readn(fd, p, h->shentsize) != h->shentsize)
247 goto err;
248 unpacksect(h, &e->sect[i], p);
250 free(p);
251 p = nil;
253 if(h->shstrndx >= e->nsect){
254 fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
255 h->shnum = 0;
256 e->nsect = 0;
257 goto nosects;
259 s = &e->sect[h->shstrndx];
260 if(elfmap(e, s) < 0)
261 goto err;
263 for(i=0; i<e->nsect; i++)
264 if(e->sect[i].name)
265 e->sect[i].name = (char*)s->base + (ulong)e->sect[i].name;
267 e->symtab = elfsection(e, ".symtab");
268 if(e->symtab){
269 if(e->symtab->link >= e->nsect)
270 e->symtab = nil;
271 else{
272 e->symstr = &e->sect[e->symtab->link];
273 e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
276 e->dynsym = elfsection(e, ".dynsym");
277 if(e->dynsym){
278 if(e->dynsym->link >= e->nsect)
279 e->dynsym = nil;
280 else{
281 e->dynstr = &e->sect[e->dynsym->link];
282 e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
286 e->bss = elfsection(e, ".bss");
288 nosects:
289 return e;
291 err:
292 free(p);
293 free(e->sect);
294 free(e->prog);
295 free(e->shstrtab);
296 free(e);
297 return nil;
300 void
301 elfclose(Elf *elf)
303 int i;
305 for(i=0; i<elf->nsect; i++)
306 free(elf->sect[i].base);
307 free(elf->sect);
308 free(elf->prog);
309 free(elf->shstrtab);
310 free(elf);
313 static void
314 unpackhdr(ElfHdr *h, void *v)
316 u16int (*e2)(uchar*);
317 u32int (*e4)(uchar*);
318 u64int (*e8)(uchar*);
319 ElfHdrBytes *b;
320 ElfHdrBytes64 *b64;
322 b = v;
323 memmove(h->magic, b->ident, 4);
324 h->class = b->ident[4];
325 h->encoding = b->ident[5];
326 switch(h->encoding){
327 case ElfDataLsb:
328 e2 = leload2;
329 e4 = leload4;
330 e8 = leload8;
331 break;
332 case ElfDataMsb:
333 e2 = beload2;
334 e4 = beload4;
335 e8 = beload8;
336 break;
337 default:
338 return;
340 h->abi = b->ident[7];
341 h->abiversion = b->ident[8];
343 h->e2 = e2;
344 h->e4 = e4;
345 h->e8 = e8;
347 if(h->class == ElfClass64)
348 goto b64;
350 h->type = e2(b->type);
351 h->machine = e2(b->machine);
352 h->version = e4(b->version);
353 h->entry = e4(b->entry);
354 h->phoff = e4(b->phoff);
355 h->shoff = e4(b->shoff);
356 h->flags = e4(b->flags);
357 h->ehsize = e2(b->ehsize);
358 h->phentsize = e2(b->phentsize);
359 h->phnum = e2(b->phnum);
360 h->shentsize = e2(b->shentsize);
361 h->shnum = e2(b->shnum);
362 h->shstrndx = e2(b->shstrndx);
363 return;
365 b64:
366 b64 = v;
367 h->type = e2(b64->type);
368 h->machine = e2(b64->machine);
369 h->version = e4(b64->version);
370 h->entry = e8(b64->entry);
371 h->phoff = e8(b64->phoff);
372 h->shoff = e8(b64->shoff);
373 h->flags = e4(b64->flags);
374 h->ehsize = e2(b64->ehsize);
375 h->phentsize = e2(b64->phentsize);
376 h->phnum = e2(b64->phnum);
377 h->shentsize = e2(b64->shentsize);
378 h->shnum = e2(b64->shnum);
379 h->shstrndx = e2(b64->shstrndx);
380 return;
383 static void
384 unpackprog(ElfHdr *h, ElfProg *p, void *v)
386 u32int (*e4)(uchar*);
387 u64int (*e8)(uchar*);
389 if(h->class == ElfClass32) {
390 ElfProgBytes *b;
392 b = v;
393 e4 = h->e4;
394 p->type = e4(b->type);
395 p->offset = e4(b->offset);
396 p->vaddr = e4(b->vaddr);
397 p->paddr = e4(b->paddr);
398 p->filesz = e4(b->filesz);
399 p->memsz = e4(b->memsz);
400 p->flags = e4(b->flags);
401 p->align = e4(b->align);
402 } else {
403 ElfProgBytes64 *b;
405 b = v;
406 e4 = h->e4;
407 e8 = h->e8;
408 p->type = e4(b->type);
409 p->offset = e8(b->offset);
410 p->vaddr = e8(b->vaddr);
411 p->paddr = e8(b->paddr);
412 p->filesz = e8(b->filesz);
413 p->memsz = e8(b->memsz);
414 p->flags = e4(b->flags);
415 p->align = e8(b->align);
419 static void
420 unpacksect(ElfHdr *h, ElfSect *s, void *v)
422 u32int (*e4)(uchar*);
423 u64int (*e8)(uchar*);
425 if(h->class == ElfClass32) {
426 ElfSectBytes *b;
428 b = v;
429 e4 = h->e4;
430 s->name = (char*)(uintptr)e4(b->name);
431 s->type = e4(b->type);
432 s->flags = e4(b->flags);
433 s->addr = e4(b->addr);
434 s->offset = e4(b->offset);
435 s->size = e4(b->size);
436 s->link = e4(b->link);
437 s->info = e4(b->info);
438 s->align = e4(b->align);
439 s->entsize = e4(b->entsize);
440 } else {
441 ElfSectBytes64 *b;
443 b = v;
444 e4 = h->e4;
445 e8 = h->e8;
446 s->name = (char*)(uintptr)e4(b->name);
447 s->type = e4(b->type);
448 s->flags = e8(b->flags);
449 s->addr = e8(b->addr);
450 s->offset = e8(b->offset);
451 s->size = e8(b->size);
452 s->link = e4(b->link);
453 s->info = e4(b->info);
454 s->align = e8(b->align);
455 s->entsize = e8(b->entsize);
459 ElfSect*
460 elfsection(Elf *elf, char *name)
462 int i;
464 for(i=0; i<elf->nsect; i++){
465 if(elf->sect[i].name == name)
466 return &elf->sect[i];
467 if(elf->sect[i].name && name
468 && strcmp(elf->sect[i].name, name) == 0)
469 return &elf->sect[i];
471 werrstr("elf section '%s' not found", name);
472 return nil;
475 int
476 elfmap(Elf *elf, ElfSect *sect)
478 if(sect->base)
479 return 0;
480 if((sect->base = malloc(sect->size)) == nil)
481 return -1;
482 werrstr("short read");
483 if(seek(elf->fd, sect->offset, 0) < 0
484 || readn(elf->fd, sect->base, sect->size) != sect->size){
485 free(sect->base);
486 sect->base = nil;
487 return -1;
489 return 0;
492 int
493 elfsym(Elf *elf, int i, ElfSym *sym)
495 ElfSect *symtab, *strtab;
496 uchar *p;
497 char *s;
498 ulong x;
500 if(i < 0){
501 werrstr("bad index %d in elfsym", i);
502 return -1;
505 if(i < elf->nsymtab){
506 symtab = elf->symtab;
507 strtab = elf->symstr;
508 extract:
509 if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
510 return -1;
511 if(elf->hdr.class == ElfClass32) {
512 p = symtab->base + i * sizeof(ElfSymBytes);
513 s = (char*)strtab->base;
514 x = elf->hdr.e4(p);
515 if(x >= strtab->size){
516 werrstr("bad symbol name offset 0x%lux", x);
517 return -1;
519 sym->name = s + x;
520 sym->value = elf->hdr.e4(p+4);
521 sym->size = elf->hdr.e4(p+8);
522 x = p[12];
523 sym->bind = x>>4;
524 sym->type = x & 0xF;
525 sym->other = p[13];
526 sym->shndx = elf->hdr.e2(p+14);
527 } else {
528 p = symtab->base + i * sizeof(ElfSymBytes64);
529 s = (char*)strtab->base;
530 x = elf->hdr.e4(p);
531 if(x >= strtab->size){
532 werrstr("bad symbol name offset 0x%lux", x);
533 return -1;
535 sym->name = s + x;
536 x = p[4];
537 sym->bind = x>>4;
538 sym->type = x & 0xF;
539 sym->other = p[5];
540 sym->shndx = elf->hdr.e2(p+6);
541 sym->value = elf->hdr.e8(p+8);
542 sym->size = elf->hdr.e8(p+16);
544 return 0;
546 i -= elf->nsymtab;
547 if(i < elf->ndynsym){
548 symtab = elf->dynsym;
549 strtab = elf->dynstr;
550 goto extract;
552 /* i -= elf->ndynsym */
554 werrstr("symbol index out of range");
555 return -1;