gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

objfile.go (23541B)


      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 }