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 }