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
638
639
640 func relocSymbolTargetOK(sym *Symbol) (bool, uint64) {
641 if ST_TYPE(sym.Info) == STT_SECTION {
642 return true, 0
643 }
644 if sym.Section != SHN_UNDEF && sym.Section < SHN_LORESERVE {
645 return true, sym.Value
646 }
647 return false, 0
648 }
649
650 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
651
652 if len(rels)%24 != 0 {
653 return errors.New("length of relocation section is not a multiple of 24")
654 }
655
656 symbols, _, err := f.getSymbols(SHT_SYMTAB)
657 if err != nil {
658 return err
659 }
660
661 b := bytes.NewReader(rels)
662 var rela Rela64
663
664 for b.Len() > 0 {
665 binary.Read(b, f.ByteOrder, &rela)
666 symNo := rela.Info >> 32
667 t := R_X86_64(rela.Info & 0xffff)
668
669 if symNo == 0 || symNo > uint64(len(symbols)) {
670 continue
671 }
672 sym := &symbols[symNo-1]
673 needed, val := relocSymbolTargetOK(sym)
674 if !needed {
675 continue
676 }
677
678
679
680
681
682 switch t {
683 case R_X86_64_64:
684 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
685 continue
686 }
687 val64 := val + uint64(rela.Addend)
688 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
689 case R_X86_64_32:
690 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
691 continue
692 }
693 val32 := uint32(val) + uint32(rela.Addend)
694 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
695 }
696 }
697
698 return nil
699 }
700
701 func (f *File) applyRelocations386(dst []byte, rels []byte) error {
702
703 if len(rels)%8 != 0 {
704 return errors.New("length of relocation section is not a multiple of 8")
705 }
706
707 symbols, _, err := f.getSymbols(SHT_SYMTAB)
708 if err != nil {
709 return err
710 }
711
712 b := bytes.NewReader(rels)
713 var rel Rel32
714
715 for b.Len() > 0 {
716 binary.Read(b, f.ByteOrder, &rel)
717 symNo := rel.Info >> 8
718 t := R_386(rel.Info & 0xff)
719
720 if symNo == 0 || symNo > uint32(len(symbols)) {
721 continue
722 }
723 sym := &symbols[symNo-1]
724
725 if t == R_386_32 {
726 if rel.Off+4 >= uint32(len(dst)) {
727 continue
728 }
729 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
730 val += uint32(sym.Value)
731 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
732 }
733 }
734
735 return nil
736 }
737
738 func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
739
740 if len(rels)%8 != 0 {
741 return errors.New("length of relocation section is not a multiple of 8")
742 }
743
744 symbols, _, err := f.getSymbols(SHT_SYMTAB)
745 if err != nil {
746 return err
747 }
748
749 b := bytes.NewReader(rels)
750 var rel Rel32
751
752 for b.Len() > 0 {
753 binary.Read(b, f.ByteOrder, &rel)
754 symNo := rel.Info >> 8
755 t := R_ARM(rel.Info & 0xff)
756
757 if symNo == 0 || symNo > uint32(len(symbols)) {
758 continue
759 }
760 sym := &symbols[symNo-1]
761
762 switch t {
763 case R_ARM_ABS32:
764 if rel.Off+4 >= uint32(len(dst)) {
765 continue
766 }
767 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
768 val += uint32(sym.Value)
769 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
770 }
771 }
772
773 return nil
774 }
775
776 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
777
778 if len(rels)%24 != 0 {
779 return errors.New("length of relocation section is not a multiple of 24")
780 }
781
782 symbols, _, err := f.getSymbols(SHT_SYMTAB)
783 if err != nil {
784 return err
785 }
786
787 b := bytes.NewReader(rels)
788 var rela Rela64
789
790 for b.Len() > 0 {
791 binary.Read(b, f.ByteOrder, &rela)
792 symNo := rela.Info >> 32
793 t := R_AARCH64(rela.Info & 0xffff)
794
795 if symNo == 0 || symNo > uint64(len(symbols)) {
796 continue
797 }
798 sym := &symbols[symNo-1]
799 needed, val := relocSymbolTargetOK(sym)
800 if !needed {
801 continue
802 }
803
804
805
806
807
808 switch t {
809 case R_AARCH64_ABS64:
810 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
811 continue
812 }
813 val64 := uint64(val) + uint64(rela.Addend)
814 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
815 case R_AARCH64_ABS32:
816 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
817 continue
818 }
819 val32 := uint32(val) + uint32(rela.Addend)
820 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
821 }
822 }
823
824 return nil
825 }
826
827 func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
828
829 if len(rels)%12 != 0 {
830 return errors.New("length of relocation section is not a multiple of 12")
831 }
832
833 symbols, _, err := f.getSymbols(SHT_SYMTAB)
834 if err != nil {
835 return err
836 }
837
838 b := bytes.NewReader(rels)
839 var rela Rela32
840
841 for b.Len() > 0 {
842 binary.Read(b, f.ByteOrder, &rela)
843 symNo := rela.Info >> 8
844 t := R_PPC(rela.Info & 0xff)
845
846 if symNo == 0 || symNo > uint32(len(symbols)) {
847 continue
848 }
849 sym := &symbols[symNo-1]
850 needed, val := relocSymbolTargetOK(sym)
851 if !needed {
852 continue
853 }
854
855 switch t {
856 case R_PPC_ADDR32:
857 if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
858 continue
859 }
860 val32 := uint32(val) + uint32(rela.Addend)
861 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
862 }
863 }
864
865 return nil
866 }
867
868 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
869
870 if len(rels)%24 != 0 {
871 return errors.New("length of relocation section is not a multiple of 24")
872 }
873
874 symbols, _, err := f.getSymbols(SHT_SYMTAB)
875 if err != nil {
876 return err
877 }
878
879 b := bytes.NewReader(rels)
880 var rela Rela64
881
882 for b.Len() > 0 {
883 binary.Read(b, f.ByteOrder, &rela)
884 symNo := rela.Info >> 32
885 t := R_PPC64(rela.Info & 0xffff)
886
887 if symNo == 0 || symNo > uint64(len(symbols)) {
888 continue
889 }
890 sym := &symbols[symNo-1]
891 needed, val := relocSymbolTargetOK(sym)
892 if !needed {
893 continue
894 }
895
896 switch t {
897 case R_PPC64_ADDR64:
898 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
899 continue
900 }
901 val64 := val + uint64(rela.Addend)
902 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
903 case R_PPC64_ADDR32:
904 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
905 continue
906 }
907 val32 := uint32(val) + uint32(rela.Addend)
908 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
909 }
910 }
911
912 return nil
913 }
914
915 func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
916
917 if len(rels)%8 != 0 {
918 return errors.New("length of relocation section is not a multiple of 8")
919 }
920
921 symbols, _, err := f.getSymbols(SHT_SYMTAB)
922 if err != nil {
923 return err
924 }
925
926 b := bytes.NewReader(rels)
927 var rel Rel32
928
929 for b.Len() > 0 {
930 binary.Read(b, f.ByteOrder, &rel)
931 symNo := rel.Info >> 8
932 t := R_MIPS(rel.Info & 0xff)
933
934 if symNo == 0 || symNo > uint32(len(symbols)) {
935 continue
936 }
937 sym := &symbols[symNo-1]
938
939 switch t {
940 case R_MIPS_32:
941 if rel.Off+4 >= uint32(len(dst)) {
942 continue
943 }
944 val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
945 val += uint32(sym.Value)
946 f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
947 }
948 }
949
950 return nil
951 }
952
953 func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
954
955 if len(rels)%24 != 0 {
956 return errors.New("length of relocation section is not a multiple of 24")
957 }
958
959 symbols, _, err := f.getSymbols(SHT_SYMTAB)
960 if err != nil {
961 return err
962 }
963
964 b := bytes.NewReader(rels)
965 var rela Rela64
966
967 for b.Len() > 0 {
968 binary.Read(b, f.ByteOrder, &rela)
969 var symNo uint64
970 var t R_MIPS
971 if f.ByteOrder == binary.BigEndian {
972 symNo = rela.Info >> 32
973 t = R_MIPS(rela.Info & 0xff)
974 } else {
975 symNo = rela.Info & 0xffffffff
976 t = R_MIPS(rela.Info >> 56)
977 }
978
979 if symNo == 0 || symNo > uint64(len(symbols)) {
980 continue
981 }
982 sym := &symbols[symNo-1]
983 needed, val := relocSymbolTargetOK(sym)
984 if !needed {
985 continue
986 }
987
988 switch t {
989 case R_MIPS_64:
990 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
991 continue
992 }
993 val64 := val + uint64(rela.Addend)
994 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
995 case R_MIPS_32:
996 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
997 continue
998 }
999 val32 := uint32(val) + uint32(rela.Addend)
1000 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1001 }
1002 }
1003
1004 return nil
1005 }
1006
1007 func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
1008
1009 if len(rels)%24 != 0 {
1010 return errors.New("length of relocation section is not a multiple of 24")
1011 }
1012
1013 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1014 if err != nil {
1015 return err
1016 }
1017
1018 b := bytes.NewReader(rels)
1019 var rela Rela64
1020
1021 for b.Len() > 0 {
1022 binary.Read(b, f.ByteOrder, &rela)
1023 symNo := rela.Info >> 32
1024 t := R_RISCV(rela.Info & 0xffff)
1025
1026 if symNo == 0 || symNo > uint64(len(symbols)) {
1027 continue
1028 }
1029 sym := &symbols[symNo-1]
1030 needed, val := relocSymbolTargetOK(sym)
1031 if !needed {
1032 continue
1033 }
1034
1035 switch t {
1036 case R_RISCV_64:
1037 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1038 continue
1039 }
1040 val64 := val + uint64(rela.Addend)
1041 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1042 case R_RISCV_32:
1043 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1044 continue
1045 }
1046 val32 := uint32(val) + uint32(rela.Addend)
1047 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1048 }
1049 }
1050
1051 return nil
1052 }
1053
1054 func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
1055
1056 if len(rels)%24 != 0 {
1057 return errors.New("length of relocation section is not a multiple of 24")
1058 }
1059
1060 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1061 if err != nil {
1062 return err
1063 }
1064
1065 b := bytes.NewReader(rels)
1066 var rela Rela64
1067
1068 for b.Len() > 0 {
1069 binary.Read(b, f.ByteOrder, &rela)
1070 symNo := rela.Info >> 32
1071 t := R_390(rela.Info & 0xffff)
1072
1073 if symNo == 0 || symNo > uint64(len(symbols)) {
1074 continue
1075 }
1076 sym := &symbols[symNo-1]
1077 needed, val := relocSymbolTargetOK(sym)
1078 if !needed {
1079 continue
1080 }
1081
1082 switch t {
1083 case R_390_64:
1084 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1085 continue
1086 }
1087 val64 := val + uint64(rela.Addend)
1088 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1089 case R_390_32:
1090 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1091 continue
1092 }
1093 val32 := uint32(val) + uint32(rela.Addend)
1094 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1095 }
1096 }
1097
1098 return nil
1099 }
1100
1101 func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
1102
1103 if len(rels)%24 != 0 {
1104 return errors.New("length of relocation section is not a multiple of 24")
1105 }
1106
1107 symbols, _, err := f.getSymbols(SHT_SYMTAB)
1108 if err != nil {
1109 return err
1110 }
1111
1112 b := bytes.NewReader(rels)
1113 var rela Rela64
1114
1115 for b.Len() > 0 {
1116 binary.Read(b, f.ByteOrder, &rela)
1117 symNo := rela.Info >> 32
1118 t := R_SPARC(rela.Info & 0xff)
1119
1120 if symNo == 0 || symNo > uint64(len(symbols)) {
1121 continue
1122 }
1123 sym := &symbols[symNo-1]
1124 needed, val := relocSymbolTargetOK(sym)
1125 if !needed {
1126 continue
1127 }
1128
1129 switch t {
1130 case R_SPARC_64, R_SPARC_UA64:
1131 if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
1132 continue
1133 }
1134 val64 := val + uint64(rela.Addend)
1135 f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val64)
1136 case R_SPARC_32, R_SPARC_UA32:
1137 if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
1138 continue
1139 }
1140 val32 := uint32(val) + uint32(rela.Addend)
1141 f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32)
1142 }
1143 }
1144
1145 return nil
1146 }
1147
1148 func (f *File) DWARF() (*dwarf.Data, error) {
1149 dwarfSuffix := func(s *Section) string {
1150 switch {
1151 case strings.HasPrefix(s.Name, ".debug_"):
1152 return s.Name[7:]
1153 case strings.HasPrefix(s.Name, ".zdebug_"):
1154 return s.Name[8:]
1155 default:
1156 return ""
1157 }
1158
1159 }
1160
1161
1162 sectionData := func(i int, s *Section) ([]byte, error) {
1163 b, err := s.Data()
1164 if err != nil && uint64(len(b)) < s.Size {
1165 return nil, err
1166 }
1167
1168 if len(b) >= 12 && string(b[:4]) == "ZLIB" {
1169 dlen := binary.BigEndian.Uint64(b[4:12])
1170 dbuf := make([]byte, dlen)
1171 r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
1172 if err != nil {
1173 return nil, err
1174 }
1175 if _, err := io.ReadFull(r, dbuf); err != nil {
1176 return nil, err
1177 }
1178 if err := r.Close(); err != nil {
1179 return nil, err
1180 }
1181 b = dbuf
1182 }
1183
1184 for _, r := range f.Sections {
1185 if r.Type != SHT_RELA && r.Type != SHT_REL {
1186 continue
1187 }
1188 if int(r.Info) != i {
1189 continue
1190 }
1191 rd, err := r.Data()
1192 if err != nil {
1193 return nil, err
1194 }
1195 err = f.applyRelocations(b, rd)
1196 if err != nil {
1197 return nil, err
1198 }
1199 }
1200 return b, nil
1201 }
1202
1203
1204
1205 var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
1206 for i, s := range f.Sections {
1207 suffix := dwarfSuffix(s)
1208 if suffix == "" {
1209 continue
1210 }
1211 if _, ok := dat[suffix]; !ok {
1212 continue
1213 }
1214 b, err := sectionData(i, s)
1215 if err != nil {
1216 return nil, err
1217 }
1218 dat[suffix] = b
1219 }
1220
1221 d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
1222 if err != nil {
1223 return nil, err
1224 }
1225
1226
1227 for i, s := range f.Sections {
1228 suffix := dwarfSuffix(s)
1229 if suffix == "" {
1230 continue
1231 }
1232 if _, ok := dat[suffix]; ok {
1233
1234 continue
1235 }
1236
1237 b, err := sectionData(i, s)
1238 if err != nil {
1239 return nil, err
1240 }
1241
1242 if suffix == "types" {
1243 if err := d.AddTypes(fmt.Sprintf("types-%d", i), b); err != nil {
1244 return nil, err
1245 }
1246 } else {
1247 if err := d.AddSection(".debug_"+suffix, b); err != nil {
1248 return nil, err
1249 }
1250 }
1251 }
1252
1253 return d, nil
1254 }
1255
1256
1257
1258
1259
1260
1261
1262 func (f *File) Symbols() ([]Symbol, error) {
1263 sym, _, err := f.getSymbols(SHT_SYMTAB)
1264 return sym, err
1265 }
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276 func (f *File) DynamicSymbols() ([]Symbol, error) {
1277 sym, str, err := f.getSymbols(SHT_DYNSYM)
1278 if err != nil {
1279 return nil, err
1280 }
1281 if f.gnuVersionInit(str) {
1282 for i := range sym {
1283 sym[i].Library, sym[i].Version = f.gnuVersion(i)
1284 }
1285 }
1286 return sym, nil
1287 }
1288
1289 type ImportedSymbol struct {
1290 Name string
1291 Version string
1292 Library string
1293 }
1294
1295
1296
1297
1298
1299 func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
1300 sym, str, err := f.getSymbols(SHT_DYNSYM)
1301 if err != nil {
1302 return nil, err
1303 }
1304 f.gnuVersionInit(str)
1305 var all []ImportedSymbol
1306 for i, s := range sym {
1307 if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
1308 all = append(all, ImportedSymbol{Name: s.Name})
1309 sym := &all[len(all)-1]
1310 sym.Library, sym.Version = f.gnuVersion(i)
1311 }
1312 }
1313 return all, nil
1314 }
1315
1316 type verneed struct {
1317 File string
1318 Name string
1319 }
1320
1321
1322
1323 func (f *File) gnuVersionInit(str []byte) bool {
1324 if f.gnuNeed != nil {
1325
1326 return true
1327 }
1328
1329
1330 vn := f.SectionByType(SHT_GNU_VERNEED)
1331 if vn == nil {
1332 return false
1333 }
1334 d, _ := vn.Data()
1335
1336 var need []verneed
1337 i := 0
1338 for {
1339 if i+16 > len(d) {
1340 break
1341 }
1342 vers := f.ByteOrder.Uint16(d[i : i+2])
1343 if vers != 1 {
1344 break
1345 }
1346 cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
1347 fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
1348 aux := f.ByteOrder.Uint32(d[i+8 : i+12])
1349 next := f.ByteOrder.Uint32(d[i+12 : i+16])
1350 file, _ := getString(str, int(fileoff))
1351
1352 var name string
1353 j := i + int(aux)
1354 for c := 0; c < int(cnt); c++ {
1355 if j+16 > len(d) {
1356 break
1357 }
1358
1359
1360 other := f.ByteOrder.Uint16(d[j+6 : j+8])
1361 nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
1362 next := f.ByteOrder.Uint32(d[j+12 : j+16])
1363 name, _ = getString(str, int(nameoff))
1364 ndx := int(other)
1365 if ndx >= len(need) {
1366 a := make([]verneed, 2*(ndx+1))
1367 copy(a, need)
1368 need = a
1369 }
1370
1371 need[ndx] = verneed{file, name}
1372 if next == 0 {
1373 break
1374 }
1375 j += int(next)
1376 }
1377
1378 if next == 0 {
1379 break
1380 }
1381 i += int(next)
1382 }
1383
1384
1385 vs := f.SectionByType(SHT_GNU_VERSYM)
1386 if vs == nil {
1387 return false
1388 }
1389 d, _ = vs.Data()
1390
1391 f.gnuNeed = need
1392 f.gnuVersym = d
1393 return true
1394 }
1395
1396
1397
1398 func (f *File) gnuVersion(i int) (library string, version string) {
1399
1400 i = (i + 1) * 2
1401 if i >= len(f.gnuVersym) {
1402 return
1403 }
1404 j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
1405 if j < 2 || j >= len(f.gnuNeed) {
1406 return
1407 }
1408 n := &f.gnuNeed[j]
1409 return n.File, n.Name
1410 }
1411
1412
1413
1414
1415 func (f *File) ImportedLibraries() ([]string, error) {
1416 return f.DynString(DT_NEEDED)
1417 }
1418
1419
1420
1421
1422
1423
1424 func (f *File) DynString(tag DynTag) ([]string, error) {
1425 switch tag {
1426 case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
1427 default:
1428 return nil, fmt.Errorf("non-string-valued tag %v", tag)
1429 }
1430 ds := f.SectionByType(SHT_DYNAMIC)
1431 if ds == nil {
1432
1433 return nil, nil
1434 }
1435 d, err := ds.Data()
1436 if err != nil {
1437 return nil, err
1438 }
1439 str, err := f.stringTable(ds.Link)
1440 if err != nil {
1441 return nil, err
1442 }
1443 var all []string
1444 for len(d) > 0 {
1445 var t DynTag
1446 var v uint64
1447 switch f.Class {
1448 case ELFCLASS32:
1449 t = DynTag(f.ByteOrder.Uint32(d[0:4]))
1450 v = uint64(f.ByteOrder.Uint32(d[4:8]))
1451 d = d[8:]
1452 case ELFCLASS64:
1453 t = DynTag(f.ByteOrder.Uint64(d[0:8]))
1454 v = f.ByteOrder.Uint64(d[8:16])
1455 d = d[16:]
1456 }
1457 if t == tag {
1458 s, ok := getString(str, int(v))
1459 if ok {
1460 all = append(all, s)
1461 }
1462 }
1463 }
1464 return all, nil
1465 }
1466
View as plain text