Black Lives Matter. Support the Equal Justice Initiative.

Source file src/debug/elf/file.go

Documentation: debug/elf

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

View as plain text