...

Source file src/debug/elf/file.go

Documentation: debug/elf

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

View as plain text