...

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

     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		"cmd/internal/objabi"
    10		"cmd/internal/sys"
    11		"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, s *sym.Symbol) uint8 {
    69		return s.P[2*arch.PtrSize+7] & objabi.KindMask //  0x13 / 0x1f
    70	}
    71	
    72	// Type.commonType.kind
    73	func decodetypeUsegcprog(arch *sys.Arch, s *sym.Symbol) uint8 {
    74		return s.P[2*arch.PtrSize+7] & objabi.KindGCProg //  0x13 / 0x1f
    75	}
    76	
    77	// Type.commonType.size
    78	func decodetypeSize(arch *sys.Arch, s *sym.Symbol) int64 {
    79		return int64(decodeInuxi(arch, s.P, arch.PtrSize)) // 0x8 / 0x10
    80	}
    81	
    82	// Type.commonType.ptrdata
    83	func decodetypePtrdata(arch *sys.Arch, s *sym.Symbol) int64 {
    84		return int64(decodeInuxi(arch, s.P[arch.PtrSize:], arch.PtrSize)) // 0x8 / 0x10
    85	}
    86	
    87	// Type.commonType.tflag
    88	func decodetypeHasUncommon(arch *sys.Arch, s *sym.Symbol) bool {
    89		return s.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)
   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, s *sym.Symbol) bool {
   185		return uint16(decodeInuxi(arch, s.P[commonsize(arch)+2:], 2))&(1<<15) != 0
   186	}
   187	
   188	// Type.FuncType.inCount
   189	func decodetypeFuncInCount(arch *sys.Arch, s *sym.Symbol) int {
   190		return int(decodeInuxi(arch, s.P[commonsize(arch):], 2))
   191	}
   192	
   193	func decodetypeFuncOutCount(arch *sys.Arch, s *sym.Symbol) int {
   194		return int(uint16(decodeInuxi(arch, s.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) {
   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))
   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) {
   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, s *sym.Symbol) int64 {
   268		return int64(decodeInuxi(arch, s.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)
   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)
   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)&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))
   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) {
   345			panic(fmt.Sprintf("no methods on %q", s.Name))
   346		}
   347		off := commonsize(arch) // reflect.rtype
   348		switch decodetypeKind(arch, s) & 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 += 3*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	}
   375	

View as plain text