Black Lives Matter. Support the Equal Justice Initiative.

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

View as plain text