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