Home | History | Annotate | Download | only in ld
      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 }
    370