podman

Форк
0
690 строк · 22.0 Кб
1
// Copyright 2019 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
// Writes dwarf information to object files.
6

7
package obj
8

9
import (
10
	"github.com/twitchyliquid64/golang-asm/dwarf"
11
	"github.com/twitchyliquid64/golang-asm/objabi"
12
	"github.com/twitchyliquid64/golang-asm/src"
13
	"fmt"
14
	"sort"
15
	"sync"
16
)
17

18
// Generate a sequence of opcodes that is as short as possible.
19
// See section 6.2.5
20
const (
21
	LINE_BASE   = -4
22
	LINE_RANGE  = 10
23
	PC_RANGE    = (255 - OPCODE_BASE) / LINE_RANGE
24
	OPCODE_BASE = 11
25
)
26

27
// generateDebugLinesSymbol fills the debug lines symbol of a given function.
28
//
29
// It's worth noting that this function doesn't generate the full debug_lines
30
// DWARF section, saving that for the linker. This function just generates the
31
// state machine part of debug_lines. The full table is generated by the
32
// linker.  Also, we use the file numbers from the full package (not just the
33
// function in question) when generating the state machine. We do this so we
34
// don't have to do a fixup on the indices when writing the full section.
35
func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
36
	dctxt := dwCtxt{ctxt}
37

38
	// Emit a LNE_set_address extended opcode, so as to establish the
39
	// starting text address of this function.
40
	dctxt.AddUint8(lines, 0)
41
	dwarf.Uleb128put(dctxt, lines, 1+int64(ctxt.Arch.PtrSize))
42
	dctxt.AddUint8(lines, dwarf.DW_LNE_set_address)
43
	dctxt.AddAddress(lines, s, 0)
44

45
	// Set up the debug_lines state machine to the default values
46
	// we expect at the start of a new sequence.
47
	stmt := true
48
	line := int64(1)
49
	pc := s.Func.Text.Pc
50
	var lastpc int64 // last PC written to line table, not last PC in func
51
	name := ""
52
	prologue, wrotePrologue := false, false
53
	// Walk the progs, generating the DWARF table.
54
	for p := s.Func.Text; p != nil; p = p.Link {
55
		prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
56
		// If we're not at a real instruction, keep looping!
57
		if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
58
			continue
59
		}
60
		newStmt := p.Pos.IsStmt() != src.PosNotStmt
61
		newName, newLine := linkgetlineFromPos(ctxt, p.Pos)
62

63
		// Output debug info.
64
		wrote := false
65
		if name != newName {
66
			newFile := ctxt.PosTable.FileIndex(newName) + 1 // 1 indexing for the table.
67
			dctxt.AddUint8(lines, dwarf.DW_LNS_set_file)
68
			dwarf.Uleb128put(dctxt, lines, int64(newFile))
69
			name = newName
70
			wrote = true
71
		}
72
		if prologue && !wrotePrologue {
73
			dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_set_prologue_end))
74
			wrotePrologue = true
75
			wrote = true
76
		}
77
		if stmt != newStmt {
78
			dctxt.AddUint8(lines, uint8(dwarf.DW_LNS_negate_stmt))
79
			stmt = newStmt
80
			wrote = true
81
		}
82

83
		if line != int64(newLine) || wrote {
84
			pcdelta := p.Pc - pc
85
			lastpc = p.Pc
86
			putpclcdelta(ctxt, dctxt, lines, uint64(pcdelta), int64(newLine)-line)
87
			line, pc = int64(newLine), p.Pc
88
		}
89
	}
90

91
	// Because these symbols will be concatenated together by the
92
	// linker, we need to reset the state machine that controls the
93
	// debug symbols. Do this using an end-of-sequence operator.
94
	//
95
	// Note: at one point in time, Delve did not support multiple end
96
	// sequence ops within a compilation unit (bug for this:
97
	// https://github.com/go-delve/delve/issues/1694), however the bug
