Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/link/internal/ld/decodesym.go

Documentation: cmd/link/internal/ld

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

View as plain text