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

View as plain text