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