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

View as plain text