github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/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 "debug/elf" 9 "encoding/binary" 10 "log" 11 12 "github.com/go-asm/go/abi" 13 "github.com/go-asm/go/cmd/link/loader" 14 "github.com/go-asm/go/cmd/link/sym" 15 "github.com/go-asm/go/cmd/objabi" 16 "github.com/go-asm/go/cmd/sys" 17 ) 18 19 // Decoding the type.* symbols. This has to be in sync with 20 // ../../runtime/type.go, or more specifically, with what 21 // github.com/go-asm/go/cmd/compile/reflectdata/reflect.go stuffs in these. 22 23 func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 { 24 switch sz { 25 case 2: 26 return uint64(arch.ByteOrder.Uint16(p)) 27 case 4: 28 return uint64(arch.ByteOrder.Uint32(p)) 29 case 8: 30 return arch.ByteOrder.Uint64(p) 31 default: 32 Exitf("dwarf: decode inuxi %d", sz) 33 panic("unreachable") 34 } 35 } 36 37 func commonsize(arch *sys.Arch) int { return abi.CommonSize(arch.PtrSize) } // runtime._type 38 func structfieldSize(arch *sys.Arch) int { return abi.StructFieldSize(arch.PtrSize) } // runtime.structfield 39 func uncommonSize(arch *sys.Arch) int { return int(abi.UncommonSize()) } // runtime.uncommontype 40 41 // Type.commonType.kind 42 func decodetypeKind(arch *sys.Arch, p []byte) uint8 { 43 return p[2*arch.PtrSize+7] & objabi.KindMask // 0x13 / 0x1f 44 } 45 46 // Type.commonType.kind 47 func decodetypeUsegcprog(arch *sys.Arch, p []byte) uint8 { 48 return p[2*arch.PtrSize+7] & objabi.KindGCProg // 0x13 / 0x1f 49 } 50 51 // Type.commonType.size 52 func decodetypeSize(arch *sys.Arch, p []byte) int64 { 53 return int64(decodeInuxi(arch, p, arch.PtrSize)) // 0x8 / 0x10 54 } 55 56 // Type.commonType.ptrdata 57 func decodetypePtrdata(arch *sys.Arch, p []byte) int64 { 58 return int64(decodeInuxi(arch, p[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10 59 } 60 61 // Type.commonType.tflag 62 func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool { 63 return abi.TFlag(p[abi.TFlagOff(arch.PtrSize)])&abi.TFlagUncommon != 0 64 } 65 66 // Type.FuncType.dotdotdot 67 func decodetypeFuncDotdotdot(arch *sys.Arch, p []byte) bool { 68 return uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2))&(1<<15) != 0 69 } 70 71 // Type.FuncType.inCount 72 func decodetypeFuncInCount(arch *sys.Arch, p []byte) int { 73 return int(decodeInuxi(arch, p[commonsize(arch):], 2)) 74 } 75 76 func decodetypeFuncOutCount(arch *sys.Arch, p []byte) int { 77 return int(uint16(decodeInuxi(arch, p[commonsize(arch)+2:], 2)) & (1<<15 - 1)) 78 } 79 80 // InterfaceType.methods.length 81 func decodetypeIfaceMethodCount(arch *sys.Arch, p []byte) int64 { 82 return int64(decodeInuxi(arch, p[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) 83 } 84 85 // Matches runtime/typekind.go and reflect.Kind. 86 const ( 87 kindArray = 17 88 kindChan = 18 89 kindFunc = 19 90 kindInterface = 20 91 kindMap = 21 92 kindPtr = 22 93 kindSlice = 23 94 kindStruct = 25 95 kindMask = (1 << 5) - 1 96 ) 97 98 func decodeReloc(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Reloc { 99 for j := 0; j < relocs.Count(); j++ { 100 rel := relocs.At(j) 101 if rel.Off() == off { 102 return rel 103 } 104 } 105 return loader.Reloc{} 106 } 107 108 func decodeRelocSym(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int32) loader.Sym { 109 return decodeReloc(ldr, symIdx, relocs, off).Sym() 110 } 111 112 // decodetypeName decodes the name from a reflect.name. 113 func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) string { 114 r := decodeRelocSym(ldr, symIdx, relocs, int32(off)) 115 if r == 0 { 116 return "" 117 } 118 119 data := ldr.DataString(r) 120 n := 1 + binary.MaxVarintLen64 121 if len(data) < n { 122 n = len(data) 123 } 124 nameLen, nameLenLen := binary.Uvarint([]byte(data[1:n])) 125 return data[1+nameLenLen : 1+nameLenLen+int(nameLen)] 126 } 127 128 func decodetypeNameEmbedded(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) bool { 129 r := decodeRelocSym(ldr, symIdx, relocs, int32(off)) 130 if r == 0 { 131 return false 132 } 133 data := ldr.Data(r) 134 return data[0]&(1<<3) != 0 135 } 136 137 func decodetypeFuncInType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym { 138 uadd := commonsize(arch) + 4 139 if arch.PtrSize == 8 { 140 uadd += 4 141 } 142 if decodetypeHasUncommon(arch, ldr.Data(symIdx)) { 143 uadd += uncommonSize(arch) 144 } 145 return decodeRelocSym(ldr, symIdx, relocs, int32(uadd+i*arch.PtrSize)) 146 } 147 148 func decodetypeFuncOutType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs, i int) loader.Sym { 149 return decodetypeFuncInType(ldr, arch, symIdx, relocs, i+decodetypeFuncInCount(arch, ldr.Data(symIdx))) 150 } 151 152 func decodetypeArrayElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 153 relocs := ldr.Relocs(symIdx) 154 return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30 155 } 156 157 func decodetypeArrayLen(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int64 { 158 data := ldr.Data(symIdx) 159 return int64(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) 160 } 161 162 func decodetypeChanElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 163 relocs := ldr.Relocs(symIdx) 164 return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30 165 } 166 167 func decodetypeMapKey(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 168 relocs := ldr.Relocs(symIdx) 169 return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30 170 } 171 172 func decodetypeMapValue(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 173 relocs := ldr.Relocs(symIdx) 174 return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))+int32(arch.PtrSize)) // 0x20 / 0x38 175 } 176 177 func decodetypePtrElem(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 178 relocs := ldr.Relocs(symIdx) 179 return decodeRelocSym(ldr, symIdx, &relocs, int32(commonsize(arch))) // 0x1c / 0x30 180 } 181 182 func decodetypeStructFieldCount(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) int { 183 data := ldr.Data(symIdx) 184 return int(decodeInuxi(arch, data[commonsize(arch)+2*arch.PtrSize:], arch.PtrSize)) 185 } 186 187 func decodetypeStructFieldArrayOff(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int { 188 data := ldr.Data(symIdx) 189 off := commonsize(arch) + 4*arch.PtrSize 190 if decodetypeHasUncommon(arch, data) { 191 off += uncommonSize(arch) 192 } 193 off += i * structfieldSize(arch) 194 return off 195 } 196 197 func decodetypeStructFieldName(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) string { 198 off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i) 199 relocs := ldr.Relocs(symIdx) 200 return decodetypeName(ldr, symIdx, &relocs, off) 201 } 202 203 func decodetypeStructFieldType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) loader.Sym { 204 off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i) 205 relocs := ldr.Relocs(symIdx) 206 return decodeRelocSym(ldr, symIdx, &relocs, int32(off+arch.PtrSize)) 207 } 208 209 func decodetypeStructFieldOffset(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) int64 { 210 off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i) 211 data := ldr.Data(symIdx) 212 return int64(decodeInuxi(arch, data[off+2*arch.PtrSize:], arch.PtrSize)) 213 } 214 215 func decodetypeStructFieldEmbedded(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, i int) bool { 216 off := decodetypeStructFieldArrayOff(ldr, arch, symIdx, i) 217 relocs := ldr.Relocs(symIdx) 218 return decodetypeNameEmbedded(ldr, symIdx, &relocs, off) 219 } 220 221 // decodetypeStr returns the contents of an rtype's str field (a nameOff). 222 func decodetypeStr(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) string { 223 relocs := ldr.Relocs(symIdx) 224 str := decodetypeName(ldr, symIdx, &relocs, 4*arch.PtrSize+8) 225 data := ldr.Data(symIdx) 226 if data[abi.TFlagOff(arch.PtrSize)]&byte(abi.TFlagExtraStar) != 0 { 227 return str[1:] 228 } 229 return str 230 } 231 232 func decodetypeGcmask(ctxt *Link, s loader.Sym) []byte { 233 if ctxt.loader.SymType(s) == sym.SDYNIMPORT { 234 symData := ctxt.loader.Data(s) 235 addr := decodetypeGcprogShlib(ctxt, symData) 236 ptrdata := decodetypePtrdata(ctxt.Arch, symData) 237 sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr) 238 if sect != nil { 239 bits := ptrdata / int64(ctxt.Arch.PtrSize) 240 r := make([]byte, (bits+7)/8) 241 // ldshlibsyms avoids closing the ELF file so sect.ReadAt works. 242 // If we remove this read (and the ones in decodetypeGcprog), we 243 // can close the file. 244 _, err := sect.ReadAt(r, int64(addr-sect.Addr)) 245 if err != nil { 246 log.Fatal(err) 247 } 248 return r 249 } 250 Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s)) 251 return nil 252 } 253 relocs := ctxt.loader.Relocs(s) 254 mask := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)) 255 return ctxt.loader.Data(mask) 256 } 257 258 // Type.commonType.gc 259 func decodetypeGcprog(ctxt *Link, s loader.Sym) []byte { 260 if ctxt.loader.SymType(s) == sym.SDYNIMPORT { 261 symData := ctxt.loader.Data(s) 262 addr := decodetypeGcprogShlib(ctxt, symData) 263 sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr) 264 if sect != nil { 265 // A gcprog is a 4-byte uint32 indicating length, followed by 266 // the actual program. 267 progsize := make([]byte, 4) 268 _, err := sect.ReadAt(progsize, int64(addr-sect.Addr)) 269 if err != nil { 270 log.Fatal(err) 271 } 272 progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize)) 273 _, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4)) 274 if err != nil { 275 log.Fatal(err) 276 } 277 return append(progsize, progbytes...) 278 } 279 Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s)) 280 return nil 281 } 282 relocs := ctxt.loader.Relocs(s) 283 rs := decodeRelocSym(ctxt.loader, s, &relocs, 2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize)) 284 return ctxt.loader.Data(rs) 285 } 286 287 // Find the elf.Section of a given shared library that contains a given address. 288 func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section { 289 for _, shlib := range ctxt.Shlibs { 290 if shlib.Path == path { 291 for _, sect := range shlib.File.Sections[1:] { // skip the NULL section 292 if sect.Addr <= addr && addr < sect.Addr+sect.Size { 293 return sect 294 } 295 } 296 } 297 } 298 return nil 299 } 300 301 func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 { 302 return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize) 303 } 304 305 // decodeItabType returns the itab._type field from an itab. 306 func decodeItabType(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym) loader.Sym { 307 relocs := ldr.Relocs(symIdx) 308 return decodeRelocSym(ldr, symIdx, &relocs, int32(arch.PtrSize)) 309 }