file.mx raw

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