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