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

View as plain text