98
	// has since been fixed (Oct 2019).
99
	//
100
	// Issue 38192: the DWARF standard specifies that when you issue
101
	// an end-sequence op, the PC value should be one past the last
102
	// text address in the translation unit, so apply a delta to the
103
	// text address before the end sequence op. If this isn't done,
104
	// GDB will assign a line number of zero the last row in the line
105
	// table, which we don't want.
106
	lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
107
	putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
108
	dctxt.AddUint8(lines, 0) // start extended opcode
109
	dwarf.Uleb128put(dctxt, lines, 1)
110
	dctxt.AddUint8(lines, dwarf.DW_LNE_end_sequence)
111
}
112

113
func putpclcdelta(linkctxt *Link, dctxt dwCtxt, s *LSym, deltaPC uint64, deltaLC int64) {
114
	// Choose a special opcode that minimizes the number of bytes needed to
115
	// encode the remaining PC delta and LC delta.
116
	var opcode int64
117
	if deltaLC < LINE_BASE {
118
		if deltaPC >= PC_RANGE {
119
			opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
120
		} else {
121
			opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
122
		}
123
	} else if deltaLC < LINE_BASE+LINE_RANGE {
124
		if deltaPC >= PC_RANGE {
125
			opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
126
			if opcode > 255 {
127
				opcode -= LINE_RANGE
128
			}
129
		} else {
130
			opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
131
		}
132
	} else {
133
		if deltaPC <= PC_RANGE {
134
			opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
135
			if opcode > 255 {
136
				opcode = 255
137
			}
138
		} else {
139
			// Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1).
140
			//
141
			// Let x=deltaPC-PC_RANGE.  If we use opcode 255, x will be the remaining
142
			// deltaPC that we need to encode separately before emitting 255.  If we
143
			// use opcode 249, we will need to encode x+1.  If x+1 takes one more
144
			// byte to encode than x, then we use opcode 255.
145
			//
146
			// In all other cases x and x+1 take the same number of bytes to encode,
147
			// so we use opcode 249, which may save us a byte in encoding deltaLC,
148
			// for similar reasons.
149
			switch deltaPC - PC_RANGE {
150
			// PC_RANGE is the largest deltaPC we can encode in one byte, using
151
			// DW_LNS_const_add_pc.
152
			//
153
			// (1<<16)-1 is the largest deltaPC we can encode in three bytes, using
154
			// DW_LNS_fixed_advance_pc.
155
			//
156
			// (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for
157
			// n=1,3,4,5,..., using DW_LNS_advance_pc.
158
			case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
159
				(1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
160
				opcode = 255
161
			default:
162
				opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
163
			}
164
		}
165
	}
166
	if opcode < OPCODE_BASE || opcode > 255 {
167
		panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
168
	}
169

170
	// Subtract from deltaPC and deltaLC the amounts that the opcode will add.
171
	deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
172
	deltaLC -= (opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE
173

174
	// Encode deltaPC.
175
	if deltaPC != 0 {
176
		if deltaPC <= PC_RANGE {
177
			// Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
178
			// instruction.
179
			opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
180
			if opcode < OPCODE_BASE {
181
				panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
182
			}
183
			dctxt.AddUint8(s, dwarf.DW_LNS_const_add_pc)
184
		} else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
185
			dctxt.AddUint8(s, dwarf.DW_LNS_fixed_advance_pc)
186
			dctxt.AddUint16(s, uint16(deltaPC))
187
		} else {
188
			dctxt.AddUint8(s, dwarf.DW_LNS_advance_pc)
189
			dwarf.Uleb128put(dctxt, s, int64(deltaPC))
190
		}
191
	}
192

193
	// Encode deltaLC.
194
	if deltaLC != 0 {
195
		dctxt.AddUint8(s, dwarf.DW_LNS_advance_line)
196
		dwarf.Sleb128put(dctxt, s, deltaLC)
197
	}
198

199
	// Output the special opcode.
200
	dctxt.AddUint8(s, uint8(opcode))
201
}
202

203
// implement dwarf.Context
204
type dwCtxt struct{ *Link }
205

206
func (c dwCtxt) PtrSize() int {
207
	return c.Arch.PtrSize
208
}
209
func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
210
	ls := s.(*LSym)
211
	ls.WriteInt(c.Link, ls.Size, size, i)
212
}
213
func (c dwCtxt) AddUint16(s dwarf.Sym, i uint16) {
214
	c.AddInt(s, 2, int64(i))
215
}
216
func (c dwCtxt) AddUint8(s dwarf.Sym, i uint8) {
217
	b := []byte{byte(i)}
218
	c.AddBytes(s, b)
219
}
220
func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
221
	ls := s.(*LSym)
