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