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