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