...

Source file src/github.com/twitchyliquid64/golang-asm/goobj/objfile.go

Documentation: github.com/twitchyliquid64/golang-asm/goobj

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This package defines the Go object file format, and provide "low-level" functions
     6  // for reading and writing object files.
     7  
     8  // The object file is understood by the compiler, assembler, linker, and tools. They
     9  // have "high level" code that operates on object files, handling application-specific
    10  // logics, and use this package for the actual reading and writing. Specifically, the
    11  // code below:
    12  //
    13  // - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile)
    14  // - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump)
    15  // - cmd/link/internal/loader package (used by cmd/link)
    16  //
    17  // If the object file format changes, they may (or may not) need to change.
    18  
    19  package goobj
    20  
    21  import (
    22  	"bytes"
    23  	"github.com/twitchyliquid64/golang-asm/bio"
    24  	"crypto/sha1"
    25  	"encoding/binary"
    26  	"errors"
    27  	"fmt"
    28  	"github.com/twitchyliquid64/golang-asm/unsafeheader"
    29  	"io"
    30  	"unsafe"
    31  )
    32  
    33  // New object file format.
    34  //
    35  //    Header struct {
    36  //       Magic       [...]byte   // "\x00go116ld"
    37  //       Fingerprint [8]byte
    38  //       Flags       uint32
    39  //       Offsets     [...]uint32 // byte offset of each block below
    40  //    }
    41  //
    42  //    Strings [...]struct {
    43  //       Data [...]byte
    44  //    }
    45  //
    46  //    Autolib  [...]struct { // imported packages (for file loading)
    47  //       Pkg         string
    48  //       Fingerprint [8]byte
    49  //    }
    50  //
    51  //    PkgIndex [...]string // referenced packages by index
    52  //
    53  //    Files [...]string
    54  //
    55  //    SymbolDefs [...]struct {
    56  //       Name  string
    57  //       ABI   uint16
    58  //       Type  uint8
    59  //       Flag  uint8
    60  //       Flag2 uint8
    61  //       Size  uint32
    62  //    }
    63  //    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
    64  //       ... // same as SymbolDefs
    65  //    }
    66  //    HashedDefs [...]struct { // hashed (content-addressable) symbol definitions
    67  //       ... // same as SymbolDefs
    68  //    }
    69  //    NonPkgDefs [...]struct { // non-pkg symbol definitions
    70  //       ... // same as SymbolDefs
    71  //    }
    72  //    NonPkgRefs [...]struct { // non-pkg symbol references
    73  //       ... // same as SymbolDefs
    74  //    }
    75  //
    76  //    RefFlags [...]struct { // referenced symbol flags
    77  //       Sym   symRef
    78  //       Flag  uint8
    79  //       Flag2 uint8
    80  //    }
    81  //
    82  //    Hash64 [...][8]byte
    83  //    Hash   [...][N]byte
    84  //
    85  //    RelocIndex [...]uint32 // index to Relocs
    86  //    AuxIndex   [...]uint32 // index to Aux
    87  //    DataIndex  [...]uint32 // offset to Data
    88  //
    89  //    Relocs [...]struct {
    90  //       Off  int32
    91  //       Size uint8
    92  //       Type uint8
    93  //       Add  int64
    94  //       Sym  symRef
    95  //    }
    96  //
    97  //    Aux [...]struct {
    98  //       Type uint8
    99  //       Sym  symRef
   100  //    }
   101  //
   102  //    Data   [...]byte
   103  //    Pcdata [...]byte
   104  //
   105  //    // blocks only used by tools (objdump, nm)
   106  //
   107  //    RefNames [...]struct { // referenced symbol names
   108  //       Sym  symRef
   109  //       Name string
   110  //       // TODO: include ABI version as well?
   111  //    }
   112  //
   113  // string is encoded as is a uint32 length followed by a uint32 offset
   114  // that points to the corresponding string bytes.
   115  //
   116  // symRef is struct { PkgIdx, SymIdx uint32 }.
   117  //
   118  // Slice type (e.g. []symRef) is encoded as a length prefix (uint32)
   119  // followed by that number of elements.
   120  //
   121  // The types below correspond to the encoded data structure in the
   122  // object file.
   123  
   124  // Symbol indexing.
   125  //
   126  // Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx },
   127  // as the symRef struct above.
   128  //
   129  // PkgIdx is either a predeclared index (see PkgIdxNone below) or
   130  // an index of an imported package. For the latter case, PkgIdx is the
   131  // index of the package in the PkgIndex array. 0 is an invalid index.
   132  //
   133  // SymIdx is the index of the symbol in the given package.
   134  // - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the
   135  //   SymbolDefs array.
   136  // - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the
   137  //   Hashed64Defs array.
   138  // - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the
   139  //   HashedDefs array.
   140  // - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the
   141  //   NonPkgDefs array (could natually overflow to NonPkgRefs array).
   142  // - Otherwise, SymIdx is the index of the symbol in some other package's
   143  //   SymbolDefs array.
   144  //
   145  // {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0.
   146  //
   147  // Hash contains the content hashes of content-addressable symbols, of
   148  // which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array.
   149  // Hash64 is similar, for PkgIdxHashed64 symbols.
   150  //
   151  // RelocIndex, AuxIndex, and DataIndex contains indices/offsets to
   152  // Relocs/Aux/Data blocks, one element per symbol, first for all the
   153  // defined symbols, then all the defined hashed and non-package symbols,
   154  // in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs
   155  // arrays. For N total defined symbols, the array is of length N+1. The
   156  // last element is the total number of relocations (aux symbols, data
   157  // blocks, etc.).
   158  //
   159  // They can be accessed by index. For the i-th symbol, its relocations
   160  // are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive)
   161  // elements in the Relocs array. Aux/Data are likewise. (The index is
   162  // 0-based.)
   163  
   164  // Auxiliary symbols.
   165  //
   166  // Each symbol may (or may not) be associated with a number of auxiliary
   167  // symbols. They are described in the Aux block. See Aux struct below.
   168  // Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols
   169  // are auxiliary symbols.
   170  
   171  const stringRefSize = 8 // two uint32s
   172  
   173  type FingerprintType [8]byte
   174  
   175  func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} }
   176  
   177  // Package Index.
   178  const (
   179  	PkgIdxNone     = (1<<31 - 1) - iota // Non-package symbols
   180  	PkgIdxHashed64                      // Short hashed (content-addressable) symbols
   181  	PkgIdxHashed                        // Hashed (content-addressable) symbols
   182  	PkgIdxBuiltin                       // Predefined runtime symbols (ex: runtime.newobject)
   183  	PkgIdxSelf                          // Symbols defined in the current package
   184  	PkgIdxInvalid  = 0
   185  	// The index of other referenced packages starts from 1.
   186  )
   187  
   188  // Blocks
   189  const (
   190  	BlkAutolib = iota
   191  	BlkPkgIdx
   192  	BlkFile
   193  	BlkSymdef
   194  	BlkHashed64def
   195  	BlkHasheddef
   196  	BlkNonpkgdef
   197  	BlkNonpkgref
   198  	BlkRefFlags
   199  	BlkHash64
   200  	BlkHash
   201  	BlkRelocIdx
   202  	BlkAuxIdx
   203  	BlkDataIdx
   204  	BlkReloc
   205  	BlkAux
   206  	BlkData
   207  	BlkPcdata
   208  	BlkRefName
   209  	BlkEnd
   210  	NBlk
   211  )
   212  
   213  // File header.
   214  // TODO: probably no need to export this.
   215  type Header struct {
   216  	Magic       string
   217  	Fingerprint FingerprintType
   218  	Flags       uint32
   219  	Offsets     [NBlk]uint32
   220  }
   221  
   222  const Magic = "\x00go116ld"
   223  
   224  func (h *Header) Write(w *Writer) {
   225  	w.RawString(h.Magic)
   226  	w.Bytes(h.Fingerprint[:])
   227  	w.Uint32(h.Flags)
   228  	for _, x := range h.Offsets {
   229  		w.Uint32(x)
   230  	}
   231  }
   232  
   233  func (h *Header) Read(r *Reader) error {
   234  	b := r.BytesAt(0, len(Magic))
   235  	h.Magic = string(b)
   236  	if h.Magic != Magic {
   237  		return errors.New("wrong magic, not a Go object file")
   238  	}
   239  	off := uint32(len(h.Magic))
   240  	copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint)))
   241  	off += 8
   242  	h.Flags = r.uint32At(off)
   243  	off += 4
   244  	for i := range h.Offsets {
   245  		h.Offsets[i] = r.uint32At(off)
   246  		off += 4
   247  	}
   248  	return nil
   249  }
   250  
   251  func (h *Header) Size() int {
   252  	return len(h.Magic) + 4 + 4*len(h.Offsets)
   253  }
   254  
   255  // Autolib
   256  type ImportedPkg struct {
   257  	Pkg         string
   258  	Fingerprint FingerprintType
   259  }
   260  
   261  const importedPkgSize = stringRefSize + 8
   262  
   263  func (p *ImportedPkg) Write(w *Writer) {
   264  	w.StringRef(p.Pkg)
   265  	w.Bytes(p.Fingerprint[:])
   266  }
   267  
   268  // Symbol definition.
   269  //
   270  // Serialized format:
   271  // Sym struct {
   272  //    Name  string
   273  //    ABI   uint16
   274  //    Type  uint8
   275  //    Flag  uint8
   276  //    Flag2 uint8
   277  //    Siz   uint32
   278  //    Align uint32
   279  // }
   280  type Sym [SymSize]byte
   281  
   282  const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4
   283  
   284  const SymABIstatic = ^uint16(0)
   285  
   286  const (
   287  	ObjFlagShared            = 1 << iota // this object is built with -shared
   288  	ObjFlagNeedNameExpansion             // the linker needs to expand `"".` to package path in symbol names
   289  	ObjFlagFromAssembly                  // object is from asm src, not go
   290  )
   291  
   292  // Sym.Flag
   293  const (
   294  	SymFlagDupok = 1 << iota
   295  	SymFlagLocal
   296  	SymFlagTypelink
   297  	SymFlagLeaf
   298  	SymFlagNoSplit
   299  	SymFlagReflectMethod
   300  	SymFlagGoType
   301  	SymFlagTopFrame
   302  )
   303  
   304  // Sym.Flag2
   305  const (
   306  	SymFlagUsedInIface = 1 << iota
   307  	SymFlagItab
   308  )
   309  
   310  // Returns the length of the name of the symbol.
   311  func (s *Sym) NameLen(r *Reader) int {
   312  	return int(binary.LittleEndian.Uint32(s[:]))
   313  }
   314  
   315  func (s *Sym) Name(r *Reader) string {
   316  	len := binary.LittleEndian.Uint32(s[:])
   317  	off := binary.LittleEndian.Uint32(s[4:])
   318  	return r.StringAt(off, len)
   319  }
   320  
   321  func (s *Sym) ABI() uint16   { return binary.LittleEndian.Uint16(s[8:]) }
   322  func (s *Sym) Type() uint8   { return s[10] }
   323  func (s *Sym) Flag() uint8   { return s[11] }
   324  func (s *Sym) Flag2() uint8  { return s[12] }
   325  func (s *Sym) Siz() uint32   { return binary.LittleEndian.Uint32(s[13:]) }
   326  func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) }
   327  
   328  func (s *Sym) Dupok() bool         { return s.Flag()&SymFlagDupok != 0 }
   329  func (s *Sym) Local() bool         { return s.Flag()&SymFlagLocal != 0 }
   330  func (s *Sym) Typelink() bool      { return s.Flag()&SymFlagTypelink != 0 }
   331  func (s *Sym) Leaf() bool          { return s.Flag()&SymFlagLeaf != 0 }
   332  func (s *Sym) NoSplit() bool       { return s.Flag()&SymFlagNoSplit != 0 }
   333  func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 }
   334  func (s *Sym) IsGoType() bool      { return s.Flag()&SymFlagGoType != 0 }
   335  func (s *Sym) TopFrame() bool      { return s.Flag()&SymFlagTopFrame != 0 }
   336  func (s *Sym) UsedInIface() bool   { return s.Flag2()&SymFlagUsedInIface != 0 }
   337  func (s *Sym) IsItab() bool        { return s.Flag2()&SymFlagItab != 0 }
   338  
   339  func (s *Sym) SetName(x string, w *Writer) {
   340  	binary.LittleEndian.PutUint32(s[:], uint32(len(x)))
   341  	binary.LittleEndian.PutUint32(s[4:], w.stringOff(x))
   342  }
   343  
   344  func (s *Sym) SetABI(x uint16)   { binary.LittleEndian.PutUint16(s[8:], x) }
   345  func (s *Sym) SetType(x uint8)   { s[10] = x }
   346  func (s *Sym) SetFlag(x uint8)   { s[11] = x }
   347  func (s *Sym) SetFlag2(x uint8)  { s[12] = x }
   348  func (s *Sym) SetSiz(x uint32)   { binary.LittleEndian.PutUint32(s[13:], x) }
   349  func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) }
   350  
   351  func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) }
   352  
   353  // for testing
   354  func (s *Sym) fromBytes(b []byte) { copy(s[:], b) }
   355  
   356  // Symbol reference.
   357  type SymRef struct {
   358  	PkgIdx uint32
   359  	SymIdx uint32
   360  }
   361  
   362  // Hash64
   363  type Hash64Type [Hash64Size]byte
   364  
   365  const Hash64Size = 8
   366  
   367  // Hash
   368  type HashType [HashSize]byte
   369  
   370  const HashSize = sha1.Size
   371  
   372  // Relocation.
   373  //
   374  // Serialized format:
   375  // Reloc struct {
   376  //    Off  int32
   377  //    Siz  uint8
   378  //    Type uint8
   379  //    Add  int64
   380  //    Sym  SymRef
   381  // }
   382  type Reloc [RelocSize]byte
   383  
   384  const RelocSize = 4 + 1 + 1 + 8 + 8
   385  
   386  func (r *Reloc) Off() int32  { return int32(binary.LittleEndian.Uint32(r[:])) }
   387  func (r *Reloc) Siz() uint8  { return r[4] }
   388  func (r *Reloc) Type() uint8 { return r[5] }
   389  func (r *Reloc) Add() int64  { return int64(binary.LittleEndian.Uint64(r[6:])) }
   390  func (r *Reloc) Sym() SymRef {
   391  	return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])}
   392  }
   393  
   394  func (r *Reloc) SetOff(x int32)  { binary.LittleEndian.PutUint32(r[:], uint32(x)) }
   395  func (r *Reloc) SetSiz(x uint8)  { r[4] = x }
   396  func (r *Reloc) SetType(x uint8) { r[5] = x }
   397  func (r *Reloc) SetAdd(x int64)  { binary.LittleEndian.PutUint64(r[6:], uint64(x)) }
   398  func (r *Reloc) SetSym(x SymRef) {
   399  	binary.LittleEndian.PutUint32(r[14:], x.PkgIdx)
   400  	binary.LittleEndian.PutUint32(r[18:], x.SymIdx)
   401  }
   402  
   403  func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) {
   404  	r.SetOff(off)
   405  	r.SetSiz(size)
   406  	r.SetType(typ)
   407  	r.SetAdd(add)
   408  	r.SetSym(sym)
   409  }
   410  
   411  func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) }
   412  
   413  // for testing
   414  func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) }
   415  
   416  // Aux symbol info.
   417  //
   418  // Serialized format:
   419  // Aux struct {
   420  //    Type uint8
   421  //    Sym  SymRef
   422  // }
   423  type Aux [AuxSize]byte
   424  
   425  const AuxSize = 1 + 8
   426  
   427  // Aux Type
   428  const (
   429  	AuxGotype = iota
   430  	AuxFuncInfo
   431  	AuxFuncdata
   432  	AuxDwarfInfo
   433  	AuxDwarfLoc
   434  	AuxDwarfRanges
   435  	AuxDwarfLines
   436  
   437  	// TODO: more. Pcdata?
   438  )
   439  
   440  func (a *Aux) Type() uint8 { return a[0] }
   441  func (a *Aux) Sym() SymRef {
   442  	return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])}
   443  }
   444  
   445  func (a *Aux) SetType(x uint8) { a[0] = x }
   446  func (a *Aux) SetSym(x SymRef) {
   447  	binary.LittleEndian.PutUint32(a[1:], x.PkgIdx)
   448  	binary.LittleEndian.PutUint32(a[5:], x.SymIdx)
   449  }
   450  
   451  func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
   452  
   453  // for testing
   454  func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
   455  
   456  // Referenced symbol flags.
   457  //
   458  // Serialized format:
   459  // RefFlags struct {
   460  //    Sym   symRef
   461  //    Flag  uint8
   462  //    Flag2 uint8
   463  // }
   464  type RefFlags [RefFlagsSize]byte
   465  
   466  const RefFlagsSize = 8 + 1 + 1
   467  
   468  func (r *RefFlags) Sym() SymRef {
   469  	return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
   470  }
   471  func (r *RefFlags) Flag() uint8  { return r[8] }
   472  func (r *RefFlags) Flag2() uint8 { return r[9] }
   473  
   474  func (r *RefFlags) SetSym(x SymRef) {
   475  	binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
   476  	binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
   477  }
   478  func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
   479  func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
   480  
   481  func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
   482  
   483  // Referenced symbol name.
   484  //
   485  // Serialized format:
   486  // RefName struct {
   487  //    Sym  symRef
   488  //    Name string
   489  // }
   490  type RefName [RefNameSize]byte
   491  
   492  const RefNameSize = 8 + stringRefSize
   493  
   494  func (n *RefName) Sym() SymRef {
   495  	return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
   496  }
   497  func (n *RefName) Name(r *Reader) string {
   498  	len := binary.LittleEndian.Uint32(n[8:])
   499  	off := binary.LittleEndian.Uint32(n[12:])
   500  	return r.StringAt(off, len)
   501  }
   502  
   503  func (n *RefName) SetSym(x SymRef) {
   504  	binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
   505  	binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
   506  }
   507  func (n *RefName) SetName(x string, w *Writer) {
   508  	binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
   509  	binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
   510  }
   511  
   512  func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
   513  
   514  type Writer struct {
   515  	wr        *bio.Writer
   516  	stringMap map[string]uint32
   517  	off       uint32 // running offset
   518  }
   519  
   520  func NewWriter(wr *bio.Writer) *Writer {
   521  	return &Writer{wr: wr, stringMap: make(map[string]uint32)}
   522  }
   523  
   524  func (w *Writer) AddString(s string) {
   525  	if _, ok := w.stringMap[s]; ok {
   526  		return
   527  	}
   528  	w.stringMap[s] = w.off
   529  	w.RawString(s)
   530  }
   531  
   532  func (w *Writer) stringOff(s string) uint32 {
   533  	off, ok := w.stringMap[s]
   534  	if !ok {
   535  		panic(fmt.Sprintf("writeStringRef: string not added: %q", s))
   536  	}
   537  	return off
   538  }
   539  
   540  func (w *Writer) StringRef(s string) {
   541  	w.Uint32(uint32(len(s)))
   542  	w.Uint32(w.stringOff(s))
   543  }
   544  
   545  func (w *Writer) RawString(s string) {
   546  	w.wr.WriteString(s)
   547  	w.off += uint32(len(s))
   548  }
   549  
   550  func (w *Writer) Bytes(s []byte) {
   551  	w.wr.Write(s)
   552  	w.off += uint32(len(s))
   553  }
   554  
   555  func (w *Writer) Uint64(x uint64) {
   556  	var b [8]byte
   557  	binary.LittleEndian.PutUint64(b[:], x)
   558  	w.wr.Write(b[:])
   559  	w.off += 8
   560  }
   561  
   562  func (w *Writer) Uint32(x uint32) {
   563  	var b [4]byte
   564  	binary.LittleEndian.PutUint32(b[:], x)
   565  	w.wr.Write(b[:])
   566  	w.off += 4
   567  }
   568  
   569  func (w *Writer) Uint16(x uint16) {
   570  	var b [2]byte
   571  	binary.LittleEndian.PutUint16(b[:], x)
   572  	w.wr.Write(b[:])
   573  	w.off += 2
   574  }
   575  
   576  func (w *Writer) Uint8(x uint8) {
   577  	w.wr.WriteByte(x)
   578  	w.off++
   579  }
   580  
   581  func (w *Writer) Offset() uint32 {
   582  	return w.off
   583  }
   584  
   585  type Reader struct {
   586  	b        []byte // mmapped bytes, if not nil
   587  	readonly bool   // whether b is backed with read-only memory
   588  
   589  	rd    io.ReaderAt
   590  	start uint32
   591  	h     Header // keep block offsets
   592  }
   593  
   594  func NewReaderFromBytes(b []byte, readonly bool) *Reader {
   595  	r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0}
   596  	err := r.h.Read(r)
   597  	if err != nil {
   598  		return nil
   599  	}
   600  	return r
   601  }
   602  
   603  func (r *Reader) BytesAt(off uint32, len int) []byte {
   604  	if len == 0 {
   605  		return nil
   606  	}
   607  	end := int(off) + len
   608  	return r.b[int(off):end:end]
   609  }
   610  
   611  func (r *Reader) uint64At(off uint32) uint64 {
   612  	b := r.BytesAt(off, 8)
   613  	return binary.LittleEndian.Uint64(b)
   614  }
   615  
   616  func (r *Reader) int64At(off uint32) int64 {
   617  	return int64(r.uint64At(off))
   618  }
   619  
   620  func (r *Reader) uint32At(off uint32) uint32 {
   621  	b := r.BytesAt(off, 4)
   622  	return binary.LittleEndian.Uint32(b)
   623  }
   624  
   625  func (r *Reader) int32At(off uint32) int32 {
   626  	return int32(r.uint32At(off))
   627  }
   628  
   629  func (r *Reader) uint16At(off uint32) uint16 {
   630  	b := r.BytesAt(off, 2)
   631  	return binary.LittleEndian.Uint16(b)
   632  }
   633  
   634  func (r *Reader) uint8At(off uint32) uint8 {
   635  	b := r.BytesAt(off, 1)
   636  	return b[0]
   637  }
   638  
   639  func (r *Reader) StringAt(off uint32, len uint32) string {
   640  	b := r.b[off : off+len]
   641  	if r.readonly {
   642  		return toString(b) // backed by RO memory, ok to make unsafe string
   643  	}
   644  	return string(b)
   645  }
   646  
   647  func toString(b []byte) string {
   648  	if len(b) == 0 {
   649  		return ""
   650  	}
   651  
   652  	var s string
   653  	hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
   654  	hdr.Data = unsafe.Pointer(&b[0])
   655  	hdr.Len = len(b)
   656  
   657  	return s
   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] + uint32(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] + uint32(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] + uint32(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] + uint32(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] + uint32(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 (*[1 << 20]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 (*[1 << 20]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  // AuxDataBase returns the base offset of the aux data block.
   843  func (r *Reader) PcdataBase() uint32 {
   844  	return r.h.Offsets[BlkPcdata]
   845  }
   846  
   847  // NRefName returns the number of referenced symbol names.
   848  func (r *Reader) NRefName() int {
   849  	return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
   850  }
   851  
   852  // RefName returns a pointer to the i-th referenced symbol name.
   853  // Note: here i is not a local symbol index, just a counter.
   854  func (r *Reader) RefName(i int) *RefName {
   855  	off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
   856  	return (*RefName)(unsafe.Pointer(&r.b[off]))
   857  }
   858  
   859  // ReadOnly returns whether r.BytesAt returns read-only bytes.
   860  func (r *Reader) ReadOnly() bool {
   861  	return r.readonly
   862  }
   863  
   864  // Flags returns the flag bits read from the object file header.
   865  func (r *Reader) Flags() uint32 {
   866  	return r.h.Flags
   867  }
   868  
   869  func (r *Reader) Shared() bool            { return r.Flags()&ObjFlagShared != 0 }
   870  func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 }
   871  func (r *Reader) FromAssembly() bool      { return r.Flags()&ObjFlagFromAssembly != 0 }
   872  

View as plain text