The Go Programming Language

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		"debug/dwarf"
    11		"encoding/binary"
    12		"fmt"
    13		"io"
    14		"os"
    15	)
    16	
    17	// TODO: error reporting detail
    18	
    19	/*
    20	 * Internal ELF representation
    21	 */
    22	
    23	// A FileHeader represents an ELF file header.
    24	type FileHeader struct {
    25		Class      Class
    26		Data       Data
    27		Version    Version
    28		OSABI      OSABI
    29		ABIVersion uint8
    30		ByteOrder  binary.ByteOrder
    31		Type       Type
    32		Machine    Machine
    33	}
    34	
    35	// A File represents an open ELF file.
    36	type File struct {
    37		FileHeader
    38		Sections  []*Section
    39		Progs     []*Prog
    40		closer    io.Closer
    41		gnuNeed   []verneed
    42		gnuVersym []byte
    43	}
    44	
    45	// A SectionHeader represents a single ELF section header.
    46	type SectionHeader struct {
    47		Name      string
    48		Type      SectionType
    49		Flags     SectionFlag
    50		Addr      uint64
    51		Offset    uint64
    52		Size      uint64
    53		Link      uint32
    54		Info      uint32
    55		Addralign uint64
    56		Entsize   uint64
    57	}
    58	
    59	// A Section represents a single section in an ELF file.
    60	type Section struct {
    61		SectionHeader
    62	
    63		// Embed ReaderAt for ReadAt method.
    64		// Do not embed SectionReader directly
    65		// to avoid having Read and Seek.
    66		// If a client wants Read and Seek it must use
    67		// Open() to avoid fighting over the seek offset
    68		// with other clients.
    69		io.ReaderAt
    70		sr *io.SectionReader
    71	}
    72	
    73	// Data reads and returns the contents of the ELF section.
    74	func (s *Section) Data() ([]byte, os.Error) {
    75		dat := make([]byte, s.sr.Size())
    76		n, err := s.sr.ReadAt(dat, 0)
    77		return dat[0:n], err
    78	}
    79	
    80	// stringTable reads and returns the string table given by the
    81	// specified link value.
    82	func (f *File) stringTable(link uint32) ([]byte, os.Error) {
    83		if link <= 0 || link >= uint32(len(f.Sections)) {
    84			return nil, os.NewError("section has invalid string table link")
    85		}
    86		return f.Sections[link].Data()
    87	}
    88	
    89	// Open returns a new ReadSeeker reading the ELF section.
    90	func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
    91	
    92	// A ProgHeader represents a single ELF program header.
    93	type ProgHeader struct {
    94		Type   ProgType
    95		Flags  ProgFlag
    96		Off    uint64
    97		Vaddr  uint64
    98		Paddr  uint64
    99		Filesz uint64
   100		Memsz  uint64
   101		Align  uint64
   102	}
   103	
   104	// A Prog represents a single ELF program header in an ELF binary.
   105	type Prog struct {
   106		ProgHeader
   107	
   108		// Embed ReaderAt for ReadAt method.
   109		// Do not embed SectionReader directly
   110		// to avoid having Read and Seek.
   111		// If a client wants Read and Seek it must use
   112		// Open() to avoid fighting over the seek offset
   113		// with other clients.
   114		io.ReaderAt
   115		sr *io.SectionReader
   116	}
   117	
   118	// Open returns a new ReadSeeker reading the ELF program body.
   119	func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
   120	
   121	// A Symbol represents an entry in an ELF symbol table section.
   122	type Symbol struct {
   123		Name        string
   124		Info, Other byte
   125		Section     SectionIndex
   126		Value, Size uint64
   127	}
   128	
   129	/*
   130	 * ELF reader
   131	 */
   132	
   133	type FormatError struct {
   134		off int64
   135		msg string
   136		val interface{}
   137	}
   138	
   139	func (e *FormatError) String() string {
   140		msg := e.msg
   141		if e.val != nil {
   142			msg += fmt.Sprintf(" '%v' ", e.val)
   143		}
   144		msg += fmt.Sprintf("in record at byte %#x", e.off)
   145		return msg
   146	}
   147	
   148	// Open opens the named file using os.Open and prepares it for use as an ELF binary.
   149	func Open(name string) (*File, os.Error) {
   150		f, err := os.Open(name)
   151		if err != nil {
   152			return nil, err
   153		}
   154		ff, err := NewFile(f)
   155		if err != nil {
   156			f.Close()
   157			return nil, err
   158		}
   159		ff.closer = f
   160		return ff, nil
   161	}
   162	
   163	// Close closes the File.
   164	// If the File was created using NewFile directly instead of Open,
   165	// Close has no effect.
   166	func (f *File) Close() os.Error {
   167		var err os.Error
   168		if f.closer != nil {
   169			err = f.closer.Close()
   170			f.closer = nil
   171		}
   172		return err
   173	}
   174	
   175	// SectionByType returns the first section in f with the
   176	// given type, or nil if there is no such section.
   177	func (f *File) SectionByType(typ SectionType) *Section {
   178		for _, s := range f.Sections {
   179			if s.Type == typ {
   180				return s
   181			}
   182		}
   183		return nil
   184	}
   185	
   186	// NewFile creates a new File for accessing an ELF binary in an underlying reader.
   187	// The ELF binary is expected to start at position 0 in the ReaderAt.
   188	func NewFile(r io.ReaderAt) (*File, os.Error) {
   189		sr := io.NewSectionReader(r, 0, 1<<63-1)
   190		// Read and decode ELF identifier
   191		var ident [16]uint8
   192		if _, err := r.ReadAt(ident[0:], 0); err != nil {
   193			return nil, err
   194		}
   195		if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
   196			return nil, &FormatError{0, "bad magic number", ident[0:4]}
   197		}
   198	
   199		f := new(File)
   200		f.Class = Class(ident[EI_CLASS])
   201		switch f.Class {
   202		case ELFCLASS32:
   203		case ELFCLASS64:
   204			// ok
   205		default:
   206			return nil, &FormatError{0, "unknown ELF class", f.Class}
   207		}
   208	
   209		f.Data = Data(ident[EI_DATA])
   210		switch f.Data {
   211		case ELFDATA2LSB:
   212			f.ByteOrder = binary.LittleEndian
   213		case ELFDATA2MSB:
   214			f.ByteOrder = binary.BigEndian
   215		default:
   216			return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
   217		}
   218	
   219		f.Version = Version(ident[EI_VERSION])
   220		if f.Version != EV_CURRENT {
   221			return nil, &FormatError{0, "unknown ELF version", f.Version}
   222		}
   223	
   224		f.OSABI = OSABI(ident[EI_OSABI])
   225		f.ABIVersion = ident[EI_ABIVERSION]
   226	
   227		// Read ELF file header
   228		var phoff int64
   229		var phentsize, phnum int
   230		var shoff int64
   231		var shentsize, shnum, shstrndx int
   232		shstrndx = -1
   233		switch f.Class {
   234		case ELFCLASS32:
   235			hdr := new(Header32)
   236			sr.Seek(0, os.SEEK_SET)
   237			if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   238				return nil, err
   239			}
   240			f.Type = Type(hdr.Type)
   241			f.Machine = Machine(hdr.Machine)
   242			if v := Version(hdr.Version); v != f.Version {
   243				return nil, &FormatError{0, "mismatched ELF version", v}
   244			}
   245			phoff = int64(hdr.Phoff)
   246			phentsize = int(hdr.Phentsize)
   247			phnum = int(hdr.Phnum)
   248			shoff = int64(hdr.Shoff)
   249			shentsize = int(hdr.Shentsize)
   250			shnum = int(hdr.Shnum)
   251			shstrndx = int(hdr.Shstrndx)
   252		case ELFCLASS64:
   253			hdr := new(Header64)
   254			sr.Seek(0, os.SEEK_SET)
   255			if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
   256				return nil, err
   257			}
   258			f.Type = Type(hdr.Type)
   259			f.Machine = Machine(hdr.Machine)
   260			if v := Version(hdr.Version); v != f.Version {
   261				return nil, &FormatError{0, "mismatched ELF version", v}
   262			}
   263			phoff = int64(hdr.Phoff)
   264			phentsize = int(hdr.Phentsize)
   265			phnum = int(hdr.Phnum)
   266			shoff = int64(hdr.Shoff)
   267			shentsize = int(hdr.Shentsize)
   268			shnum = int(hdr.Shnum)
   269			shstrndx = int(hdr.Shstrndx)
   270		}
   271		if shstrndx < 0 || shstrndx >= shnum {
   272			return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx}
   273		}
   274	
   275		// Read program headers
   276		f.Progs = make([]*Prog, phnum)
   277		for i := 0; i < phnum; i++ {
   278			off := phoff + int64(i)*int64(phentsize)
   279			sr.Seek(off, os.SEEK_SET)
   280			p := new(Prog)
   281			switch f.Class {
   282			case ELFCLASS32:
   283				ph := new(Prog32)
   284				if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   285					return nil, err
   286				}
   287				p.ProgHeader = ProgHeader{
   288					Type:   ProgType(ph.Type),
   289					Flags:  ProgFlag(ph.Flags),
   290					Off:    uint64(ph.Off),
   291					Vaddr:  uint64(ph.Vaddr),
   292					Paddr:  uint64(ph.Paddr),
   293					Filesz: uint64(ph.Filesz),
   294					Memsz:  uint64(ph.Memsz),
   295					Align:  uint64(ph.Align),
   296				}
   297			case ELFCLASS64:
   298				ph := new(Prog64)
   299				if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
   300					return nil, err
   301				}
   302				p.ProgHeader = ProgHeader{
   303					Type:   ProgType(ph.Type),
   304					Flags:  ProgFlag(ph.Flags),
   305					Off:    uint64(ph.Off),
   306					Vaddr:  uint64(ph.Vaddr),
   307					Paddr:  uint64(ph.Paddr),
   308					Filesz: uint64(ph.Filesz),
   309					Memsz:  uint64(ph.Memsz),
   310					Align:  uint64(ph.Align),
   311				}
   312			}
   313			p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
   314			p.ReaderAt = p.sr
   315			f.Progs[i] = p
   316		}
   317	
   318		// Read section headers
   319		f.Sections = make([]*Section, shnum)
   320		names := make([]uint32, shnum)
   321		for i := 0; i < shnum; i++ {
   322			off := shoff + int64(i)*int64(shentsize)
   323			sr.Seek(off, os.SEEK_SET)
   324			s := new(Section)
   325			switch f.Class {
   326			case ELFCLASS32:
   327				sh := new(Section32)
   328				if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   329					return nil, err
   330				}
   331				names[i] = sh.Name
   332				s.SectionHeader = SectionHeader{
   333					Type:      SectionType(sh.Type),
   334					Flags:     SectionFlag(sh.Flags),
   335					Addr:      uint64(sh.Addr),
   336					Offset:    uint64(sh.Off),
   337					Size:      uint64(sh.Size),
   338					Link:      uint32(sh.Link),
   339					Info:      uint32(sh.Info),
   340					Addralign: uint64(sh.Addralign),
   341					Entsize:   uint64(sh.Entsize),
   342				}
   343			case ELFCLASS64:
   344				sh := new(Section64)
   345				if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
   346					return nil, err
   347				}
   348				names[i] = sh.Name
   349				s.SectionHeader = SectionHeader{
   350					Type:      SectionType(sh.Type),
   351					Flags:     SectionFlag(sh.Flags),
   352					Offset:    uint64(sh.Off),
   353					Size:      uint64(sh.Size),
   354					Addr:      uint64(sh.Addr),
   355					Link:      uint32(sh.Link),
   356					Info:      uint32(sh.Info),
   357					Addralign: uint64(sh.Addralign),
   358					Entsize:   uint64(sh.Entsize),
   359				}
   360			}
   361			s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
   362			s.ReaderAt = s.sr
   363			f.Sections[i] = s
   364		}
   365	
   366		// Load section header string table.
   367		shstrtab, err := f.Sections[shstrndx].Data()
   368		if err != nil {
   369			return nil, err
   370		}
   371		for i, s := range f.Sections {
   372			var ok bool
   373			s.Name, ok = getString(shstrtab, int(names[i]))
   374			if !ok {
   375				return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]}
   376			}
   377		}
   378	
   379		return f, nil
   380	}
   381	
   382	// getSymbols returns a slice of Symbols from parsing the symbol table
   383	// with the given type, along with the associated string table.
   384	func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
   385		switch f.Class {
   386		case ELFCLASS64:
   387			return f.getSymbols64(typ)
   388	
   389		case ELFCLASS32:
   390			return f.getSymbols32(typ)
   391		}
   392	
   393		return nil, nil, os.NewError("not implemented")
   394	}
   395	
   396	func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
   397		symtabSection := f.SectionByType(typ)
   398		if symtabSection == nil {
   399			return nil, nil, os.NewError("no symbol section")
   400		}
   401	
   402		data, err := symtabSection.Data()
   403		if err != nil {
   404			return nil, nil, os.NewError("cannot load symbol section")
   405		}
   406		symtab := bytes.NewBuffer(data)
   407		if symtab.Len()%Sym32Size != 0 {
   408			return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
   409		}
   410	
   411		strdata, err := f.stringTable(symtabSection.Link)
   412		if err != nil {
   413			return nil, nil, os.NewError("cannot load string table section")
   414		}
   415	
   416		// The first entry is all zeros.
   417		var skip [Sym32Size]byte
   418		symtab.Read(skip[0:])
   419	
   420		symbols := make([]Symbol, symtab.Len()/Sym32Size)
   421	
   422		i := 0
   423		var sym Sym32
   424		for symtab.Len() > 0 {
   425			binary.Read(symtab, f.ByteOrder, &sym)
   426			str, _ := getString(strdata, int(sym.Name))
   427			symbols[i].Name = str
   428			symbols[i].Info = sym.Info
   429			symbols[i].Other = sym.Other
   430			symbols[i].Section = SectionIndex(sym.Shndx)
   431			symbols[i].Value = uint64(sym.Value)
   432			symbols[i].Size = uint64(sym.Size)
   433			i++
   434		}
   435	
   436		return symbols, strdata, nil
   437	}
   438	
   439	func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
   440		symtabSection := f.SectionByType(typ)
   441		if symtabSection == nil {
   442			return nil, nil, os.NewError("no symbol section")
   443		}
   444	
   445		data, err := symtabSection.Data()
   446		if err != nil {
   447			return nil, nil, os.NewError("cannot load symbol section")
   448		}
   449		symtab := bytes.NewBuffer(data)
   450		if symtab.Len()%Sym64Size != 0 {
   451			return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
   452		}
   453	
   454		strdata, err := f.stringTable(symtabSection.Link)
   455		if err != nil {
   456			return nil, nil, os.NewError("cannot load string table section")
   457		}
   458	
   459		// The first entry is all zeros.
   460		var skip [Sym64Size]byte
   461		symtab.Read(skip[0:])
   462	
   463		symbols := make([]Symbol, symtab.Len()/Sym64Size)
   464	
   465		i := 0
   466		var sym Sym64
   467		for symtab.Len() > 0 {
   468			binary.Read(symtab, f.ByteOrder, &sym)
   469			str, _ := getString(strdata, int(sym.Name))
   470			symbols[i].Name = str
   471			symbols[i].Info = sym.Info
   472			symbols[i].Other = sym.Other
   473			symbols[i].Section = SectionIndex(sym.Shndx)
   474			symbols[i].Value = sym.Value
   475			symbols[i].Size = sym.Size
   476			i++
   477		}
   478	
   479		return symbols, strdata, nil
   480	}
   481	
   482	// getString extracts a string from an ELF string table.
   483	func getString(section []byte, start int) (string, bool) {
   484		if start < 0 || start >= len(section) {
   485			return "", false
   486		}
   487	
   488		for end := start; end < len(section); end++ {
   489			if section[end] == 0 {
   490				return string(section[start:end]), true
   491			}
   492		}
   493		return "", false
   494	}
   495	
   496	// Section returns a section with the given name, or nil if no such
   497	// section exists.
   498	func (f *File) Section(name string) *Section {
   499		for _, s := range f.Sections {
   500			if s.Name == name {
   501				return s
   502			}
   503		}
   504		return nil
   505	}
   506	
   507	// applyRelocations applies relocations to dst. rels is a relocations section
   508	// in RELA format.
   509	func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
   510		if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
   511			return f.applyRelocationsAMD64(dst, rels)
   512		}
   513	
   514		return os.NewError("not implemented")
   515	}
   516	
   517	func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
   518		if len(rels)%Sym64Size != 0 {
   519			return os.NewError("length of relocation section is not a multiple of Sym64Size")
   520		}
   521	
   522		symbols, _, err := f.getSymbols(SHT_SYMTAB)
   523		if err != nil {
   524			return err
   525		}
   526	
   527		b := bytes.NewBuffer(rels)
   528		var rela Rela64
   529	
   530		for b.Len() > 0 {
   531			binary.Read(b, f.ByteOrder, &rela)
   532			symNo := rela.Info >> 32
   533			t := R_X86_64(rela.Info & 0xffff)
   534	
   535			if symNo >= uint64(len(symbols)) {
   536				continue
   537			}
   538			sym := &symbols[symNo]
   539			if SymType(sym.Info&0xf) != STT_SECTION {
   540				// We don't handle non-section relocations for now.
   541				continue
   542			}
   543	
   544			switch t {
   545			case R_X86_64_64:
   546				if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
   547					continue
   548				}
   549				f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
   550			case R_X86_64_32:
   551				if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
   552					continue
   553				}
   554				f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
   555			}
   556		}
   557	
   558		return nil
   559	}
   560	
   561	func (f *File) DWARF() (*dwarf.Data, os.Error) {
   562		// There are many other DWARF sections, but these
   563		// are the required ones, and the debug/dwarf package
   564		// does not use the others, so don't bother loading them.
   565		var names = [...]string{"abbrev", "info", "str"}
   566		var dat [len(names)][]byte
   567		for i, name := range names {
   568			name = ".debug_" + name
   569			s := f.Section(name)
   570			if s == nil {
   571				continue
   572			}
   573			b, err := s.Data()
   574			if err != nil && uint64(len(b)) < s.Size {
   575				return nil, err
   576			}
   577			dat[i] = b
   578		}
   579	
   580		// If there's a relocation table for .debug_info, we have to process it
   581		// now otherwise the data in .debug_info is invalid for x86-64 objects.
   582		rela := f.Section(".rela.debug_info")
   583		if rela != nil && rela.Type == SHT_RELA && f.Machine == EM_X86_64 {
   584			data, err := rela.Data()
   585			if err != nil {
   586				return nil, err
   587			}
   588			err = f.applyRelocations(dat[1], data)
   589			if err != nil {
   590				return nil, err
   591			}
   592		}
   593	
   594		abbrev, info, str := dat[0], dat[1], dat[2]
   595		return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
   596	}
   597	
   598	// Symbols returns the symbol table for f.
   599	func (f *File) Symbols() ([]Symbol, os.Error) {
   600		sym, _, err := f.getSymbols(SHT_SYMTAB)
   601		return sym, err
   602	}
   603	
   604	type ImportedSymbol struct {
   605		Name    string
   606		Version string
   607		Library string
   608	}
   609	
   610	// ImportedSymbols returns the names of all symbols
   611	// referred to by the binary f that are expected to be
   612	// satisfied by other libraries at dynamic load time.
   613	// It does not return weak symbols.
   614	func (f *File) ImportedSymbols() ([]ImportedSymbol, os.Error) {
   615		sym, str, err := f.getSymbols(SHT_DYNSYM)
   616		if err != nil {
   617			return nil, err
   618		}
   619		f.gnuVersionInit(str)
   620		var all []ImportedSymbol
   621		for i, s := range sym {
   622			if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
   623				all = append(all, ImportedSymbol{Name: s.Name})
   624				f.gnuVersion(i, &all[len(all)-1])
   625			}
   626		}
   627		return all, nil
   628	}
   629	
   630	type verneed struct {
   631		File string
   632		Name string
   633	}
   634	
   635	// gnuVersionInit parses the GNU version tables
   636	// for use by calls to gnuVersion.
   637	func (f *File) gnuVersionInit(str []byte) {
   638		// Accumulate verneed information.
   639		vn := f.SectionByType(SHT_GNU_VERNEED)
   640		if vn == nil {
   641			return
   642		}
   643		d, _ := vn.Data()
   644	
   645		var need []verneed
   646		i := 0
   647		for {
   648			if i+16 > len(d) {
   649				break
   650			}
   651			vers := f.ByteOrder.Uint16(d[i : i+2])
   652			if vers != 1 {
   653				break
   654			}
   655			cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
   656			fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
   657			aux := f.ByteOrder.Uint32(d[i+8 : i+12])
   658			next := f.ByteOrder.Uint32(d[i+12 : i+16])
   659			file, _ := getString(str, int(fileoff))
   660	
   661			var name string
   662			j := i + int(aux)
   663			for c := 0; c < int(cnt); c++ {
   664				if j+16 > len(d) {
   665					break
   666				}
   667				// hash := f.ByteOrder.Uint32(d[j:j+4])
   668				// flags := f.ByteOrder.Uint16(d[j+4:j+6])
   669				other := f.ByteOrder.Uint16(d[j+6 : j+8])
   670				nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
   671				next := f.ByteOrder.Uint32(d[j+12 : j+16])
   672				name, _ = getString(str, int(nameoff))
   673				ndx := int(other)
   674				if ndx >= len(need) {
   675					a := make([]verneed, 2*(ndx+1))
   676					copy(a, need)
   677					need = a
   678				}
   679	
   680				need[ndx] = verneed{file, name}
   681				if next == 0 {
   682					break
   683				}
   684				j += int(next)
   685			}
   686	
   687			if next == 0 {
   688				break
   689			}
   690			i += int(next)
   691		}
   692	
   693		// Versym parallels symbol table, indexing into verneed.
   694		vs := f.SectionByType(SHT_GNU_VERSYM)
   695		if vs == nil {
   696			return
   697		}
   698		d, _ = vs.Data()
   699	
   700		f.gnuNeed = need
   701		f.gnuVersym = d
   702	}
   703	
   704	// gnuVersion adds Library and Version information to sym,
   705	// which came from offset i of the symbol table.
   706	func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
   707		// Each entry is two bytes; skip undef entry at beginning.
   708		i = (i + 1) * 2
   709		if i >= len(f.gnuVersym) {
   710			return
   711		}
   712		j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
   713		if j < 2 || j >= len(f.gnuNeed) {
   714			return
   715		}
   716		n := &f.gnuNeed[j]
   717		sym.Library = n.File
   718		sym.Version = n.Name
   719	}
   720	
   721	// ImportedLibraries returns the names of all libraries
   722	// referred to by the binary f that are expected to be
   723	// linked with the binary at dynamic link time.
   724	func (f *File) ImportedLibraries() ([]string, os.Error) {
   725		ds := f.SectionByType(SHT_DYNAMIC)
   726		if ds == nil {
   727			// not dynamic, so no libraries
   728			return nil, nil
   729		}
   730		d, err := ds.Data()
   731		if err != nil {
   732			return nil, err
   733		}
   734		str, err := f.stringTable(ds.Link)
   735		if err != nil {
   736			return nil, err
   737		}
   738		var all []string
   739		for len(d) > 0 {
   740			var tag DynTag
   741			var value uint64
   742			switch f.Class {
   743			case ELFCLASS32:
   744				tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
   745				value = uint64(f.ByteOrder.Uint32(d[4:8]))
   746				d = d[8:]
   747			case ELFCLASS64:
   748				tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
   749				value = f.ByteOrder.Uint64(d[8:16])
   750				d = d[16:]
   751			}
   752			if tag == DT_NEEDED {
   753				s, ok := getString(str, int(value))
   754				if ok {
   755					all = append(all, s)
   756				}
   757			}
   758		}
   759	
   760		return all, nil
   761	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.