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