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