1
2
3
4
5
6 package elf
7
8 import (
9 "bytes"
10 "debug/dwarf"
11 "encoding/binary"
12 "fmt"
13 "io"
14 "os"
15 )
16
17
18
19 20 21
22
23
24 type FileHeader struct {
25 Class Class
26 Data Data
27 Version Version
28 OSABI OSABI
29 ABIVersion uint8
30 ByteOrder binary.ByteOrder
31 Type Type
32 Machine Machine
33 }
34
35
36 type File struct {
37 FileHeader
38 Sections []*Section
39 Progs []*Prog
40 closer io.Closer
41 gnuNeed []verneed
42 gnuVersym []byte
43 }
44
45
46 type SectionHeader struct {
47 Name string
48 Type SectionType
49 Flags SectionFlag
50 Addr uint64
51 Offset uint64
52 Size uint64
53 Link uint32
54 Info uint32
55 Addralign uint64
56 Entsize uint64
57 }
58
59
60 type Section struct {
61 SectionHeader
62
63
64
65
66
67
68
69 io.ReaderAt
70 sr *io.SectionReader
71 }
72
73
74 func (s *Section) Data() ([]byte, os.Error) {
75 dat := make([]byte, s.sr.Size())
76 n, err := s.sr.ReadAt(dat, 0)
77 return dat[0:n], err
78 }
79
80
81
82 func (f *File) stringTable(link uint32) ([]byte, os.Error) {
83 if link <= 0 || link >= uint32(len(f.Sections)) {
84 return nil, os.NewError("section has invalid string table link")
85 }
86 return f.Sections[link].Data()
87 }
88
89
90 func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
91
92
93 type ProgHeader struct {
94 Type ProgType
95 Flags ProgFlag
96 Off uint64
97 Vaddr uint64
98 Paddr uint64
99 Filesz uint64
100 Memsz uint64
101 Align uint64
102 }
103
104
105 type Prog struct {
106 ProgHeader
107
108
109
110
111
112
113
114 io.ReaderAt
115 sr *io.SectionReader
116 }
117
118
119 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
120
121
122 type Symbol struct {
123 Name string
124 Info, Other byte
125 Section SectionIndex
126 Value, Size uint64
127 }
128
129 130 131
132
133 type FormatError struct {
134 off int64
135 msg string
136 val interface{}
137 }
138
139 func (e *FormatError) String() string {
140 msg := e.msg
141 if e.val != nil {
142 msg += fmt.Sprintf(" '%v' ", e.val)
143 }
144 msg += fmt.Sprintf("in record at byte %#x", e.off)
145 return msg
146 }
147
148
149 func Open(name string) (*File, os.Error) {
150 f, err := os.Open(name)
151 if err != nil {
152 return nil, err
153 }
154 ff, err := NewFile(f)
155 if err != nil {
156 f.Close()
157 return nil, err
158 }
159 ff.closer = f
160 return ff, nil
161 }
162
163
164
165
166 func (f *File) Close() os.Error {
167 var err os.Error
168 if f.closer != nil {
169 err = f.closer.Close()
170 f.closer = nil
171 }
172 return err
173 }
174
175
176
177 func (f *File) SectionByType(typ SectionType) *Section {
178 for _, s := range f.Sections {
179 if s.Type == typ {
180 return s
181 }
182 }
183 return nil
184 }
185
186
187
188 func NewFile(r io.ReaderAt) (*File, os.Error) {
189 sr := io.NewSectionReader(r, 0, 1<<63-1)
190
191 var ident [16]uint8
192 if _, err := r.ReadAt(ident[0:], 0); err != nil {
193 return nil, err
194 }
195 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
196 return nil, &FormatError{0, "bad magic number", ident[0:4]}
197 }
198
199 f := new(File)
200 f.Class = Class(ident[EI_CLASS])
201 switch f.Class {
202 case ELFCLASS32:
203 case ELFCLASS64:
204
205 default:
206 return nil, &FormatError{0, "unknown ELF class", f.Class}
207 }
208
209 f.Data = Data(ident[EI_DATA])
210 switch f.Data {
211 case ELFDATA2LSB:
212 f.ByteOrder = binary.LittleEndian
213 case ELFDATA2MSB:
214 f.ByteOrder = binary.BigEndian
215 default:
216 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
217 }
218
219 f.Version = Version(ident[EI_VERSION])
220 if f.Version != EV_CURRENT {
221 return nil, &FormatError{0, "unknown ELF version", f.Version}
222 }
223
224 f.OSABI = OSABI(ident[EI_OSABI])
225 f.ABIVersion = ident[EI_ABIVERSION]
226
227
228 var phoff int64
229 var phentsize, phnum int
230 var shoff int64
231 var shentsize, shnum, shstrndx int
232 shstrndx = -1
233 switch f.Class {
234 case ELFCLASS32:
235 hdr := new(Header32)
236 sr.Seek(0, os.SEEK_SET)
237 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
238 return nil, err
239 }
240 f.Type = Type(hdr.Type)
241 f.Machine = Machine(hdr.Machine)
242 if v := Version(hdr.Version); v != f.Version {
243 return nil, &FormatError{0, "mismatched ELF version", v}
244 }
245 phoff = int64(hdr.Phoff)
246 phentsize = int(hdr.Phentsize)
247 phnum = int(hdr.Phnum)
248 shoff = int64(hdr.Shoff)
249 shentsize = int(hdr.Shentsize)
250 shnum = int(hdr.Shnum)
251 shstrndx = int(hdr.Shstrndx)
252 case ELFCLASS64:
253 hdr := new(Header64)
254 sr.Seek(0, os.SEEK_SET)
255 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
256 return nil, err
257 }
258 f.Type = Type(hdr.Type)
259 f.Machine = Machine(hdr.Machine)
260 if v := Version(hdr.Version); v != f.Version {
261 return nil, &FormatError{0, "mismatched ELF version", v}
262 }
263 phoff = int64(hdr.Phoff)
264 phentsize = int(hdr.Phentsize)
265 phnum = int(hdr.Phnum)
266 shoff = int64(hdr.Shoff)
267 shentsize = int(hdr.Shentsize)
268 shnum = int(hdr.Shnum)
269 shstrndx = int(hdr.Shstrndx)
270 }
271 if shstrndx < 0 || shstrndx >= shnum {
272 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
273 }
274
275
276 f.Progs = make([]*Prog, phnum)
277 for i := 0; i < phnum; i++ {
278 off := phoff + int64(i)*int64(phentsize)
279 sr.Seek(off, os.SEEK_SET)
280 p := new(Prog)
281 switch f.Class {
282 case ELFCLASS32:
283 ph := new(Prog32)
284 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
285 return nil, err
286 }
287 p.ProgHeader = ProgHeader{
288 Type: ProgType(ph.Type),
289 Flags: ProgFlag(ph.Flags),
290 Off: uint64(ph.Off),
291 Vaddr: uint64(ph.Vaddr),
292 Paddr: uint64(ph.Paddr),
293 Filesz: uint64(ph.Filesz),
294 Memsz: uint64(ph.Memsz),
295 Align: uint64(ph.Align),
296 }
297 case ELFCLASS64:
298 ph := new(Prog64)
299 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
300 return nil, err
301 }
302 p.ProgHeader = ProgHeader{
303 Type: ProgType(ph.Type),
304 Flags: ProgFlag(ph.Flags),
305 Off: uint64(ph.Off),
306 Vaddr: uint64(ph.Vaddr),
307 Paddr: uint64(ph.Paddr),
308 Filesz: uint64(ph.Filesz),
309 Memsz: uint64(ph.Memsz),
310 Align: uint64(ph.Align),
311 }
312 }
313 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
314 p.ReaderAt = p.sr
315 f.Progs[i] = p
316 }
317
318
319 f.Sections = make([]*Section, shnum)
320 names := make([]uint32, shnum)
321 for i := 0; i < shnum; i++ {
322 off := shoff + int64(i)*int64(shentsize)
323 sr.Seek(off, os.SEEK_SET)
324 s := new(Section)
325 switch f.Class {
326 case ELFCLASS32:
327 sh := new(Section32)
328 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
329 return nil, err
330 }
331 names[i] = sh.Name
332 s.SectionHeader = SectionHeader{
333 Type: SectionType(sh.Type),
334 Flags: SectionFlag(sh.Flags),
335 Addr: uint64(sh.Addr),
336 Offset: uint64(sh.Off),
337 Size: uint64(sh.Size),
338 Link: uint32(sh.Link),
339 Info: uint32(sh.Info),
340 Addralign: uint64(sh.Addralign),
341 Entsize: uint64(sh.Entsize),
342 }
343 case ELFCLASS64:
344 sh := new(Section64)
345 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
346 return nil, err
347 }
348 names[i] = sh.Name
349 s.SectionHeader = SectionHeader{
350 Type: SectionType(sh.Type),
351 Flags: SectionFlag(sh.Flags),
352 Offset: uint64(sh.Off),
353 Size: uint64(sh.Size),
354 Addr: uint64(sh.Addr),
355 Link: uint32(sh.Link),
356 Info: uint32(sh.Info),
357 Addralign: uint64(sh.Addralign),
358 Entsize: uint64(sh.Entsize),
359 }
360 }
361 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
362 s.ReaderAt = s.sr
363 f.Sections[i] = s
364 }
365
366
367 shstrtab, err := f.Sections[shstrndx].Data()
368 if err != nil {
369 return nil, err
370 }
371 for i, s := range f.Sections {
372 var ok bool
373 s.Name, ok = getString(shstrtab, int(names[i]))
374 if !ok {
375 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
376 }
377 }
378
379 return f, nil
380 }
381
382
383
384 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
385 switch f.Class {
386 case ELFCLASS64:
387 return f.getSymbols64(typ)
388
389 case ELFCLASS32:
390 return f.getSymbols32(typ)
391 }
392
393 return nil, nil, os.NewError("not implemented")
394 }
395
396 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
397 symtabSection := f.SectionByType(typ)
398 if symtabSection == nil {
399 return nil, nil, os.NewError("no symbol section")
400 }
401
402 data, err := symtabSection.Data()
403 if err != nil {
404 return nil, nil, os.NewError("cannot load symbol section")
405 }
406 symtab := bytes.NewBuffer(data)
407 if symtab.Len()%Sym32Size != 0 {
408 return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
409 }
410
411 strdata, err := f.stringTable(symtabSection.Link)
412 if err != nil {
413 return nil, nil, os.NewError("cannot load string table section")
414 }
415
416
417 var skip [Sym32Size]byte
418 symtab.Read(skip[0:])
419
420 symbols := make([]Symbol, symtab.Len()/Sym32Size)
421
422 i := 0
423 var sym Sym32
424 for symtab.Len() > 0 {
425 binary.Read(symtab, f.ByteOrder, &sym)
426 str, _ := getString(strdata, int(sym.Name))
427 symbols[i].Name = str
428 symbols[i].Info = sym.Info
429 symbols[i].Other = sym.Other
430 symbols[i].Section = SectionIndex(sym.Shndx)
431 symbols[i].Value = uint64(sym.Value)
432 symbols[i].Size = uint64(sym.Size)
433 i++
434 }
435
436 return symbols, strdata, nil
437 }
438
439 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
440 symtabSection := f.SectionByType(typ)
441 if symtabSection == nil {
442 return nil, nil, os.NewError("no symbol section")
443 }
444
445 data, err := symtabSection.Data()
446 if err != nil {
447 return nil, nil, os.NewError("cannot load symbol section")
448 }
449 symtab := bytes.NewBuffer(data)
450 if symtab.Len()%Sym64Size != 0 {
451 return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
452 }
453
454 strdata, err := f.stringTable(symtabSection.Link)
455 if err != nil {
456 return nil, nil, os.NewError("cannot load string table section")
457 }
458
459
460 var skip [Sym64Size]byte
461 symtab.Read(skip[0:])
462
463 symbols := make([]Symbol, symtab.Len()/Sym64Size)
464
465 i := 0
466 var sym Sym64
467 for symtab.Len() > 0 {
468 binary.Read(symtab, f.ByteOrder, &sym)
469 str, _ := getString(strdata, int(sym.Name))
470 symbols[i].Name = str
471 symbols[i].Info = sym.Info
472 symbols[i].Other = sym.Other
473 symbols[i].Section = SectionIndex(sym.Shndx)
474 symbols[i].Value = sym.Value
475 symbols[i].Size = sym.Size
476 i++
477 }
478
479 return symbols, strdata, nil
480 }
481
482
483 func getString(section []byte, start int) (string, bool) {
484 if start < 0 || start >= len(section) {
485 return "", false
486 }
487
488 for end := start; end < len(section); end++ {
489 if section[end] == 0 {
490 return string(section[start:end]), true
491 }
492 }
493 return "", false
494 }
495
496
497
498 func (f *File) Section(name string) *Section {
499 for _, s := range f.Sections {
500 if s.Name == name {
501 return s
502 }
503 }
504 return nil
505 }
506
507
508
509 func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
510 if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
511 return f.applyRelocationsAMD64(dst, rels)
512 }
513
514 return os.NewError("not implemented")
515 }
516
517 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
518 if len(rels)%Sym64Size != 0 {
519 return os.NewError("length of relocation section is not a multiple of Sym64Size")
520 }
521
522 symbols, _, err := f.getSymbols(SHT_SYMTAB)
523 if err != nil {
524 return err
525 }
526
527 b := bytes.NewBuffer(rels)
528 var rela Rela64
529
530 for b.Len() > 0 {
531 binary.Read(b, f.ByteOrder, &rela)
532 symNo := rela.Info >> 32
533 t := R_X86_64(rela.Info & 0xffff)
534
535 if symNo >= uint64(len(symbols)) {
536 continue
537 }
538 sym := &symbols[symNo]
539 if SymType(sym.Info&0xf) != STT_SECTION {
540
541 continue
542 }
543
544 switch t {
545 case R_X86_64_64:
546 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
547 continue
548 }
549 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
550 case R_X86_64_32:
551 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
552 continue
553 }
554 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
555 }
556 }
557
558 return nil
559 }
560
561 func (f *File) DWARF() (*dwarf.Data, os.Error) {
562
563
564
565 var names = [...]string{"abbrev", "info", "str"}
566 var dat [len(names)][]byte
567 for i, name := range names {
568 name = ".debug_" + name
569 s := f.Section(name)
570 if s == nil {
571 continue
572 }
573 b, err := s.Data()
574 if err != nil && uint64(len(b)) < s.Size {
575 return nil, err
576 }
577 dat[i] = b
578 }
579
580
581
582 rela := f.Section(".rela.debug_info")
583 if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
584 data, err := rela.Data()
585 if err != nil {
586 return nil, err
587 }
588 err = f.applyRelocations(dat[1], data)
589 if err != nil {
590 return nil, err
591 }
592 }
593
594 abbrev, info, str := dat[0], dat[1], dat[2]
595 return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
596 }
597
598
599 func (f *File) Symbols() ([]Symbol, os.Error) {
600 sym, _, err := f.getSymbols(SHT_SYMTAB)
601 return sym, err
602 }
603
604 type ImportedSymbol struct {
605 Name string
606 Version string
607 Library string
608 }
609
610
611
612
613
614 func (f *File) ImportedSymbols() ([]ImportedSymbol, os.Error) {
615 sym, str, err := f.getSymbols(SHT_DYNSYM)
616 if err != nil {
617 return nil, err
618 }
619 f.gnuVersionInit(str)
620 var all []ImportedSymbol
621 for i, s := range sym {
622 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
623 all = append(all, ImportedSymbol{Name: s.Name})
624 f.gnuVersion(i, &all[len(all)-1])
625 }
626 }
627 return all, nil
628 }
629
630 type verneed struct {
631 File string
632 Name string
633 }
634
635
636
637 func (f *File) gnuVersionInit(str []byte) {
638
639 vn := f.SectionByType(SHT_GNU_VERNEED)
640 if vn == nil {
641 return
642 }
643 d, _ := vn.Data()
644
645 var need []verneed
646 i := 0
647 for {
648 if i+16 > len(d) {
649 break
650 }
651 vers := f.ByteOrder.Uint16(d[i : i+2])
652 if vers != 1 {
653 break
654 }
655 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
656 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
657 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
658 next := f.ByteOrder.Uint32(d[i+12 : i+16])
659 file, _ := getString(str, int(fileoff))
660
661 var name string
662 j := i + int(aux)
663 for c := 0; c < int(cnt); c++ {
664 if j+16 > len(d) {
665 break
666 }
667
668
669 other := f.ByteOrder.Uint16(d[j+6 : j+8])
670 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
671 next := f.ByteOrder.Uint32(d[j+12 : j+16])
672 name, _ = getString(str, int(nameoff))
673 ndx := int(other)
674 if ndx >= len(need) {
675 a := make([]verneed, 2*(ndx+1))
676 copy(a, need)
677 need = a
678 }
679
680 need[ndx] = verneed{file, name}
681 if next == 0 {
682 break
683 }
684 j += int(next)
685 }
686
687 if next == 0 {
688 break
689 }
690 i += int(next)
691 }
692
693
694 vs := f.SectionByType(SHT_GNU_VERSYM)
695 if vs == nil {
696 return
697 }
698 d, _ = vs.Data()
699
700 f.gnuNeed = need
701 f.gnuVersym = d
702 }
703
704
705
706 func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
707
708 i = (i + 1) * 2
709 if i >= len(f.gnuVersym) {
710 return
711 }
712 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
713 if j < 2 || j >= len(f.gnuNeed) {
714 return
715 }
716 n := &f.gnuNeed[j]
717 sym.Library = n.File
718 sym.Version = n.Name
719 }
720
721
722
723
724 func (f *File) ImportedLibraries() ([]string, os.Error) {
725 ds := f.SectionByType(SHT_DYNAMIC)
726 if ds == nil {
727
728 return nil, nil
729 }
730 d, err := ds.Data()
731 if err != nil {
732 return nil, err
733 }
734 str, err := f.stringTable(ds.Link)
735 if err != nil {
736 return nil, err
737 }
738 var all []string
739 for len(d) > 0 {
740 var tag DynTag
741 var value uint64
742 switch f.Class {
743 case ELFCLASS32:
744 tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
745 value = uint64(f.ByteOrder.Uint32(d[4:8]))
746 d = d[8:]
747 case ELFCLASS64:
748 tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
749 value = f.ByteOrder.Uint64(d[8:16])
750 d = d[16:]
751 }
752 if tag == DT_NEEDED {
753 s, ok := getString(str, int(value))
754 if ok {
755 all = append(all, s)
756 }
757 }
758 }
759
760 return all, nil
761 }