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