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  	"crypto/sha1"
    24  	"encoding/binary"
    25  	"errors"
    26  	"fmt"
    27  	"internal/unsafeheader"
    28  	"unsafe"
    29  )
    30  
    31  // New object file format.
    32  //
    33  //    Header struct {
    34  //       Magic       [...]byte   // "\x00go118ld"
    35  //       Fingerprint [8]byte
    36  //       Flags       uint32
    37  //       Offsets     [...]uint32 // byte offset of each block below
    38  //    }
    39  //
    40  //    Strings [...]struct {
    41  //       Data [...]byte
    42  //    }
    43  //
    44  //    Autolib  [...]struct { // imported packages (for file loading)
    45  //       Pkg         string
    46  //       Fingerprint [8]byte
    47  //    }
    48  //
    49  //    PkgIndex [...]string // referenced packages by index
    50  //
    51  //    Files [...]string
    52  //
    53  //    SymbolDefs [...]struct {
    54  //       Name  string
    55  //       ABI   uint16
    56  //       Type  uint8
    57  //       Flag  uint8
    58  //       Flag2 uint8
    59  //       Size  uint32
    60  //    }
    61  //    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
    62  //       ... // same as SymbolDefs
    63  //    }
    64  //    HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
    65  //       ... // same as SymbolDefs
    66  //    }
    67  //    NonPkgDefs [...]struct { // non-pkg symbol definitions
    68  //       ... // same as SymbolDefs
    69  //    }
    70  //    NonPkgRefs [...]struct { // non-pkg symbol references
    71  //       ... // same as SymbolDefs
    72  //    }
    73  //
    74  //    RefFlags [...]struct { // referenced symbol flags
    75  //       Sym   symRef
    76  //       Flag  uint8
    77  //       Flag2 uint8
    78  //    }
    79  //
    80  //    Hash64 [...][8]byte
    81  //    Hash   [...][N]byte
    82  //
    83  //    RelocIndex [...]uint32 // index to Relocs
    84  //    AuxIndex   [...]uint32 // index to Aux
    85  //    DataIndex  [...]uint32 // offset to Data
    86  //
    87  //    Relocs [...]struct {
    88  //       Off  int32
    89  //       Size uint8
    90  //       Type uint16
    91  //       Add  int64
    92  //       Sym  symRef
    93  //    }
    94  //
    95  //    Aux [...]struct {
    96  //       Type uint8
    97  //       Sym  symRef
    98  //    }
    99  //
   100  //    Data   [...]byte
   101  //
   102  //    // blocks only used by tools (objdump, nm)
   103  //
   104  //    RefNames [...]struct { // referenced symbol names
   105  //       Sym  symRef
   106  //       Name string
   107  //       // TODO: include ABI version as well?
   108  //    }
   109  //
   110  // string is encoded as is a uint32 length followed by a uint32 offset
   111  // that points to the corresponding string bytes.
   112  //
   113  // symRef is struct { PkgIdx, SymIdx uint32 }.
   114  //
   115  // Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
   116  // followed by that number of elements.
   117  //
   118  // The types below correspond to the encoded data structure in the
   119  // object file.
   120  
   121  // Symbol indexing.
   122  //
   123  // Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
   124  // as the symRef struct above.
   125  //
   126  // PkgIdx is either a predeclared index (see PkgIdxNone below) or
   127  // an index of an imported package. For the latter case, PkgIdx is the
   128  // index of the package in the PkgIndex array. 0 is an invalid index.
   129  //
   130  // SymIdx is the index of the symbol in the given package.
   131  // - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
   132  //   SymbolDefs array.
   133  // - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
   134  //   Hashed64Defs array.
   135  // - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
   136  //   HashedDefs array.
   137  // - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
   138  //   NonPkgDefs array (could natually overflow to NonPkgRefs array).
   139  // - Otherwise, SymIdx is the index of the symbol in some other package's
   140  //   SymbolDefs array.
   141  //
   142  // {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
   143  //
   144  // Hash contains the content hashes of content-addressable symbols, of
   145  // which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
   146  // Hash64 is similar, for PkgIdxHashed64 symbols.
   147  //
   148  // RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
   149  // Relocs/Aux/Data blocks, one element per symbol, first for all the
   150  // defined symbols, then all the defined hashed and non-package symbols,
   151  // in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
   152  // arrays. For N total defined symbols, the array is of length N+1. The
   153  // last element is the total number of relocations (aux symbols, data
   154  // blocks, etc.).
   155  //
   156  // They can be accessed by index. For the i-th symbol, its relocations
   157  // are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
   158  // elements in the Relocs array. Aux/Data are likewise. (The index is
   159  // 0-based.)
   160  
   161  // Auxiliary symbols.
   162  //
   163  // Each symbol may (or may not) be associated with a number of auxiliary
   164  // symbols. They are described in the Aux block. See Aux struct below.
   165  // Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
   166  // are auxiliary symbols.
   167  
   168  const stringRefSize = 8 // two uint32s
   169  
   170  type FingerprintType [8]byte
   171  
   172  func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
   173  
   174  // Package Index.
   175  const (
   176  	PkgIdxNone     = (1<<31 - 1) - iota // Non-package symbols
   177  	PkgIdxHashed64                      // Short hashed (content-addressable) symbols
   178  	PkgIdxHashed                        // Hashed (content-addressable) symbols
   179  	PkgIdxBuiltin                       // Predefined runtime symbols (ex: runtime.newobject)
   180  	PkgIdxSelf                          // Symbols defined in the current package
   181  	PkgIdxInvalid  = 0
   182  	// The index of other referenced packages starts from 1.
   183  )
   184  
   185  // Blocks
   186  const (
   187  	BlkAutolib = iota
   188  	BlkPkgIdx
   189  	BlkFile
   190  	BlkSymdef
   191  	BlkHashed64def
   192  	BlkHasheddef
   193  	BlkNonpkgdef
   194  	BlkNonpkgref
   195  	BlkRefFlags
   196  	BlkHash64
   197  	BlkHash
   198  	BlkRelocIdx
   199  	BlkAuxIdx
   200  	BlkDataIdx
   201  	BlkReloc
   202  	BlkAux
   203  	BlkData
   204  	BlkRefName
   205  	BlkEnd
   206  	NBlk
   207  )
   208  
   209  // File header.
   210  // TODO: probably no need to export this.
   211  type Header struct {
   212  	Magic       string
   213  	Fingerprint FingerprintType
   214  	Flags       uint32
   215  	Offsets     [NBlk]uint32
   216  }
   217  
   218  const Magic = "\x00go118ld"
   219  
   220  func (h *Header) Write(w *Writer) {
   221  	w.RawString(h.Magic)
   222  	w.Bytes(h.Fingerprint[:])
   223  	w.Uint32(h.Flags)
   224  	for _, x := range h.Offsets {
   225  		w.Uint32(x)
   226  	}
   227  }
   228  
   229  func (h *Header) Read(r *Reader) error {
   230  	b := r.BytesAt(0, len(Magic))
   231  	h.Magic = string(b)
   232  	if h.Magic != Magic {
   233  		return errors.New("wrong magic, not a Go object file")
   234  	}
   235  	off := uint32(len(h.Magic))
   236  	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
   237  	off += 8
   238  	h.Flags = r.uint32At(off)
   239  	off += 4
   240  	for i := range h.Offsets {
   241  		h.Offsets[i] = r.uint32At(off)
   242  		off += 4
   243  	}
   244  	return nil
   245  }
   246  
   247  func (h *Header) Size() int {
   248  	return len(h.Magic) + 4 + 4*len(h.Offsets)
   249  }
   250  
   251  // Autolib
   252  type ImportedPkg struct {
   253  	Pkg         string
   254  	Fingerprint FingerprintType
   255  }
   256  
   257  const importedPkgSize = stringRefSize + 8
   258  
   259  func (p *ImportedPkg) Write(w *Writer) {
   260  	w.StringRef(p.Pkg)
   261  	w.Bytes(p.Fingerprint[:])
   262  }
   263  
   264  // Symbol definition.
   265  //
   266  // Serialized format:
   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  	ObjFlagNeedNameExpansion             // the linker needs to expand `"".` to package path in symbol names
   285  	ObjFlagFromAssembly                  // object is from asm src, not go
   286  )
   287  
   288  // Sym.Flag
   289  const (
   290  	SymFlagDupok = 1 << iota
   291  	SymFlagLocal
   292  	SymFlagTypelink
   293  	SymFlagLeaf
   294  	SymFlagNoSplit
   295  	SymFlagReflectMethod
   296  	SymFlagGoType
   297  )
   298  
   299  // Sym.Flag2
   300  const (
   301  	SymFlagUsedInIface = 1 << iota
   302  	SymFlagItab
   303  	SymFlagDict
   304  )
   305  
   306  // Returns the length of the name of the symbol.
   307  func (s *Sym) NameLen(r *Reader) int {
   308  	return int(binary.LittleEndian.Uint32(s[:]))
   309  }
   310  
   311  func (s *Sym) Name(r *Reader) string {
   312  	len := binary.LittleEndian.Uint32(s[:])
   313  	off := binary.LittleEndian.Uint32(s[4:])
   314  	return r.StringAt(off, len)
   315  }
   316  
   317  func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
   318  func (s *Sym) Type() uint8   { return s[10] }
   319  func (s *Sym) Flag() uint8   { return s[11] }
   320  func (s *Sym) Flag2() uint8  { return s[12] }
   321  func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
   322  func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
   323  
   324  func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
   325  func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
   326  func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
   327  func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
   328  func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
   329  func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
   330  func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
   331  func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
   332  func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
   333  func (s *Sym) IsDict() bool        { return s.Flag2()&SymFlagDict != 0 }
   334  
   335  func (s *Sym) SetName(x string, w *Writer) {
   336  	binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
   337  	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
   338  }
   339  
   340  func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) }
   341  func (s *Sym) SetType(x uint8)   { s[10] = x }
   342  func (s *Sym) SetFlag(x uint8)   { s[11] = x }
   343  func (s *Sym) SetFlag2(x uint8)  { s[12] = x }
   344  func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) }
   345  func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
   346  
   347  func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
   348  
   349  // for testing
   350  func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
   351  
   352  // Symbol reference.
   353  type SymRef struct {
   354  	PkgIdx uint32
   355  	SymIdx uint32
   356  }
   357  
   358  func (s SymRef) IsZero() bool { return s == SymRef{} }
   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  	start uint32
   596  	h     Header // keep block offsets
   597  }
   598  
   599  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   600  	r := &Reader{b: b, readonly: readonly, start: 0}
   601  	err := r.h.Read(r)
   602  	if err != nil {
   603  		return nil
   604  	}
   605  	return r
   606  }
   607  
   608  func (r *Reader) BytesAt(off uint32, len int) []byte {
   609  	if len == 0 {
   610  		return nil
   611  	}
   612  	end := int(off) + len
   613  	return r.b[int(off):end:end]
   614  }
   615  
   616  func (r *Reader) uint64At(off uint32) uint64 {
   617  	b := r.BytesAt(off, 8)
   618  	return binary.LittleEndian.Uint64(b)
   619  }
   620  
   621  func (r *Reader) int64At(off uint32) int64 {
   622  	return int64(r.uint64At(off))
   623  }
   624  
   625  func (r *Reader) uint32At(off uint32) uint32 {
   626  	b := r.BytesAt(off, 4)
   627  	return binary.LittleEndian.Uint32(b)
   628  }
   629  
   630  func (r *Reader) int32At(off uint32) int32 {
   631  	return int32(r.uint32At(off))
   632  }
   633  
   634  func (r *Reader) uint16At(off uint32) uint16 {
   635  	b := r.BytesAt(off, 2)
   636  	return binary.LittleEndian.Uint16(b)
   637  }
   638  
   639  func (r *Reader) uint8At(off uint32) uint8 {
   640  	b := r.BytesAt(off, 1)
   641  	return b[0]
   642  }
   643  
   644  func (r *Reader) StringAt(off uint32, len uint32) string {
   645  	b := r.b[off : off+len]
   646  	if r.readonly {
   647  		return toString(b) // backed by RO memory, ok to make unsafe string
   648  	}
   649  	return string(b)
   650  }
   651  
   652  func toString(b []byte) string {
   653  	if len(b) == 0 {
   654  		return ""
   655  	}
   656  
   657  	var s string
   658  	hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
   659  	hdr.Data = unsafe.Pointer(&b[0])
   660  	hdr.Len = len(b)
   661  
   662  	return s
   663  }
   664  
   665  func (r *Reader) StringRef(off uint32) string {
   666  	l := r.uint32At(off)
   667  	return r.StringAt(r.uint32At(off+4), l)
   668  }
   669  
   670  func (r *Reader) Fingerprint() FingerprintType {
   671  	return r.h.Fingerprint
   672  }
   673  
   674  func (r *Reader) Autolib() []ImportedPkg {
   675  	n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize
   676  	s := make([]ImportedPkg, n)
   677  	off := r.h.Offsets[BlkAutolib]
   678  	for i := range s {
   679  		s[i].Pkg = r.StringRef(off)
   680  		copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint)))
   681  		off += importedPkgSize
   682  	}
   683  	return s
   684  }
   685  
   686  func (r *Reader) Pkglist() []string {
   687  	n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize
   688  	s := make([]string, n)
   689  	off := r.h.Offsets[BlkPkgIdx]
   690  	for i := range s {
   691  		s[i] = r.StringRef(off)
   692  		off += stringRefSize
   693  	}
   694  	return s
   695  }
   696  
   697  func (r *Reader) NPkg() int {
   698  	return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize
   699  }
   700  
   701  func (r *Reader) Pkg(i int) string {
   702  	off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize
   703  	return r.StringRef(off)
   704  }
   705  
   706  func (r *Reader) NFile() int {
   707  	return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize
   708  }
   709  
   710  func (r *Reader) File(i int) string {
   711  	off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize
   712  	return r.StringRef(off)
   713  }
   714  
   715  func (r *Reader) NSym() int {
   716  	return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize
   717  }
   718  
   719  func (r *Reader) NHashed64def() int {
   720  	return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize
   721  }
   722  
   723  func (r *Reader) NHasheddef() int {
   724  	return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize
   725  }
   726  
   727  func (r *Reader) NNonpkgdef() int {
   728  	return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize
   729  }
   730  
   731  func (r *Reader) NNonpkgref() int {
   732  	return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize
   733  }
   734  
   735  // SymOff returns the offset of the i-th symbol.
   736  func (r *Reader) SymOff(i uint32) uint32 {
   737  	return r.h.Offsets[BlkSymdef] + uint32(i*SymSize)
   738  }
   739  
   740  // Sym returns a pointer to the i-th symbol.
   741  func (r *Reader) Sym(i uint32) *Sym {
   742  	off := r.SymOff(i)
   743  	return (*Sym)(unsafe.Pointer(&r.b[off]))
   744  }
   745  
   746  // NRefFlags returns the number of referenced symbol flags.
   747  func (r *Reader) NRefFlags() int {
   748  	return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
   749  }
   750  
   751  // RefFlags returns a pointer to the i-th referenced symbol flags.
   752  // Note: here i is not a local symbol index, just a counter.
   753  func (r *Reader) RefFlags(i int) *RefFlags {
   754  	off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
   755  	return (*RefFlags)(unsafe.Pointer(&r.b[off]))
   756  }
   757  
   758  // Hash64 returns the i-th short hashed symbol's hash.
   759  // Note: here i is the index of short hashed symbols, not all symbols
   760  // (unlike other accessors).
   761  func (r *Reader) Hash64(i uint32) uint64 {
   762  	off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size)
   763  	return r.uint64At(off)
   764  }
   765  
   766  // Hash returns a pointer to the i-th hashed symbol's hash.
   767  // Note: here i is the index of hashed symbols, not all symbols
   768  // (unlike other accessors).
   769  func (r *Reader) Hash(i uint32) *HashType {
   770  	off := r.h.Offsets[BlkHash] + uint32(i*HashSize)
   771  	return (*HashType)(unsafe.Pointer(&r.b[off]))
   772  }
   773  
   774  // NReloc returns the number of relocations of the i-th symbol.
   775  func (r *Reader) NReloc(i uint32) int {
   776  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   777  	return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff))
   778  }
   779  
   780  // RelocOff returns the offset of the j-th relocation of the i-th symbol.
   781  func (r *Reader) RelocOff(i uint32, j int) uint32 {
   782  	relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4)
   783  	relocIdx := r.uint32At(relocIdxOff)
   784  	return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize)
   785  }
   786  
   787  // Reloc returns a pointer to the j-th relocation of the i-th symbol.
   788  func (r *Reader) Reloc(i uint32, j int) *Reloc {
   789  	off := r.RelocOff(i, j)
   790  	return (*Reloc)(unsafe.Pointer(&r.b[off]))
   791  }
   792  
   793  // Relocs returns a pointer to the relocations of the i-th symbol.
   794  func (r *Reader) Relocs(i uint32) []Reloc {
   795  	off := r.RelocOff(i, 0)
   796  	n := r.NReloc(i)
   797  	return (*[huge]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n]
   798  }
   799  
   800  // NAux returns the number of aux symbols of the i-th symbol.
   801  func (r *Reader) NAux(i uint32) int {
   802  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   803  	return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff))
   804  }
   805  
   806  // AuxOff returns the offset of the j-th aux symbol of the i-th symbol.
   807  func (r *Reader) AuxOff(i uint32, j int) uint32 {
   808  	auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4
   809  	auxIdx := r.uint32At(auxIdxOff)
   810  	return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize)
   811  }
   812  
   813  // Aux returns a pointer to the j-th aux symbol of the i-th symbol.
   814  func (r *Reader) Aux(i uint32, j int) *Aux {
   815  	off := r.AuxOff(i, j)
   816  	return (*Aux)(unsafe.Pointer(&r.b[off]))
   817  }
   818  
   819  // Auxs returns the aux symbols of the i-th symbol.
   820  func (r *Reader) Auxs(i uint32) []Aux {
   821  	off := r.AuxOff(i, 0)
   822  	n := r.NAux(i)
   823  	return (*[huge]Aux)(unsafe.Pointer(&r.b[off]))[:n:n]
   824  }
   825  
   826  // DataOff returns the offset of the i-th symbol's data.
   827  func (r *Reader) DataOff(i uint32) uint32 {
   828  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   829  	return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff)
   830  }
   831  
   832  // DataSize returns the size of the i-th symbol's data.
   833  func (r *Reader) DataSize(i uint32) int {
   834  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   835  	return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff))
   836  }
   837  
   838  // Data returns the i-th symbol's data.
   839  func (r *Reader) Data(i uint32) []byte {
   840  	dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
   841  	base := r.h.Offsets[BlkData]
   842  	off := r.uint32At(dataIdxOff)
   843  	end := r.uint32At(dataIdxOff + 4)
   844  	return r.BytesAt(base+off, int(end-off))
   845  }
   846  
   847  // NRefName returns the number of referenced symbol names.
   848  func (r *Reader) NRefName() int {
   849  	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
   850  }
   851  
   852  // RefName returns a pointer to the i-th referenced symbol name.
   853  // Note: here i is not a local symbol index, just a counter.
   854  func (r *Reader) RefName(i int) *RefName {
   855  	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
   856  	return (*RefName)(unsafe.Pointer(&r.b[off]))
   857  }
   858  
   859  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   860  func (r *Reader) ReadOnly() bool {
   861  	return r.readonly
   862  }
   863  
   864  // Flags returns the flag bits read from the object file header.
   865  func (r *Reader) Flags() uint32 {
   866  	return r.h.Flags
   867  }
   868  
   869  func (r *Reader) Shared() bool            { return r.Flags()&ObjFlagShared != 0 }
   870  func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 }
   871  func (r *Reader) FromAssembly() bool      { return r.Flags()&ObjFlagFromAssembly != 0 }
   872  

View as plain text