...

Source file src/debug/elf/file.go

Documentation: debug/elf

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

View as plain text