1
2
3
4
5
6 package elf
7
8 import (
9 "bytes"
10 "compress/zlib"
11 "debug/dwarf"
12 "encoding/binary"
13 "errors"
14 "fmt"
15 "io"
16 "os"
17 "strings"
18 )
19
20
21
22
23
24
25 const (
26 seekStart int = 0
27 seekCurrent int = 1
28 seekEnd int = 2
29 )
30
31
32
33
36
37
38 type FileHeader struct {
39 Class Class
40 Data Data
41 Version Version
42 OSABI OSABI
43 ABIVersion uint8
44 ByteOrder binary.ByteOrder
45 Type Type
46 Machine Machine
47 Entry uint64
48 }
49
50
51 type File struct {
52 FileHeader
53 Sections []*Section
54 Progs []*Prog
55 closer io.Closer
56 gnuNeed []verneed
57 gnuVersym []byte
58 }
59
60
61 type SectionHeader struct {
62 Name string
63 Type SectionType
64 Flags SectionFlag
65 Addr uint64
66 Offset uint64
67 Size uint64
68 Link uint32
69 Info uint32
70 Addralign uint64
71 Entsize uint64
72
73
74
75
76
77 FileSize uint64
78 }
79
80
81 type Section struct {
82 SectionHeader
83
84
85
86
87
88
89
90
91
92
93
94 io.ReaderAt
95 sr *io.SectionReader
96
97 compressionType CompressionType
98 compressionOffset int64
99 }
100
101
102
103
104 func (s *Section) Data() ([]byte, error) {
105 dat := make([]byte, s.Size)
106 n, err := io.ReadFull(s.Open(), dat)
107 return dat[0:n], err
108 }
109
110
111
112 func (f *File) stringTable(link uint32) ([]byte, error) {
113 if link <= 0 || link >= uint32(len(f.Sections)) {
114 return nil, errors.New("section has invalid string table link")
115 }
116 return f.Sections[link].Data()
117 }
118
119
120
121
122 func (s *Section) Open() io.ReadSeeker {
123 if s.Flags&SHF_COMPRESSED == 0 {
124 return io.NewSectionReader(s.sr, 0, 1<<63-1)
125 }
126 if s.compressionType == COMPRESS_ZLIB {
127 return &readSeekerFromReader{
128 reset: func() (io.Reader, error) {
129 fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
130 return zlib.NewReader(fr)
131 },
132 size: int64(s.Size),
133 }
134 }
135 err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
136 return errorReader{err}
137 }
138
139
140 type ProgHeader struct {
141 Type ProgType
142 Flags ProgFlag
143 Off uint64
144 Vaddr uint64
145 Paddr uint64
146 Filesz uint64
147 Memsz uint64
148 Align uint64
149 }
150
151
152 type Prog struct {
153 ProgHeader
154
155
156
157
158
159
160
161 io.ReaderAt
162 sr *io.SectionReader
163 }
164
165
166 func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
167
168
169 type Symbol struct {
170 Name string
171 Info, Other byte
172 Section SectionIndex
173 Value, Size uint64
174 }
175
176
179
180 type FormatError struct {
181 off int64
182 msg string
183 val interface{}
184 }
185
186 func (e *FormatError) Error() string {
187 msg := e.msg
188 if e.val != nil {
189 msg += fmt.Sprintf(" '%v' ", e.val)
190 }
191 msg += fmt.Sprintf("in record at byte %#x", e.off)
192 return msg
193 }
194
195
196 func Open(name string) (*File, error) {
197 f, err := os.Open(name)
198 if err != nil {
199 return nil, err
200 }
201 ff, err := NewFile(f)
202 if err != nil {
203 f.Close()
204 return nil, err
205 }
206 ff.closer = f
207 return ff, nil
208 }
209
210
211
212
213 func (f *File) Close() error {
214 var err error
215 if f.closer != nil {
216 err = f.closer.Close()
217 f.closer = nil
218 }
219 return err
220 }
221
222
223
224 func (f *File) SectionByType(typ SectionType) *Section {
225 for _, s := range f.Sections {
226 if s.Type == typ {
227 return s
228 }
229 }
230 return nil
231 }
232
233
234
235 func NewFile(r io.ReaderAt) (*File, error) {
236 sr := io.NewSectionReader(r, 0, 1<<63-1)
237
238 var ident [16]uint8
239 if _, err := r.ReadAt(ident[0:], 0); err != nil {
240 return nil, err
241 }
242 if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
243 return nil, &FormatError{0, "bad magic number", ident[0:4]}
244 }
245
246 f := new(File)
247 f.Class = Class(ident[EI_CLASS])
248 switch f.Class {
249 case ELFCLASS32:
250 case ELFCLASS64:
251
252 default:
253 return nil, &FormatError{0, "unknown ELF class", f.Class}
254 }
255
256 f.Data = Data(ident[EI_DATA])
257 switch f.Data {
258 case ELFDATA2LSB:
259 f.ByteOrder = binary.LittleEndian
260 case ELFDATA2MSB:
261 f.ByteOrder = binary.BigEndian
262 default:
263 return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
264 }
265
266 f.Version = Version(ident[EI_VERSION])
267 if f.Version != EV_CURRENT {
268 return nil, &FormatError{0, "unknown ELF version", f.Version}
269 }
270
271 f.OSABI = OSABI(ident[EI_OSABI])
272 f.ABIVersion = ident[EI_ABIVERSION]
273
274
275 var phoff int64
276 var phentsize, phnum int
277 var shoff int64
278 var shentsize, shnum, shstrndx int
279 shstrndx = -1
280 switch f.Class {
281 case ELFCLASS32:
282 hdr := new(Header32)
283 sr.Seek(0, seekStart)
284 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
285 return nil, err
286 }
287 f.Type = Type(hdr.Type)
288 f.Machine = Machine(hdr.Machine)
289 f.Entry = uint64(hdr.Entry)
290 if v := Version(hdr.Version); v != f.Version {
291 return nil, &FormatError{0, "mismatched ELF version", v}
292 }
293 phoff = int64(hdr.Phoff)
294 phentsize = int(hdr.Phentsize)
295 phnum = int(hdr.Phnum)
296 shoff = int64(hdr.Shoff)
297 shentsize = int(hdr.Shentsize)
298 shnum = int(hdr.Shnum)
299 shstrndx = int(hdr.Shstrndx)
300 case ELFCLASS64:
301 hdr := new(Header64)
302 sr.Seek(0, seekStart)
303 if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
304 return nil, err
305 }
306 f.Type = Type(hdr.Type)
307 f.Machine = Machine(hdr.Machine)
308 f.Entry = hdr.Entry
309 if v := Version(hdr.Version); v != f.Version {
310 return nil, &FormatError{0, "mismatched ELF version", v}
311 }
312 phoff = int64(hdr.Phoff)
313 phentsize = int(hdr.Phentsize)
314 phnum = int(hdr.Phnum)
315 shoff = int64(hdr.Shoff)
316 shentsize = int(hdr.Shentsize)
317 shnum = int(hdr.Shnum)
318 shstrndx = int(hdr.Shstrndx)
319 }
320
321 if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) {
322 return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
323 }
324
325
326 f.Progs = make([]*Prog, phnum)
327 for i := 0; i < phnum; i++ {
328 off := phoff + int64(i)*int64(phentsize)
329 sr.Seek(off, seekStart)
330 p := new(Prog)
331 switch f.Class {
332 case ELFCLASS32:
333 ph := new(Prog32)
334 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
335 return nil, err
336 }
337 p.ProgHeader = ProgHeader{
338 Type: ProgType(ph.Type),
339 Flags: ProgFlag(ph.Flags),
340 Off: uint64(ph.Off),
341 Vaddr: uint64(ph.Vaddr),
342 Paddr: uint64(ph.Paddr),
343 Filesz: uint64(ph.Filesz),
344 Memsz: uint64(ph.Memsz),
345 Align: uint64(ph.Align),
346 }
347 case ELFCLASS64:
348 ph := new(Prog64)
349 if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
350 return nil, err
351 }
352 p.ProgHeader = ProgHeader{
353 Type: ProgType(ph.Type),
354 Flags: ProgFlag(ph.Flags),
355 Off: ph.Off,
356 Vaddr: ph.Vaddr,
357 Paddr: ph.Paddr,
358 Filesz: ph.Filesz,
359 Memsz: ph.Memsz,
360 Align: ph.Align,
361 }
362 }
363 p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
364 p.ReaderAt = p.sr
365 f.Progs[i] = p
366 }
367
368
369 f.Sections = make([]*Section, shnum)
370 names := make([]uint32, shnum)
371 for i := 0; i < shnum; i++ {
372 off := shoff + int64(i)*int64(shentsize)
373 sr.Seek(off, seekStart)
374 s := new(Section)
375 switch f.Class {
376 case ELFCLASS32:
377 sh := new(Section32)
378 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
379 return nil, err
380 }
381 names[i] = sh.Name
382 s.SectionHeader = SectionHeader{
383 Type: SectionType(sh.Type),
384 Flags: SectionFlag(sh.Flags),
385 Addr: uint64(sh.Addr),
386 Offset: uint64(sh.Off),
387 FileSize: uint64(sh.Size),
388 Link: sh.Link,
389 Info: sh.Info,
390 Addralign: uint64(sh.Addralign),
391 Entsize: uint64(sh.Entsize),
392 }
393 case ELFCLASS64:
394 sh := new(Section64)
395 if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
396 return nil, err
397 }
398 names[i] = sh.Name
399 s.SectionHeader = SectionHeader{
400 Type: SectionType(sh.Type),
401 Flags: SectionFlag(sh.Flags),
402 Offset: sh.Off,
403 FileSize: sh.Size,
404 Addr: sh.Addr,
405 Link: sh.Link,
406 Info: sh.Info,
407 Addralign: sh.Addralign,
408 Entsize: sh.Entsize,
409 }
410 }
411 s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
412
413 if s.Flags&SHF_COMPRESSED == 0 {
414 s.ReaderAt = s.sr
415 s.Size = s.FileSize
416 } else {
417
418 switch f.Class {
419 case ELFCLASS32:
420 ch := new(Chdr32)
421 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
422 return nil, err
423 }
424 s.compressionType = CompressionType(ch.Type)
425 s.Size = uint64(ch.Size)
426 s.Addralign = uint64(ch.Addralign)
427 s.compressionOffset = int64(binary.Size(ch))
428 case ELFCLASS64:
429 ch := new(Chdr64)
430 if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
431 return nil, err
432 }
433 s.compressionType = CompressionType(ch.Type)
434 s.Size = ch.Size
435 s.Addralign = ch.Addralign
436 s.compressionOffset = int64(binary.Size(ch))
437 }
438 }
439
440 f.Sections[i] = s
441 }
442
443 if len(f.Sections) == 0 {
444 return f, nil
445 }
446
447
448 shstrtab, err := f.Sections[shstrndx].Data()
449 if err != nil {
450 return nil, err
451 }
452 for i, s := range f.Sections {
453 var ok bool
454 s.Name, ok = getString(shstrtab, int(names[i]))
455 if !ok {
456 return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
457 }
458 }
459
460 return f, nil
461 }
462
463
464
465 func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
466 switch f.Class {
467 case ELFCLASS64:
468 return f.getSymbols64(typ)
469
470 case ELFCLASS32:
471 return f.getSymbols32(typ)
472 }
473
474 return nil, nil, errors.New("not implemented")
475 }
476
477
478
479 var ErrNoSymbols = errors.New("no symbol section")
480
481 func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
482 symtabSection := f.SectionByType(typ)
483 if symtabSection == nil {
484 return nil, nil, ErrNoSymbols
485 }
486
487 data, err := symtabSection.Data()
488 if err != nil {
489 return nil, nil, errors.New("cannot load symbol section")
490 }
491 symtab := bytes.NewReader(data)
492 if symtab.Len()%Sym32Size != 0 {
493 return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
494 }
495
496 strdata, err := f.stringTable(symtabSection.Link)
497 if err != nil {
498 return nil, nil, errors.New("cannot load string table section")
499 }
500
501
502 var skip [Sym32Size]byte
503 symtab.Read(skip[:])
504
505 symbols := make([]Symbol, symtab.Len()/Sym32Size)
506
507 i := 0
508 var sym Sym32
509 for symtab.Len() > 0 {
510 binary.Read(symtab, f.ByteOrder, &sym)
511 str, _ := getString(strdata, int(sym.Name))
512 symbols[i].Name = str
513 symbols[i].Info = sym.Info
514 symbols[i].Other = sym.Other
515 symbols[i].Section = SectionIndex(sym.Shndx)
516 symbols[i].Value = uint64(sym.Value)
517 symbols[i].Size = uint64(sym.Size)
518 i++
519 }
520
521 return symbols, strdata, nil
522 }
523
524 func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
525 symtabSection := f.SectionByType(typ)
526 if symtabSection == nil {
527 return nil, nil, ErrNoSymbols
528 }
529
530 data, err := symtabSection.Data()
531 if err != nil {
532 return nil, nil, errors.New("cannot load symbol section")
533 }
534 symtab := bytes.NewReader(data)
535 if symtab.Len()%Sym64Size != 0 {
536 return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
537 }
538
539 strdata, err := f.stringTable(symtabSection.Link)
540 if err != nil {
541 return nil, nil, errors.New("cannot load string table section")
542 }
543
544
545 var skip [Sym64Size]byte
546 symtab.Read(skip[:])
547
548 symbols := make([]Symbol, symtab.Len()/Sym64Size)
549
550 i := 0
551 var sym Sym64
552 for symtab.Len() > 0 {
553 binary.Read(symtab, f.ByteOrder, &sym)
554 str, _ := getString(strdata, int(sym.Name))
555 symbols[i].Name = str
556 symbols[i].Info = sym.Info
557 symbols[i].Other = sym.Other
558 symbols[i].Section = SectionIndex(sym.Shndx)
559 symbols[i].Value = sym.Value
560 symbols[i].Size = sym.Size
561 i++
562 }
563
564 return symbols, strdata, nil
565 }
566
567
568 func getString(section []byte, start int) (string, bool) {
569 if start < 0 || start >= len(section) {
570 return "", false
571 }
572
573 for end := start; end < len(section); end++ {
574 if section[end] == 0 {
575 return string(section[start:end]), true
576 }
577 }
578 return "", false
579 }
580
581
582
583 func (f *File) Section(name string) *Section {
584 for _, s := range f.Sections {
585 if s.Name == name {
586 return s
587 }
588 }
589 return nil
590 }
591
592
593
594 func (f *File) applyRelocations(dst []byte, rels []byte) error {
595 switch {
596 case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
597 return f.applyRelocationsAMD64(dst, rels)
598 case f.Class == ELFCLASS32 && f.Machine == EM_386:
599 return f.applyRelocations386(dst, rels)
600 case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
601 return f.applyRelocationsARM(dst, rels)
602 case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
603 return f.applyRelocationsARM64(dst, rels)
604 case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
605 return f.applyRelocationsPPC(dst, rels)
606 case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
607 return f.applyRelocationsPPC64(dst, rels)
608 case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
609 return f.applyRelocationsMIPS(dst, rels)
610 case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
611 return f.applyRelocationsMIPS64(dst, rels)
612 case f.Class == ELFCLASS64 && f.Machine == EM_S390:
613 return f.applyRelocationss390x(dst, rels)
614 case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
615 return f.applyRelocationsSPARC64(dst, rels)
616 default:
617 return errors.New("applyRelocations: not implemented")
618 }
619 }
620
621 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
622
623 if len(rels)%24 != 0 {
624 return errors.New("length of relocation section is not a multiple of 24")
625 }
626
627 symbols, _, err := f.getSymbols(SHT_SYMTAB)
628 if err != nil {
629 return err
630 }
631
632 b := bytes.NewReader(rels)
633 var rela Rela64
634
635 for b.Len() > 0 {
636 binary.Read(b, f.ByteOrder, &rela)
637 symNo := rela.Info >> 32
638 t := R_X86_64(rela.Info & 0xffff)
639
640 if symNo == 0 || symNo > uint64(len(symbols)) {
641 continue
642 }
643 sym := &symbols[symNo-1]
644 if SymType(sym.Info&0xf) != STT_SECTION {
645
646 continue
647 }
648
649
650
651
652
653 switch t {
654 case R_X86_64_64:
655 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
656 continue
657 }
658 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
659 case R_X86_64_32:
660 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
661 continue
662 }
663 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
664 }
665 }
666
667 return nil
668 }
669
670 func (f *File) applyRelocations386(dst []byte, rels []byte) error {
671
672 if len(rels)%8 != 0 {
673 return errors.New("length of relocation section is not a multiple of 8")
674 }
675
676 symbols, _, err := f.getSymbols(SHT_SYMTAB)
677 if err != nil {
678 return err
679 }
680
681 b := bytes.NewReader(rels)
682 var rel Rel32
683
684 for b.Len() > 0 {
685 binary.Read(b, f.ByteOrder, &rel)
686 symNo := rel.Info >> 8
687 t := R_386(rel.Info & 0xff)
688
689 if symNo == 0 || symNo > uint32(len(symbols)) {
690 continue
691 }
692 sym := &symbols[symNo-1]
693
694 if t == R_386_32 {
695 if rel.Off+4 >= uint32(len(dst)) {
696 continue
697 }
698 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
699 val += uint32(sym.Value)
700 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
701 }
702 }
703
704 return nil
705 }
706
707 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
708
709 if len(rels)%8 != 0 {
710 return errors.New("length of relocation section is not a multiple of 8")
711 }
712
713 symbols, _, err := f.getSymbols(SHT_SYMTAB)
714 if err != nil {
715 return err
716 }
717
718 b := bytes.NewReader(rels)
719 var rel Rel32
720
721 for b.Len() > 0 {
722 binary.Read(b, f.ByteOrder, &rel)
723 symNo := rel.Info >> 8
724 t := R_ARM(rel.Info & 0xff)
725
726 if symNo == 0 || symNo > uint32(len(symbols)) {
727 continue
728 }
729 sym := &symbols[symNo-1]
730
731 switch t {
732 case R_ARM_ABS32:
733 if rel.Off+4 >= uint32(len(dst)) {
734 continue
735 }
736 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
737 val += uint32(sym.Value)
738 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
739 }
740 }
741
742 return nil
743 }
744
745 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
746
747 if len(rels)%24 != 0 {
748 return errors.New("length of relocation section is not a multiple of 24")
749 }
750
751 symbols, _, err := f.getSymbols(SHT_SYMTAB)
752 if err != nil {
753 return err
754 }
755
756 b := bytes.NewReader(rels)
757 var rela Rela64
758
759 for b.Len() > 0 {
760 binary.Read(b, f.ByteOrder, &rela)
761 symNo := rela.Info >> 32
762 t := R_AARCH64(rela.Info & 0xffff)
763
764 if symNo == 0 || symNo > uint64(len(symbols)) {
765 continue
766 }
767 sym := &symbols[symNo-1]
768 if SymType(sym.Info&0xf) != STT_SECTION {
769
770 continue
771 }
772
773
774
775
776
777 switch t {
778 case R_AARCH64_ABS64:
779 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
780 continue
781 }
782 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
783 case R_AARCH64_ABS32:
784 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
785 continue
786 }
787 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
788 }
789 }
790
791 return nil
792 }
793
794 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
795
796 if len(rels)%12 != 0 {
797 return errors.New("length of relocation section is not a multiple of 12")
798 }
799
800 symbols, _, err := f.getSymbols(SHT_SYMTAB)
801 if err != nil {
802 return err
803 }
804
805 b := bytes.NewReader(rels)
806 var rela Rela32
807
808 for b.Len() > 0 {
809 binary.Read(b, f.ByteOrder, &rela)
810 symNo := rela.Info >> 8
811 t := R_PPC(rela.Info & 0xff)
812
813 if symNo == 0 || symNo > uint32(len(symbols)) {
814 continue
815 }
816 sym := &symbols[symNo-1]
817 if SymType(sym.Info&0xf) != STT_SECTION {
818
819 continue
820 }
821
822 switch t {
823 case R_PPC_ADDR32:
824 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
825 continue
826 }
827 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
828 }
829 }
830
831 return nil
832 }
833
834 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
835
836 if len(rels)%24 != 0 {
837 return errors.New("length of relocation section is not a multiple of 24")
838 }
839
840 symbols, _, err := f.getSymbols(SHT_SYMTAB)
841 if err != nil {
842 return err
843 }
844
845 b := bytes.NewReader(rels)
846 var rela Rela64
847
848 for b.Len() > 0 {
849 binary.Read(b, f.ByteOrder, &rela)
850 symNo := rela.Info >> 32
851 t := R_PPC64(rela.Info & 0xffff)
852
853 if symNo == 0 || symNo > uint64(len(symbols)) {
854 continue
855 }
856 sym := &symbols[symNo-1]
857 if SymType(sym.Info&0xf) != STT_SECTION {
858
859 continue
860 }
861
862 switch t {
863 case R_PPC64_ADDR64:
864 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
865 continue
866 }
867 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
868 case R_PPC64_ADDR32:
869 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
870 continue
871 }
872 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
873 }
874 }
875
876 return nil
877 }
878
879 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
880
881 if len(rels)%8 != 0 {
882 return errors.New("length of relocation section is not a multiple of 8")
883 }
884
885 symbols, _, err := f.getSymbols(SHT_SYMTAB)
886 if err != nil {
887 return err
888 }
889
890 b := bytes.NewReader(rels)
891 var rel Rel32
892
893 for b.Len() > 0 {
894 binary.Read(b, f.ByteOrder, &rel)
895 symNo := rel.Info >> 8
896 t := R_MIPS(rel.Info & 0xff)
897
898 if symNo == 0 || symNo > uint32(len(symbols)) {
899 continue
900 }
901 sym := &symbols[symNo-1]
902
903 switch t {
904 case R_MIPS_32:
905 if rel.Off+4 >= uint32(len(dst)) {
906 continue
907 }
908 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
909 val += uint32(sym.Value)
910 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
911 }
912 }
913
914 return nil
915 }
916
917 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
918
919 if len(rels)%24 != 0 {
920 return errors.New("length of relocation section is not a multiple of 24")
921 }
922
923 symbols, _, err := f.getSymbols(SHT_SYMTAB)
924 if err != nil {
925 return err
926 }
927
928 b := bytes.NewReader(rels)
929 var rela Rela64
930
931 for b.Len() > 0 {
932 binary.Read(b, f.ByteOrder, &rela)
933 var symNo uint64
934 var t R_MIPS
935 if f.ByteOrder == binary.BigEndian {
936 symNo = rela.Info >> 32
937 t = R_MIPS(rela.Info & 0xff)
938 } else {
939 symNo = rela.Info & 0xffffffff
940 t = R_MIPS(rela.Info >> 56)
941 }
942
943 if symNo == 0 || symNo > uint64(len(symbols)) {
944 continue
945 }
946 sym := &symbols[symNo-1]
947 if SymType(sym.Info&0xf) != STT_SECTION {
948
949 continue
950 }
951
952 switch t {
953 case R_MIPS_64:
954 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
955 continue
956 }
957 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
958 case R_MIPS_32:
959 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
960 continue
961 }
962 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
963 }
964 }
965
966 return nil
967 }
968
969 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
970
971 if len(rels)%24 != 0 {
972 return errors.New("length of relocation section is not a multiple of 24")
973 }
974
975 symbols, _, err := f.getSymbols(SHT_SYMTAB)
976 if err != nil {
977 return err
978 }
979
980 b := bytes.NewReader(rels)
981 var rela Rela64
982
983 for b.Len() > 0 {
984 binary.Read(b, f.ByteOrder, &rela)
985 symNo := rela.Info >> 32
986 t := R_390(rela.Info & 0xffff)
987
988 if symNo == 0 || symNo > uint64(len(symbols)) {
989 continue
990 }
991 sym := &symbols[symNo-1]
992 switch SymType(sym.Info & 0xf) {
993 case STT_SECTION, STT_NOTYPE:
994 break
995 default:
996 continue
997 }
998
999 switch t {
1000 case R_390_64:
1001 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1002 continue
1003 }
1004 val := sym.Value + uint64(rela.Addend)
1005 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
1006 case R_390_32:
1007 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1008 continue
1009 }
1010 val := uint32(sym.Value) + uint32(rela.Addend)
1011 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
1012 }
1013 }
1014
1015 return nil
1016 }
1017
1018 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1019
1020 if len(rels)%24 != 0 {
1021 return errors.New("length of relocation section is not a multiple of 24")
1022 }
1023
1024 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1025 if err != nil {
1026 return err
1027 }
1028
1029 b := bytes.NewReader(rels)
1030 var rela Rela64
1031
1032 for b.Len() > 0 {
1033 binary.Read(b, f.ByteOrder, &rela)
1034 symNo := rela.Info >> 32
1035 t := R_SPARC(rela.Info & 0xff)
1036
1037 if symNo == 0 || symNo > uint64(len(symbols)) {
1038 continue
1039 }
1040 sym := &symbols[symNo-1]
1041 if SymType(sym.Info&0xf) != STT_SECTION {
1042
1043 continue
1044 }
1045
1046 switch t {
1047 case R_SPARC_64, R_SPARC_UA64:
1048 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1049 continue
1050 }
1051 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
1052 case R_SPARC_32, R_SPARC_UA32:
1053 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1054 continue
1055 }
1056 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
1057 }
1058 }
1059
1060 return nil
1061 }
1062
1063 func (f *File) DWARF() (*dwarf.Data, error) {
1064
1065
1066 sectionData := func(i int, s *Section) ([]byte, error) {
1067 b, err := s.Data()
1068 if err != nil && uint64(len(b)) < s.Size {
1069 return nil, err
1070 }
1071
1072 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1073 dlen := binary.BigEndian.Uint64(b[4:12])
1074 dbuf := make([]byte, dlen)
1075 r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1076 if err != nil {
1077 return nil, err
1078 }
1079 if _, err := io.ReadFull(r, dbuf); err != nil {
1080 return nil, err
1081 }
1082 if err := r.Close(); err != nil {
1083 return nil, err
1084 }
1085 b = dbuf
1086 }
1087
1088 for _, r := range f.Sections {
1089 if r.Type != SHT_RELA && r.Type != SHT_REL {
1090 continue
1091 }
1092 if int(r.Info) != i {
1093 continue
1094 }
1095 rd, err := r.Data()
1096 if err != nil {
1097 return nil, err
1098 }
1099 err = f.applyRelocations(b, rd)
1100 if err != nil {
1101 return nil, err
1102 }
1103 }
1104 return b, nil
1105 }
1106
1107
1108
1109
1110 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1111 for i, s := range f.Sections {
1112 suffix := ""
1113 switch {
1114 case strings.HasPrefix(s.Name, ".debug_"):
1115 suffix = s.Name[7:]
1116 case strings.HasPrefix(s.Name, ".zdebug_"):
1117 suffix = s.Name[8:]
1118 default:
1119 continue
1120 }
1121 if _, ok := dat[suffix]; !ok {
1122 continue
1123 }
1124 b, err := sectionData(i, s)
1125 if err != nil {
1126 return nil, err
1127 }
1128 dat[suffix] = b
1129 }
1130
1131 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1132 if err != nil {
1133 return nil, err
1134 }
1135
1136
1137 for i, s := range f.Sections {
1138 if s.Name == ".debug_types" {
1139 b, err := sectionData(i, s)
1140 if err != nil {
1141 return nil, err
1142 }
1143
1144 err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
1145 if err != nil {
1146 return nil, err
1147 }
1148 }
1149 }
1150
1151 return d, nil
1152 }
1153
1154
1155
1156
1157
1158
1159
1160 func (f *File) Symbols() ([]Symbol, error) {
1161 sym, _, err := f.getSymbols(SHT_SYMTAB)
1162 return sym, err
1163 }
1164
1165
1166
1167
1168
1169
1170
1171 func (f *File) DynamicSymbols() ([]Symbol, error) {
1172 sym, _, err := f.getSymbols(SHT_DYNSYM)
1173 return sym, err
1174 }
1175
1176 type ImportedSymbol struct {
1177 Name string
1178 Version string
1179 Library string
1180 }
1181
1182
1183
1184
1185
1186 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1187 sym, str, err := f.getSymbols(SHT_DYNSYM)
1188 if err != nil {
1189 return nil, err
1190 }
1191 f.gnuVersionInit(str)
1192 var all []ImportedSymbol
1193 for i, s := range sym {
1194 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1195 all = append(all, ImportedSymbol{Name: s.Name})
1196 f.gnuVersion(i, &all[len(all)-1])
1197 }
1198 }
1199 return all, nil
1200 }
1201
1202 type verneed struct {
1203 File string
1204 Name string
1205 }
1206
1207
1208
1209 func (f *File) gnuVersionInit(str []byte) {
1210
1211 vn := f.SectionByType(SHT_GNU_VERNEED)
1212 if vn == nil {
1213 return
1214 }
1215 d, _ := vn.Data()
1216
1217 var need []verneed
1218 i := 0
1219 for {
1220 if i+16 > len(d) {
1221 break
1222 }
1223 vers := f.ByteOrder.Uint16(d[i : i+2])
1224 if vers != 1 {
1225 break
1226 }
1227 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1228 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1229 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1230 next := f.ByteOrder.Uint32(d[i+12 : i+16])
1231 file, _ := getString(str, int(fileoff))
1232
1233 var name string
1234 j := i + int(aux)
1235 for c := 0; c < int(cnt); c++ {
1236 if j+16 > len(d) {
1237 break
1238 }
1239
1240
1241 other := f.ByteOrder.Uint16(d[j+6 : j+8])
1242 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1243 next := f.ByteOrder.Uint32(d[j+12 : j+16])
1244 name, _ = getString(str, int(nameoff))
1245 ndx := int(other)
1246 if ndx >= len(need) {
1247 a := make([]verneed, 2*(ndx+1))
1248 copy(a, need)
1249 need = a
1250 }
1251
1252 need[ndx] = verneed{file, name}
1253 if next == 0 {
1254 break
1255 }
1256 j += int(next)
1257 }
1258
1259 if next == 0 {
1260 break
1261 }
1262 i += int(next)
1263 }
1264
1265
1266 vs := f.SectionByType(SHT_GNU_VERSYM)
1267 if vs == nil {
1268 return
1269 }
1270 d, _ = vs.Data()
1271
1272 f.gnuNeed = need
1273 f.gnuVersym = d
1274 }
1275
1276
1277
1278 func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
1279
1280 i = (i + 1) * 2
1281 if i >= len(f.gnuVersym) {
1282 return
1283 }
1284 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
1285 if j < 2 || j >= len(f.gnuNeed) {
1286 return
1287 }
1288 n := &f.gnuNeed[j]
1289 sym.Library = n.File
1290 sym.Version = n.Name
1291 }
1292
1293
1294
1295
1296 func (f *File) ImportedLibraries() ([]string, error) {
1297 return f.DynString(DT_NEEDED)
1298 }
1299
1300
1301
1302
1303
1304
1305 func (f *File) DynString(tag DynTag) ([]string, error) {
1306 switch tag {
1307 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1308 default:
1309 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1310 }
1311 ds := f.SectionByType(SHT_DYNAMIC)
1312 if ds == nil {
1313
1314 return nil, nil
1315 }
1316 d, err := ds.Data()
1317 if err != nil {
1318 return nil, err
1319 }
1320 str, err := f.stringTable(ds.Link)
1321 if err != nil {
1322 return nil, err
1323 }
1324 var all []string
1325 for len(d) > 0 {
1326 var t DynTag
1327 var v uint64
1328 switch f.Class {
1329 case ELFCLASS32:
1330 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1331 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1332 d = d[8:]
1333 case ELFCLASS64:
1334 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1335 v = f.ByteOrder.Uint64(d[8:16])
1336 d = d[16:]
1337 }
1338 if t == tag {
1339 s, ok := getString(str, int(v))
1340 if ok {
1341 all = append(all, s)
1342 }
1343 }
1344 }
1345 return all, nil
1346 }
1347
View as plain text