222
	ls.WriteBytes(c.Link, ls.Size, b)
223
}
224
func (c dwCtxt) AddString(s dwarf.Sym, v string) {
225
	ls := s.(*LSym)
226
	ls.WriteString(c.Link, ls.Size, len(v), v)
227
	ls.WriteInt(c.Link, ls.Size, 1, 0)
228
}
229
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
230
	ls := s.(*LSym)
231
	size := c.PtrSize()
232
	if data != nil {
233
		rsym := data.(*LSym)
234
		ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
235
	} else {
236
		ls.WriteInt(c.Link, ls.Size, size, value)
237
	}
238
}
239
func (c dwCtxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
240
	ls := s.(*LSym)
241
	rsym := data.(*LSym)
242
	ls.WriteCURelativeAddr(c.Link, ls.Size, rsym, value)
243
}
244
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
245
	panic("should be used only in the linker")
246
}
247
func (c dwCtxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
248
	size := 4
249
	if isDwarf64(c.Link) {
250
		size = 8
251
	}
252

253
	ls := s.(*LSym)
254
	rsym := t.(*LSym)
255
	ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
256
	r := &ls.R[len(ls.R)-1]
257
	r.Type = objabi.R_DWARFSECREF
258
}
259

260
func (c dwCtxt) AddFileRef(s dwarf.Sym, f interface{}) {
261
	ls := s.(*LSym)
262
	rsym := f.(*LSym)
263
	fidx := c.Link.PosTable.FileIndex(rsym.Name)
264
	// Note the +1 here -- the value we're writing is going to be an
265
	// index into the DWARF line table file section, whose entries
266
	// are numbered starting at 1, not 0.
267
	ls.WriteInt(c.Link, ls.Size, 4, int64(fidx+1))
268
}
269

270
func (c dwCtxt) CurrentOffset(s dwarf.Sym) int64 {
271
	ls := s.(*LSym)
272
	return ls.Size
273
}
274

275
// Here "from" is a symbol corresponding to an inlined or concrete
276
// function, "to" is the symbol for the corresponding abstract
277
// function, and "dclIdx" is the index of the symbol of interest with
278
// respect to the Dcl slice of the original pre-optimization version
279
// of the inlined function.
280
func (c dwCtxt) RecordDclReference(from dwarf.Sym, to dwarf.Sym, dclIdx int, inlIndex int) {
281
	ls := from.(*LSym)
282
	tls := to.(*LSym)
283
	ridx := len(ls.R) - 1
284
	c.Link.DwFixups.ReferenceChildDIE(ls, ridx, tls, dclIdx, inlIndex)
285
}
286

287
func (c dwCtxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
288
	ls := s.(*LSym)
289
	c.Link.DwFixups.RegisterChildDIEOffsets(ls, vars, offsets)
290
}
291

292
func (c dwCtxt) Logf(format string, args ...interface{}) {
293
	c.Link.Logf(format, args...)
294
}
295

296
func isDwarf64(ctxt *Link) bool {
297
	return ctxt.Headtype == objabi.Haix
298
}
299

