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

View as plain text