1// Copyright 2017 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 sym
6
7import (
8	"cmd/internal/obj"
9	"cmd/internal/objabi"
10	"cmd/internal/sys"
11	"debug/elf"
12	"fmt"
13	"log"
14)
15
16// Symbol is an entry in the symbol table.
17type Symbol struct {
18	Name        string
19	Type        SymKind
20	Version     int16
21	Attr        Attribute
22	Dynid       int32
23	Align       int32
24	Elfsym      int32
25	LocalElfsym int32
26	Value       int64
27	Size        int64
28	Sub         *Symbol
29	Outer       *Symbol
30	Gotype      *Symbol
31	File        string // actually package!
32	auxinfo     *AuxSymbol
33	Sect        *Section
34	FuncInfo    *FuncInfo
35	Unit        *CompilationUnit
36	// P contains the raw symbol data.
37	P []byte
38	R []Reloc
39}
40
41// AuxSymbol contains less-frequently used sym.Symbol fields.
42type AuxSymbol struct {
43	extname    string
44	dynimplib  string
45	dynimpvers string
46	localentry uint8
47	plt        int32
48	got        int32
49	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
50	// is not set for symbols defined by the packages being linked or by symbols
51	// read by ldelf (and so is left as elf.STT_NOTYPE).
52	elftype elf.SymType
53}
54
55const (
56	SymVerABI0        = 0
57	SymVerABIInternal = 1
58	SymVerStatic      = 10 // Minimum version used by static (file-local) syms
59)
60
61func ABIToVersion(abi obj.ABI) int {
62	switch abi {
63	case obj.ABI0:
64		return SymVerABI0
65	case obj.ABIInternal:
66		return SymVerABIInternal
67	}
68	return -1
69}
70
71func VersionToABI(v int) (obj.ABI, bool) {
72	switch v {
73	case SymVerABI0:
74		return obj.ABI0, true
75	case SymVerABIInternal:
76		return obj.ABIInternal, true
77	}
78	return ^obj.ABI(0), false
79}
80
81func (s *Symbol) String() string {
82	if s.Version == 0 {
83		return s.Name
84	}
85	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
86}
87
88func (s *Symbol) IsFileLocal() bool {
89	return s.Version >= SymVerStatic
90}
91
92func (s *Symbol) ElfsymForReloc() int32 {
93	// If putelfsym created a local version of this symbol, use that in all
94	// relocations.
95	if s.LocalElfsym != 0 {
96		return s.LocalElfsym
97	} else {
98		return s.Elfsym
99	}
100}
101
102func (s *Symbol) Len() int64 {
103	return s.Size
104}
105
106func (s *Symbol) Grow(siz int64) {
107	if int64(int(siz)) != siz {
108		log.Fatalf("symgrow size %d too long", siz)
109	}
110	if int64(len(s.P)) >= siz {
111		return
112	}
113	if cap(s.P) < int(siz) {
114		p := make([]byte, 2*(siz+1))
115		s.P = append(p[:0], s.P...)
116	}
117	s.P = s.P[:siz]
118}
119
120func (s *Symbol) AddBytes(bytes []byte) int64 {
121	if s.Type == 0 {
122		s.Type = SDATA
123	}
124	s.Attr |= AttrReachable
125	s.P = append(s.P, bytes...)
126	s.Size = int64(len(s.P))
127
128	return s.Size
129}
130
131func (s *Symbol) AddUint8(v uint8) int64 {
132	off := s.Size
133	if s.Type == 0 {
134		s.Type = SDATA
135	}
136	s.Attr |= AttrReachable
137	s.Size++
138	s.P = append(s.P, v)
139
140	return off
141}
142
143func (s *Symbol) AddUint16(arch *sys.Arch, v uint16) int64 {
144	return s.AddUintXX(arch, uint64(v), 2)
145}
146
147func (s *Symbol) AddUint32(arch *sys.Arch, v uint32) int64 {
148	return s.AddUintXX(arch, uint64(v), 4)
149}
150
151func (s *Symbol) AddUint64(arch *sys.Arch, v uint64) int64 {
152	return s.AddUintXX(arch, v, 8)
153}
154
155func (s *Symbol) AddUint(arch *sys.Arch, v uint64) int64 {
156	return s.AddUintXX(arch, v, arch.PtrSize)
157}
158
159func (s *Symbol) SetUint8(arch *sys.Arch, r int64, v uint8) int64 {
160	return s.setUintXX(arch, r, uint64(v), 1)
161}
162
163func (s *Symbol) SetUint16(arch *sys.Arch, r int64, v uint16) int64 {
164	return s.setUintXX(arch, r, uint64(v), 2)
165}
166
167func (s *Symbol) SetUint32(arch *sys.Arch, r int64, v uint32) int64 {
168	return s.setUintXX(arch, r, uint64(v), 4)
169}
170
171func (s *Symbol) SetUint(arch *sys.Arch, r int64, v uint64) int64 {
172	return s.setUintXX(arch, r, v, int64(arch.PtrSize))
173}
174
175func (s *Symbol) addAddrPlus(arch *sys.Arch, t *Symbol, add int64, typ objabi.RelocType) int64 {
176	if s.Type == 0 {
177		s.Type = SDATA
178	}
179	s.Attr |= AttrReachable
180	i := s.Size
181	s.Size += int64(arch.PtrSize)
182	s.Grow(s.Size)
183	r := s.AddRel()
184	r.Sym = t
185	r.Off = int32(i)
186	r.Siz = uint8(arch.PtrSize)
187	r.Type = typ
188	r.Add = add
189	return i + int64(r.Siz)
190}
191
192func (s *Symbol) AddAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
193	return s.addAddrPlus(arch, t, add, objabi.R_ADDR)
194}
195
196func (s *Symbol) AddCURelativeAddrPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
197	return s.addAddrPlus(arch, t, add, objabi.R_ADDRCUOFF)
198}
199
200func (s *Symbol) AddPCRelPlus(arch *sys.Arch, t *Symbol, add int64) int64 {
201	if s.Type == 0 {
202		s.Type = SDATA
203	}
204	s.Attr |= AttrReachable
205	i := s.Size
206	s.Size += 4
207	s.Grow(s.Size)
208	r := s.AddRel()
209	r.Sym = t
210	r.Off = int32(i)
211	r.Add = add
212	r.Type = objabi.R_PCREL
213	r.Siz = 4
214	if arch.Family == sys.S390X || arch.Family == sys.PPC64 {
215		r.InitExt()
216	}
217	if arch.Family == sys.S390X {
218		r.Variant = RV_390_DBL
219	}
220	return i + int64(r.Siz)
221}
222
223func (s *Symbol) AddAddr(arch *sys.Arch, t *Symbol) int64 {
224	return s.AddAddrPlus(arch, t, 0)
225}
226
227func (s *Symbol) SetAddrPlus(arch *sys.Arch, off int64, t *Symbol, add int64) int64 {
228	if s.Type == 0 {
229		s.Type = SDATA
230	}
231	s.Attr |= AttrReachable
232	if off+int64(arch.PtrSize) > s.Size {
233		s.Size = off + int64(arch.PtrSize)
234		s.Grow(s.Size)
235	}
236
237	r := s.AddRel()
238	r.Sym = t
239	r.Off = int32(off)
240	r.Siz = uint8(arch.PtrSize)
241	r.Type = objabi.R_ADDR
242	r.Add = add
243	return off + int64(r.Siz)
244}
245
246func (s *Symbol) SetAddr(arch *sys.Arch, off int64, t *Symbol) int64 {
247	return s.SetAddrPlus(arch, off, t, 0)
248}
249
250func (s *Symbol) AddSize(arch *sys.Arch, t *Symbol) int64 {
251	if s.Type == 0 {
252		s.Type = SDATA
253	}
254	s.Attr |= AttrReachable
255	i := s.Size
256	s.Size += int64(arch.PtrSize)
257	s.Grow(s.Size)
258	r := s.AddRel()
259	r.Sym = t
260	r.Off = int32(i)
261	r.Siz = uint8(arch.PtrSize)
262	r.Type = objabi.R_SIZE
263	return i + int64(r.Siz)
264}
265
266func (s *Symbol) AddAddrPlus4(t *Symbol, add int64) int64 {
267	if s.Type == 0 {
268		s.Type = SDATA
269	}
270	s.Attr |= AttrReachable
271	i := s.Size
272	s.Size += 4
273	s.Grow(s.Size)
274	r := s.AddRel()
275	r.Sym = t
276	r.Off = int32(i)
277	r.Siz = 4
278	r.Type = objabi.R_ADDR
279	r.Add = add
280	return i + int64(r.Siz)
281}
282
283func (s *Symbol) AddRel() *Reloc {
284	s.R = append(s.R, Reloc{})
285	return &s.R[len(s.R)-1]
286}
287
288func (s *Symbol) AddUintXX(arch *sys.Arch, v uint64, wid int) int64 {
289	off := s.Size
290	s.setUintXX(arch, off, v, int64(wid))
291	return off
292}
293
294func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 {
295	if s.Type == 0 {
296		s.Type = SDATA
297	}
298	s.Attr |= AttrReachable
299	if s.Size < off+wid {
300		s.Size = off + wid
301		s.Grow(s.Size)
302	}
303
304	switch wid {
305	case 1:
306		s.P[off] = uint8(v)
307	case 2:
308		arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
309	case 4:
310		arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
311	case 8:
312		arch.ByteOrder.PutUint64(s.P[off:], v)
313	}
314
315	return off + wid
316}
317
318func (s *Symbol) makeAuxInfo() {
319	if s.auxinfo == nil {
320		s.auxinfo = &AuxSymbol{extname: s.Name, plt: -1, got: -1}
321	}
322}
323
324func (s *Symbol) Extname() string {
325	if s.auxinfo == nil {
326		return s.Name
327	}
328	return s.auxinfo.extname
329}
330
331func (s *Symbol) SetExtname(n string) {
332	if s.auxinfo == nil {
333		if s.Name == n {
334			return
335		}
336		s.makeAuxInfo()
337	}
338	s.auxinfo.extname = n
339}
340
341func (s *Symbol) Dynimplib() string {
342	if s.auxinfo == nil {
343		return ""
344	}
345	return s.auxinfo.dynimplib
346}
347
348func (s *Symbol) Dynimpvers() string {
349	if s.auxinfo == nil {
350		return ""
351	}
352	return s.auxinfo.dynimpvers
353}
354
355func (s *Symbol) SetDynimplib(lib string) {
356	if s.auxinfo == nil {
357		s.makeAuxInfo()
358	}
359	s.auxinfo.dynimplib = lib
360}
361
362func (s *Symbol) SetDynimpvers(vers string) {
363	if s.auxinfo == nil {
364		s.makeAuxInfo()
365	}
366	s.auxinfo.dynimpvers = vers
367}
368
369func (s *Symbol) ResetDyninfo() {
370	if s.auxinfo != nil {
371		s.auxinfo.dynimplib = ""
372		s.auxinfo.dynimpvers = ""
373	}
374}
375
376func (s *Symbol) Localentry() uint8 {
377	if s.auxinfo == nil {
378		return 0
379	}
380	return s.auxinfo.localentry
381}
382
383func (s *Symbol) SetLocalentry(val uint8) {
384	if s.auxinfo == nil {
385		if val != 0 {
386			return
387		}
388		s.makeAuxInfo()
389	}
390	s.auxinfo.localentry = val
391}
392
393func (s *Symbol) Plt() int32 {
394	if s.auxinfo == nil {
395		return -1
396	}
397	return s.auxinfo.plt
398}
399
400func (s *Symbol) SetPlt(val int32) {
401	if s.auxinfo == nil {
402		if val == -1 {
403			return
404		}
405		s.makeAuxInfo()
406	}
407	s.auxinfo.plt = val
408}
409
410func (s *Symbol) Got() int32 {
411	if s.auxinfo == nil {
412		return -1
413	}
414	return s.auxinfo.got
415}
416
417func (s *Symbol) SetGot(val int32) {
418	if s.auxinfo == nil {
419		if val == -1 {
420			return
421		}
422		s.makeAuxInfo()
423	}
424	s.auxinfo.got = val
425}
426
427func (s *Symbol) ElfType() elf.SymType {
428	if s.auxinfo == nil {
429		return elf.STT_NOTYPE
430	}
431	return s.auxinfo.elftype
432}
433
434func (s *Symbol) SetElfType(val elf.SymType) {
435	if s.auxinfo == nil {
436		if val == elf.STT_NOTYPE {
437			return
438		}
439		s.makeAuxInfo()
440	}
441	s.auxinfo.elftype = val
442}
443
444// SortSub sorts a linked-list (by Sub) of *Symbol by Value.
445// Used for sub-symbols when loading host objects (see e.g. ldelf.go).
446func SortSub(l *Symbol) *Symbol {
447	if l == nil || l.Sub == nil {
448		return l
449	}
450
451	l1 := l
452	l2 := l
453	for {
454		l2 = l2.Sub
455		if l2 == nil {
456			break
457		}
458		l2 = l2.Sub
459		if l2 == nil {
460			break
461		}
462		l1 = l1.Sub
463	}
464
465	l2 = l1.Sub
466	l1.Sub = nil
467	l1 = SortSub(l)
468	l2 = SortSub(l2)
469
470	/* set up lead element */
471	if l1.Value < l2.Value {
472		l = l1
473		l1 = l1.Sub
474	} else {
475		l = l2
476		l2 = l2.Sub
477	}
478
479	le := l
480
481	for {
482		if l1 == nil {
483			for l2 != nil {
484				le.Sub = l2
485				le = l2
486				l2 = l2.Sub
487			}
488
489			le.Sub = nil
490			break
491		}
492
493		if l2 == nil {
494			for l1 != nil {
495				le.Sub = l1
496				le = l1
497				l1 = l1.Sub
498			}
499
500			break
501		}
502
503		if l1.Value < l2.Value {
504			le.Sub = l1
505			le = l1
506			l1 = l1.Sub
507		} else {
508			le.Sub = l2
509			le = l2
510			l2 = l2.Sub
511		}
512	}
513
514	le.Sub = nil
515	return l
516}
517
518type FuncInfo struct {
519	Args        int32
520	Locals      int32
521	Pcsp        Pcdata
522	Pcfile      Pcdata
523	Pcline      Pcdata
524	Pcinline    Pcdata
525	Pcdata      []Pcdata
526	Funcdata    []*Symbol
527	Funcdataoff []int64
528	File        []*Symbol
529	InlTree     []InlinedCall
530}
531
532// InlinedCall is a node in a local inlining tree (FuncInfo.InlTree).
533type InlinedCall struct {
534	Parent   int32   // index of parent in InlTree
535	File     *Symbol // file of the inlined call
536	Line     int32   // line number of the inlined call
537	Func     string  // name of the function that was inlined
538	ParentPC int32   // PC of the instruction just before the inlined body (offset from function start)
539}
540
541type Pcdata struct {
542	P []byte
543}
544