github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/debug/elf/file.go (about)

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