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