github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/debug/elf/file.go (about)

     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  }