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