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

View as plain text