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