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