Source file src/debug/elf/file.go

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

View as plain text