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