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 }