300
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym, dwarfAbsFnSym, dwarfDebugLines *LSym) {
301
	if s.Type != objabi.STEXT {
302
		ctxt.Diag("dwarfSym of non-TEXT %v", s)
303
	}
304
	if s.Func.dwarfInfoSym == nil {
305
		s.Func.dwarfInfoSym = &LSym{
306
			Type: objabi.SDWARFFCN,
307
		}
308
		if ctxt.Flag_locationlists {
309
			s.Func.dwarfLocSym = &LSym{
310
				Type: objabi.SDWARFLOC,
311
			}
312
		}
313
		s.Func.dwarfRangesSym = &LSym{
314
			Type: objabi.SDWARFRANGE,
315
		}
316
		s.Func.dwarfDebugLinesSym = &LSym{
317
			Type: objabi.SDWARFLINES,
318
		}
319
		if s.WasInlined() {
320
			s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
321
		}
322
	}
323
	return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
324
}
325

326
func (s *LSym) Length(dwarfContext interface{}) int64 {
327
	return s.Size
328
}
329

330
// fileSymbol returns a symbol corresponding to the source file of the
331
// first instruction (prog) of the specified function. This will
332
// presumably be the file in which the function is defined.
333
func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
334
	p := fn.Func.Text
335
	if p != nil {
336
		f, _ := linkgetlineFromPos(ctxt, p.Pos)
337
		fsym := ctxt.Lookup(f)
338
		return fsym
339
	}
340
	return nil
341
}
342

343
// populateDWARF fills in the DWARF Debugging Information Entries for
344
// TEXT symbol 's'. The various DWARF symbols must already have been
345
// initialized in InitTextSym.
346
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym, myimportpath string) {
347
	info, loc, ranges, absfunc, lines := ctxt.dwarfSym(s)
348
	if info.Size != 0 {
349
		ctxt.Diag("makeFuncDebugEntry double process %v", s)
350
	}
351
	var scopes []dwarf.Scope
352
	var inlcalls dwarf.InlCalls
353
	if ctxt.DebugInfo != nil {
354
		scopes, inlcalls = ctxt.DebugInfo(s, info, curfn)
355
	}
356
	var err error
357
	dwctxt := dwCtxt{ctxt}
358
	filesym := ctxt.fileSymbol(s)
359
	fnstate := &dwarf.FnState{
360
		Name:          s.Name,
361
		Importpath:    myimportpath,
362
		Info:          info,
363
		Filesym:       filesym,
364
		Loc:           loc,
365
		Ranges:        ranges,
366
		Absfn:         absfunc,
367
		StartPC:       s,
368
		Size:          s.Size,
369
		External:      !s.Static(),
370
		Scopes:        scopes,
371
		InlCalls:      inlcalls,
372
		UseBASEntries: ctxt.UseBASEntries,
373
	}
374
	if absfunc != nil {
375
		err = dwarf.PutAbstractFunc(dwctxt, fnstate)
376
		if err != nil {
377
			ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
378
		}
379
		err = dwarf.PutConcreteFunc(dwctxt, fnstate)
380
	} else {
381
		err = dwarf.PutDefaultFunc(dwctxt, fnstate)
382
	}
383
	if err != nil {
384
		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
385
	}
386
	// Fill in the debug lines symbol.
387
	ctxt.generateDebugLinesSymbol(s, lines)
388
}
389

390
// DwarfIntConst creates a link symbol for an integer constant with the
391
// given name, type and value.
392
func (ctxt *Link) DwarfIntConst(myimportpath, name, typename string, val int64) {
393
	if myimportpath == "" {
394
		return
395
	}
396
	s := ctxt.LookupInit(dwarf.ConstInfoPrefix+myimportpath, func(s *LSym) {
397
		s.Type = objabi.SDWARFCONST
398
		ctxt.Data = append(ctxt.Data, s)
399
	})
400
	dwarf.PutIntConst(dwCtxt{ctxt}, s, ctxt.Lookup(dwarf.InfoPrefix+typename), myimportpath+"."+name, val)
401
}
402

