github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/ld/decodesym.go (about)

     1  // Copyright 2012 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  package ld
     6  
     7  import (
     8  	"bytes"
     9  	"github.com/gagliardetto/golang-go/cmd/internal/objabi"
    10  	"github.com/gagliardetto/golang-go/cmd/internal/sys"
    11  	"github.com/gagliardetto/golang-go/cmd/link/internal/sym"
    12  	"debug/elf"
    13  	"fmt"
    14  )
    15  
    16  // Decoding the type.* symbols.	 This has to be in sync with
    17  // ../../runtime/type.go, or more specifically, with what
    18  // cmd/compile/internal/gc/reflect.go stuffs in these.
    19  
    20  // tflag is documented in reflect/type.go.
    21  //
    22  // tflag values must be kept in sync with copies in:
    23  //	cmd/compile/internal/gc/reflect.go
    24  //	cmd/link/internal/ld/decodesym.go
    25  //	reflect/type.go
    26  //	runtime/type.go
    27  const (
    28  	tflagUncommon  = 1 << 0
    29  	tflagExtraStar = 1 << 1
    30  )
    31  
    32  func decodeReloc(s *sym.Symbol, off int32) *sym.Reloc {
    33  	for i := range s.R {
    34  		if s.R[i].Off == off {
    35  			return &s.R[i]
    36  		}
    37  	}
    38  	return nil
    39  }
    40  
    41  func decodeRelocSym(s *sym.Symbol, off int32) *sym.Symbol {
    42  	r := decodeReloc(s, off)
    43  	if r == nil {
    44  		return nil
    45  	}
    46  	return r.Sym
    47  }
    48  
    49  func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
    50  	switch sz {
    51  	case 2:
    52  		return uint64(arch.ByteOrder.Uint16(p))
    53  	case 4:
    54  		return uint64(arch.ByteOrder.Uint32(p))
    55  	case 8:
    56  		return arch.ByteOrder.Uint64(p)
    57  	default:
    58  		Exitf("dwarf: decode inuxi %d", sz)
    59  		panic("unreachable")
    60  	}
    61  }
    62  
    63  func commonsize(arch *sys.Arch) int      { return 4*arch.PtrSize + 8 + 8 } // runtime._type
    64  func structfieldSize(arch *sys.Arch) int { return 3 * arch.PtrSize }       // runtime.structfield
    65  func uncommonSize() int                  { return 4 + 2 + 2 + 4 + 4 }      // runtime.uncommontype
    66  
    67  // Type.commonType.kind
    68  func decodetypeKind(arch *sys.Arch, p []byte) uint8 {
    69  	return p[2*arch.PtrSize+7] & objabi.KindMask //  0x13 / 0x1f
    70  }
    71  
    72  // Type.commonType.kind
    73  func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 {
    74  	return p[2*arch.PtrSize+7] & objabi.KindGCProg //  0x13 / 0x1f
    75  }
    76  
    77  // Type.commonType.size
    78  func decodetypeSize(arch *sys.Arch, p []byte) int64 {
    79  	return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10
    80  }
    81  
    82  // Type.commonType.ptrdata
    83  func decodetypePtrdata(arch *sys.Arch, p []byte) int64 {
    84  	return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
    85  }
    86  
    87  // Type.commonType.tflag
    88  func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
    89  	return p[2*arch.PtrSize+4]&tflagUncommon != 0
    90  }
    91  
    92  // Find the elf.Section of a given shared library that contains a given address.
    93  func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
    94  	for _, shlib := range ctxt.Shlibs {
    95  		if shlib.Path == path {
    96  			for _, sect := range shlib.File.Sections {
    97  				if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
    98  					return sect
    99  				}
   100  			}
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  // Type.commonType.gc
   107  func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
   108  	if s.Type == sym.SDYNIMPORT {
   109  		addr := decodetypeGcprogShlib(ctxt, s)
   110  		sect := findShlibSection(ctxt, s.File, addr)
   111  		if sect != nil {
   112  			// A gcprog is a 4-byte uint32 indicating length, followed by
   113  			// the actual program.
   114  			progsize := make([]byte, 4)
   115  			sect.ReadAt(progsize, int64(addr-sect.Addr))
   116  			progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
   117  			sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
   118  			return append(progsize, progbytes...)
   119  		}
   120  		Exitf("cannot find gcprog for %s", s.Name)
   121  		return nil
   122  	}
   123  	return decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)).P
   124  }
   125  
   126  func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
   127  	if ctxt.Arch.Family == sys.ARM64 {
   128  		for _, shlib := range ctxt.Shlibs {
   129  			if shlib.Path == s.File {
   130  				return shlib.gcdataAddresses[s]
   131  			}
   132  		}
   133  		return 0
   134  	}
   135  	return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
   136  }
   137  
   138  func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
   139  	if s.Type == sym.SDYNIMPORT {
   140  		addr := decodetypeGcprogShlib(ctxt, s)
   141  		ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
   142  		sect := findShlibSection(ctxt, s.File, addr)
   143  		if sect != nil {
   144  			r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
   145  			sect.ReadAt(r, int64(addr-sect.Addr))
   146  			return r
   147  		}
   148  		Exitf("cannot find gcmask for %s", s.Name)
   149  		return nil
   150  	}
   151  	mask := decodeRelocSym(s, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize))
   152  	return mask.P
   153  }
   154  
   155  // Type.ArrayType.elem and Type.SliceType.Elem
   156  func decodetypeArrayElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
   157  	return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
   158  }
   159  
   160  func decodetypeArrayLen(arch *sys.Arch, s *sym.Symbol) int64 {
   161  	return int64(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
   162  }
   163  
   164  // Type.PtrType.elem
   165  func decodetypePtrElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
   166  	return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
   167  }
   168  
   169  // Type.MapType.key, elem
   170  func decodetypeMapKey(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
   171  	return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
   172  }
   173  
   174  func decodetypeMapValue(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
   175  	return decodeRelocSym(s, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38
   176  }
   177  
   178  // Type.ChanType.elem
   179  func decodetypeChanElem(arch *sys.Arch, s *sym.Symbol) *sym.Symbol {
   180  	return decodeRelocSym(s, int32(commonsize(arch))) // 0x1c / 0x30
   181  }
   182  
   183  // Type.FuncType.dotdotdot
   184  func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool {
   185  	return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0
   186  }
   187  
   188  // Type.FuncType.inCount
   189  func decodetypeFuncInCount(arch *sys.Arch, p []byte) int {
   190  	return int(decodeInuxi(arch, p[commonsize(arch):], 2))
   191  }
   192  
   193  func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int {
   194  	return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1))
   195  }
   196  
   197  func decodetypeFuncInType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
   198  	uadd := commonsize(arch) + 4
   199  	if arch.PtrSize == 8 {
   200  		uadd += 4
   201  	}
   202  	if decodetypeHasUncommon(arch, s.P) {
   203  		uadd += uncommonSize()
   204  	}
   205  	return decodeRelocSym(s, int32(uadd+i*arch.PtrSize))
   206  }
   207  
   208  func decodetypeFuncOutType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
   209  	return decodetypeFuncInType(arch, s, i+decodetypeFuncInCount(arch, s.P))
   210  }
   211  
   212  // Type.StructType.fields.Slice::length
   213  func decodetypeStructFieldCount(arch *sys.Arch, s *sym.Symbol) int {
   214  	return int(decodeInuxi(arch, s.P[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
   215  }
   216  
   217  func decodetypeStructFieldArrayOff(arch *sys.Arch, s *sym.Symbol, i int) int {
   218  	off := commonsize(arch) + 4*arch.PtrSize
   219  	if decodetypeHasUncommon(arch, s.P) {
   220  		off += uncommonSize()
   221  	}
   222  	off += i * structfieldSize(arch)
   223  	return off
   224  }
   225  
   226  // decodetypeStr returns the contents of an rtype's str field (a nameOff).
   227  func decodetypeStr(arch *sys.Arch, s *sym.Symbol) string {
   228  	str := decodetypeName(s, 4*arch.PtrSize+8)
   229  	if s.P[2*arch.PtrSize+4]&tflagExtraStar != 0 {
   230  		return str[1:]
   231  	}
   232  	return str
   233  }
   234  
   235  // decodetypeName decodes the name from a reflect.name.
   236  func decodetypeName(s *sym.Symbol, off int) string {
   237  	r := decodeReloc(s, int32(off))
   238  	if r == nil {
   239  		return ""
   240  	}
   241  
   242  	data := r.Sym.P
   243  	namelen := int(uint16(data[1])<<8 | uint16(data[2]))
   244  	return string(data[3 : 3+namelen])
   245  }
   246  
   247  func decodetypeStructFieldName(arch *sys.Arch, s *sym.Symbol, i int) string {
   248  	off := decodetypeStructFieldArrayOff(arch, s, i)
   249  	return decodetypeName(s, off)
   250  }
   251  
   252  func decodetypeStructFieldType(arch *sys.Arch, s *sym.Symbol, i int) *sym.Symbol {
   253  	off := decodetypeStructFieldArrayOff(arch, s, i)
   254  	return decodeRelocSym(s, int32(off+arch.PtrSize))
   255  }
   256  
   257  func decodetypeStructFieldOffs(arch *sys.Arch, s *sym.Symbol, i int) int64 {
   258  	return decodetypeStructFieldOffsAnon(arch, s, i) >> 1
   259  }
   260  
   261  func decodetypeStructFieldOffsAnon(arch *sys.Arch, s *sym.Symbol, i int) int64 {
   262  	off := decodetypeStructFieldArrayOff(arch, s, i)
   263  	return int64(decodeInuxi(arch, s.P[off+2*arch.PtrSize:], arch.PtrSize))
   264  }
   265  
   266  // InterfaceType.methods.length
   267  func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 {
   268  	return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize))
   269  }
   270  
   271  // methodsig is a fully qualified typed method signature, like
   272  // "Visit(type.go/ast.Node) (type.go/ast.Visitor)".
   273  type methodsig string
   274  
   275  // Matches runtime/typekind.go and reflect.Kind.
   276  const (
   277  	kindArray     = 17
   278  	kindChan      = 18
   279  	kindFunc      = 19
   280  	kindInterface = 20
   281  	kindMap       = 21
   282  	kindPtr       = 22
   283  	kindSlice     = 23
   284  	kindStruct    = 25
   285  	kindMask      = (1 << 5) - 1
   286  )
   287  
   288  // decodeMethodSig decodes an array of method signature information.
   289  // Each element of the array is size bytes. The first 4 bytes is a
   290  // nameOff for the method name, and the next 4 bytes is a typeOff for
   291  // the function type.
   292  //
   293  // Conveniently this is the layout of both runtime.method and runtime.imethod.
   294  func decodeMethodSig(arch *sys.Arch, s *sym.Symbol, off, size, count int) []methodsig {
   295  	var buf bytes.Buffer
   296  	var methods []methodsig
   297  	for i := 0; i < count; i++ {
   298  		buf.WriteString(decodetypeName(s, off))
   299  		mtypSym := decodeRelocSym(s, int32(off+4))
   300  
   301  		buf.WriteRune('(')
   302  		inCount := decodetypeFuncInCount(arch, mtypSym.P)
   303  		for i := 0; i < inCount; i++ {
   304  			if i > 0 {
   305  				buf.WriteString(", ")
   306  			}
   307  			buf.WriteString(decodetypeFuncInType(arch, mtypSym, i).Name)
   308  		}
   309  		buf.WriteString(") (")
   310  		outCount := decodetypeFuncOutCount(arch, mtypSym.P)
   311  		for i := 0; i < outCount; i++ {
   312  			if i > 0 {
   313  				buf.WriteString(", ")
   314  			}
   315  			buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
   316  		}
   317  		buf.WriteRune(')')
   318  
   319  		off += size
   320  		methods = append(methods, methodsig(buf.String()))
   321  		buf.Reset()
   322  	}
   323  	return methods
   324  }
   325  
   326  func decodeIfaceMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
   327  	if decodetypeKind(arch, s.P)&kindMask != kindInterface {
   328  		panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
   329  	}
   330  	r := decodeReloc(s, int32(commonsize(arch)+arch.PtrSize))
   331  	if r == nil {
   332  		return nil
   333  	}
   334  	if r.Sym != s {
   335  		panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
   336  	}
   337  	off := int(r.Add) // array of reflect.imethod values
   338  	numMethods := int(decodetypeIfaceMethodCount(arch, s.P))
   339  	sizeofIMethod := 4 + 4
   340  	return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
   341  }
   342  
   343  func decodetypeMethods(arch *sys.Arch, s *sym.Symbol) []methodsig {
   344  	if !decodetypeHasUncommon(arch, s.P) {
   345  		panic(fmt.Sprintf("no methods on %q", s.Name))
   346  	}
   347  	off := commonsize(arch) // reflect.rtype
   348  	switch decodetypeKind(arch, s.P) & kindMask {
   349  	case kindStruct: // reflect.structType
   350  		off += 4 * arch.PtrSize
   351  	case kindPtr: // reflect.ptrType
   352  		off += arch.PtrSize
   353  	case kindFunc: // reflect.funcType
   354  		off += arch.PtrSize // 4 bytes, pointer aligned
   355  	case kindSlice: // reflect.sliceType
   356  		off += arch.PtrSize
   357  	case kindArray: // reflect.arrayType
   358  		off += 3 * arch.PtrSize
   359  	case kindChan: // reflect.chanType
   360  		off += 2 * arch.PtrSize
   361  	case kindMap: // reflect.mapType
   362  		off += 4*arch.PtrSize + 8
   363  	case kindInterface: // reflect.interfaceType
   364  		off += 3 * arch.PtrSize
   365  	default:
   366  		// just Sizeof(rtype)
   367  	}
   368  
   369  	mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
   370  	moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
   371  	off += moff                // offset to array of reflect.method values
   372  	const sizeofMethod = 4 * 4 // sizeof reflect.method in program
   373  	return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
   374  }