...
Run Format

Source file src/debug/elf/file.go

Documentation: debug/elf

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

View as plain text