github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/nm/debug_goobj.go (about)

     1  // DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle
     2  // bundle -p main -x goobj_ debug/goobj
     3  
     4  /* read.go */
     5  
     6  // Copyright 2013 The Go Authors.  All rights reserved.
     7  // Use of this source code is governed by a BSD-style
     8  // license that can be found in the LICENSE file.
     9  
    10  // Package goobj implements reading of Go object files and archives.
    11  //
    12  // TODO(rsc): Decide where this package should live. (golang.org/issue/6932)
    13  // TODO(rsc): Decide the appropriate integer types for various fields.
    14  // TODO(rsc): Write tests. (File format still up in the air a little.)
    15  
    16  package main
    17  
    18  import (
    19  	"bufio"
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"strconv"
    25  	"strings"
    26  )
    27  
    28  // A SymKind describes the kind of memory represented by a symbol.
    29  type goobj_SymKind int
    30  
    31  // This list is taken from include/link.h.
    32  
    33  // Defined SymKind values.
    34  // TODO(rsc): Give idiomatic Go names.
    35  // TODO(rsc): Reduce the number of symbol types in the object files.
    36  const (
    37  	_ goobj_SymKind = iota
    38  
    39  	// readonly, executable
    40  	goobj_STEXT
    41  	goobj_SELFRXSECT
    42  
    43  	// readonly, non-executable
    44  	goobj_STYPE
    45  	goobj_SSTRING
    46  	goobj_SGOSTRING
    47  	goobj_SGOFUNC
    48  	goobj_SRODATA
    49  	goobj_SFUNCTAB
    50  	goobj_STYPELINK
    51  	goobj_SSYMTAB // TODO: move to unmapped section
    52  	goobj_SPCLNTAB
    53  	goobj_SELFROSECT
    54  
    55  	// writable, non-executable
    56  	goobj_SMACHOPLT
    57  	goobj_SELFSECT
    58  	goobj_SMACHO // Mach-O __nl_symbol_ptr
    59  	goobj_SMACHOGOT
    60  	goobj_SNOPTRDATA
    61  	goobj_SINITARR
    62  	goobj_SDATA
    63  	goobj_SWINDOWS
    64  	goobj_SBSS
    65  	goobj_SNOPTRBSS
    66  	goobj_STLSBSS
    67  
    68  	// not mapped
    69  	goobj_SXREF
    70  	goobj_SMACHOSYMSTR
    71  	goobj_SMACHOSYMTAB
    72  	goobj_SMACHOINDIRECTPLT
    73  	goobj_SMACHOINDIRECTGOT
    74  	goobj_SFILE
    75  	goobj_SFILEPATH
    76  	goobj_SCONST
    77  	goobj_SDYNIMPORT
    78  	goobj_SHOSTOBJ
    79  )
    80  
    81  var goobj_symKindStrings = []string{
    82  	goobj_SBSS:              "SBSS",
    83  	goobj_SCONST:            "SCONST",
    84  	goobj_SDATA:             "SDATA",
    85  	goobj_SDYNIMPORT:        "SDYNIMPORT",
    86  	goobj_SELFROSECT:        "SELFROSECT",
    87  	goobj_SELFRXSECT:        "SELFRXSECT",
    88  	goobj_SELFSECT:          "SELFSECT",
    89  	goobj_SFILE:             "SFILE",
    90  	goobj_SFILEPATH:         "SFILEPATH",
    91  	goobj_SFUNCTAB:          "SFUNCTAB",
    92  	goobj_SGOFUNC:           "SGOFUNC",
    93  	goobj_SGOSTRING:         "SGOSTRING",
    94  	goobj_SHOSTOBJ:          "SHOSTOBJ",
    95  	goobj_SINITARR:          "SINITARR",
    96  	goobj_SMACHO:            "SMACHO",
    97  	goobj_SMACHOGOT:         "SMACHOGOT",
    98  	goobj_SMACHOINDIRECTGOT: "SMACHOINDIRECTGOT",
    99  	goobj_SMACHOINDIRECTPLT: "SMACHOINDIRECTPLT",
   100  	goobj_SMACHOPLT:         "SMACHOPLT",
   101  	goobj_SMACHOSYMSTR:      "SMACHOSYMSTR",
   102  	goobj_SMACHOSYMTAB:      "SMACHOSYMTAB",
   103  	goobj_SNOPTRBSS:         "SNOPTRBSS",
   104  	goobj_SNOPTRDATA:        "SNOPTRDATA",
   105  	goobj_SPCLNTAB:          "SPCLNTAB",
   106  	goobj_SRODATA:           "SRODATA",
   107  	goobj_SSTRING:           "SSTRING",
   108  	goobj_SSYMTAB:           "SSYMTAB",
   109  	goobj_STEXT:             "STEXT",
   110  	goobj_STLSBSS:           "STLSBSS",
   111  	goobj_STYPE:             "STYPE",
   112  	goobj_STYPELINK:         "STYPELINK",
   113  	goobj_SWINDOWS:          "SWINDOWS",
   114  	goobj_SXREF:             "SXREF",
   115  }
   116  
   117  func (k goobj_SymKind) String() string {
   118  	if k < 0 || int(k) >= len(goobj_symKindStrings) {
   119  		return fmt.Sprintf("SymKind(%d)", k)
   120  	}
   121  	return goobj_symKindStrings[k]
   122  }
   123  
   124  // A Sym is a named symbol in an object file.
   125  type goobj_Sym struct {
   126  	goobj_SymID               // symbol identifier (name and version)
   127  	Kind        goobj_SymKind // kind of symbol
   128  	DupOK       bool          // are duplicate definitions okay?
   129  	Size        int           // size of corresponding data
   130  	Type        goobj_SymID   // symbol for Go type information
   131  	Data        goobj_Data    // memory image of symbol
   132  	Reloc       []goobj_Reloc // relocations to apply to Data
   133  	Func        *goobj_Func   // additional data for functions
   134  }
   135  
   136  // A SymID - the combination of Name and Version - uniquely identifies
   137  // a symbol within a package.
   138  type goobj_SymID struct {
   139  	// Name is the name of a symbol.
   140  	Name string
   141  
   142  	// Version is zero for symbols with global visibility.
   143  	// Symbols with only file visibility (such as file-level static
   144  	// declarations in C) have a non-zero version distinguishing
   145  	// a symbol in one file from a symbol of the same name
   146  	// in another file
   147  	Version int
   148  }
   149  
   150  func (s goobj_SymID) String() string {
   151  	if s.Version == 0 {
   152  		return s.Name
   153  	}
   154  	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
   155  }
   156  
   157  // A Data is a reference to data stored in an object file.
   158  // It records the offset and size of the data, so that a client can
   159  // read the data only if necessary.
   160  type goobj_Data struct {
   161  	Offset int64
   162  	Size   int64
   163  }
   164  
   165  // A Reloc describes a relocation applied to a memory image to refer
   166  // to an address within a particular symbol.
   167  type goobj_Reloc struct {
   168  	// The bytes at [Offset, Offset+Size) within the memory image
   169  	// should be updated to refer to the address Add bytes after the start
   170  	// of the symbol Sym.
   171  	Offset int
   172  	Size   int
   173  	Sym    goobj_SymID
   174  	Add    int
   175  
   176  	// The Type records the form of address expected in the bytes
   177  	// described by the previous fields: absolute, PC-relative, and so on.
   178  	// TODO(rsc): The interpretation of Type is not exposed by this package.
   179  	Type int
   180  }
   181  
   182  // A Var describes a variable in a function stack frame: a declared
   183  // local variable, an input argument, or an output result.
   184  type goobj_Var struct {
   185  	// The combination of Name, Kind, and Offset uniquely
   186  	// identifies a variable in a function stack frame.
   187  	// Using fewer of these - in particular, using only Name - does not.
   188  	Name   string // Name of variable.
   189  	Kind   int    // TODO(rsc): Define meaning.
   190  	Offset int    // Frame offset. TODO(rsc): Define meaning.
   191  
   192  	Type goobj_SymID // Go type for variable.
   193  }
   194  
   195  // Func contains additional per-symbol information specific to functions.
   196  type goobj_Func struct {
   197  	Args     int              // size in bytes of argument frame: inputs and outputs
   198  	Frame    int              // size in bytes of local variable frame
   199  	Leaf     bool             // function omits save of link register (ARM)
   200  	NoSplit  bool             // function omits stack split prologue
   201  	Var      []goobj_Var      // detail about local variables
   202  	PCSP     goobj_Data       // PC → SP offset map
   203  	PCFile   goobj_Data       // PC → file number map (index into File)
   204  	PCLine   goobj_Data       // PC → line number map
   205  	PCData   []goobj_Data     // PC → runtime support data map
   206  	FuncData []goobj_FuncData // non-PC-specific runtime support data
   207  	File     []string         // paths indexed by PCFile
   208  }
   209  
   210  // TODO: Add PCData []byte and PCDataIter (similar to liblink).
   211  
   212  // A FuncData is a single function-specific data value.
   213  type goobj_FuncData struct {
   214  	Sym    goobj_SymID // symbol holding data
   215  	Offset int64       // offset into symbol for funcdata pointer
   216  }
   217  
   218  // A Package is a parsed Go object file or archive defining a Go package.
   219  type goobj_Package struct {
   220  	ImportPath string       // import path denoting this package
   221  	Imports    []string     // packages imported by this package
   222  	Syms       []*goobj_Sym // symbols defined by this package
   223  	MaxVersion int          // maximum Version in any SymID in Syms
   224  }
   225  
   226  var (
   227  	goobj_archiveHeader = []byte("!<arch>\n")
   228  	goobj_archiveMagic  = []byte("`\n")
   229  	goobj_goobjHeader   = []byte("go objec") // truncated to size of archiveHeader
   230  
   231  	goobj_errCorruptArchive   = errors.New("corrupt archive")
   232  	goobj_errTruncatedArchive = errors.New("truncated archive")
   233  	goobj_errNotArchive       = errors.New("unrecognized archive format")
   234  
   235  	goobj_errCorruptObject   = errors.New("corrupt object file")
   236  	goobj_errTruncatedObject = errors.New("truncated object file")
   237  	goobj_errNotObject       = errors.New("unrecognized object file format")
   238  )
   239  
   240  // An objReader is an object file reader.
   241  type goobj_objReader struct {
   242  	p         *goobj_Package
   243  	b         *bufio.Reader
   244  	f         io.ReadSeeker
   245  	err       error
   246  	offset    int64
   247  	limit     int64
   248  	tmp       [256]byte
   249  	pkg       string
   250  	pkgprefix string
   251  }
   252  
   253  // importPathToPrefix returns the prefix that will be used in the
   254  // final symbol table for the given import path.
   255  // We escape '%', '"', all control characters and non-ASCII bytes,
   256  // and any '.' after the final slash.
   257  //
   258  // See ../../../cmd/ld/lib.c:/^pathtoprefix and
   259  // ../../../cmd/gc/subr.c:/^pathtoprefix.
   260  func goobj_importPathToPrefix(s string) string {
   261  	// find index of last slash, if any, or else -1.
   262  	// used for determining whether an index is after the last slash.
   263  	slash := strings.LastIndex(s, "/")
   264  
   265  	// check for chars that need escaping
   266  	n := 0
   267  	for r := 0; r < len(s); r++ {
   268  		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
   269  			n++
   270  		}
   271  	}
   272  
   273  	// quick exit
   274  	if n == 0 {
   275  		return s
   276  	}
   277  
   278  	// escape
   279  	const hex = "0123456789abcdef"
   280  	p := make([]byte, 0, len(s)+2*n)
   281  	for r := 0; r < len(s); r++ {
   282  		if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F {
   283  			p = append(p, '%', hex[c>>4], hex[c&0xF])
   284  		} else {
   285  			p = append(p, c)
   286  		}
   287  	}
   288  
   289  	return string(p)
   290  }
   291  
   292  // init initializes r to read package p from f.
   293  func (r *goobj_objReader) init(f io.ReadSeeker, p *goobj_Package) {
   294  	r.f = f
   295  	r.p = p
   296  	r.offset, _ = f.Seek(0, 1)
   297  	r.limit, _ = f.Seek(0, 2)
   298  	f.Seek(r.offset, 0)
   299  	r.b = bufio.NewReader(f)
   300  	r.pkgprefix = goobj_importPathToPrefix(p.ImportPath) + "."
   301  }
   302  
   303  // error records that an error occurred.
   304  // It returns only the first error, so that an error
   305  // caused by an earlier error does not discard information
   306  // about the earlier error.
   307  func (r *goobj_objReader) error(err error) error {
   308  	if r.err == nil {
   309  		if err == io.EOF {
   310  			err = io.ErrUnexpectedEOF
   311  		}
   312  		r.err = err
   313  	}
   314  	// panic("corrupt") // useful for debugging
   315  	return r.err
   316  }
   317  
   318  // readByte reads and returns a byte from the input file.
   319  // On I/O error or EOF, it records the error but returns byte 0.
   320  // A sequence of 0 bytes will eventually terminate any
   321  // parsing state in the object file. In particular, it ends the
   322  // reading of a varint.
   323  func (r *goobj_objReader) readByte() byte {
   324  	if r.err != nil {
   325  		return 0
   326  	}
   327  	if r.offset >= r.limit {
   328  		r.error(io.ErrUnexpectedEOF)
   329  		return 0
   330  	}
   331  	b, err := r.b.ReadByte()
   332  	if err != nil {
   333  		if err == io.EOF {
   334  			err = io.ErrUnexpectedEOF
   335  		}
   336  		r.error(err)
   337  		b = 0
   338  	} else {
   339  		r.offset++
   340  	}
   341  	return b
   342  }
   343  
   344  // read reads exactly len(b) bytes from the input file.
   345  // If an error occurs, read returns the error but also
   346  // records it, so it is safe for callers to ignore the result
   347  // as long as delaying the report is not a problem.
   348  func (r *goobj_objReader) readFull(b []byte) error {
   349  	if r.err != nil {
   350  		return r.err
   351  	}
   352  	if r.offset+int64(len(b)) > r.limit {
   353  		return r.error(io.ErrUnexpectedEOF)
   354  	}
   355  	n, err := io.ReadFull(r.b, b)
   356  	r.offset += int64(n)
   357  	if err != nil {
   358  		return r.error(err)
   359  	}
   360  	return nil
   361  }
   362  
   363  // readInt reads a zigzag varint from the input file.
   364  func (r *goobj_objReader) readInt() int {
   365  	var u uint64
   366  
   367  	for shift := uint(0); ; shift += 7 {
   368  		if shift >= 64 {
   369  			r.error(goobj_errCorruptObject)
   370  			return 0
   371  		}
   372  		c := r.readByte()
   373  		u |= uint64(c&0x7F) << shift
   374  		if c&0x80 == 0 {
   375  			break
   376  		}
   377  	}
   378  
   379  	v := int64(u>>1) ^ (int64(u) << 63 >> 63)
   380  	if int64(int(v)) != v {
   381  		r.error(goobj_errCorruptObject) // TODO
   382  		return 0
   383  	}
   384  	return int(v)
   385  }
   386  
   387  // readString reads a length-delimited string from the input file.
   388  func (r *goobj_objReader) readString() string {
   389  	n := r.readInt()
   390  	buf := make([]byte, n)
   391  	r.readFull(buf)
   392  	return string(buf)
   393  }
   394  
   395  // readSymID reads a SymID from the input file.
   396  func (r *goobj_objReader) readSymID() goobj_SymID {
   397  	name, vers := r.readString(), r.readInt()
   398  
   399  	// In a symbol name in an object file, "". denotes the
   400  	// prefix for the package in which the object file has been found.
   401  	// Expand it.
   402  	name = strings.Replace(name, `"".`, r.pkgprefix, -1)
   403  
   404  	// An individual object file only records version 0 (extern) or 1 (static).
   405  	// To make static symbols unique across all files being read, we
   406  	// replace version 1 with the version corresponding to the current
   407  	// file number. The number is incremented on each call to parseObject.
   408  	if vers != 0 {
   409  		vers = r.p.MaxVersion
   410  	}
   411  
   412  	return goobj_SymID{name, vers}
   413  }
   414  
   415  // readData reads a data reference from the input file.
   416  func (r *goobj_objReader) readData() goobj_Data {
   417  	n := r.readInt()
   418  	d := goobj_Data{Offset: r.offset, Size: int64(n)}
   419  	r.skip(int64(n))
   420  	return d
   421  }
   422  
   423  // skip skips n bytes in the input.
   424  func (r *goobj_objReader) skip(n int64) {
   425  	if n < 0 {
   426  		r.error(fmt.Errorf("debug/goobj: internal error: misuse of skip"))
   427  	}
   428  	if n < int64(len(r.tmp)) {
   429  		// Since the data is so small, a just reading from the buffered
   430  		// reader is better than flushing the buffer and seeking.
   431  		r.readFull(r.tmp[:n])
   432  	} else if n <= int64(r.b.Buffered()) {
   433  		// Even though the data is not small, it has already been read.
   434  		// Advance the buffer instead of seeking.
   435  		for n > int64(len(r.tmp)) {
   436  			r.readFull(r.tmp[:])
   437  			n -= int64(len(r.tmp))
   438  		}
   439  		r.readFull(r.tmp[:n])
   440  	} else {
   441  		// Seek, giving up buffered data.
   442  		_, err := r.f.Seek(r.offset+n, 0)
   443  		if err != nil {
   444  			r.error(err)
   445  		}
   446  		r.offset += n
   447  		r.b.Reset(r.f)
   448  	}
   449  }
   450  
   451  // Parse parses an object file or archive from r,
   452  // assuming that its import path is pkgpath.
   453  func goobj_Parse(r io.ReadSeeker, pkgpath string) (*goobj_Package, error) {
   454  	if pkgpath == "" {
   455  		pkgpath = `""`
   456  	}
   457  	p := new(goobj_Package)
   458  	p.ImportPath = pkgpath
   459  
   460  	var rd goobj_objReader
   461  	rd.init(r, p)
   462  	err := rd.readFull(rd.tmp[:8])
   463  	if err != nil {
   464  		if err == io.EOF {
   465  			err = io.ErrUnexpectedEOF
   466  		}
   467  		return nil, err
   468  	}
   469  
   470  	switch {
   471  	default:
   472  		return nil, goobj_errNotObject
   473  
   474  	case bytes.Equal(rd.tmp[:8], goobj_archiveHeader):
   475  		if err := rd.parseArchive(); err != nil {
   476  			return nil, err
   477  		}
   478  	case bytes.Equal(rd.tmp[:8], goobj_goobjHeader):
   479  		if err := rd.parseObject(goobj_goobjHeader); err != nil {
   480  			return nil, err
   481  		}
   482  	}
   483  
   484  	return p, nil
   485  }
   486  
   487  // trimSpace removes trailing spaces from b and returns the corresponding string.
   488  // This effectively parses the form used in archive headers.
   489  func goobj_trimSpace(b []byte) string {
   490  	return string(bytes.TrimRight(b, " "))
   491  }
   492  
   493  // parseArchive parses a Unix archive of Go object files.
   494  // TODO(rsc): Need to skip non-Go object files.
   495  // TODO(rsc): Maybe record table of contents in r.p so that
   496  // linker can avoid having code to parse archives too.
   497  func (r *goobj_objReader) parseArchive() error {
   498  	for r.offset < r.limit {
   499  		if err := r.readFull(r.tmp[:60]); err != nil {
   500  			return err
   501  		}
   502  		data := r.tmp[:60]
   503  
   504  		// Each file is preceded by this text header (slice indices in first column):
   505  		//	 0:16	name
   506  		//	16:28 date
   507  		//	28:34 uid
   508  		//	34:40 gid
   509  		//	40:48 mode
   510  		//	48:58 size
   511  		//	58:60 magic - `\n
   512  		// We only care about name, size, and magic.
   513  		// The fields are space-padded on the right.
   514  		// The size is in decimal.
   515  		// The file data - size bytes - follows the header.
   516  		// Headers are 2-byte aligned, so if size is odd, an extra padding
   517  		// byte sits between the file data and the next header.
   518  		// The file data that follows is padded to an even number of bytes:
   519  		// if size is odd, an extra padding byte is inserted betw the next header.
   520  		if len(data) < 60 {
   521  			return goobj_errTruncatedArchive
   522  		}
   523  		if !bytes.Equal(data[58:60], goobj_archiveMagic) {
   524  			return goobj_errCorruptArchive
   525  		}
   526  		name := goobj_trimSpace(data[0:16])
   527  		size, err := strconv.ParseInt(goobj_trimSpace(data[48:58]), 10, 64)
   528  		if err != nil {
   529  			return goobj_errCorruptArchive
   530  		}
   531  		data = data[60:]
   532  		fsize := size + size&1
   533  		if fsize < 0 || fsize < size {
   534  			return goobj_errCorruptArchive
   535  		}
   536  		switch name {
   537  		case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF":
   538  			r.skip(size)
   539  		default:
   540  			oldLimit := r.limit
   541  			r.limit = r.offset + size
   542  			if err := r.parseObject(nil); err != nil {
   543  				return fmt.Errorf("parsing archive member %q: %v", name, err)
   544  			}
   545  			r.skip(r.limit - r.offset)
   546  			r.limit = oldLimit
   547  		}
   548  		if size&1 != 0 {
   549  			r.skip(1)
   550  		}
   551  	}
   552  	return nil
   553  }
   554  
   555  // parseObject parses a single Go object file.
   556  // The prefix is the bytes already read from the file,
   557  // typically in order to detect that this is an object file.
   558  // The object file consists of a textual header ending in "\n!\n"
   559  // and then the part we want to parse begins.
   560  // The format of that part is defined in a comment at the top
   561  // of src/liblink/objfile.c.
   562  func (r *goobj_objReader) parseObject(prefix []byte) error {
   563  	// TODO(rsc): Maybe use prefix and the initial input to
   564  	// record the header line from the file, which would
   565  	// give the architecture and other version information.
   566  
   567  	r.p.MaxVersion++
   568  	var c1, c2, c3 byte
   569  	for {
   570  		c1, c2, c3 = c2, c3, r.readByte()
   571  		if c3 == 0 { // NUL or EOF, either is bad
   572  			return goobj_errCorruptObject
   573  		}
   574  		if c1 == '\n' && c2 == '!' && c3 == '\n' {
   575  			break
   576  		}
   577  	}
   578  
   579  	r.readFull(r.tmp[:8])
   580  	if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) {
   581  		return r.error(goobj_errCorruptObject)
   582  	}
   583  
   584  	b := r.readByte()
   585  	if b != 1 {
   586  		return r.error(goobj_errCorruptObject)
   587  	}
   588  
   589  	// Direct package dependencies.
   590  	for {
   591  		s := r.readString()
   592  		if s == "" {
   593  			break
   594  		}
   595  		r.p.Imports = append(r.p.Imports, s)
   596  	}
   597  
   598  	// Symbols.
   599  	for {
   600  		if b := r.readByte(); b != 0xfe {
   601  			if b != 0xff {
   602  				return r.error(goobj_errCorruptObject)
   603  			}
   604  			break
   605  		}
   606  
   607  		typ := r.readInt()
   608  		s := &goobj_Sym{goobj_SymID: r.readSymID()}
   609  		r.p.Syms = append(r.p.Syms, s)
   610  		s.Kind = goobj_SymKind(typ)
   611  		s.DupOK = r.readInt() != 0
   612  		s.Size = r.readInt()
   613  		s.Type = r.readSymID()
   614  		s.Data = r.readData()
   615  		s.Reloc = make([]goobj_Reloc, r.readInt())
   616  		for i := range s.Reloc {
   617  			rel := &s.Reloc[i]
   618  			rel.Offset = r.readInt()
   619  			rel.Size = r.readInt()
   620  			rel.Type = r.readInt()
   621  			rel.Add = r.readInt()
   622  			r.readInt() // Xadd - ignored
   623  			rel.Sym = r.readSymID()
   624  			r.readSymID() // Xsym - ignored
   625  		}
   626  
   627  		if s.Kind == goobj_STEXT {
   628  			f := new(goobj_Func)
   629  			s.Func = f
   630  			f.Args = r.readInt()
   631  			f.Frame = r.readInt()
   632  			f.Leaf = r.readInt() != 0
   633  			f.NoSplit = r.readInt() != 0
   634  			f.Var = make([]goobj_Var, r.readInt())
   635  			for i := range f.Var {
   636  				v := &f.Var[i]
   637  				v.Name = r.readSymID().Name
   638  				v.Offset = r.readInt()
   639  				v.Kind = r.readInt()
   640  				v.Type = r.readSymID()
   641  			}
   642  
   643  			f.PCSP = r.readData()
   644  			f.PCFile = r.readData()
   645  			f.PCLine = r.readData()
   646  			f.PCData = make([]goobj_Data, r.readInt())
   647  			for i := range f.PCData {
   648  				f.PCData[i] = r.readData()
   649  			}
   650  			f.FuncData = make([]goobj_FuncData, r.readInt())
   651  			for i := range f.FuncData {
   652  				f.FuncData[i].Sym = r.readSymID()
   653  			}
   654  			for i := range f.FuncData {
   655  				f.FuncData[i].Offset = int64(r.readInt()) // TODO
   656  			}
   657  			f.File = make([]string, r.readInt())
   658  			for i := range f.File {
   659  				f.File[i] = r.readSymID().Name
   660  			}
   661  		}
   662  	}
   663  
   664  	r.readFull(r.tmp[:7])
   665  	if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) {
   666  		return r.error(goobj_errCorruptObject)
   667  	}
   668  
   669  	return nil
   670  }