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

View as plain text