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