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