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

View as plain text