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;
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);
238 e->nsect = h->shnum;
239 if(e->nsect == 0)
240 goto nosects;
241 e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
242 p = mallocz(h->shentsize, 1);
243 for(i=0; i<e->nsect; i++){
244 if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
245 || readn(fd, p, h->shentsize) != h->shentsize)
246 goto err;
247 unpacksect(h, &e->sect[i], p);
249 free(p);
251 if(h->shstrndx >= e->nsect){
252 fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
253 h->shnum = 0;
254 e->nsect = 0;
255 goto nosects;
257 s = &e->sect[h->shstrndx];
258 if(elfmap(e, s) < 0)
259 goto err;
261 for(i=0; i<e->nsect; i++)
262 if(e->sect[i].name)
263 e->sect[i].name = (char*)s->base + (ulong)e->sect[i].name;
265 e->symtab = elfsection(e, ".symtab");
266 if(e->symtab){
267 if(e->symtab->link >= e->nsect)
268 e->symtab = nil;
269 else{
270 e->symstr = &e->sect[e->symtab->link];
271 e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
274 e->dynsym = elfsection(e, ".dynsym");
275 if(e->dynsym){
276 if(e->dynsym->link >= e->nsect)
277 e->dynsym = nil;
278 else{
279 e->dynstr = &e->sect[e->dynsym->link];
280 e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
284 e->bss = elfsection(e, ".bss");
286 nosects:
287 return e;
289 err:
290 free(e->sect);
291 free(e->prog);
292 free(e->shstrtab);
293 free(e);
294 return nil;
297 void
298 elfclose(Elf *elf)
300 int i;
302 for(i=0; i<elf->nsect; i++)
303 free(elf->sect[i].base);
304 free(elf->sect);
305 free(elf->prog);
306 free(elf->shstrtab);
307 free(elf);
310 static void
311 unpackhdr(ElfHdr *h, void *v)
313 u16int (*e2)(uchar*);
314 u32int (*e4)(uchar*);
315 u64int (*e8)(uchar*);
316 ElfHdrBytes *b;
317 ElfHdrBytes64 *b64;
319 b = v;
320 memmove(h->magic, b->ident, 4);
321 h->class = b->ident[4];
322 h->encoding = b->ident[5];
323 switch(h->encoding){
324 case ElfDataLsb:
325 e2 = leload2;
326 e4 = leload4;
327 e8 = leload8;
328 break;
329 case ElfDataMsb:
330 e2 = beload2;
331 e4 = beload4;
332 e8 = beload8;
333 break;
334 default:
335 return;
337 h->abi = b->ident[7];
338 h->abiversion = b->ident[8];
340 h->e2 = e2;
341 h->e4 = e4;
342 h->e8 = e8;
344 if(h->class == ElfClass64)
345 goto b64;
347 h->type = e2(b->type);
348 h->machine = e2(b->machine);
349 h->version = e4(b->version);
350 h->entry = e4(b->entry);
351 h->phoff = e4(b->phoff);
352 h->shoff = e4(b->shoff);
353 h->flags = e4(b->flags);
354 h->ehsize = e2(b->ehsize);
355 h->phentsize = e2(b->phentsize);
356 h->phnum = e2(b->phnum);
357 h->shentsize = e2(b->shentsize);
358 h->shnum = e2(b->shnum);
359 h->shstrndx = e2(b->shstrndx);
360 return;
362 b64:
363 b64 = v;
364 h->type = e2(b64->type);
365 h->machine = e2(b64->machine);
366 h->version = e4(b64->version);
367 h->entry = e8(b64->entry);
368 h->phoff = e8(b64->phoff);
369 h->shoff = e8(b64->shoff);
370 h->flags = e4(b64->flags);
371 h->ehsize = e2(b64->ehsize);
372 h->phentsize = e2(b64->phentsize);
373 h->phnum = e2(b64->phnum);
374 h->shentsize = e2(b64->shentsize);
375 h->shnum = e2(b64->shnum);
376 h->shstrndx = e2(b64->shstrndx);
377 return;
380 static void
381 unpackprog(ElfHdr *h, ElfProg *p, void *v)
383 u32int (*e4)(uchar*);
384 u64int (*e8)(uchar*);
386 if(h->class == ElfClass32) {
387 ElfProgBytes *b;
389 b = v;
390 e4 = h->e4;
391 p->type = e4(b->type);
392 p->offset = e4(b->offset);
393 p->vaddr = e4(b->vaddr);
394 p->paddr = e4(b->paddr);
395 p->filesz = e4(b->filesz);
396 p->memsz = e4(b->memsz);
397 p->flags = e4(b->flags);
398 p->align = e4(b->align);
399 } else {
400 ElfProgBytes64 *b;
402 b = v;
403 e4 = h->e4;
404 e8 = h->e8;
405 p->type = e4(b->type);
406 p->offset = e8(b->offset);
407 p->vaddr = e8(b->vaddr);
408 p->paddr = e8(b->paddr);
409 p->filesz = e8(b->filesz);
410 p->memsz = e8(b->memsz);
411 p->flags = e4(b->flags);
412 p->align = e8(b->align);
416 static void
417 unpacksect(ElfHdr *h, ElfSect *s, void *v)
419 u32int (*e4)(uchar*);
420 u64int (*e8)(uchar*);
422 if(h->class == ElfClass32) {
423 ElfSectBytes *b;
425 b = v;
426 e4 = h->e4;
427 s->name = (char*)(uintptr)e4(b->name);
428 s->type = e4(b->type);
429 s->flags = e4(b->flags);
430 s->addr = e4(b->addr);
431 s->offset = e4(b->offset);
432 s->size = e4(b->size);
433 s->link = e4(b->link);
434 s->info = e4(b->info);
435 s->align = e4(b->align);
436 s->entsize = e4(b->entsize);
437 } else {
438 ElfSectBytes64 *b;
440 b = v;
441 e4 = h->e4;
442 e8 = h->e8;
443 s->name = (char*)(uintptr)e4(b->name);
444 s->type = e4(b->type);
445 s->flags = e8(b->flags);
446 s->addr = e8(b->addr);
447 s->offset = e8(b->offset);
448 s->size = e8(b->size);
449 s->link = e4(b->link);
450 s->info = e4(b->info);
451 s->align = e8(b->align);
452 s->entsize = e8(b->entsize);
456 ElfSect*
457 elfsection(Elf *elf, char *name)
459 int i;
461 for(i=0; i<elf->nsect; i++){
462 if(elf->sect[i].name == name)
463 return &elf->sect[i];
464 if(elf->sect[i].name && name
465 && strcmp(elf->sect[i].name, name) == 0)
466 return &elf->sect[i];
468 werrstr("elf section '%s' not found", name);
469 return nil;
472 int
473 elfmap(Elf *elf, ElfSect *sect)
475 if(sect->base)
476 return 0;
477 if((sect->base = malloc(sect->size)) == nil)
478 return -1;
479 werrstr("short read");
480 if(seek(elf->fd, sect->offset, 0) < 0
481 || readn(elf->fd, sect->base, sect->size) != sect->size){
482 free(sect->base);
483 sect->base = nil;
484 return -1;
486 return 0;
489 int
490 elfsym(Elf *elf, int i, ElfSym *sym)
492 ElfSect *symtab, *strtab;
493 uchar *p;
494 char *s;
495 ulong x;
497 if(i < 0){
498 werrstr("bad index %d in elfsym", i);
499 return -1;
502 if(i < elf->nsymtab){
503 symtab = elf->symtab;
504 strtab = elf->symstr;
505 extract:
506 if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
507 return -1;
508 if(elf->hdr.class == ElfClass32) {
509 p = symtab->base + i * sizeof(ElfSymBytes);
510 s = (char*)strtab->base;
511 x = elf->hdr.e4(p);
512 if(x >= strtab->size){
513 werrstr("bad symbol name offset 0x%lux", x);
514 return -1;
516 sym->name = s + x;
517 sym->value = elf->hdr.e4(p+4);
518 sym->size = elf->hdr.e4(p+8);
519 x = p[12];
520 sym->bind = x>>4;
521 sym->type = x & 0xF;
522 sym->other = p[13];
523 sym->shndx = elf->hdr.e2(p+14);
524 } else {
525 p = symtab->base + i * sizeof(ElfSymBytes64);
526 s = (char*)strtab->base;
527 x = elf->hdr.e4(p);
528 if(x >= strtab->size){
529 werrstr("bad symbol name offset 0x%lux", x);
530 return -1;
532 sym->name = s + x;
533 x = p[4];
534 sym->bind = x>>4;
535 sym->type = x & 0xF;
536 sym->other = p[5];
537 sym->shndx = elf->hdr.e2(p+6);
538 sym->value = elf->hdr.e8(p+8);
539 sym->size = elf->hdr.e8(p+16);
541 return 0;
543 i -= elf->nsymtab;
544 if(i < elf->ndynsym){
545 symtab = elf->dynsym;
546 strtab = elf->dynstr;
547 goto extract;
549 /* i -= elf->ndynsym */
551 werrstr("symbol index out of range");
552 return -1;