403
func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath string) {
404
	absfn := ctxt.DwFixups.AbsFuncDwarfSym(s)
405
	if absfn.Size != 0 {
406
		ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
407
	}
408
	if s.Func == nil {
409
		s.Func = new(FuncInfo)
410
	}
411
	scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
412
	dwctxt := dwCtxt{ctxt}
413
	filesym := ctxt.fileSymbol(s)
414
	fnstate := dwarf.FnState{
415
		Name:          s.Name,
416
		Importpath:    myimportpath,
417
		Info:          absfn,
418
		Filesym:       filesym,
419
		Absfn:         absfn,
420
		External:      !s.Static(),
421
		Scopes:        scopes,
422
		UseBASEntries: ctxt.UseBASEntries,
423
	}
424
	if err := dwarf.PutAbstractFunc(dwctxt, &fnstate); err != nil {
425
		ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
426
	}
427
}
428

429
// This table is designed to aid in the creation of references between
430
// DWARF subprogram DIEs.
431
//
432
// In most cases when one DWARF DIE has to refer to another DWARF DIE,
433
// the target of the reference has an LSym, which makes it easy to use
434
// the existing relocation mechanism. For DWARF inlined routine DIEs,
435
// however, the subprogram DIE has to refer to a child
436
// parameter/variable DIE of the abstract subprogram. This child DIE
437
// doesn't have an LSym, and also of interest is the fact that when
438
// DWARF generation is happening for inlined function F within caller
439
// G, it's possible that DWARF generation hasn't happened yet for F,
440
// so there is no way to know the offset of a child DIE within F's
441
// abstract function. Making matters more complex, each inlined
442
// instance of F may refer to a subset of the original F's variables
443
// (depending on what happens with optimization, some vars may be
444
// eliminated).
445
//
446
// The fixup table below helps overcome this hurdle. At the point
447
// where a parameter/variable reference is made (via a call to
448
// "ReferenceChildDIE"), a fixup record is generate that records
449
// the relocation that is targeting that child variable. At a later
450
// point when the abstract function DIE is emitted, there will be
451
// a call to "RegisterChildDIEOffsets", at which point the offsets
452
// needed to apply fixups are captured. Finally, once the parallel
453
// portion of the compilation is done, fixups can actually be applied
454
// during the "Finalize" method (this can't be done during the
455
// parallel portion of the compile due to the possibility of data
456
// races).
457
//
458
// This table is also used to record the "precursor" function node for
459
// each function that is the target of an inline -- child DIE references
460
// have to be made with respect to the original pre-optimization
461
// version of the function (to allow for the fact that each inlined
462
// body may be optimized differently).
463
type DwarfFixupTable struct {
464
	ctxt      *Link
465
	mu        sync.Mutex
466
	symtab    map[*LSym]int // maps abstract fn LSYM to index in svec
467
	svec      []symFixups
468
	precursor map[*LSym]fnState // maps fn Lsym to precursor Node, absfn sym
469
}
470

471
type symFixups struct {
472
	fixups   []relFixup
473
	doffsets []declOffset
474
	inlIndex int32
475
	defseen  bool
476
}
477

478
type declOffset struct {
479
	// Index of variable within DCL list of pre-optimization function
480
	dclIdx int32
481
	// Offset of var's child DIE with respect to containing subprogram DIE
482
	offset int32
483
}
484

485
type relFixup struct {
486
	refsym *LSym
487
	relidx int32
488
	dclidx int32
489
}
490

491
type fnState struct {
492
	// precursor function (really *gc.Node)
493
	precursor interface{}
494
	// abstract function symbol
495
	absfn *LSym
496
}
497

498
func NewDwarfFixupTable(ctxt *Link) *DwarfFixupTable {
499
	return &DwarfFixupTable{
500
		ctxt:      ctxt,
501
		symtab:    make(map[*LSym]int),
502
		precursor: make(map[*LSym]fnState),
503
	}
504
}
505

