...

Source file src/cmd/internal/goobj/objfile.go

Documentation: cmd/internal/goobj

     1  // Copyright 2019 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  // This package defines the Go object file format, and provide "low-level" functions
     6  // for reading and writing object files.
     7  
     8  // The object file is understood by the compiler, assembler, linker, and tools. They
     9  // have "high level" code that operates on object files, handling application-specific
    10  // logics, and use this package for the actual reading and writing. Specifically, the
    11  // code below:
    12  //
    13  // - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
    14  // - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump)
    15  // - cmd/link/internal/loader package (used by cmd/link)
    16  //
    17  // If the object file format changes, they may (or may not) need to change.
    18  
    19  package goobj
    20  
    21  import (
    22  	"cmd/internal/bio"
    23  	"encoding/binary"
    24  	"errors"
    25  	"fmt"
    26  	"unsafe"
    27  )
    28  
    29  // New object file format.
    30  //
    31  //    Header struct {
    32  //       Magic       [...]byte   // "\x00go120ld"
    33  //       Fingerprint [8]byte
    34  //       Flags       uint32
    35  //       Offsets     [...]uint32 // byte offset of each block below
    36  //    }
    37  //
    38  //    Strings [...]struct {
    39  //       Data [...]byte
    40  //    }
    41  //
    42  //    Autolib  [...]struct { // imported packages (for file loading)
    43  //       Pkg         string
    44  //       Fingerprint [8]byte
    45  //    }
    46  //
    47  //    PkgIndex [...]string // referenced packages by index
    48  //
    49  //    Files [...]string
    50  //
    51  //    SymbolDefs [...]struct {
    52  //       Name  string
    53  //       ABI   uint16
    54  //       Type  uint8
    55  //       Flag  uint8
    56  //       Flag2 uint8
    57  //       Size  uint32
    58  //    }
    59  //    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
    60  //       ... // same as SymbolDefs
    61  //    }
    62  //    HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
    63  //       ... // same as SymbolDefs
    64  //    }
    65  //    NonPkgDefs [...]struct { // non-pkg symbol definitions
    66  //       ... // same as SymbolDefs
    67  //    }
    68  //    NonPkgRefs [...]struct { // non-pkg symbol references
    69  //       ... // same as SymbolDefs
    70  //    }
    71  //
    72  //    RefFlags [...]struct { // referenced symbol flags
    73  //       Sym   symRef
    74  //       Flag  uint8
    75  //       Flag2 uint8
    76  //    }
    77  //
    78  //    Hash64 [...][8]byte
    79  //    Hash   [...][N]byte
    80  //
    81  //    RelocIndex [...]uint32 // index to Relocs
    82  //    AuxIndex   [...]uint32 // index to Aux
    83  //    DataIndex  [...]uint32 // offset to Data
    84  //
    85  //    Relocs [...]struct {
    86  //       Off  int32
    87  //       Size uint8
    88  //       Type uint16
    89  //       Add  int64
    90  //       Sym  symRef
    91  //    }
    92  //
    93  //    Aux [...]struct {
    94  //       Type uint8
    95  //       Sym  symRef
    96  //    }
    97  //
    98  //    Data   [...]byte
    99  //
   100  //    // blocks only used by tools (objdump, nm)
   101  //
   102  //    RefNames [...]struct { // referenced symbol names
   103  //       Sym  symRef
   104  //       Name string
   105  //       // TODO: include ABI version as well?
   106  //    }
   107  //
   108  // string is encoded as is a uint32 length followed by a uint32 offset
   109  // that points to the corresponding string bytes.
   110  //
   111  // symRef is struct { PkgIdx, SymIdx uint32 }.
   112  //
   113  // Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
   114  // followed by that number of elements.
   115  //
   116  // The types below correspond to the encoded data structure in the
   117  // object file.
   118  
   119  // Symbol indexing.
   120  //
   121  // Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
   122  // as the symRef struct above.
   123  //
   124  // PkgIdx is either a predeclared index (see PkgIdxNone below) or
   125  // an index of an imported package. For the latter case, PkgIdx is the
   126  // index of the package in the PkgIndex array. 0 is an invalid index.
   127  //
   128  // SymIdx is the index of the symbol in the given package.
   129  // - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
   130  //   SymbolDefs array.
   131  // - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
   132  //   Hashed64Defs array.
   133  // - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
   134  //   HashedDefs array.
   135  // - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
   136  //   NonPkgDefs array (could naturally overflow to NonPkgRefs array).
   137  // - Otherwise, SymIdx is the index of the symbol in some other package's
   138  //   SymbolDefs array.
   139  //
   140  // {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
   141  //
   142  // Hash contains the content hashes of content-addressable symbols, of
   143  // which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
   144  // Hash64 is similar, for PkgIdxHashed64 symbols.
   145  //
   146  // RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
   147  // Relocs/Aux/Data blocks, one element per symbol, first for all the
   148  // defined symbols, then all the defined hashed and non-package symbols,
   149  // in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
   150  // arrays. For N total defined symbols, the array is of length N+1. The
   151  // last element is the total number of relocations (aux symbols, data
   152  // blocks, etc.).
   153  //
   154  // They can be accessed by index. For the i-th symbol, its relocations
   155  // are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
   156  // elements in the Relocs array. Aux/Data are likewise. (The index is
   157  // 0-based.)
   158  
   159  // Auxiliary symbols.
   160  //
   161  // Each symbol may (or may not) be associated with a number of auxiliary
   162  // symbols. They are described in the Aux block. See Aux struct below.
   163  // Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
   164  // are auxiliary symbols.
   165  
   166  const stringRefSize = 8 // two uint32s
   167  
   168  type FingerprintType [8]byte
   169  
   170  func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
   171  
   172  // Package Index.
   173  const (
   174  	PkgIdxNone     = (1<<31 - 1) - iota // Non-package symbols
   175  	PkgIdxHashed64                      // Short hashed (content-addressable) symbols
   176  	PkgIdxHashed                        // Hashed (content-addressable) symbols
   177  	PkgIdxBuiltin                       // Predefined runtime symbols (ex: runtime.newobject)
   178  	PkgIdxSelf                          // Symbols defined in the current package
   179  	PkgIdxSpecial  = PkgIdxSelf         // Indices above it has special meanings
   180  	PkgIdxInvalid  = 0
   181  	// The index of other referenced packages starts from 1.
   182  )
   183  
   184  // Blocks
   185  const (
   186  	BlkAutolib = iota
   187  	BlkPkgIdx
   188  	BlkFile
   189  	BlkSymdef
   190  	BlkHashed64def
   191  	BlkHasheddef
   192  	BlkNonpkgdef
   193  	BlkNonpkgref
   194  	BlkRefFlags
   195  	BlkHash64
   196  	BlkHash
   197  	BlkRelocIdx
   198  	BlkAuxIdx
   199  	BlkDataIdx
   200  	BlkReloc
   201  	BlkAux
   202  	BlkData
   203  	BlkRefName
   204  	BlkEnd
   205  	NBlk
   206  )
   207  
   208  // File header.
   209  // TODO: probably no need to export this.
   210  type Header struct {
   211  	Magic       string
   212  	Fingerprint FingerprintType
   213  	Flags       uint32
   214  	Offsets     [NBlk]uint32
   215  }
   216  
   217  const Magic = "\x00go120ld"
   218  
   219  func (h *Header) Write(w *Writer) {
   220  	w.RawString(h.Magic)
   221  	w.Bytes(h.Fingerprint[:])
   222  	w.Uint32(h.Flags)
   223  	for _, x := range h.Offsets {
   224  		w.Uint32(x)
   225  	}
   226  }
   227  
   228  func (h *Header) Read(r *Reader) error {
   229  	b := r.BytesAt(0, len(Magic))
   230  	h.Magic = string(b)
   231  	if h.Magic != Magic {
   232  		return errors.New("wrong magic, not a Go object file")
   233  	}
   234  	off := uint32(len(h.Magic))
   235  	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
   236  	off += 8
   237  	h.Flags = r.uint32At(off)
   238  	off += 4
   239  	for i := range h.Offsets {
   240  		h.Offsets[i] = r.uint32At(off)
   241  		off += 4
   242  	}
   243  	return nil
   244  }
   245  
   246  func (h *Header) Size() int {
   247  	return len(h.Magic) + len(h.Fingerprint) + 4 + 4*len(h.Offsets)
   248  }
   249  
   250  // Autolib
   251  type ImportedPkg struct {
   252  	Pkg         string
   253  	Fingerprint FingerprintType
   254  }
   255  
   256  const importedPkgSize = stringRefSize + 8
   257  
   258  func (p *ImportedPkg) Write(w *Writer) {
   259  	w.StringRef(p.Pkg)
   260  	w.Bytes(p.Fingerprint[:])
   261  }
   262  
   263  // Symbol definition.
   264  //
   265  // Serialized format:
   266  //
   267  //	Sym struct {
   268  //	   Name  string
   269  //	   ABI   uint16
   270  //	   Type  uint8
   271  //	   Flag  uint8
   272  //	   Flag2 uint8
   273  //	   Siz   uint32
   274  //	   Align uint32
   275  //	}
   276  type Sym [SymSize]byte
   277  
   278  const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
   279  
   280  const SymABIstatic = ^uint16(0)
   281  
   282  const (
   283  	ObjFlagShared       = 1 << iota // this object is built with -shared
   284  	_                               // was ObjFlagNeedNameExpansion
   285  	ObjFlagFromAssembly             // object is from asm src, not go
   286  	ObjFlagUnlinkable               // unlinkable package (linker will emit an error)
   287  	ObjFlagStd                      // standard library package
   288  )
   289  
   290  // Sym.Flag
   291  const (
   292  	SymFlagDupok = 1 << iota
   293  	SymFlagLocal
   294  	SymFlagTypelink
   295  	SymFlagLeaf
   296  	SymFlagNoSplit
   297  	SymFlagReflectMethod
   298  	SymFlagGoType
   299  )
   300  
   301  // Sym.Flag2
   302  const (
   303  	SymFlagUsedInIface = 1 << iota
   304  	SymFlagItab
   305  	SymFlagDict
   306  	SymFlagPkgInit
   307  	SymFlagLinkname
   308  	SymFlagABIWrapper
   309  )
   310  
   311  // Returns the length of the name of the symbol.
   312  func (s *Sym) NameLen(r *Reader) int {
   313  	return int(binary.LittleEndian.Uint32(s[:]))
   314  }
   315  
   316  func (s *Sym) Name(r *Reader) string {
   317  	len := binary.LittleEndian.Uint32(s[:])
   318  	off := binary.LittleEndian.Uint32(s[4:])
   319  	return r.StringAt(off, len)
   320  }
   321  
   322  func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
   323  func (s *Sym) Type() uint8   { return s[10] }
   324  func (s *Sym) Flag() uint8   { return s[11] }
   325  func (s *Sym) Flag2() uint8  { return s[12] }
   326  func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
   327  func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
   328  
   329  func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
   330  func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
   331  func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
   332  func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
   333  func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
   334  func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
   335  func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
   336  func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
   337  func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
   338  func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
   339  func (s *Sym) IsPkgInit() bool     { return s.Flag2()&SymFlagPkgInit != 0 }
   340  func (s *Sym) IsLinkname() bool    { return s.Flag2()&SymFlagLinkname != 0 }
   341  func (s *Sym) ABIWrapper() bool    { return s.Flag2()&SymFlagABIWrapper != 0 }
   342  
   343  func (s *Sym) SetName(x string, w *Writer) {
   344  	binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
   345  	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
   346  }
   347  
   348  func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) }
   349  func (s *Sym) SetType(x uint8)   { s[10] = x }
   350  func (s *Sym) SetFlag(x uint8)   { s[11] = x }
   351  func (s *Sym) SetFlag2(x uint8)  { s[12] = x }
   352  func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) }
   353  func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
   354  
   355  func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
   356  
   357  // for testing
   358  func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
   359  
   360  // Symbol reference.
   361  type SymRef struct {
   362  	PkgIdx uint32
   363  	SymIdx uint32
   364  }
   365  
   366  func (s SymRef) IsZero() bool { return s == SymRef{} }
   367  
   368  // Hash64
   369  type Hash64Type [Hash64Size]byte
   370  
   371  const Hash64Size = 8
   372  
   373  // Hash
   374  type HashType [HashSize]byte
   375  
   376  const HashSize = 16 // truncated SHA256
   377  
   378  // Relocation.
   379  //
   380  // Serialized format:
   381  //
   382  //	Reloc struct {
   383  //	   Off  int32
   384  //	   Siz  uint8
   385  //	   Type uint16
   386  //	   Add  int64
   387  //	   Sym  SymRef
   388  //	}
   389  type Reloc [RelocSize]byte
   390  
   391  const RelocSize = 4 + 1 + 2 + 8 + 8
   392  
   393  func (r *Reloc) Off() int32   { return int32(binary.LittleEndian.Uint32(r[:])) }
   394  func (r *Reloc) Siz() uint8   { return r[4] }
   395  func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) }
   396  func (r *Reloc) Add() int64   { return int64(binary.LittleEndian.Uint64(r[7:])) }
   397  func (r *Reloc) Sym() SymRef {
   398  	return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])}
   399  }
   400  
   401  func (r *Reloc) SetOff(x int32)   { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
   402  func (r *Reloc) SetSiz(x uint8)   { r[4] = x }
   403  func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) }
   404  func (r *Reloc) SetAdd(x int64)   { binary.LittleEndian.PutUint64(r[7:], uint64(x)) }
   405  func (r *Reloc) SetSym(x SymRef) {
   406  	binary.LittleEndian.PutUint32(r[15:], x.PkgIdx)
   407  	binary.LittleEndian.PutUint32(r[19:], x.SymIdx)
   408  }
   409  
   410  func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) {
   411  	r.SetOff(off)
   412  	r.SetSiz(size)
   413  	r.SetType(typ)
   414  	r.SetAdd(add)
   415  	r.SetSym(sym)
   416  }
   417  
   418  func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
   419  
   420  // for testing
   421  func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
   422  
   423  // Aux symbol info.
   424  //
   425  // Serialized format:
   426  //
   427  //	Aux struct {
   428  //	   Type uint8
   429  //	   Sym  SymRef
   430  //	}
   431  type Aux [AuxSize]byte
   432  
   433  const AuxSize = 1 + 8
   434  
   435  // Aux Type
   436  const (
   437  	AuxGotype = iota
   438  	AuxFuncInfo
   439  	AuxFuncdata
   440  	AuxDwarfInfo
   441  	AuxDwarfLoc
   442  	AuxDwarfRanges
   443  	AuxDwarfLines
   444  	AuxPcsp
   445  	AuxPcfile
   446  	AuxPcline
   447  	AuxPcinline
   448  	AuxPcdata
   449  	AuxWasmImport
   450  	AuxSehUnwindInfo
   451  )
   452  
   453  func (a *Aux) Type() uint8 { return a[0] }
   454  func (a *Aux) Sym() SymRef {
   455  	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
   456  }
   457  
   458  func (a *Aux) SetType(x uint8) { a[0] = x }
   459  func (a *Aux) SetSym(x SymRef) {
   460  	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
   461  	binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
   462  }
   463  
   464  func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
   465  
   466  // for testing
   467  func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
   468  
   469  // Referenced symbol flags.
   470  //
   471  // Serialized format:
   472  //
   473  //	RefFlags struct {
   474  //	   Sym   symRef
   475  //	   Flag  uint8
   476  //	   Flag2 uint8
   477  //	}
   478  type RefFlags [RefFlagsSize]byte
   479  
   480  const RefFlagsSize = 8 + 1 + 1
   481  
   482  func (r *RefFlags) Sym() SymRef {
   483  	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
   484  }
   485  func (r *RefFlags) Flag() uint8  { return r[8] }
   486  func (r *RefFlags) Flag2() uint8 { return r[9] }
   487  
   488  func (r *RefFlags) SetSym(x SymRef) {
   489  	binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
   490  	binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
   491  }
   492  func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
   493  func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
   494  
   495  func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
   496  
   497  // Used to construct an artificially large array type when reading an
   498  // item from the object file relocs section or aux sym section (needs
   499  // to work on 32-bit as well as 64-bit). See issue 41621.
   500  const huge = (1<<31 - 1) / RelocSize
   501  
   502  // Referenced symbol name.
   503  //
   504  // Serialized format:
   505  //
   506  //	RefName struct {
   507  //	   Sym  symRef
   508  //	   Name string
   509  //	}
   510  type RefName [RefNameSize]byte
   511  
   512  const RefNameSize = 8 + stringRefSize
   513  
   514  func (n *RefName) Sym() SymRef {
   515  	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
   516  }
   517  func (n *RefName) Name(r *Reader) string {
   518  	len := binary.LittleEndian.Uint32(n[8:])
   519  	off := binary.LittleEndian.Uint32(n[12:])
   520  	return r.StringAt(off, len)
   521  }
   522  
   523  func (n *RefName) SetSym(x SymRef) {
   524  	binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
   525  	binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
   526  }
   527  func (n *RefName) SetName(x string, w *Writer) {
   528  	binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
   529  	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
   530  }
   531  
   532  func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
   533  
   534  type Writer struct {
   535  	wr        *bio.Writer
   536  	stringMap map[string]uint32
   537  	off       uint32 // running offset
   538  
   539  	b [8]byte // scratch space for writing bytes
   540  }
   541  
   542  func NewWriter(wr *bio.Writer) *Writer {
   543  	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
   544  }
   545  
   546  func (w *Writer) AddString(s string) {
   547  	if _, ok := w.stringMap[s]; ok {
   548  		return
   549  	}
   550  	w.stringMap[s] = w.off
   551  	w.RawString(s)
   552  }
   553  
   554  func (w *Writer) stringOff(s string) uint32 {
   555  	off, ok := w.stringMap[s]
   556  	if !ok {
   557  		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
   558  	}
   559  	return off
   560  }
   561  
   562  func (w *Writer) StringRef(s string) {
   563  	w.Uint32(uint32(len(s)))
   564  	w.Uint32(w.stringOff(s))
   565  }
   566  
   567  func (w *Writer) RawString(s string) {
   568  	w.wr.WriteString(s)
   569  	w.off += uint32(len(s))
   570  }
   571  
   572  func (w *Writer) Bytes(s []byte) {
   573  	w.wr.Write(s)
   574  	w.off += uint32(len(s))
   575  }
   576  
   577  func (w *Writer) Uint64(x uint64) {
   578  	binary.LittleEndian.PutUint64(w.b[:], x)
   579  	w.wr.Write(w.b[:])
   580  	w.off += 8
   581  }
   582  
   583  func (w *Writer) Uint32(x uint32) {
   584  	binary.LittleEndian.PutUint32(w.b[:4], x)
   585  	w.wr.Write(w.b[:4])
   586  	w.off += 4
   587  }
   588  
   589  func (w *Writer) Uint16(x uint16) {
   590  	binary.LittleEndian.PutUint16(w.b[:2], x)
   591  	w.wr.Write(w.b[:2])
   592  	w.off += 2
   593  }
   594  
   595  func (w *Writer) Uint8(x uint8) {
   596  	w.wr.WriteByte(x)
   597  	w.off++
   598  }
   599  
   600  func (w *Writer) Offset() uint32 {
   601  	return w.off
   602  }
   603  
   604  type Reader struct {
   605  	b        []byte // mmapped bytes, if not nil
   606  	readonly bool   // whether b is backed with read-only memory
   607  
   608  	start uint32
   609  	h     Header // keep block offsets
   610  }
   611  
   612  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   613  	r := &Reader{b: b, readonly: readonly, start: 0}
   614  	err := r.h.Read(r)
   615  	if err != nil {
   616  		return nil
   617  	}
   618  	return r
   619  }
   620  
   621  func (r *Reader) BytesAt(off uint32, len int) []byte {
   622  	if len == 0 {
   623  		return nil
   624  	}
   625  	end := int(off) + len
   626  	return r.b[int(off):end:end]
   627  }
   628  
   629  func (r *Reader) uint64At(off uint32) uint64 {
   630  	b := r.BytesAt(off, 8)
   631  	return binary.LittleEndian.Uint64(b)
   632  }
   633  
   634  func (r *Reader) int64At(off uint32) int64 {
   635  	return int64(r.uint64At(off))
   636  }
   637  
   638  func (r *Reader) uint32At(off uint32) uint32 {
   639  	b := r.BytesAt(off, 4)
   640  	return binary.LittleEndian.Uint32(b)
   641  }
   642  
   643  func (r *Reader) int32At(off uint32) int32 {
   644  	return int32(r.uint32At(off))
   645  }
   646  
   647  func (r *Reader) uint16At(off uint32) uint16 {
   648  	b := r.BytesAt(off, 2)
   649  	return binary.LittleEndian.Uint16(b)
   650  }
   651  
   652  func (r *Reader) uint8At(off uint32) uint8 {
   653  	b := r.BytesAt(off, 1)
   654  	return b[0]
   655  }
   656  
   657  func (r *Reader) StringAt(off uint32, len uint32) string {
   658  	b := r.b[off : off+len]
   659  	if r.readonly {
   660  		return toString(b) // backed by RO memory, ok to make unsafe string
   661  	}
   662  	return string(b)
   663  }
   664  
   665  func toString(b []byte) string {
   666  	if len(b) == 0 {
   667  		return ""
   668  	}
   669  	return unsafe.String(&b[0], len(b))
   670  }
   671  
   672  func (r *Reader) StringRef(off uint32) string {
   673  	l := r.uint32At(off)
   674  	return r.StringAt(r.uint32At(off+4), l)
   675  }
   676  
   677  func (r *Reader) Fingerprint() FingerprintType {
   678  	return r.h.Fingerprint
   679  }
   680  
   681  func (r *Reader) Autolib() []ImportedPkg {
   682  	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
   683  	s := make([]ImportedPkg, n)
   684  	off := r.h.Offsets[BlkAutolib]
   685  	for i := range s {
   686  		s[i].Pkg = r.StringRef(off)
   687  		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
   688  		off += importedPkgSize
   689  	}
   690  	return s
   691  }
   692  
   693  func (r *Reader) Pkglist() []string {
   694  	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
   695  	s := make([]string, n)
   696  	off := r.h.Offsets[BlkPkgIdx]
   697  	for i := range s {
   698  		s[i] = r.StringRef(off)
   699  		off += stringRefSize
   700  	}
   701  	return s
   702  }
   703  
   704  func (r *Reader) NPkg() int {
   705  	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
   706  }
   707  
   708  func (r *Reader) Pkg(i int) string {
   709  	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
   710  	return r.StringRef(off)
   711  }
   712  
   713  func (r *Reader) NFile() int {
   714  	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
   715  }
   716  
   717  func (r *Reader) File(i int) string {
   718  	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
   719  	return r.StringRef(off)
   720  }
   721  
   722  func (r *Reader) NSym() int {
   723  	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
   724  }
   725  
   726  func (r *Reader) NHashed64def() int {
   727  	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
   728  }
   729  
   730  func (r *Reader) NHasheddef() int {
   731  	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
   732  }
   733  
   734  func (r *Reader) NNonpkgdef() int {
   735  	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
   736  }
   737  
   738  func (r *Reader) NNonpkgref() int {
   739  	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
   740  }
   741  
   742  // SymOff returns the offset of the i-th symbol.
   743  func (r *Reader) SymOff(i uint32) uint32 {
   744  	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
   745  }
   746  
   747  // Sym returns a pointer to the i-th symbol.
   748  func (r *Reader) Sym(i uint32) *Sym {
   749  	off := r.SymOff(i)
   750  	return (*Sym)(unsafe.Pointer(&r.b[off]))
   751  }
   752  
   753  // NRefFlags returns the number of referenced symbol flags.
   754  func (r *Reader) NRefFlags() int {
   755  	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
   756  }
   757  
   758  // RefFlags returns a pointer to the i-th referenced symbol flags.
   759  // Note: here i is not a local symbol index, just a counter.
   760  func (r *Reader) RefFlags(i int) *RefFlags {
   761  	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
   762  	return (*RefFlags)(unsafe.Pointer(&r.b[off]))
   763  }
   764  
   765  // Hash64 returns the i-th short hashed symbol's hash.
   766  // Note: here i is the index of short hashed symbols, not all symbols
   767  // (unlike other accessors).
   768  func (r *Reader) Hash64(i uint32) uint64 {
   769  	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
   770  	return r.uint64At(off)
   771  }
   772  
   773  // Hash returns a pointer to the i-th hashed symbol's hash.
   774  // Note: here i is the index of hashed symbols, not all symbols
   775  // (unlike other accessors).
   776  func (r *Reader) Hash(i uint32) *HashType {
   777  	off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
   778  	return (*HashType)(unsafe.Pointer(&r.b[off]))
   779  }
   780  
   781  // NReloc returns the number of relocations of the i-th symbol.
   782  func (r *Reader) NReloc(i uint32) int {
   783  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   784  	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
   785  }
   786  
   787  // RelocOff returns the offset of the j-th relocation of the i-th symbol.
   788  func (r *Reader) RelocOff(i uint32, j int) uint32 {
   789  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   790  	relocIdx := r.uint32At(relocIdxOff)
   791  	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
   792  }
   793  
   794  // Reloc returns a pointer to the j-th relocation of the i-th symbol.
   795  func (r *Reader) Reloc(i uint32, j int) *Reloc {
   796  	off := r.RelocOff(i, j)
   797  	return (*Reloc)(unsafe.Pointer(&r.b[off]))
   798  }
   799  
   800  // Relocs returns a pointer to the relocations of the i-th symbol.
   801  func (r *Reader) Relocs(i uint32) []Reloc {
   802  	off := r.RelocOff(i, 0)
   803  	n := r.NReloc(i)
   804  	return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
   805  }
   806  
   807  // NAux returns the number of aux symbols of the i-th symbol.
   808  func (r *Reader) NAux(i uint32) int {
   809  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   810  	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
   811  }
   812  
   813  // AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
   814  func (r *Reader) AuxOff(i uint32, j int) uint32 {
   815  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   816  	auxIdx := r.uint32At(auxIdxOff)
   817  	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
   818  }
   819  
   820  // Aux returns a pointer to the j-th aux symbol of the i-th symbol.
   821  func (r *Reader) Aux(i uint32, j int) *Aux {
   822  	off := r.AuxOff(i, j)
   823  	return (*Aux)(unsafe.Pointer(&r.b[off]))
   824  }
   825  
   826  // Auxs returns the aux symbols of the i-th symbol.
   827  func (r *Reader) Auxs(i uint32) []Aux {
   828  	off := r.AuxOff(i, 0)
   829  	n := r.NAux(i)
   830  	return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
   831  }
   832  
   833  // DataOff returns the offset of the i-th symbol's data.
   834  func (r *Reader) DataOff(i uint32) uint32 {
   835  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   836  	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
   837  }
   838  
   839  // DataSize returns the size of the i-th symbol's data.
   840  func (r *Reader) DataSize(i uint32) int {
   841  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   842  	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
   843  }
   844  
   845  // Data returns the i-th symbol's data.
   846  func (r *Reader) Data(i uint32) []byte {
   847  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   848  	base := r.h.Offsets[BlkData]
   849  	off := r.uint32At(dataIdxOff)
   850  	end := r.uint32At(dataIdxOff + 4)
   851  	return r.BytesAt(base+off, int(end-off))
   852  }
   853  
   854  // DataString returns the i-th symbol's data as a string.
   855  func (r *Reader) DataString(i uint32) string {
   856  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   857  	base := r.h.Offsets[BlkData]
   858  	off := r.uint32At(dataIdxOff)
   859  	end := r.uint32At(dataIdxOff + 4)
   860  	return r.StringAt(base+off, end-off)
   861  }
   862  
   863  // NRefName returns the number of referenced symbol names.
   864  func (r *Reader) NRefName() int {
   865  	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
   866  }
   867  
   868  // RefName returns a pointer to the i-th referenced symbol name.
   869  // Note: here i is not a local symbol index, just a counter.
   870  func (r *Reader) RefName(i int) *RefName {
   871  	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
   872  	return (*RefName)(unsafe.Pointer(&r.b[off]))
   873  }
   874  
   875  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   876  func (r *Reader) ReadOnly() bool {
   877  	return r.readonly
   878  }
   879  
   880  // Flags returns the flag bits read from the object file header.
   881  func (r *Reader) Flags() uint32 {
   882  	return r.h.Flags
   883  }
   884  
   885  func (r *Reader) Shared() bool       { return r.Flags()&ObjFlagShared != 0 }
   886  func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
   887  func (r *Reader) Unlinkable() bool   { return r.Flags()&ObjFlagUnlinkable != 0 }
   888  func (r *Reader) Std() bool          { return r.Flags()&ObjFlagStd != 0 }
   889  

View as plain text