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

View as plain text