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

     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  )
   288  
   289  // Sym.Flag
   290  const (
   291  	SymFlagDupok = 1 << iota
   292  	SymFlagLocal
   293  	SymFlagTypelink
   294  	SymFlagLeaf
   295  	SymFlagNoSplit
   296  	SymFlagReflectMethod
   297  	SymFlagGoType
   298  )
   299  
   300  // Sym.Flag2
   301  const (
   302  	SymFlagUsedInIface = 1 << iota
   303  	SymFlagItab
   304  	SymFlagDict
   305  	SymFlagPkgInit
   306  )
   307  
   308  // Returns the length of the name of the symbol.
   309  func (s *Sym) NameLen(r *Reader) int {
   310  	return int(binary.LittleEndian.Uint32(s[:]))
   311  }
   312  
   313  func (s *Sym) Name(r *Reader) string {
   314  	len := binary.LittleEndian.Uint32(s[:])
   315  	off := binary.LittleEndian.Uint32(s[4:])
   316  	return r.StringAt(off, len)
   317  }
   318  
   319  func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
   320  func (s *Sym) Type() uint8   { return s[10] }
   321  func (s *Sym) Flag() uint8   { return s[11] }
   322  func (s *Sym) Flag2() uint8  { return s[12] }
   323  func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
   324  func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
   325  
   326  func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
   327  func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
   328  func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
   329  func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
   330  func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
   331  func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
   332  func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
   333  func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
   334  func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
   335  func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
   336  func (s *Sym) IsPkgInit() bool     { return s.Flag2()&SymFlagPkgInit != 0 }
   337  
   338  func (s *Sym) SetName(x string, w *Writer) {
   339  	binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
   340  	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
   341  }
   342  
   343  func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) }
   344  func (s *Sym) SetType(x uint8)   { s[10] = x }
   345  func (s *Sym) SetFlag(x uint8)   { s[11] = x }
   346  func (s *Sym) SetFlag2(x uint8)  { s[12] = x }
   347  func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) }
   348  func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
   349  
   350  func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
   351  
   352  // for testing
   353  func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
   354  
   355  // Symbol reference.
   356  type SymRef struct {
   357  	PkgIdx uint32
   358  	SymIdx uint32
   359  }
   360  
   361  func (s SymRef) IsZero() bool { return s == SymRef{} }
   362  
   363  // Hash64
   364  type Hash64Type [Hash64Size]byte
   365  
   366  const Hash64Size = 8
   367  
   368  // Hash
   369  type HashType [HashSize]byte
   370  
   371  const HashSize = 16 // truncated SHA256
   372  
   373  // Relocation.
   374  //
   375  // Serialized format:
   376  //
   377  //	Reloc struct {
   378  //	   Off  int32
   379  //	   Siz  uint8
   380  //	   Type uint16
   381  //	   Add  int64
   382  //	   Sym  SymRef
   383  //	}
   384  type Reloc [RelocSize]byte
   385  
   386  const RelocSize = 4 + 1 + 2 + 8 + 8
   387  
   388  func (r *Reloc) Off() int32   { return int32(binary.LittleEndian.Uint32(r[:])) }
   389  func (r *Reloc) Siz() uint8   { return r[4] }
   390  func (r *Reloc) Type() uint16 { return binary.LittleEndian.Uint16(r[5:]) }
   391  func (r *Reloc) Add() int64   { return int64(binary.LittleEndian.Uint64(r[7:])) }
   392  func (r *Reloc) Sym() SymRef {
   393  	return SymRef{binary.LittleEndian.Uint32(r[15:]), binary.LittleEndian.Uint32(r[19:])}
   394  }
   395  
   396  func (r *Reloc) SetOff(x int32)   { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
   397  func (r *Reloc) SetSiz(x uint8)   { r[4] = x }
   398  func (r *Reloc) SetType(x uint16) { binary.LittleEndian.PutUint16(r[5:], x) }
   399  func (r *Reloc) SetAdd(x int64)   { binary.LittleEndian.PutUint64(r[7:], uint64(x)) }
   400  func (r *Reloc) SetSym(x SymRef) {
   401  	binary.LittleEndian.PutUint32(r[15:], x.PkgIdx)
   402  	binary.LittleEndian.PutUint32(r[19:], x.SymIdx)
   403  }
   404  
   405  func (r *Reloc) Set(off int32, size uint8, typ uint16, add int64, sym SymRef) {
   406  	r.SetOff(off)
   407  	r.SetSiz(size)
   408  	r.SetType(typ)
   409  	r.SetAdd(add)
   410  	r.SetSym(sym)
   411  }
   412  
   413  func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
   414  
   415  // for testing
   416  func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
   417  
   418  // Aux symbol info.
   419  //
   420  // Serialized format:
   421  //
   422  //	Aux struct {
   423  //	   Type uint8
   424  //	   Sym  SymRef
   425  //	}
   426  type Aux [AuxSize]byte
   427  
   428  const AuxSize = 1 + 8
   429  
   430  // Aux Type
   431  const (
   432  	AuxGotype = iota
   433  	AuxFuncInfo
   434  	AuxFuncdata
   435  	AuxDwarfInfo
   436  	AuxDwarfLoc
   437  	AuxDwarfRanges
   438  	AuxDwarfLines
   439  	AuxPcsp
   440  	AuxPcfile
   441  	AuxPcline
   442  	AuxPcinline
   443  	AuxPcdata
   444  	AuxWasmImport
   445  	AuxSehUnwindInfo
   446  )
   447  
   448  func (a *Aux) Type() uint8 { return a[0] }
   449  func (a *Aux) Sym() SymRef {
   450  	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
   451  }
   452  
   453  func (a *Aux) SetType(x uint8) { a[0] = x }
   454  func (a *Aux) SetSym(x SymRef) {
   455  	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
   456  	binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
   457  }
   458  
   459  func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
   460  
   461  // for testing
   462  func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
   463  
   464  // Referenced symbol flags.
   465  //
   466  // Serialized format:
   467  //
   468  //	RefFlags struct {
   469  //	   Sym   symRef
   470  //	   Flag  uint8
   471  //	   Flag2 uint8
   472  //	}
   473  type RefFlags [RefFlagsSize]byte
   474  
   475  const RefFlagsSize = 8 + 1 + 1
   476  
   477  func (r *RefFlags) Sym() SymRef {
   478  	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
   479  }
   480  func (r *RefFlags) Flag() uint8  { return r[8] }
   481  func (r *RefFlags) Flag2() uint8 { return r[9] }
   482  
   483  func (r *RefFlags) SetSym(x SymRef) {
   484  	binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
   485  	binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
   486  }
   487  func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
   488  func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
   489  
   490  func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
   491  
   492  // Used to construct an artificially large array type when reading an
   493  // item from the object file relocs section or aux sym section (needs
   494  // to work on 32-bit as well as 64-bit). See issue 41621.
   495  const huge = (1<<31 - 1) / RelocSize
   496  
   497  // Referenced symbol name.
   498  //
   499  // Serialized format:
   500  //
   501  //	RefName struct {
   502  //	   Sym  symRef
   503  //	   Name string
   504  //	}
   505  type RefName [RefNameSize]byte
   506  
   507  const RefNameSize = 8 + stringRefSize
   508  
   509  func (n *RefName) Sym() SymRef {
   510  	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
   511  }
   512  func (n *RefName) Name(r *Reader) string {
   513  	len := binary.LittleEndian.Uint32(n[8:])
   514  	off := binary.LittleEndian.Uint32(n[12:])
   515  	return r.StringAt(off, len)
   516  }
   517  
   518  func (n *RefName) SetSym(x SymRef) {
   519  	binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
   520  	binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
   521  }
   522  func (n *RefName) SetName(x string, w *Writer) {
   523  	binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
   524  	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
   525  }
   526  
   527  func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
   528  
   529  type Writer struct {
   530  	wr        *bio.Writer
   531  	stringMap map[string]uint32
   532  	off       uint32 // running offset
   533  
   534  	b [8]byte // scratch space for writing bytes
   535  }
   536  
   537  func NewWriter(wr *bio.Writer) *Writer {
   538  	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
   539  }
   540  
   541  func (w *Writer) AddString(s string) {
   542  	if _, ok := w.stringMap[s]; ok {
   543  		return
   544  	}
   545  	w.stringMap[s] = w.off
   546  	w.RawString(s)
   547  }
   548  
   549  func (w *Writer) stringOff(s string) uint32 {
   550  	off, ok := w.stringMap[s]
   551  	if !ok {
   552  		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
   553  	}
   554  	return off
   555  }
   556  
   557  func (w *Writer) StringRef(s string) {
   558  	w.Uint32(uint32(len(s)))
   559  	w.Uint32(w.stringOff(s))
   560  }
   561  
   562  func (w *Writer) RawString(s string) {
   563  	w.wr.WriteString(s)
   564  	w.off += uint32(len(s))
   565  }
   566  
   567  func (w *Writer) Bytes(s []byte) {
   568  	w.wr.Write(s)
   569  	w.off += uint32(len(s))
   570  }
   571  
   572  func (w *Writer) Uint64(x uint64) {
   573  	binary.LittleEndian.PutUint64(w.b[:], x)
   574  	w.wr.Write(w.b[:])
   575  	w.off += 8
   576  }
   577  
   578  func (w *Writer) Uint32(x uint32) {
   579  	binary.LittleEndian.PutUint32(w.b[:4], x)
   580  	w.wr.Write(w.b[:4])
   581  	w.off += 4
   582  }
   583  
   584  func (w *Writer) Uint16(x uint16) {
   585  	binary.LittleEndian.PutUint16(w.b[:2], x)
   586  	w.wr.Write(w.b[:2])
   587  	w.off += 2
   588  }
   589  
   590  func (w *Writer) Uint8(x uint8) {
   591  	w.wr.WriteByte(x)
   592  	w.off++
   593  }
   594  
   595  func (w *Writer) Offset() uint32 {
   596  	return w.off
   597  }
   598  
   599  type Reader struct {
   600  	b        []byte // mmapped bytes, if not nil
   601  	readonly bool   // whether b is backed with read-only memory
   602  
   603  	start uint32
   604  	h     Header // keep block offsets
   605  }
   606  
   607  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   608  	r := &Reader{b: b, readonly: readonly, start: 0}
   609  	err := r.h.Read(r)
   610  	if err != nil {
   611  		return nil
   612  	}
   613  	return r
   614  }
   615  
   616  func (r *Reader) BytesAt(off uint32, len int) []byte {
   617  	if len == 0 {
   618  		return nil
   619  	}
   620  	end := int(off) + len
   621  	return r.b[int(off):end:end]
   622  }
   623  
   624  func (r *Reader) uint64At(off uint32) uint64 {
   625  	b := r.BytesAt(off, 8)
   626  	return binary.LittleEndian.Uint64(b)
   627  }
   628  
   629  func (r *Reader) int64At(off uint32) int64 {
   630  	return int64(r.uint64At(off))
   631  }
   632  
   633  func (r *Reader) uint32At(off uint32) uint32 {
   634  	b := r.BytesAt(off, 4)
   635  	return binary.LittleEndian.Uint32(b)
   636  }
   637  
   638  func (r *Reader) int32At(off uint32) int32 {
   639  	return int32(r.uint32At(off))
   640  }
   641  
   642  func (r *Reader) uint16At(off uint32) uint16 {
   643  	b := r.BytesAt(off, 2)
   644  	return binary.LittleEndian.Uint16(b)
   645  }
   646  
   647  func (r *Reader) uint8At(off uint32) uint8 {
   648  	b := r.BytesAt(off, 1)
   649  	return b[0]
   650  }
   651  
   652  func (r *Reader) StringAt(off uint32, len uint32) string {
   653  	b := r.b[off : off+len]
   654  	if r.readonly {
   655  		return toString(b) // backed by RO memory, ok to make unsafe string
   656  	}
   657  	return string(b)
   658  }
   659  
   660  func toString(b []byte) string {
   661  	if len(b) == 0 {
   662  		return ""
   663  	}
   664  	return unsafe.String(&b[0], len(b))
   665  }
   666  
   667  func (r *Reader) StringRef(off uint32) string {
   668  	l := r.uint32At(off)
   669  	return r.StringAt(r.uint32At(off+4), l)
   670  }
   671  
   672  func (r *Reader) Fingerprint() FingerprintType {
   673  	return r.h.Fingerprint
   674  }
   675  
   676  func (r *Reader) Autolib() []ImportedPkg {
   677  	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
   678  	s := make([]ImportedPkg, n)
   679  	off := r.h.Offsets[BlkAutolib]
   680  	for i := range s {
   681  		s[i].Pkg = r.StringRef(off)
   682  		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
   683  		off += importedPkgSize
   684  	}
   685  	return s
   686  }
   687  
   688  func (r *Reader) Pkglist() []string {
   689  	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
   690  	s := make([]string, n)
   691  	off := r.h.Offsets[BlkPkgIdx]
   692  	for i := range s {
   693  		s[i] = r.StringRef(off)
   694  		off += stringRefSize
   695  	}
   696  	return s
   697  }
   698  
   699  func (r *Reader) NPkg() int {
   700  	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
   701  }
   702  
   703  func (r *Reader) Pkg(i int) string {
   704  	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
   705  	return r.StringRef(off)
   706  }
   707  
   708  func (r *Reader) NFile() int {
   709  	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
   710  }
   711  
   712  func (r *Reader) File(i int) string {
   713  	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
   714  	return r.StringRef(off)
   715  }
   716  
   717  func (r *Reader) NSym() int {
   718  	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
   719  }
   720  
   721  func (r *Reader) NHashed64def() int {
   722  	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
   723  }
   724  
   725  func (r *Reader) NHasheddef() int {
   726  	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
   727  }
   728  
   729  func (r *Reader) NNonpkgdef() int {
   730  	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
   731  }
   732  
   733  func (r *Reader) NNonpkgref() int {
   734  	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
   735  }
   736  
   737  // SymOff returns the offset of the i-th symbol.
   738  func (r *Reader) SymOff(i uint32) uint32 {
   739  	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
   740  }
   741  
   742  // Sym returns a pointer to the i-th symbol.
   743  func (r *Reader) Sym(i uint32) *Sym {
   744  	off := r.SymOff(i)
   745  	return (*Sym)(unsafe.Pointer(&r.b[off]))
   746  }
   747  
   748  // NRefFlags returns the number of referenced symbol flags.
   749  func (r *Reader) NRefFlags() int {
   750  	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
   751  }
   752  
   753  // RefFlags returns a pointer to the i-th referenced symbol flags.
   754  // Note: here i is not a local symbol index, just a counter.
   755  func (r *Reader) RefFlags(i int) *RefFlags {
   756  	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
   757  	return (*RefFlags)(unsafe.Pointer(&r.b[off]))
   758  }
   759  
   760  // Hash64 returns the i-th short hashed symbol's hash.
   761  // Note: here i is the index of short hashed symbols, not all symbols
   762  // (unlike other accessors).
   763  func (r *Reader) Hash64(i uint32) uint64 {
   764  	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
   765  	return r.uint64At(off)
   766  }
   767  
   768  // Hash returns a pointer to the i-th hashed symbol's hash.
   769  // Note: here i is the index of hashed symbols, not all symbols
   770  // (unlike other accessors).
   771  func (r *Reader) Hash(i uint32) *HashType {
   772  	off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
   773  	return (*HashType)(unsafe.Pointer(&r.b[off]))
   774  }
   775  
   776  // NReloc returns the number of relocations of the i-th symbol.
   777  func (r *Reader) NReloc(i uint32) int {
   778  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   779  	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
   780  }
   781  
   782  // RelocOff returns the offset of the j-th relocation of the i-th symbol.
   783  func (r *Reader) RelocOff(i uint32, j int) uint32 {
   784  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   785  	relocIdx := r.uint32At(relocIdxOff)
   786  	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
   787  }
   788  
   789  // Reloc returns a pointer to the j-th relocation of the i-th symbol.
   790  func (r *Reader) Reloc(i uint32, j int) *Reloc {
   791  	off := r.RelocOff(i, j)
   792  	return (*Reloc)(unsafe.Pointer(&r.b[off]))
   793  }
   794  
   795  // Relocs returns a pointer to the relocations of the i-th symbol.
   796  func (r *Reader) Relocs(i uint32) []Reloc {
   797  	off := r.RelocOff(i, 0)
   798  	n := r.NReloc(i)
   799  	return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
   800  }
   801  
   802  // NAux returns the number of aux symbols of the i-th symbol.
   803  func (r *Reader) NAux(i uint32) int {
   804  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   805  	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
   806  }
   807  
   808  // AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
   809  func (r *Reader) AuxOff(i uint32, j int) uint32 {
   810  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   811  	auxIdx := r.uint32At(auxIdxOff)
   812  	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
   813  }
   814  
   815  // Aux returns a pointer to the j-th aux symbol of the i-th symbol.
   816  func (r *Reader) Aux(i uint32, j int) *Aux {
   817  	off := r.AuxOff(i, j)
   818  	return (*Aux)(unsafe.Pointer(&r.b[off]))
   819  }
   820  
   821  // Auxs returns the aux symbols of the i-th symbol.
   822  func (r *Reader) Auxs(i uint32) []Aux {
   823  	off := r.AuxOff(i, 0)
   824  	n := r.NAux(i)
   825  	return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
   826  }
   827  
   828  // DataOff returns the offset of the i-th symbol's data.
   829  func (r *Reader) DataOff(i uint32) uint32 {
   830  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   831  	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
   832  }
   833  
   834  // DataSize returns the size of the i-th symbol's data.
   835  func (r *Reader) DataSize(i uint32) int {
   836  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   837  	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
   838  }
   839  
   840  // Data returns the i-th symbol's data.
   841  func (r *Reader) Data(i uint32) []byte {
   842  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   843  	base := r.h.Offsets[BlkData]
   844  	off := r.uint32At(dataIdxOff)
   845  	end := r.uint32At(dataIdxOff + 4)
   846  	return r.BytesAt(base+off, int(end-off))
   847  }
   848  
   849  // DataString returns the i-th symbol's data as a string.
   850  func (r *Reader) DataString(i uint32) string {
   851  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   852  	base := r.h.Offsets[BlkData]
   853  	off := r.uint32At(dataIdxOff)
   854  	end := r.uint32At(dataIdxOff + 4)
   855  	return r.StringAt(base+off, end-off)
   856  }
   857  
   858  // NRefName returns the number of referenced symbol names.
   859  func (r *Reader) NRefName() int {
   860  	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
   861  }
   862  
   863  // RefName returns a pointer to the i-th referenced symbol name.
   864  // Note: here i is not a local symbol index, just a counter.
   865  func (r *Reader) RefName(i int) *RefName {
   866  	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
   867  	return (*RefName)(unsafe.Pointer(&r.b[off]))
   868  }
   869  
   870  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   871  func (r *Reader) ReadOnly() bool {
   872  	return r.readonly
   873  }
   874  
   875  // Flags returns the flag bits read from the object file header.
   876  func (r *Reader) Flags() uint32 {
   877  	return r.h.Flags
   878  }
   879  
   880  func (r *Reader) Shared() bool       { return r.Flags()&ObjFlagShared != 0 }
   881  func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }
   882  func (r *Reader) Unlinkable() bool   { return r.Flags()&ObjFlagUnlinkable != 0 }
   883  

View as plain text