github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/debug/elf/file.go (about)

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