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