...

Source file src/pkg/debug/elf/file.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Package elf implements access to ELF object files.
     6	package elf
     7	
     8	import (
     9		"bytes"
    10		"compress/zlib"
    11		"debug/dwarf"
    12		"encoding/binary"
    13		"errors"
    14		"fmt"
    15		"io"
    16		"os"
    17		"strings"
    18	)
    19	
    20	// seekStart, seekCurrent, seekEnd are copies of
    21	// io.SeekStart, io.SeekCurrent, and io.SeekEnd.
    22	// We can't use the ones from package io because
    23	// we want this code to build with Go 1.4 during
    24	// cmd/dist bootstrap.
    25	const (
    26		seekStart   int = 0
    27		seekCurrent int = 1
    28		seekEnd     int = 2
    29	)
    30	
    31	// TODO: error reporting detail
    32	
    33	/*
    34	 * Internal ELF representation
    35	 */
    36	
    37	// A FileHeader represents an ELF file header.
    38	type FileHeader struct {
    39		Class      Class
    40		Data       Data
    41		Version    Version
    42		OSABI      OSABI
    43		ABIVersion uint8
    44		ByteOrder  binary.ByteOrder
    45		Type       Type
    46		Machine    Machine
    47		Entry      uint64
    48	}
    49	
    50	// A File represents an open ELF file.
    51	type File struct {
    52		FileHeader
    53		Sections  []*Section
    54		Progs     []*Prog
    55		closer    io.Closer
    56		gnuNeed   []verneed
    57		gnuVersym []byte
    58	}
    59	
    60	// A SectionHeader represents a single ELF section header.
    61	type SectionHeader struct {
    62		Name      string
    63		Type      SectionType
    64		Flags     SectionFlag
    65		Addr      uint64
    66		Offset    uint64
    67		Size      uint64
    68		Link      uint32
    69		Info      uint32
    70		Addralign uint64
    71		Entsize   uint64
    72	
    73		// FileSize is the size of this section in the file in bytes.
    74		// If a section is compressed, FileSize is the size of the
    75		// compressed data, while Size (above) is the size of the
    76		// uncompressed data.
    77		FileSize uint64
    78	}
    79	
    80	// A Section represents a single section in an ELF file.
    81	type Section struct {
    82		SectionHeader
    83	
    84		// Embed ReaderAt for ReadAt method.
    85		// Do not embed SectionReader directly
    86		// to avoid having Read and Seek.
    87		// If a client wants Read and Seek it must use
    88		// Open() to avoid fighting over the seek offset
    89		// with other clients.
    90		//
    91		// ReaderAt may be nil if the section is not easily available
    92		// in a random-access form. For example, a compressed section
    93		// may have a nil ReaderAt.
    94		io.ReaderAt
    95		sr *io.SectionReader
    96	
    97		compressionType   CompressionType
    98		compressionOffset int64
    99	}
   100	
   101	// Data reads and returns the contents of the ELF section.
   102	// Even if the section is stored compressed in the ELF file,
   103	// Data returns uncompressed data.
   104	func (s *Section) Data() ([]byte, error) {
   105		dat := make([]byte, s.Size)
   106		n, err := io.ReadFull(s.Open(), dat)
   107		return dat[0:n], err
   108	}
   109	
   110	// stringTable reads and returns the string table given by the
   111	// specified link value.
   112	func (f *File) stringTable(link uint32) ([]byte, error) {
   113		if link <= 0 || link >= uint32(len(f.Sections)) {
   114			return nil, errors.New("section has invalid string table link")
   115		}
   116		return f.Sections[link].Data()
   117	}
   118	
   119	// Open returns a new ReadSeeker reading the ELF section.
   120	// Even if the section is stored compressed in the ELF file,
   121	// the ReadSeeker reads uncompressed data.
   122	func (s *Section) Open() io.ReadSeeker {
   123		if s.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	func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
   632		// 24 is the size of Rela64.
   633		if len(rels)%24 != 0 {
   634			return errors.New("length of relocation section is not a multiple of 24")
   635		}
   636	
   637		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   638		if err != nil {
   639			return err
   640		}
   641	
   642		b := bytes.NewReader(rels)
   643		var rela Rela64
   644	
   645		for b.Len() > 0 {
   646			binary.Read(b, f.ByteOrder, &rela)
   647			symNo := rela.Info >> 32
   648			t := R_X86_64(rela.Info & 0xffff)
   649	
   650			if symNo == 0 || symNo > uint64(len(symbols)) {
   651				continue
   652			}
   653			sym := &symbols[symNo-1]
   654			if SymType(sym.Info&0xf) != STT_SECTION {
   655				// We don't handle non-section relocations for now.
   656				continue
   657			}
   658	
   659			// There are relocations, so this must be a normal
   660			// object file, and we only look at section symbols,
   661			// so we assume that the symbol value is 0.
   662	
   663			switch t {
   664			case R_X86_64_64:
   665				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   666					continue
   667				}
   668				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   669			case R_X86_64_32:
   670				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   671					continue
   672				}
   673				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   674			}
   675		}
   676	
   677		return nil
   678	}
   679	
   680	func (f *File) applyRelocations386(dst []byte, rels []byte) error {
   681		// 8 is the size of Rel32.
   682		if len(rels)%8 != 0 {
   683			return errors.New("length of relocation section is not a multiple of 8")
   684		}
   685	
   686		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   687		if err != nil {
   688			return err
   689		}
   690	
   691		b := bytes.NewReader(rels)
   692		var rel Rel32
   693	
   694		for b.Len() > 0 {
   695			binary.Read(b, f.ByteOrder, &rel)
   696			symNo := rel.Info >> 8
   697			t := R_386(rel.Info & 0xff)
   698	
   699			if symNo == 0 || symNo > uint32(len(symbols)) {
   700				continue
   701			}
   702			sym := &symbols[symNo-1]
   703	
   704			if t == R_386_32 {
   705				if rel.Off+4 >= uint32(len(dst)) {
   706					continue
   707				}
   708				val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
   709				val += uint32(sym.Value)
   710				f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
   711			}
   712		}
   713	
   714		return nil
   715	}
   716	
   717	func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
   718		// 8 is the size of Rel32.
   719		if len(rels)%8 != 0 {
   720			return errors.New("length of relocation section is not a multiple of 8")
   721		}
   722	
   723		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   724		if err != nil {
   725			return err
   726		}
   727	
   728		b := bytes.NewReader(rels)
   729		var rel Rel32
   730	
   731		for b.Len() > 0 {
   732			binary.Read(b, f.ByteOrder, &rel)
   733			symNo := rel.Info >> 8
   734			t := R_ARM(rel.Info & 0xff)
   735	
   736			if symNo == 0 || symNo > uint32(len(symbols)) {
   737				continue
   738			}
   739			sym := &symbols[symNo-1]
   740	
   741			switch t {
   742			case R_ARM_ABS32:
   743				if rel.Off+4 >= uint32(len(dst)) {
   744					continue
   745				}
   746				val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
   747				val += uint32(sym.Value)
   748				f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
   749			}
   750		}
   751	
   752		return nil
   753	}
   754	
   755	func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
   756		// 24 is the size of Rela64.
   757		if len(rels)%24 != 0 {
   758			return errors.New("length of relocation section is not a multiple of 24")
   759		}
   760	
   761		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   762		if err != nil {
   763			return err
   764		}
   765	
   766		b := bytes.NewReader(rels)
   767		var rela Rela64
   768	
   769		for b.Len() > 0 {
   770			binary.Read(b, f.ByteOrder, &rela)
   771			symNo := rela.Info >> 32
   772			t := R_AARCH64(rela.Info & 0xffff)
   773	
   774			if symNo == 0 || symNo > uint64(len(symbols)) {
   775				continue
   776			}
   777			sym := &symbols[symNo-1]
   778			if SymType(sym.Info&0xf) != STT_SECTION {
   779				// We don't handle non-section relocations for now.
   780				continue
   781			}
   782	
   783			// There are relocations, so this must be a normal
   784			// object file, and we only look at section symbols,
   785			// so we assume that the symbol value is 0.
   786	
   787			switch t {
   788			case R_AARCH64_ABS64:
   789				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   790					continue
   791				}
   792				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   793			case R_AARCH64_ABS32:
   794				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   795					continue
   796				}
   797				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   798			}
   799		}
   800	
   801		return nil
   802	}
   803	
   804	func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
   805		// 12 is the size of Rela32.
   806		if len(rels)%12 != 0 {
   807			return errors.New("length of relocation section is not a multiple of 12")
   808		}
   809	
   810		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   811		if err != nil {
   812			return err
   813		}
   814	
   815		b := bytes.NewReader(rels)
   816		var rela Rela32
   817	
   818		for b.Len() > 0 {
   819			binary.Read(b, f.ByteOrder, &rela)
   820			symNo := rela.Info >> 8
   821			t := R_PPC(rela.Info & 0xff)
   822	
   823			if symNo == 0 || symNo > uint32(len(symbols)) {
   824				continue
   825			}
   826			sym := &symbols[symNo-1]
   827			if SymType(sym.Info&0xf) != STT_SECTION {
   828				// We don't handle non-section relocations for now.
   829				continue
   830			}
   831	
   832			switch t {
   833			case R_PPC_ADDR32:
   834				if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
   835					continue
   836				}
   837				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   838			}
   839		}
   840	
   841		return nil
   842	}
   843	
   844	func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
   845		// 24 is the size of Rela64.
   846		if len(rels)%24 != 0 {
   847			return errors.New("length of relocation section is not a multiple of 24")
   848		}
   849	
   850		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   851		if err != nil {
   852			return err
   853		}
   854	
   855		b := bytes.NewReader(rels)
   856		var rela Rela64
   857	
   858		for b.Len() > 0 {
   859			binary.Read(b, f.ByteOrder, &rela)
   860			symNo := rela.Info >> 32
   861			t := R_PPC64(rela.Info & 0xffff)
   862	
   863			if symNo == 0 || symNo > uint64(len(symbols)) {
   864				continue
   865			}
   866			sym := &symbols[symNo-1]
   867			if SymType(sym.Info&0xf) != STT_SECTION {
   868				// We don't handle non-section relocations for now.
   869				continue
   870			}
   871	
   872			switch t {
   873			case R_PPC64_ADDR64:
   874				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   875					continue
   876				}
   877				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   878			case R_PPC64_ADDR32:
   879				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   880					continue
   881				}
   882				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   883			}
   884		}
   885	
   886		return nil
   887	}
   888	
   889	func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
   890		// 8 is the size of Rel32.
   891		if len(rels)%8 != 0 {
   892			return errors.New("length of relocation section is not a multiple of 8")
   893		}
   894	
   895		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   896		if err != nil {
   897			return err
   898		}
   899	
   900		b := bytes.NewReader(rels)
   901		var rel Rel32
   902	
   903		for b.Len() > 0 {
   904			binary.Read(b, f.ByteOrder, &rel)
   905			symNo := rel.Info >> 8
   906			t := R_MIPS(rel.Info & 0xff)
   907	
   908			if symNo == 0 || symNo > uint32(len(symbols)) {
   909				continue
   910			}
   911			sym := &symbols[symNo-1]
   912	
   913			switch t {
   914			case R_MIPS_32:
   915				if rel.Off+4 >= uint32(len(dst)) {
   916					continue
   917				}
   918				val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
   919				val += uint32(sym.Value)
   920				f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
   921			}
   922		}
   923	
   924		return nil
   925	}
   926	
   927	func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
   928		// 24 is the size of Rela64.
   929		if len(rels)%24 != 0 {
   930			return errors.New("length of relocation section is not a multiple of 24")
   931		}
   932	
   933		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   934		if err != nil {
   935			return err
   936		}
   937	
   938		b := bytes.NewReader(rels)
   939		var rela Rela64
   940	
   941		for b.Len() > 0 {
   942			binary.Read(b, f.ByteOrder, &rela)
   943			var symNo uint64
   944			var t R_MIPS
   945			if f.ByteOrder == binary.BigEndian {
   946				symNo = rela.Info >> 32
   947				t = R_MIPS(rela.Info & 0xff)
   948			} else {
   949				symNo = rela.Info & 0xffffffff
   950				t = R_MIPS(rela.Info >> 56)
   951			}
   952	
   953			if symNo == 0 || symNo > uint64(len(symbols)) {
   954				continue
   955			}
   956			sym := &symbols[symNo-1]
   957			if SymType(sym.Info&0xf) != STT_SECTION {
   958				// We don't handle non-section relocations for now.
   959				continue
   960			}
   961	
   962			switch t {
   963			case R_MIPS_64:
   964				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   965					continue
   966				}
   967				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   968			case R_MIPS_32:
   969				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   970					continue
   971				}
   972				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   973			}
   974		}
   975	
   976		return nil
   977	}
   978	
   979	func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
   980		// 24 is the size of Rela64.
   981		if len(rels)%24 != 0 {
   982			return errors.New("length of relocation section is not a multiple of 24")
   983		}
   984	
   985		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   986		if err != nil {
   987			return err
   988		}
   989	
   990		b := bytes.NewReader(rels)
   991		var rela Rela64
   992	
   993		for b.Len() > 0 {
   994			binary.Read(b, f.ByteOrder, &rela)
   995			symNo := rela.Info >> 32
   996			t := R_RISCV(rela.Info & 0xffff)
   997	
   998			if symNo == 0 || symNo > uint64(len(symbols)) {
   999				continue
  1000			}
  1001			sym := &symbols[symNo-1]
  1002			switch SymType(sym.Info & 0xf) {
  1003			case STT_SECTION, STT_NOTYPE:
  1004				break
  1005			default:
  1006				continue
  1007			}
  1008	
  1009			switch t {
  1010			case R_RISCV_64:
  1011				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
  1012					continue
  1013				}
  1014				val := sym.Value + uint64(rela.Addend)
  1015				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
  1016			case R_RISCV_32:
  1017				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
  1018					continue
  1019				}
  1020				val := uint32(sym.Value) + uint32(rela.Addend)
  1021				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
  1022			}
  1023		}
  1024	
  1025		return nil
  1026	}
  1027	
  1028	func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
  1029		// 24 is the size of Rela64.
  1030		if len(rels)%24 != 0 {
  1031			return errors.New("length of relocation section is not a multiple of 24")
  1032		}
  1033	
  1034		symbols, _, err := f.getSymbols(SHT_SYMTAB)
  1035		if err != nil {
  1036			return err
  1037		}
  1038	
  1039		b := bytes.NewReader(rels)
  1040		var rela Rela64
  1041	
  1042		for b.Len() > 0 {
  1043			binary.Read(b, f.ByteOrder, &rela)
  1044			symNo := rela.Info >> 32
  1045			t := R_390(rela.Info & 0xffff)
  1046	
  1047			if symNo == 0 || symNo > uint64(len(symbols)) {
  1048				continue
  1049			}
  1050			sym := &symbols[symNo-1]
  1051			switch SymType(sym.Info & 0xf) {
  1052			case STT_SECTION, STT_NOTYPE:
  1053				break
  1054			default:
  1055				continue
  1056			}
  1057	
  1058			switch t {
  1059			case R_390_64:
  1060				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
  1061					continue
  1062				}
  1063				val := sym.Value + uint64(rela.Addend)
  1064				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
  1065			case R_390_32:
  1066				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
  1067					continue
  1068				}
  1069				val := uint32(sym.Value) + uint32(rela.Addend)
  1070				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
  1071			}
  1072		}
  1073	
  1074		return nil
  1075	}
  1076	
  1077	func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
  1078		// 24 is the size of Rela64.
  1079		if len(rels)%24 != 0 {
  1080			return errors.New("length of relocation section is not a multiple of 24")
  1081		}
  1082	
  1083		symbols, _, err := f.getSymbols(SHT_SYMTAB)
  1084		if err != nil {
  1085			return err
  1086		}
  1087	
  1088		b := bytes.NewReader(rels)
  1089		var rela Rela64
  1090	
  1091		for b.Len() > 0 {
  1092			binary.Read(b, f.ByteOrder, &rela)
  1093			symNo := rela.Info >> 32
  1094			t := R_SPARC(rela.Info & 0xff)
  1095	
  1096			if symNo == 0 || symNo > uint64(len(symbols)) {
  1097				continue
  1098			}
  1099			sym := &symbols[symNo-1]
  1100			if SymType(sym.Info&0xf) != STT_SECTION {
  1101				// We don't handle non-section relocations for now.
  1102				continue
  1103			}
  1104	
  1105			switch t {
  1106			case R_SPARC_64, R_SPARC_UA64:
  1107				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
  1108					continue
  1109				}
  1110				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
  1111			case R_SPARC_32, R_SPARC_UA32:
  1112				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
  1113					continue
  1114				}
  1115				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
  1116			}
  1117		}
  1118	
  1119		return nil
  1120	}
  1121	
  1122	func (f *File) DWARF() (*dwarf.Data, error) {
  1123		dwarfSuffix := func(s *Section) string {
  1124			switch {
  1125			case strings.HasPrefix(s.Name, ".debug_"):
  1126				return s.Name[7:]
  1127			case strings.HasPrefix(s.Name, ".zdebug_"):
  1128				return s.Name[8:]
  1129			default:
  1130				return ""
  1131			}
  1132	
  1133		}
  1134		// sectionData gets the data for s, checks its size, and
  1135		// applies any applicable relations.
  1136		sectionData := func(i int, s *Section) ([]byte, error) {
  1137			b, err := s.Data()
  1138			if err != nil && uint64(len(b)) < s.Size {
  1139				return nil, err
  1140			}
  1141	
  1142			if len(b) >= 12 && string(b[:4]) == "ZLIB" {
  1143				dlen := binary.BigEndian.Uint64(b[4:12])
  1144				dbuf := make([]byte, dlen)
  1145				r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
  1146				if err != nil {
  1147					return nil, err
  1148				}
  1149				if _, err := io.ReadFull(r, dbuf); err != nil {
  1150					return nil, err
  1151				}
  1152				if err := r.Close(); err != nil {
  1153					return nil, err
  1154				}
  1155				b = dbuf
  1156			}
  1157	
  1158			for _, r := range f.Sections {
  1159				if r.Type != SHT_RELA && r.Type != SHT_REL {
  1160					continue
  1161				}
  1162				if int(r.Info) != i {
  1163					continue
  1164				}
  1165				rd, err := r.Data()
  1166				if err != nil {
  1167					return nil, err
  1168				}
  1169				err = f.applyRelocations(b, rd)
  1170				if err != nil {
  1171					return nil, err
  1172				}
  1173			}
  1174			return b, nil
  1175		}
  1176	
  1177		// There are many other DWARF sections, but these
  1178		// are the ones the debug/dwarf package uses.
  1179		// Don't bother loading others.
  1180		var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
  1181		for i, s := range f.Sections {
  1182			suffix := dwarfSuffix(s)
  1183			if suffix == "" {
  1184				continue
  1185			}
  1186			if _, ok := dat[suffix]; !ok {
  1187				continue
  1188			}
  1189			b, err := sectionData(i, s)
  1190			if err != nil {
  1191				return nil, err
  1192			}
  1193			dat[suffix] = b
  1194		}
  1195	
  1196		d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
  1197		if err != nil {
  1198			return nil, err
  1199		}
  1200	
  1201		// Look for DWARF4 .debug_types sections.
  1202		for i, s := range f.Sections {
  1203			suffix := dwarfSuffix(s)
  1204			if suffix != "types" {
  1205				continue
  1206			}
  1207	
  1208			b, err := sectionData(i, s)
  1209			if err != nil {
  1210				return nil, err
  1211			}
  1212	
  1213			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
  1214			if err != nil {
  1215				return nil, err
  1216			}
  1217		}
  1218	
  1219		return d, nil
  1220	}
  1221	
  1222	// Symbols returns the symbol table for f. The symbols will be listed in the order
  1223	// they appear in f.
  1224	//
  1225	// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
  1226	// After retrieving the symbols as symtab, an externally supplied index x
  1227	// corresponds to symtab[x-1], not symtab[x].
  1228	func (f *File) Symbols() ([]Symbol, error) {
  1229		sym, _, err := f.getSymbols(SHT_SYMTAB)
  1230		return sym, err
  1231	}
  1232	
  1233	// DynamicSymbols returns the dynamic symbol table for f. The symbols
  1234	// will be listed in the order they appear in f.
  1235	//
  1236	// If f has a symbol version table, the returned Symbols will have
  1237	// initialized Version and Library fields.
  1238	//
  1239	// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
  1240	// After retrieving the symbols as symtab, an externally supplied index x
  1241	// corresponds to symtab[x-1], not symtab[x].
  1242	func (f *File) DynamicSymbols() ([]Symbol, error) {
  1243		sym, str, err := f.getSymbols(SHT_DYNSYM)
  1244		if err != nil {
  1245			return nil, err
  1246		}
  1247		if f.gnuVersionInit(str) {
  1248			for i := range sym {
  1249				sym[i].Library, sym[i].Version = f.gnuVersion(i)
  1250			}
  1251		}
  1252		return sym, nil
  1253	}
  1254	
  1255	type ImportedSymbol struct {
  1256		Name    string
  1257		Version string
  1258		Library string
  1259	}
  1260	
  1261	// ImportedSymbols returns the names of all symbols
  1262	// referred to by the binary f that are expected to be
  1263	// satisfied by other libraries at dynamic load time.
  1264	// It does not return weak symbols.
  1265	func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
  1266		sym, str, err := f.getSymbols(SHT_DYNSYM)
  1267		if err != nil {
  1268			return nil, err
  1269		}
  1270		f.gnuVersionInit(str)
  1271		var all []ImportedSymbol
  1272		for i, s := range sym {
  1273			if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
  1274				all = append(all, ImportedSymbol{Name: s.Name})
  1275				sym := &all[len(all)-1]
  1276				sym.Library, sym.Version = f.gnuVersion(i)
  1277			}
  1278		}
  1279		return all, nil
  1280	}
  1281	
  1282	type verneed struct {
  1283		File string
  1284		Name string
  1285	}
  1286	
  1287	// gnuVersionInit parses the GNU version tables
  1288	// for use by calls to gnuVersion.
  1289	func (f *File) gnuVersionInit(str []byte) bool {
  1290		if f.gnuNeed != nil {
  1291			// Already initialized
  1292			return true
  1293		}
  1294	
  1295		// Accumulate verneed information.
  1296		vn := f.SectionByType(SHT_GNU_VERNEED)
  1297		if vn == nil {
  1298			return false
  1299		}
  1300		d, _ := vn.Data()
  1301	
  1302		var need []verneed
  1303		i := 0
  1304		for {
  1305			if i+16 > len(d) {
  1306				break
  1307			}
  1308			vers := f.ByteOrder.Uint16(d[i : i+2])
  1309			if vers != 1 {
  1310				break
  1311			}
  1312			cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
  1313			fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
  1314			aux := f.ByteOrder.Uint32(d[i+8 : i+12])
  1315			next := f.ByteOrder.Uint32(d[i+12 : i+16])
  1316			file, _ := getString(str, int(fileoff))
  1317	
  1318			var name string
  1319			j := i + int(aux)
  1320			for c := 0; c < int(cnt); c++ {
  1321				if j+16 > len(d) {
  1322					break
  1323				}
  1324				// hash := f.ByteOrder.Uint32(d[j:j+4])
  1325				// flags := f.ByteOrder.Uint16(d[j+4:j+6])
  1326				other := f.ByteOrder.Uint16(d[j+6 : j+8])
  1327				nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
  1328				next := f.ByteOrder.Uint32(d[j+12 : j+16])
  1329				name, _ = getString(str, int(nameoff))
  1330				ndx := int(other)
  1331				if ndx >= len(need) {
  1332					a := make([]verneed, 2*(ndx+1))
  1333					copy(a, need)
  1334					need = a
  1335				}
  1336	
  1337				need[ndx] = verneed{file, name}
  1338				if next == 0 {
  1339					break
  1340				}
  1341				j += int(next)
  1342			}
  1343	
  1344			if next == 0 {
  1345				break
  1346			}
  1347			i += int(next)
  1348		}
  1349	
  1350		// Versym parallels symbol table, indexing into verneed.
  1351		vs := f.SectionByType(SHT_GNU_VERSYM)
  1352		if vs == nil {
  1353			return false
  1354		}
  1355		d, _ = vs.Data()
  1356	
  1357		f.gnuNeed = need
  1358		f.gnuVersym = d
  1359		return true
  1360	}
  1361	
  1362	// gnuVersion adds Library and Version information to sym,
  1363	// which came from offset i of the symbol table.
  1364	func (f *File) gnuVersion(i int) (library string, version string) {
  1365		// Each entry is two bytes.
  1366		i = (i + 1) * 2
  1367		if i >= len(f.gnuVersym) {
  1368			return
  1369		}
  1370		j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
  1371		if j < 2 || j >= len(f.gnuNeed) {
  1372			return
  1373		}
  1374		n := &f.gnuNeed[j]
  1375		return n.File, n.Name
  1376	}
  1377	
  1378	// ImportedLibraries returns the names of all libraries
  1379	// referred to by the binary f that are expected to be
  1380	// linked with the binary at dynamic link time.
  1381	func (f *File) ImportedLibraries() ([]string, error) {
  1382		return f.DynString(DT_NEEDED)
  1383	}
  1384	
  1385	// DynString returns the strings listed for the given tag in the file's dynamic
  1386	// section.
  1387	//
  1388	// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
  1389	// DT_RUNPATH.
  1390	func (f *File) DynString(tag DynTag) ([]string, error) {
  1391		switch tag {
  1392		case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
  1393		default:
  1394			return nil, fmt.Errorf("non-string-valued tag %v", tag)
  1395		}
  1396		ds := f.SectionByType(SHT_DYNAMIC)
  1397		if ds == nil {
  1398			// not dynamic, so no libraries
  1399			return nil, nil
  1400		}
  1401		d, err := ds.Data()
  1402		if err != nil {
  1403			return nil, err
  1404		}
  1405		str, err := f.stringTable(ds.Link)
  1406		if err != nil {
  1407			return nil, err
  1408		}
  1409		var all []string
  1410		for len(d) > 0 {
  1411			var t DynTag
  1412			var v uint64
  1413			switch f.Class {
  1414			case ELFCLASS32:
  1415				t = DynTag(f.ByteOrder.Uint32(d[0:4]))
  1416				v = uint64(f.ByteOrder.Uint32(d[4:8]))
  1417				d = d[8:]
  1418			case ELFCLASS64:
  1419				t = DynTag(f.ByteOrder.Uint64(d[0:8]))
  1420				v = f.ByteOrder.Uint64(d[8:16])
  1421				d = d[16:]
  1422			}
  1423			if t == tag {
  1424				s, ok := getString(str, int(v))
  1425				if ok {
  1426					all = append(all, s)
  1427				}
  1428			}
  1429		}
  1430		return all, nil
  1431	}
  1432	

View as plain text