github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/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  	"debug/dwarf"
    11  	"encoding/binary"
    12  	"errors"
    13  	"fmt"
    14  	"io"
    15  	"os"
    16  )
    17  
    18  // TODO: error reporting detail
    19  
    20  /*
    21   * Internal ELF representation
    22   */
    23  
    24  // A FileHeader represents an ELF file header.
    25  type FileHeader struct {
    26  	Class      Class
    27  	Data       Data
    28  	Version    Version
    29  	OSABI      OSABI
    30  	ABIVersion uint8
    31  	ByteOrder  binary.ByteOrder
    32  	Type       Type
    33  	Machine    Machine
    34  	Entry      uint64
    35  }
    36  
    37  // A File represents an open ELF file.
    38  type File struct {
    39  	FileHeader
    40  	Sections  []*Section
    41  	Progs     []*Prog
    42  	closer    io.Closer
    43  	gnuNeed   []verneed
    44  	gnuVersym []byte
    45  }
    46  
    47  // A SectionHeader represents a single ELF section header.
    48  type SectionHeader struct {
    49  	Name      string
    50  	Type      SectionType
    51  	Flags     SectionFlag
    52  	Addr      uint64
    53  	Offset    uint64
    54  	Size      uint64
    55  	Link      uint32
    56  	Info      uint32
    57  	Addralign uint64
    58  	Entsize   uint64
    59  }
    60  
    61  // A Section represents a single section in an ELF file.
    62  type Section struct {
    63  	SectionHeader
    64  
    65  	// Embed ReaderAt for ReadAt method.
    66  	// Do not embed SectionReader directly
    67  	// to avoid having Read and Seek.
    68  	// If a client wants Read and Seek it must use
    69  	// Open() to avoid fighting over the seek offset
    70  	// with other clients.
    71  	io.ReaderAt
    72  	sr *io.SectionReader
    73  }
    74  
    75  // Data reads and returns the contents of the ELF section.
    76  func (s *Section) Data() ([]byte, error) {
    77  	dat := make([]byte, s.sr.Size())
    78  	n, err := s.sr.ReadAt(dat, 0)
    79  	if n == len(dat) {
    80  		err = nil
    81  	}
    82  	return dat[0:n], err
    83  }
    84  
    85  // stringTable reads and returns the string table given by the
    86  // specified link value.
    87  func (f *File) stringTable(link uint32) ([]byte, error) {
    88  	if link <= 0 || link >= uint32(len(f.Sections)) {
    89  		return nil, errors.New("section has invalid string table link")
    90  	}
    91  	return f.Sections[link].Data()
    92  }
    93  
    94  // Open returns a new ReadSeeker reading the ELF section.
    95  func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
    96  
    97  // A ProgHeader represents a single ELF program header.
    98  type ProgHeader struct {
    99  	Type   ProgType
   100  	Flags  ProgFlag
   101  	Off    uint64
   102  	Vaddr  uint64
   103  	Paddr  uint64
   104  	Filesz uint64
   105  	Memsz  uint64
   106  	Align  uint64
   107  }
   108  
   109  // A Prog represents a single ELF program header in an ELF binary.
   110  type Prog struct {
   111  	ProgHeader
   112  
   113  	// Embed ReaderAt for ReadAt method.
   114  	// Do not embed SectionReader directly
   115  	// to avoid having Read and Seek.
   116  	// If a client wants Read and Seek it must use
   117  	// Open() to avoid fighting over the seek offset
   118  	// with other clients.
   119  	io.ReaderAt
   120  	sr *io.SectionReader
   121  }
   122  
   123  // Open returns a new ReadSeeker reading the ELF program body.
   124  func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
   125  
   126  // A Symbol represents an entry in an ELF symbol table section.
   127  type Symbol struct {
   128  	Name        string
   129  	Info, Other byte
   130  	Section     SectionIndex
   131  	Value, Size uint64
   132  }
   133  
   134  /*
   135   * ELF reader
   136   */
   137  
   138  type FormatError struct {
   139  	off int64
   140  	msg string
   141  	val interface{}
   142  }
   143  
   144  func (e *FormatError) Error() string {
   145  	msg := e.msg
   146  	if e.val != nil {
   147  		msg += fmt.Sprintf(" '%v' ", e.val)
   148  	}
   149  	msg += fmt.Sprintf("in record at byte %#x", e.off)
   150  	return msg
   151  }
   152  
   153  // Open opens the named file using os.Open and prepares it for use as an ELF binary.
   154  func Open(name string) (*File, error) {
   155  	f, err := os.Open(name)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	ff, err := NewFile(f)
   160  	if err != nil {
   161  		f.Close()
   162  		return nil, err
   163  	}
   164  	ff.closer = f
   165  	return ff, nil
   166  }
   167  
   168  // Close closes the File.
   169  // If the File was created using NewFile directly instead of Open,
   170  // Close has no effect.
   171  func (f *File) Close() error {
   172  	var err error
   173  	if f.closer != nil {
   174  		err = f.closer.Close()
   175  		f.closer = nil
   176  	}
   177  	return err
   178  }
   179  
   180  // SectionByType returns the first section in f with the
   181  // given type, or nil if there is no such section.
   182  func (f *File) SectionByType(typ SectionType) *Section {
   183  	for _, s := range f.Sections {
   184  		if s.Type == typ {
   185  			return s
   186  		}
   187  	}
   188  	return nil
   189  }
   190  
   191  // NewFile creates a new File for accessing an ELF binary in an underlying reader.
   192  // The ELF binary is expected to start at position 0 in the ReaderAt.
   193  func NewFile(r io.ReaderAt) (*File, error) {
   194  	sr := io.NewSectionReader(r, 0, 1<<63-1)
   195  	// Read and decode ELF identifier
   196  	var ident [16]uint8
   197  	if _, err := r.ReadAt(ident[0:], 0); err != nil {
   198  		return nil, err
   199  	}
   200  	if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
   201  		return nil, &FormatError{0, "bad magic number", ident[0:4]}
   202  	}
   203  
   204  	f := new(File)
   205  	f.Class = Class(ident[EI_CLASS])
   206  	switch f.Class {
   207  	case ELFCLASS32:
   208  	case ELFCLASS64:
   209  		// ok
   210  	default:
   211  		return nil, &FormatError{0, "unknown ELF class", f.Class}
   212  	}
   213  
   214  	f.Data = Data(ident[EI_DATA])
   215  	switch f.Data {
   216  	case ELFDATA2LSB:
   217  		f.ByteOrder = binary.LittleEndian
   218  	case ELFDATA2MSB:
   219  		f.ByteOrder = binary.BigEndian
   220  	default:
   221  		return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
   222  	}
   223  
   224  	f.Version = Version(ident[EI_VERSION])
   225  	if f.Version != EV_CURRENT {
   226  		return nil, &FormatError{0, "unknown ELF version", f.Version}
   227  	}
   228  
   229  	f.OSABI = OSABI(ident[EI_OSABI])
   230  	f.ABIVersion = ident[EI_ABIVERSION]
   231  
   232  	// Read ELF file header
   233  	var phoff int64
   234  	var phentsize, phnum int
   235  	var shoff int64
   236  	var shentsize, shnum, shstrndx int
   237  	shstrndx = -1
   238  	switch f.Class {
   239  	case ELFCLASS32:
   240  		hdr := new(Header32)
   241  		sr.Seek(0, os.SEEK_SET)
   242  		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   243  			return nil, err
   244  		}
   245  		f.Type = Type(hdr.Type)
   246  		f.Machine = Machine(hdr.Machine)
   247  		f.Entry = uint64(hdr.Entry)
   248  		if v := Version(hdr.Version); v != f.Version {
   249  			return nil, &FormatError{0, "mismatched ELF version", v}
   250  		}
   251  		phoff = int64(hdr.Phoff)
   252  		phentsize = int(hdr.Phentsize)
   253  		phnum = int(hdr.Phnum)
   254  		shoff = int64(hdr.Shoff)
   255  		shentsize = int(hdr.Shentsize)
   256  		shnum = int(hdr.Shnum)
   257  		shstrndx = int(hdr.Shstrndx)
   258  	case ELFCLASS64:
   259  		hdr := new(Header64)
   260  		sr.Seek(0, os.SEEK_SET)
   261  		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   262  			return nil, err
   263  		}
   264  		f.Type = Type(hdr.Type)
   265  		f.Machine = Machine(hdr.Machine)
   266  		f.Entry = uint64(hdr.Entry)
   267  		if v := Version(hdr.Version); v != f.Version {
   268  			return nil, &FormatError{0, "mismatched ELF version", v}
   269  		}
   270  		phoff = int64(hdr.Phoff)
   271  		phentsize = int(hdr.Phentsize)
   272  		phnum = int(hdr.Phnum)
   273  		shoff = int64(hdr.Shoff)
   274  		shentsize = int(hdr.Shentsize)
   275  		shnum = int(hdr.Shnum)
   276  		shstrndx = int(hdr.Shstrndx)
   277  	}
   278  
   279  	if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) {
   280  		return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
   281  	}
   282  
   283  	// Read program headers
   284  	f.Progs = make([]*Prog, phnum)
   285  	for i := 0; i < phnum; i++ {
   286  		off := phoff + int64(i)*int64(phentsize)
   287  		sr.Seek(off, os.SEEK_SET)
   288  		p := new(Prog)
   289  		switch f.Class {
   290  		case ELFCLASS32:
   291  			ph := new(Prog32)
   292  			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   293  				return nil, err
   294  			}
   295  			p.ProgHeader = ProgHeader{
   296  				Type:   ProgType(ph.Type),
   297  				Flags:  ProgFlag(ph.Flags),
   298  				Off:    uint64(ph.Off),
   299  				Vaddr:  uint64(ph.Vaddr),
   300  				Paddr:  uint64(ph.Paddr),
   301  				Filesz: uint64(ph.Filesz),
   302  				Memsz:  uint64(ph.Memsz),
   303  				Align:  uint64(ph.Align),
   304  			}
   305  		case ELFCLASS64:
   306  			ph := new(Prog64)
   307  			if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   308  				return nil, err
   309  			}
   310  			p.ProgHeader = ProgHeader{
   311  				Type:   ProgType(ph.Type),
   312  				Flags:  ProgFlag(ph.Flags),
   313  				Off:    uint64(ph.Off),
   314  				Vaddr:  uint64(ph.Vaddr),
   315  				Paddr:  uint64(ph.Paddr),
   316  				Filesz: uint64(ph.Filesz),
   317  				Memsz:  uint64(ph.Memsz),
   318  				Align:  uint64(ph.Align),
   319  			}
   320  		}
   321  		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
   322  		p.ReaderAt = p.sr
   323  		f.Progs[i] = p
   324  	}
   325  
   326  	// Read section headers
   327  	f.Sections = make([]*Section, shnum)
   328  	names := make([]uint32, shnum)
   329  	for i := 0; i < shnum; i++ {
   330  		off := shoff + int64(i)*int64(shentsize)
   331  		sr.Seek(off, os.SEEK_SET)
   332  		s := new(Section)
   333  		switch f.Class {
   334  		case ELFCLASS32:
   335  			sh := new(Section32)
   336  			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   337  				return nil, err
   338  			}
   339  			names[i] = sh.Name
   340  			s.SectionHeader = SectionHeader{
   341  				Type:      SectionType(sh.Type),
   342  				Flags:     SectionFlag(sh.Flags),
   343  				Addr:      uint64(sh.Addr),
   344  				Offset:    uint64(sh.Off),
   345  				Size:      uint64(sh.Size),
   346  				Link:      uint32(sh.Link),
   347  				Info:      uint32(sh.Info),
   348  				Addralign: uint64(sh.Addralign),
   349  				Entsize:   uint64(sh.Entsize),
   350  			}
   351  		case ELFCLASS64:
   352  			sh := new(Section64)
   353  			if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   354  				return nil, err
   355  			}
   356  			names[i] = sh.Name
   357  			s.SectionHeader = SectionHeader{
   358  				Type:      SectionType(sh.Type),
   359  				Flags:     SectionFlag(sh.Flags),
   360  				Offset:    uint64(sh.Off),
   361  				Size:      uint64(sh.Size),
   362  				Addr:      uint64(sh.Addr),
   363  				Link:      uint32(sh.Link),
   364  				Info:      uint32(sh.Info),
   365  				Addralign: uint64(sh.Addralign),
   366  				Entsize:   uint64(sh.Entsize),
   367  			}
   368  		}
   369  		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
   370  		s.ReaderAt = s.sr
   371  		f.Sections[i] = s
   372  	}
   373  
   374  	if len(f.Sections) == 0 {
   375  		return f, nil
   376  	}
   377  
   378  	// Load section header string table.
   379  	shstrtab, err := f.Sections[shstrndx].Data()
   380  	if err != nil {
   381  		return nil, err
   382  	}
   383  	for i, s := range f.Sections {
   384  		var ok bool
   385  		s.Name, ok = getString(shstrtab, int(names[i]))
   386  		if !ok {
   387  			return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
   388  		}
   389  	}
   390  
   391  	return f, nil
   392  }
   393  
   394  // getSymbols returns a slice of Symbols from parsing the symbol table
   395  // with the given type, along with the associated string table.
   396  func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
   397  	switch f.Class {
   398  	case ELFCLASS64:
   399  		return f.getSymbols64(typ)
   400  
   401  	case ELFCLASS32:
   402  		return f.getSymbols32(typ)
   403  	}
   404  
   405  	return nil, nil, errors.New("not implemented")
   406  }
   407  
   408  func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
   409  	symtabSection := f.SectionByType(typ)
   410  	if symtabSection == nil {
   411  		return nil, nil, errors.New("no symbol section")
   412  	}
   413  
   414  	data, err := symtabSection.Data()
   415  	if err != nil {
   416  		return nil, nil, errors.New("cannot load symbol section")
   417  	}
   418  	symtab := bytes.NewReader(data)
   419  	if symtab.Len()%Sym32Size != 0 {
   420  		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
   421  	}
   422  
   423  	strdata, err := f.stringTable(symtabSection.Link)
   424  	if err != nil {
   425  		return nil, nil, errors.New("cannot load string table section")
   426  	}
   427  
   428  	// The first entry is all zeros.
   429  	var skip [Sym32Size]byte
   430  	symtab.Read(skip[:])
   431  
   432  	symbols := make([]Symbol, symtab.Len()/Sym32Size)
   433  
   434  	i := 0
   435  	var sym Sym32
   436  	for symtab.Len() > 0 {
   437  		binary.Read(symtab, f.ByteOrder, &sym)
   438  		str, _ := getString(strdata, int(sym.Name))
   439  		symbols[i].Name = str
   440  		symbols[i].Info = sym.Info
   441  		symbols[i].Other = sym.Other
   442  		symbols[i].Section = SectionIndex(sym.Shndx)
   443  		symbols[i].Value = uint64(sym.Value)
   444  		symbols[i].Size = uint64(sym.Size)
   445  		i++
   446  	}
   447  
   448  	return symbols, strdata, nil
   449  }
   450  
   451  func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
   452  	symtabSection := f.SectionByType(typ)
   453  	if symtabSection == nil {
   454  		return nil, nil, errors.New("no symbol section")
   455  	}
   456  
   457  	data, err := symtabSection.Data()
   458  	if err != nil {
   459  		return nil, nil, errors.New("cannot load symbol section")
   460  	}
   461  	symtab := bytes.NewReader(data)
   462  	if symtab.Len()%Sym64Size != 0 {
   463  		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
   464  	}
   465  
   466  	strdata, err := f.stringTable(symtabSection.Link)
   467  	if err != nil {
   468  		return nil, nil, errors.New("cannot load string table section")
   469  	}
   470  
   471  	// The first entry is all zeros.
   472  	var skip [Sym64Size]byte
   473  	symtab.Read(skip[:])
   474  
   475  	symbols := make([]Symbol, symtab.Len()/Sym64Size)
   476  
   477  	i := 0
   478  	var sym Sym64
   479  	for symtab.Len() > 0 {
   480  		binary.Read(symtab, f.ByteOrder, &sym)
   481  		str, _ := getString(strdata, int(sym.Name))
   482  		symbols[i].Name = str
   483  		symbols[i].Info = sym.Info
   484  		symbols[i].Other = sym.Other
   485  		symbols[i].Section = SectionIndex(sym.Shndx)
   486  		symbols[i].Value = sym.Value
   487  		symbols[i].Size = sym.Size
   488  		i++
   489  	}
   490  
   491  	return symbols, strdata, nil
   492  }
   493  
   494  // getString extracts a string from an ELF string table.
   495  func getString(section []byte, start int) (string, bool) {
   496  	if start < 0 || start >= len(section) {
   497  		return "", false
   498  	}
   499  
   500  	for end := start; end < len(section); end++ {
   501  		if section[end] == 0 {
   502  			return string(section[start:end]), true
   503  		}
   504  	}
   505  	return "", false
   506  }
   507  
   508  // Section returns a section with the given name, or nil if no such
   509  // section exists.
   510  func (f *File) Section(name string) *Section {
   511  	for _, s := range f.Sections {
   512  		if s.Name == name {
   513  			return s
   514  		}
   515  	}
   516  	return nil
   517  }
   518  
   519  // applyRelocations applies relocations to dst. rels is a relocations section
   520  // in RELA format.
   521  func (f *File) applyRelocations(dst []byte, rels []byte) error {
   522  	if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
   523  		return f.applyRelocationsAMD64(dst, rels)
   524  	}
   525  	if f.Class == ELFCLASS32 && f.Machine == EM_386 {
   526  		return f.applyRelocations386(dst, rels)
   527  	}
   528  
   529  	return errors.New("not implemented")
   530  }
   531  
   532  func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
   533  	// 24 is the size of Rela64.
   534  	if len(rels)%24 != 0 {
   535  		return errors.New("length of relocation section is not a multiple of 24")
   536  	}
   537  
   538  	symbols, _, err := f.getSymbols(SHT_SYMTAB)
   539  	if err != nil {
   540  		return err
   541  	}
   542  
   543  	b := bytes.NewReader(rels)
   544  	var rela Rela64
   545  
   546  	for b.Len() > 0 {
   547  		binary.Read(b, f.ByteOrder, &rela)
   548  		symNo := rela.Info >> 32
   549  		t := R_X86_64(rela.Info & 0xffff)
   550  
   551  		if symNo == 0 || symNo > uint64(len(symbols)) {
   552  			continue
   553  		}
   554  		sym := &symbols[symNo-1]
   555  		if SymType(sym.Info&0xf) != STT_SECTION {
   556  			// We don't handle non-section relocations for now.
   557  			continue
   558  		}
   559  
   560  		switch t {
   561  		case R_X86_64_64:
   562  			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   563  				continue
   564  			}
   565  			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   566  		case R_X86_64_32:
   567  			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   568  				continue
   569  			}
   570  			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   571  		}
   572  	}
   573  
   574  	return nil
   575  }
   576  
   577  func (f *File) applyRelocations386(dst []byte, rels []byte) error {
   578  	// 8 is the size of Rel32.
   579  	if len(rels)%8 != 0 {
   580  		return errors.New("length of relocation section is not a multiple of 8")
   581  	}
   582  
   583  	symbols, _, err := f.getSymbols(SHT_SYMTAB)
   584  	if err != nil {
   585  		return err
   586  	}
   587  
   588  	b := bytes.NewReader(rels)
   589  	var rel Rel32
   590  
   591  	for b.Len() > 0 {
   592  		binary.Read(b, f.ByteOrder, &rel)
   593  		symNo := rel.Info >> 8
   594  		t := R_386(rel.Info & 0xff)
   595  
   596  		if symNo == 0 || symNo > uint32(len(symbols)) {
   597  			continue
   598  		}
   599  		sym := &symbols[symNo-1]
   600  
   601  		if t == R_386_32 {
   602  			if rel.Off+4 >= uint32(len(dst)) {
   603  				continue
   604  			}
   605  			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
   606  			val += uint32(sym.Value)
   607  			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
   608  		}
   609  	}
   610  
   611  	return nil
   612  }
   613  
   614  func (f *File) DWARF() (*dwarf.Data, error) {
   615  	// There are many other DWARF sections, but these
   616  	// are the required ones, and the debug/dwarf package
   617  	// does not use the others, so don't bother loading them.
   618  	var names = [...]string{"abbrev", "info", "str"}
   619  	var dat [len(names)][]byte
   620  	for i, name := range names {
   621  		name = ".debug_" + name
   622  		s := f.Section(name)
   623  		if s == nil {
   624  			continue
   625  		}
   626  		b, err := s.Data()
   627  		if err != nil && uint64(len(b)) < s.Size {
   628  			return nil, err
   629  		}
   630  		dat[i] = b
   631  	}
   632  
   633  	// If there's a relocation table for .debug_info, we have to process it
   634  	// now otherwise the data in .debug_info is invalid for x86-64 objects.
   635  	rela := f.Section(".rela.debug_info")
   636  	if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
   637  		data, err := rela.Data()
   638  		if err != nil {
   639  			return nil, err
   640  		}
   641  		err = f.applyRelocations(dat[1], data)
   642  		if err != nil {
   643  			return nil, err
   644  		}
   645  	}
   646  
   647  	// When using clang we need to process relocations even for 386.
   648  	rel := f.Section(".rel.debug_info")
   649  	if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 {
   650  		data, err := rel.Data()
   651  		if err != nil {
   652  			return nil, err
   653  		}
   654  		err = f.applyRelocations(dat[1], data)
   655  		if err != nil {
   656  			return nil, err
   657  		}
   658  	}
   659  
   660  	abbrev, info, str := dat[0], dat[1], dat[2]
   661  	d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
   662  	if err != nil {
   663  		return nil, err
   664  	}
   665  
   666  	// Look for DWARF4 .debug_types sections.
   667  	for i, s := range f.Sections {
   668  		if s.Name == ".debug_types" {
   669  			b, err := s.Data()
   670  			if err != nil && uint64(len(b)) < s.Size {
   671  				return nil, err
   672  			}
   673  
   674  			for _, r := range f.Sections {
   675  				if r.Type != SHT_RELA && r.Type != SHT_REL {
   676  					continue
   677  				}
   678  				if int(r.Info) != i {
   679  					continue
   680  				}
   681  				rd, err := r.Data()
   682  				if err != nil {
   683  					return nil, err
   684  				}
   685  				err = f.applyRelocations(b, rd)
   686  				if err != nil {
   687  					return nil, err
   688  				}
   689  			}
   690  
   691  			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
   692  			if err != nil {
   693  				return nil, err
   694  			}
   695  		}
   696  	}
   697  
   698  	return d, nil
   699  }
   700  
   701  // Symbols returns the symbol table for f.
   702  //
   703  // For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
   704  // After retrieving the symbols as symtab, an externally supplied index x
   705  // corresponds to symtab[x-1], not symtab[x].
   706  func (f *File) Symbols() ([]Symbol, error) {
   707  	sym, _, err := f.getSymbols(SHT_SYMTAB)
   708  	return sym, err
   709  }
   710  
   711  type ImportedSymbol struct {
   712  	Name    string
   713  	Version string
   714  	Library string
   715  }
   716  
   717  // ImportedSymbols returns the names of all symbols
   718  // referred to by the binary f that are expected to be
   719  // satisfied by other libraries at dynamic load time.
   720  // It does not return weak symbols.
   721  func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
   722  	sym, str, err := f.getSymbols(SHT_DYNSYM)
   723  	if err != nil {
   724  		return nil, err
   725  	}
   726  	f.gnuVersionInit(str)
   727  	var all []ImportedSymbol
   728  	for i, s := range sym {
   729  		if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
   730  			all = append(all, ImportedSymbol{Name: s.Name})
   731  			f.gnuVersion(i, &all[len(all)-1])
   732  		}
   733  	}
   734  	return all, nil
   735  }
   736  
   737  type verneed struct {
   738  	File string
   739  	Name string
   740  }
   741  
   742  // gnuVersionInit parses the GNU version tables
   743  // for use by calls to gnuVersion.
   744  func (f *File) gnuVersionInit(str []byte) {
   745  	// Accumulate verneed information.
   746  	vn := f.SectionByType(SHT_GNU_VERNEED)
   747  	if vn == nil {
   748  		return
   749  	}
   750  	d, _ := vn.Data()
   751  
   752  	var need []verneed
   753  	i := 0
   754  	for {
   755  		if i+16 > len(d) {
   756  			break
   757  		}
   758  		vers := f.ByteOrder.Uint16(d[i : i+2])
   759  		if vers != 1 {
   760  			break
   761  		}
   762  		cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
   763  		fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
   764  		aux := f.ByteOrder.Uint32(d[i+8 : i+12])
   765  		next := f.ByteOrder.Uint32(d[i+12 : i+16])
   766  		file, _ := getString(str, int(fileoff))
   767  
   768  		var name string
   769  		j := i + int(aux)
   770  		for c := 0; c < int(cnt); c++ {
   771  			if j+16 > len(d) {
   772  				break
   773  			}
   774  			// hash := f.ByteOrder.Uint32(d[j:j+4])
   775  			// flags := f.ByteOrder.Uint16(d[j+4:j+6])
   776  			other := f.ByteOrder.Uint16(d[j+6 : j+8])
   777  			nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
   778  			next := f.ByteOrder.Uint32(d[j+12 : j+16])
   779  			name, _ = getString(str, int(nameoff))
   780  			ndx := int(other)
   781  			if ndx >= len(need) {
   782  				a := make([]verneed, 2*(ndx+1))
   783  				copy(a, need)
   784  				need = a
   785  			}
   786  
   787  			need[ndx] = verneed{file, name}
   788  			if next == 0 {
   789  				break
   790  			}
   791  			j += int(next)
   792  		}
   793  
   794  		if next == 0 {
   795  			break
   796  		}
   797  		i += int(next)
   798  	}
   799  
   800  	// Versym parallels symbol table, indexing into verneed.
   801  	vs := f.SectionByType(SHT_GNU_VERSYM)
   802  	if vs == nil {
   803  		return
   804  	}
   805  	d, _ = vs.Data()
   806  
   807  	f.gnuNeed = need
   808  	f.gnuVersym = d
   809  }
   810  
   811  // gnuVersion adds Library and Version information to sym,
   812  // which came from offset i of the symbol table.
   813  func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
   814  	// Each entry is two bytes.
   815  	i = (i + 1) * 2
   816  	if i >= len(f.gnuVersym) {
   817  		return
   818  	}
   819  	j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
   820  	if j < 2 || j >= len(f.gnuNeed) {
   821  		return
   822  	}
   823  	n := &f.gnuNeed[j]
   824  	sym.Library = n.File
   825  	sym.Version = n.Name
   826  }
   827  
   828  // ImportedLibraries returns the names of all libraries
   829  // referred to by the binary f that are expected to be
   830  // linked with the binary at dynamic link time.
   831  func (f *File) ImportedLibraries() ([]string, error) {
   832  	return f.DynString(DT_NEEDED)
   833  }
   834  
   835  // DynString returns the strings listed for the given tag in the file's dynamic
   836  // section.
   837  //
   838  // The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
   839  // DT_RUNPATH.
   840  func (f *File) DynString(tag DynTag) ([]string, error) {
   841  	switch tag {
   842  	case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
   843  	default:
   844  		return nil, fmt.Errorf("non-string-valued tag %v", tag)
   845  	}
   846  	ds := f.SectionByType(SHT_DYNAMIC)
   847  	if ds == nil {
   848  		// not dynamic, so no libraries
   849  		return nil, nil
   850  	}
   851  	d, err := ds.Data()
   852  	if err != nil {
   853  		return nil, err
   854  	}
   855  	str, err := f.stringTable(ds.Link)
   856  	if err != nil {
   857  		return nil, err
   858  	}
   859  	var all []string
   860  	for len(d) > 0 {
   861  		var t DynTag
   862  		var v uint64
   863  		switch f.Class {
   864  		case ELFCLASS32:
   865  			t = DynTag(f.ByteOrder.Uint32(d[0:4]))
   866  			v = uint64(f.ByteOrder.Uint32(d[4:8]))
   867  			d = d[8:]
   868  		case ELFCLASS64:
   869  			t = DynTag(f.ByteOrder.Uint64(d[0:8]))
   870  			v = f.ByteOrder.Uint64(d[8:16])
   871  			d = d[16:]
   872  		}
   873  		if t == tag {
   874  			s, ok := getString(str, int(v))
   875  			if ok {
   876  				all = append(all, s)
   877  			}
   878  		}
   879  	}
   880  	return all, nil
   881  }