Source file src/debug/elf/file.go

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

View as plain text