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

View as plain text