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

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

View as plain text