Black Lives Matter. Support the Equal Justice Initiative.

Source file src/debug/elf/file.go

Documentation: debug/elf

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

View as plain text