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

View as plain text