506
func (ft *DwarfFixupTable) GetPrecursorFunc(s *LSym) interface{} {
507
	if fnstate, found := ft.precursor[s]; found {
508
		return fnstate.precursor
509
	}
510
	return nil
511
}
512

513
func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
514
	if _, found := ft.precursor[s]; found {
515
		ft.ctxt.Diag("internal error: DwarfFixupTable.SetPrecursorFunc double call on %v", s)
516
	}
517

518
	// initialize abstract function symbol now. This is done here so
519
	// as to avoid data races later on during the parallel portion of
520
	// the back end.
521
	absfn := ft.ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name+dwarf.AbstractFuncSuffix)
522
	absfn.Set(AttrDuplicateOK, true)
523
	absfn.Type = objabi.SDWARFABSFCN
524
	ft.ctxt.Data = append(ft.ctxt.Data, absfn)
525

526
	// In the case of "late" inlining (inlines that happen during
527
	// wrapper generation as opposed to the main inlining phase) it's
528
	// possible that we didn't cache the abstract function sym for the
529
	// text symbol -- do so now if needed. See issue 38068.
530
	if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
531
		s.Func.dwarfAbsFnSym = absfn
532
	}
533

534
	ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
535
}
536

537
// Make a note of a child DIE reference: relocation 'ridx' within symbol 's'
538
// is targeting child 'c' of DIE with symbol 'tgt'.
539
func (ft *DwarfFixupTable) ReferenceChildDIE(s *LSym, ridx int, tgt *LSym, dclidx int, inlIndex int) {
540
	// Protect against concurrent access if multiple backend workers
541
	ft.mu.Lock()
542
	defer ft.mu.Unlock()
543

544
	// Create entry for symbol if not already present.
545
	idx, found := ft.symtab[tgt]
546
	if !found {
547
		ft.svec = append(ft.svec, symFixups{inlIndex: int32(inlIndex)})
548
		idx = len(ft.svec) - 1
549
		ft.symtab[tgt] = idx
550
	}
551

552
	// Do we have child DIE offsets available? If so, then apply them,
553
	// otherwise create a fixup record.
554
	sf := &ft.svec[idx]
555
	if len(sf.doffsets) > 0 {
556
		found := false
557
		for _, do := range sf.doffsets {
558
			if do.dclIdx == int32(dclidx) {
559
				off := do.offset
560
				s.R[ridx].Add += int64(off)
561
				found = true
562
				break
563
			}
564
		}
565
		if !found {
566
			ft.ctxt.Diag("internal error: DwarfFixupTable.ReferenceChildDIE unable to locate child DIE offset for dclIdx=%d src=%v tgt=%v", dclidx, s, tgt)
567
		}
568
	} else {
569
		sf.fixups = append(sf.fixups, relFixup{s, int32(ridx), int32(dclidx)})
570
	}
571
}
572

573
// Called once DWARF generation is complete for a given abstract function,
574
// whose children might have been referenced via a call above. Stores
575
// the offsets for any child DIEs (vars, params) so that they can be
576
// consumed later in on DwarfFixupTable.Finalize, which applies any
577
// outstanding fixups.
578
func (ft *DwarfFixupTable) RegisterChildDIEOffsets(s *LSym, vars []*dwarf.Var, coffsets []int32) {
579
	// Length of these two slices should agree
580
	if len(vars) != len(coffsets) {
581
		ft.ctxt.Diag("internal error: RegisterChildDIEOffsets vars/offsets length mismatch")
582
		return
583
	}
584

585
	// Generate the slice of declOffset's based in vars/coffsets
586
	doffsets := make([]declOffset, len(coffsets))
587
	for i := range coffsets {
588
		doffsets[i].dclIdx = vars[i].ChildIndex
589
		doffsets[i].offset = coffsets[i]
590
	}
591

592
	ft.mu.Lock()
593
	defer ft.mu.Unlock()
594

595
	// Store offsets for this symbol.
596
	idx, found := ft.symtab[s]
597
	if !found {
598
		sf := symFixups{inlIndex: -1, defseen: true, doffsets: doffsets}
599
		ft.svec = append(ft.svec, sf)
600
		ft.symtab[s] = len(ft.svec) - 1
601
	} else {
602
		sf := &ft.svec[idx]
603
		sf.doffsets = doffsets
604
		sf.defseen = true
605
	}
606
}
607

