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

View as plain text