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  }