Source file src/internal/xcoff/file.go

     1  // Copyright 2018 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 xcoff implements access to XCOFF (Extended Common Object File Format) files.
     6  package xcoff
     7  
     8  import (
     9  	"debug/dwarf"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"strings"
    15  )
    16  
    17  // SectionHeader holds information about an XCOFF section header.
    18  type SectionHeader struct {
    19  	Name           string
    20  	VirtualAddress uint64
    21  	Size           uint64
    22  	Type           uint32
    23  	Relptr         uint64
    24  	Nreloc         uint32
    25  }
    26  
    27  type Section struct {
    28  	SectionHeader
    29  	Relocs []Reloc
    30  	io.ReaderAt
    31  	sr *io.SectionReader
    32  }
    33  
    34  // AuxiliaryCSect holds information about an XCOFF symbol in an AUX_CSECT entry.
    35  type AuxiliaryCSect struct {
    36  	Length              int64
    37  	StorageMappingClass int
    38  	SymbolType          int
    39  }
    40  
    41  // AuxiliaryFcn holds information about an XCOFF symbol in an AUX_FCN entry.
    42  type AuxiliaryFcn struct {
    43  	Size int64
    44  }
    45  
    46  type Symbol struct {
    47  	Name          string
    48  	Value         uint64
    49  	SectionNumber int
    50  	StorageClass  int
    51  	AuxFcn        AuxiliaryFcn
    52  	AuxCSect      AuxiliaryCSect
    53  }
    54  
    55  type Reloc struct {
    56  	VirtualAddress   uint64
    57  	Symbol           *Symbol
    58  	Signed           bool
    59  	InstructionFixed bool
    60  	Length           uint8
    61  	Type             uint8
    62  }
    63  
    64  // ImportedSymbol holds information about an imported XCOFF symbol.
    65  type ImportedSymbol struct {
    66  	Name    string
    67  	Library string
    68  }
    69  
    70  // FileHeader holds information about an XCOFF file header.
    71  type FileHeader struct {
    72  	TargetMachine uint16
    73  }
    74  
    75  // A File represents an open XCOFF file.
    76  type File struct {
    77  	FileHeader
    78  	Sections     []*Section
    79  	Symbols      []*Symbol
    80  	StringTable  []byte
    81  	LibraryPaths []string
    82  
    83  	closer io.Closer
    84  }
    85  
    86  // Open opens the named file using os.Open and prepares it for use as an XCOFF binary.
    87  func Open(name string) (*File, error) {
    88  	f, err := os.Open(name)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	ff, err := NewFile(f)
    93  	if err != nil {
    94  		f.Close()
    95  		return nil, err
    96  	}
    97  	ff.closer = f
    98  	return ff, nil
    99  }
   100  
   101  // Close closes the File.
   102  // If the File was created using NewFile directly instead of Open,
   103  // Close has no effect.
   104  func (f *File) Close() error {
   105  	var err error
   106  	if f.closer != nil {
   107  		err = f.closer.Close()
   108  		f.closer = nil
   109  	}
   110  	return err
   111  }
   112  
   113  // Section returns the first section with the given name, or nil if no such
   114  // section exists.
   115  // Xcoff have section's name limited to 8 bytes. Some sections like .gosymtab
   116  // can be trunked but this method will still find them.
   117  func (f *File) Section(name string) *Section {
   118  	for _, s := range f.Sections {
   119  		if s.Name == name || (len(name) > 8 && s.Name == name[:8]) {
   120  			return s
   121  		}
   122  	}
   123  	return nil
   124  }
   125  
   126  // SectionByType returns the first section in f with the
   127  // given type, or nil if there is no such section.
   128  func (f *File) SectionByType(typ uint32) *Section {
   129  	for _, s := range f.Sections {
   130  		if s.Type == typ {
   131  			return s
   132  		}
   133  	}
   134  	return nil
   135  }
   136  
   137  // cstring converts ASCII byte sequence b to string.
   138  // It stops once it finds 0 or reaches end of b.
   139  func cstring(b []byte) string {
   140  	var i int
   141  	for i = 0; i < len(b) && b[i] != 0; i++ {
   142  	}
   143  	return string(b[:i])
   144  }
   145  
   146  // getString extracts a string from an XCOFF string table.
   147  func getString(st []byte, offset uint32) (string, bool) {
   148  	if offset < 4 || int(offset) >= len(st) {
   149  		return "", false
   150  	}
   151  	return cstring(st[offset:]), true
   152  }
   153  
   154  // NewFile creates a new File for accessing an XCOFF binary in an underlying reader.
   155  func NewFile(r io.ReaderAt) (*File, error) {
   156  	sr := io.NewSectionReader(r, 0, 1<<63-1)
   157  	// Read XCOFF target machine
   158  	var magic uint16
   159  	if err := binary.Read(sr, binary.BigEndian, &magic); err != nil {
   160  		return nil, err
   161  	}
   162  	if magic != U802TOCMAGIC && magic != U64_TOCMAGIC {
   163  		return nil, fmt.Errorf("unrecognised XCOFF magic: 0x%x", magic)
   164  	}
   165  
   166  	f := new(File)
   167  	f.TargetMachine = magic
   168  
   169  	// Read XCOFF file header
   170  	if _, err := sr.Seek(0, os.SEEK_SET); err != nil {
   171  		return nil, err
   172  	}
   173  	var nscns uint16
   174  	var symptr uint64
   175  	var nsyms int32
   176  	var opthdr uint16
   177  	var hdrsz int
   178  	switch f.TargetMachine {
   179  	case U802TOCMAGIC:
   180  		fhdr := new(FileHeader32)
   181  		if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
   182  			return nil, err
   183  		}
   184  		nscns = fhdr.Fnscns
   185  		symptr = uint64(fhdr.Fsymptr)
   186  		nsyms = fhdr.Fnsyms
   187  		opthdr = fhdr.Fopthdr
   188  		hdrsz = FILHSZ_32
   189  	case U64_TOCMAGIC:
   190  		fhdr := new(FileHeader64)
   191  		if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
   192  			return nil, err
   193  		}
   194  		nscns = fhdr.Fnscns
   195  		symptr = fhdr.Fsymptr
   196  		nsyms = fhdr.Fnsyms
   197  		opthdr = fhdr.Fopthdr
   198  		hdrsz = FILHSZ_64
   199  	}
   200  
   201  	if symptr == 0 || nsyms <= 0 {
   202  		return nil, fmt.Errorf("no symbol table")
   203  	}
   204  
   205  	// Read string table (located right after symbol table).
   206  	offset := symptr + uint64(nsyms)*SYMESZ
   207  	if _, err := sr.Seek(int64(offset), os.SEEK_SET); err != nil {
   208  		return nil, err
   209  	}
   210  	// The first 4 bytes contain the length (in bytes).
   211  	var l uint32
   212  	if err := binary.Read(sr, binary.BigEndian, &l); err != nil {
   213  		return nil, err
   214  	}
   215  	if l > 4 {
   216  		if _, err := sr.Seek(int64(offset), os.SEEK_SET); err != nil {
   217  			return nil, err
   218  		}
   219  		f.StringTable = make([]byte, l)
   220  		if _, err := io.ReadFull(sr, f.StringTable); err != nil {
   221  			return nil, err
   222  		}
   223  	}
   224  
   225  	// Read section headers
   226  	if _, err := sr.Seek(int64(hdrsz)+int64(opthdr), os.SEEK_SET); err != nil {
   227  		return nil, err
   228  	}
   229  	f.Sections = make([]*Section, nscns)
   230  	for i := 0; i < int(nscns); i++ {
   231  		var scnptr uint64
   232  		s := new(Section)
   233  		switch f.TargetMachine {
   234  		case U802TOCMAGIC:
   235  			shdr := new(SectionHeader32)
   236  			if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
   237  				return nil, err
   238  			}
   239  			s.Name = cstring(shdr.Sname[:])
   240  			s.VirtualAddress = uint64(shdr.Svaddr)
   241  			s.Size = uint64(shdr.Ssize)
   242  			scnptr = uint64(shdr.Sscnptr)
   243  			s.Type = shdr.Sflags
   244  			s.Relptr = uint64(shdr.Srelptr)
   245  			s.Nreloc = uint32(shdr.Snreloc)
   246  		case U64_TOCMAGIC:
   247  			shdr := new(SectionHeader64)
   248  			if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
   249  				return nil, err
   250  			}
   251  			s.Name = cstring(shdr.Sname[:])
   252  			s.VirtualAddress = shdr.Svaddr
   253  			s.Size = shdr.Ssize
   254  			scnptr = shdr.Sscnptr
   255  			s.Type = shdr.Sflags
   256  			s.Relptr = shdr.Srelptr
   257  			s.Nreloc = shdr.Snreloc
   258  		}
   259  		r2 := r
   260  		if scnptr == 0 { // .bss must have all 0s
   261  			r2 = zeroReaderAt{}
   262  		}
   263  		s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size))
   264  		s.ReaderAt = s.sr
   265  		f.Sections[i] = s
   266  	}
   267  
   268  	// Symbol map needed by relocation
   269  	var idxToSym = make(map[int]*Symbol)
   270  
   271  	// Read symbol table
   272  	if _, err := sr.Seek(int64(symptr), os.SEEK_SET); err != nil {
   273  		return nil, err
   274  	}
   275  	f.Symbols = make([]*Symbol, 0)
   276  	for i := 0; i < int(nsyms); i++ {
   277  		var numaux int
   278  		var ok, needAuxFcn bool
   279  		sym := new(Symbol)
   280  		switch f.TargetMachine {
   281  		case U802TOCMAGIC:
   282  			se := new(SymEnt32)
   283  			if err := binary.Read(sr, binary.BigEndian, se); err != nil {
   284  				return nil, err
   285  			}
   286  			numaux = int(se.Nnumaux)
   287  			sym.SectionNumber = int(se.Nscnum)
   288  			sym.StorageClass = int(se.Nsclass)
   289  			sym.Value = uint64(se.Nvalue)
   290  			needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
   291  			zeroes := binary.BigEndian.Uint32(se.Nname[:4])
   292  			if zeroes != 0 {
   293  				sym.Name = cstring(se.Nname[:])
   294  			} else {
   295  				offset := binary.BigEndian.Uint32(se.Nname[4:])
   296  				sym.Name, ok = getString(f.StringTable, offset)
   297  				if !ok {
   298  					goto skip
   299  				}
   300  			}
   301  		case U64_TOCMAGIC:
   302  			se := new(SymEnt64)
   303  			if err := binary.Read(sr, binary.BigEndian, se); err != nil {
   304  				return nil, err
   305  			}
   306  			numaux = int(se.Nnumaux)
   307  			sym.SectionNumber = int(se.Nscnum)
   308  			sym.StorageClass = int(se.Nsclass)
   309  			sym.Value = se.Nvalue
   310  			needAuxFcn = se.Ntype&SYM_TYPE_FUNC != 0 && numaux > 1
   311  			sym.Name, ok = getString(f.StringTable, se.Noffset)
   312  			if !ok {
   313  				goto skip
   314  			}
   315  		}
   316  		if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT {
   317  			goto skip
   318  		}
   319  		// Must have at least one csect auxiliary entry.
   320  		if numaux < 1 || i+numaux >= int(nsyms) {
   321  			goto skip
   322  		}
   323  
   324  		if sym.SectionNumber > int(nscns) {
   325  			goto skip
   326  		}
   327  		if sym.SectionNumber == 0 {
   328  			sym.Value = 0
   329  		} else {
   330  			sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress
   331  		}
   332  
   333  		idxToSym[i] = sym
   334  
   335  		// If this symbol is a function, it must retrieve its size from
   336  		// its AUX_FCN entry.
   337  		// It can happen that a function symbol doesn't have any AUX_FCN.
   338  		// In this case, needAuxFcn is false and their size will be set to 0.
   339  		if needAuxFcn {
   340  			switch f.TargetMachine {
   341  			case U802TOCMAGIC:
   342  				aux := new(AuxFcn32)
   343  				if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
   344  					return nil, err
   345  				}
   346  				sym.AuxFcn.Size = int64(aux.Xfsize)
   347  			case U64_TOCMAGIC:
   348  				aux := new(AuxFcn64)
   349  				if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
   350  					return nil, err
   351  				}
   352  				sym.AuxFcn.Size = int64(aux.Xfsize)
   353  			}
   354  		}
   355  
   356  		// Read csect auxiliary entry (by convention, it is the last).
   357  		if !needAuxFcn {
   358  			if _, err := sr.Seek(int64(numaux-1)*SYMESZ, os.SEEK_CUR); err != nil {
   359  				return nil, err
   360  			}
   361  		}
   362  		i += numaux
   363  		numaux = 0
   364  		switch f.TargetMachine {
   365  		case U802TOCMAGIC:
   366  			aux := new(AuxCSect32)
   367  			if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
   368  				return nil, err
   369  			}
   370  			sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
   371  			sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
   372  			sym.AuxCSect.Length = int64(aux.Xscnlen)
   373  		case U64_TOCMAGIC:
   374  			aux := new(AuxCSect64)
   375  			if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
   376  				return nil, err
   377  			}
   378  			sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
   379  			sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
   380  			sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo)
   381  		}
   382  		f.Symbols = append(f.Symbols, sym)
   383  	skip:
   384  		i += numaux // Skip auxiliary entries
   385  		if _, err := sr.Seek(int64(numaux)*SYMESZ, os.SEEK_CUR); err != nil {
   386  			return nil, err
   387  		}
   388  	}
   389  
   390  	// Read relocations
   391  	// Only for .data or .text section
   392  	for _, sect := range f.Sections {
   393  		if sect.Type != STYP_TEXT && sect.Type != STYP_DATA {
   394  			continue
   395  		}
   396  		sect.Relocs = make([]Reloc, sect.Nreloc)
   397  		if sect.Relptr == 0 {
   398  			continue
   399  		}
   400  		if _, err := sr.Seek(int64(sect.Relptr), os.SEEK_SET); err != nil {
   401  			return nil, err
   402  		}
   403  		for i := uint32(0); i < sect.Nreloc; i++ {
   404  			switch f.TargetMachine {
   405  			case U802TOCMAGIC:
   406  				rel := new(Reloc32)
   407  				if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
   408  					return nil, err
   409  				}
   410  				sect.Relocs[i].VirtualAddress = uint64(rel.Rvaddr)
   411  				sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
   412  				sect.Relocs[i].Type = rel.Rtype
   413  				sect.Relocs[i].Length = rel.Rsize&0x3F + 1
   414  
   415  				if rel.Rsize&0x80 != 0 {
   416  					sect.Relocs[i].Signed = true
   417  				}
   418  				if rel.Rsize&0x40 != 0 {
   419  					sect.Relocs[i].InstructionFixed = true
   420  				}
   421  
   422  			case U64_TOCMAGIC:
   423  				rel := new(Reloc64)
   424  				if err := binary.Read(sr, binary.BigEndian, rel); err != nil {
   425  					return nil, err
   426  				}
   427  				sect.Relocs[i].VirtualAddress = rel.Rvaddr
   428  				sect.Relocs[i].Symbol = idxToSym[int(rel.Rsymndx)]
   429  				sect.Relocs[i].Type = rel.Rtype
   430  				sect.Relocs[i].Length = rel.Rsize&0x3F + 1
   431  				if rel.Rsize&0x80 != 0 {
   432  					sect.Relocs[i].Signed = true
   433  				}
   434  				if rel.Rsize&0x40 != 0 {
   435  					sect.Relocs[i].InstructionFixed = true
   436  				}
   437  			}
   438  		}
   439  	}
   440  
   441  	return f, nil
   442  }
   443  
   444  // zeroReaderAt is ReaderAt that reads 0s.
   445  type zeroReaderAt struct{}
   446  
   447  // ReadAt writes len(p) 0s into p.
   448  func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
   449  	for i := range p {
   450  		p[i] = 0
   451  	}
   452  	return len(p), nil
   453  }
   454  
   455  // Data reads and returns the contents of the XCOFF section s.
   456  func (s *Section) Data() ([]byte, error) {
   457  	dat := make([]byte, s.sr.Size())
   458  	n, err := s.sr.ReadAt(dat, 0)
   459  	if n == len(dat) {
   460  		err = nil
   461  	}
   462  	return dat[:n], err
   463  }
   464  
   465  // CSect reads and returns the contents of a csect.
   466  func (f *File) CSect(name string) []byte {
   467  	for _, sym := range f.Symbols {
   468  		if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD {
   469  			if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
   470  				s := f.Sections[i]
   471  				if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size {
   472  					dat := make([]byte, sym.AuxCSect.Length)
   473  					_, err := s.sr.ReadAt(dat, int64(sym.Value))
   474  					if err != nil {
   475  						return nil
   476  					}
   477  					return dat
   478  				}
   479  			}
   480  			break
   481  		}
   482  	}
   483  	return nil
   484  }
   485  
   486  func (f *File) DWARF() (*dwarf.Data, error) {
   487  	// There are many other DWARF sections, but these
   488  	// are the ones the debug/dwarf package uses.
   489  	// Don't bother loading others.
   490  	var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWRNGES, SSUBTYP_DWSTR}
   491  	var dat [len(subtypes)][]byte
   492  	for i, subtype := range subtypes {
   493  		s := f.SectionByType(STYP_DWARF | subtype)
   494  		if s != nil {
   495  			b, err := s.Data()
   496  			if err != nil && uint64(len(b)) < s.Size {
   497  				return nil, err
   498  			}
   499  			dat[i] = b
   500  		}
   501  	}
   502  
   503  	abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
   504  	return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
   505  }
   506  
   507  // readImportID returns the import file IDs stored inside the .loader section.
   508  // Library name pattern is either path/base/member or base/member
   509  func (f *File) readImportIDs(s *Section) ([]string, error) {
   510  	// Read loader header
   511  	if _, err := s.sr.Seek(0, os.SEEK_SET); err != nil {
   512  		return nil, err
   513  	}
   514  	var istlen uint32
   515  	var nimpid int32
   516  	var impoff uint64
   517  	switch f.TargetMachine {
   518  	case U802TOCMAGIC:
   519  		lhdr := new(LoaderHeader32)
   520  		if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
   521  			return nil, err
   522  		}
   523  		istlen = lhdr.Listlen
   524  		nimpid = lhdr.Lnimpid
   525  		impoff = uint64(lhdr.Limpoff)
   526  	case U64_TOCMAGIC:
   527  		lhdr := new(LoaderHeader64)
   528  		if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
   529  			return nil, err
   530  		}
   531  		istlen = lhdr.Listlen
   532  		nimpid = lhdr.Lnimpid
   533  		impoff = lhdr.Limpoff
   534  	}
   535  
   536  	// Read loader import file ID table
   537  	if _, err := s.sr.Seek(int64(impoff), os.SEEK_SET); err != nil {
   538  		return nil, err
   539  	}
   540  	table := make([]byte, istlen)
   541  	if _, err := io.ReadFull(s.sr, table); err != nil {
   542  		return nil, err
   543  	}
   544  
   545  	offset := 0
   546  	// First import file ID is the default LIBPATH value
   547  	libpath := cstring(table[offset:])
   548  	f.LibraryPaths = strings.Split(libpath, ":")
   549  	offset += len(libpath) + 3 // 3 null bytes
   550  	all := make([]string, 0)
   551  	for i := 1; i < int(nimpid); i++ {
   552  		impidpath := cstring(table[offset:])
   553  		offset += len(impidpath) + 1
   554  		impidbase := cstring(table[offset:])
   555  		offset += len(impidbase) + 1
   556  		impidmem := cstring(table[offset:])
   557  		offset += len(impidmem) + 1
   558  		var path string
   559  		if len(impidpath) > 0 {
   560  			path = impidpath + "/" + impidbase + "/" + impidmem
   561  		} else {
   562  			path = impidbase + "/" + impidmem
   563  		}
   564  		all = append(all, path)
   565  	}
   566  
   567  	return all, nil
   568  }
   569  
   570  // ImportedSymbols returns the names of all symbols
   571  // referred to by the binary f that are expected to be
   572  // satisfied by other libraries at dynamic load time.
   573  // It does not return weak symbols.
   574  func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
   575  	s := f.SectionByType(STYP_LOADER)
   576  	if s == nil {
   577  		return nil, nil
   578  	}
   579  	// Read loader header
   580  	if _, err := s.sr.Seek(0, os.SEEK_SET); err != nil {
   581  		return nil, err
   582  	}
   583  	var stlen uint32
   584  	var stoff uint64
   585  	var nsyms int32
   586  	var symoff uint64
   587  	switch f.TargetMachine {
   588  	case U802TOCMAGIC:
   589  		lhdr := new(LoaderHeader32)
   590  		if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
   591  			return nil, err
   592  		}
   593  		stlen = lhdr.Lstlen
   594  		stoff = uint64(lhdr.Lstoff)
   595  		nsyms = lhdr.Lnsyms
   596  		symoff = LDHDRSZ_32
   597  	case U64_TOCMAGIC:
   598  		lhdr := new(LoaderHeader64)
   599  		if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
   600  			return nil, err
   601  		}
   602  		stlen = lhdr.Lstlen
   603  		stoff = lhdr.Lstoff
   604  		nsyms = lhdr.Lnsyms
   605  		symoff = lhdr.Lsymoff
   606  	}
   607  
   608  	// Read loader section string table
   609  	if _, err := s.sr.Seek(int64(stoff), os.SEEK_SET); err != nil {
   610  		return nil, err
   611  	}
   612  	st := make([]byte, stlen)
   613  	if _, err := io.ReadFull(s.sr, st); err != nil {
   614  		return nil, err
   615  	}
   616  
   617  	// Read imported libraries
   618  	libs, err := f.readImportIDs(s)
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  
   623  	// Read loader symbol table
   624  	if _, err := s.sr.Seek(int64(symoff), os.SEEK_SET); err != nil {
   625  		return nil, err
   626  	}
   627  	all := make([]ImportedSymbol, 0)
   628  	for i := 0; i < int(nsyms); i++ {
   629  		var name string
   630  		var ifile int32
   631  		var ok bool
   632  		switch f.TargetMachine {
   633  		case U802TOCMAGIC:
   634  			ldsym := new(LoaderSymbol32)
   635  			if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
   636  				return nil, err
   637  			}
   638  			if ldsym.Lsmtype&0x40 == 0 {
   639  				continue // Imported symbols only
   640  			}
   641  			zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4])
   642  			if zeroes != 0 {
   643  				name = cstring(ldsym.Lname[:])
   644  			} else {
   645  				offset := binary.BigEndian.Uint32(ldsym.Lname[4:])
   646  				name, ok = getString(st, offset)
   647  				if !ok {
   648  					continue
   649  				}
   650  			}
   651  			ifile = ldsym.Lifile
   652  		case U64_TOCMAGIC:
   653  			ldsym := new(LoaderSymbol64)
   654  			if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
   655  				return nil, err
   656  			}
   657  			if ldsym.Lsmtype&0x40 == 0 {
   658  				continue // Imported symbols only
   659  			}
   660  			name, ok = getString(st, ldsym.Loffset)
   661  			if !ok {
   662  				continue
   663  			}
   664  			ifile = ldsym.Lifile
   665  		}
   666  		var sym ImportedSymbol
   667  		sym.Name = name
   668  		if ifile >= 1 && int(ifile) <= len(libs) {
   669  			sym.Library = libs[ifile-1]
   670  		}
   671  		all = append(all, sym)
   672  	}
   673  
   674  	return all, nil
   675  }
   676  
   677  // ImportedLibraries returns the names of all libraries
   678  // referred to by the binary f that are expected to be
   679  // linked with the binary at dynamic link time.
   680  func (f *File) ImportedLibraries() ([]string, error) {
   681  	s := f.SectionByType(STYP_LOADER)
   682  	if s == nil {
   683  		return nil, nil
   684  	}
   685  	all, err := f.readImportIDs(s)
   686  	return all, err
   687  }
   688  

View as plain text