608
func (ft *DwarfFixupTable) processFixups(slot int, s *LSym) {
609
	sf := &ft.svec[slot]
610
	for _, f := range sf.fixups {
611
		dfound := false
612
		for _, doffset := range sf.doffsets {
613
			if doffset.dclIdx == f.dclidx {
614
				f.refsym.R[f.relidx].Add += int64(doffset.offset)
615
				dfound = true
616
				break
617
			}
618
		}
619
		if !dfound {
620
			ft.ctxt.Diag("internal error: DwarfFixupTable has orphaned fixup on %v targeting %v relidx=%d dclidx=%d", f.refsym, s, f.relidx, f.dclidx)
621
		}
622
	}
623
}
624

625
// return the LSym corresponding to the 'abstract subprogram' DWARF
626
// info entry for a function.
627
func (ft *DwarfFixupTable) AbsFuncDwarfSym(fnsym *LSym) *LSym {
628
	// Protect against concurrent access if multiple backend workers
629
	ft.mu.Lock()
630
	defer ft.mu.Unlock()
631

632
	if fnstate, found := ft.precursor[fnsym]; found {
633
		return fnstate.absfn
634
	}
635
	ft.ctxt.Diag("internal error: AbsFuncDwarfSym requested for %v, not seen during inlining", fnsym)
636
	return nil
637
}
638

639
// Called after all functions have been compiled; the main job of this
640
// function is to identify cases where there are outstanding fixups.
641
// This scenario crops up when we have references to variables of an
642
// inlined routine, but that routine is defined in some other package.
643
// This helper walks through and locate these fixups, then invokes a
644
// helper to create an abstract subprogram DIE for each one.
645
func (ft *DwarfFixupTable) Finalize(myimportpath string, trace bool) {
646
	if trace {
647
		ft.ctxt.Logf("DwarfFixupTable.Finalize invoked for %s\n", myimportpath)
648
	}
649

650
	// Collect up the keys from the precursor map, then sort the
651
	// resulting list (don't want to rely on map ordering here).
652
	fns := make([]*LSym, len(ft.precursor))
653
	idx := 0
654
	for fn := range ft.precursor {
655
		fns[idx] = fn
656
		idx++
657
	}
658
	sort.Sort(BySymName(fns))
659

660
	// Should not be called during parallel portion of compilation.
661
	if ft.ctxt.InParallel {
662
		ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize call during parallel backend")
663
	}
664

665
	// Generate any missing abstract functions.
666
	for _, s := range fns {
667
		absfn := ft.AbsFuncDwarfSym(s)
668
		slot, found := ft.symtab[absfn]
669
		if !found || !ft.svec[slot].defseen {
670
			ft.ctxt.GenAbstractFunc(s)
671
		}
672
	}
673

674
	// Apply fixups.
675
	for _, s := range fns {
676
		absfn := ft.AbsFuncDwarfSym(s)
677
		slot, found := ft.symtab[absfn]
678
		if !found {
679
			ft.ctxt.Diag("internal error: DwarfFixupTable.Finalize orphan abstract function for %v", s)
680
		} else {
681
			ft.processFixups(slot, s)
682
		}
683
	}
684
}
685

686
type BySymName []*LSym
687

688
func (s BySymName) Len() int           { return len(s) }
689
func (s BySymName) Less(i, j int) bool { return s[i].Name < s[j].Name }
690
func (s BySymName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
691

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.