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