1
2
3
4
5 package dwarfgen
6
7 import (
8 "fmt"
9 "strings"
10
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/internal/dwarf"
14 "cmd/internal/obj"
15 "cmd/internal/src"
16 )
17
18
19 type varPos struct {
20 DeclName string
21 DeclFile string
22 DeclLine uint
23 DeclCol uint
24 }
25
26
27
28
29 func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
30 var inlcalls dwarf.InlCalls
31
32 if base.Debug.DwarfInl != 0 {
33 base.Ctxt.Logf("assembling DWARF inlined routine info for %v\n", fnsym.Name)
34 }
35
36
37 imap := make(map[int]int)
38
39
40 var prevpos src.XPos
41 for p := fnsym.Func().Text; p != nil; p = p.Link {
42 if p.Pos == prevpos {
43 continue
44 }
45 ii := posInlIndex(p.Pos)
46 if ii >= 0 {
47 insertInlCall(&inlcalls, ii, imap)
48 }
49 prevpos = p.Pos
50 }
51
52
53
54 vmap := make(map[int32][]*dwarf.Var)
55
56
57
58
59 for _, dwv := range dwVars {
60
61 vmap[dwv.InlIndex] = append(vmap[dwv.InlIndex], dwv)
62
63
64 if dwv.InlIndex == 0 {
65 continue
66 }
67
68
69
70 ii := int(dwv.InlIndex) - 1
71 idx, ok := imap[ii]
72 if !ok {
73
74
75
76 idx = insertInlCall(&inlcalls, ii, imap)
77 }
78 inlcalls.Calls[idx].InlVars =
79 append(inlcalls.Calls[idx].InlVars, dwv)
80 }
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 for ii, sl := range vmap {
102 var m map[varPos]int
103 if ii == 0 {
104 if !fnsym.WasInlined() {
105 for j, v := range sl {
106 v.ChildIndex = int32(j)
107 }
108 continue
109 }
110 m = makePreinlineDclMap(fnsym)
111 } else {
112 ifnlsym := base.Ctxt.InlTree.InlinedFunction(int(ii - 1))
113 m = makePreinlineDclMap(ifnlsym)
114 }
115
116
117
118
119
120
121
122
123
124
125 synthCount := len(m)
126 for _, v := range sl {
127 canonName := unversion(v.Name)
128 vp := varPos{
129 DeclName: canonName,
130 DeclFile: v.DeclFile,
131 DeclLine: v.DeclLine,
132 DeclCol: v.DeclCol,
133 }
134 synthesized := strings.HasPrefix(v.Name, "~r") || canonName == "_" || strings.HasPrefix(v.Name, "~b")
135 if idx, found := m[vp]; found {
136 v.ChildIndex = int32(idx)
137 v.IsInAbstract = !synthesized
138 v.Name = canonName
139 } else {
140
141
142
143
144
145
146 v.ChildIndex = int32(synthCount)
147 synthCount++
148 }
149 }
150 }
151
152
153
154 start := int64(-1)
155 curii := -1
156 var prevp *obj.Prog
157 for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
158 if prevp != nil && p.Pos == prevp.Pos {
159 continue
160 }
161 ii := posInlIndex(p.Pos)
162 if ii == curii {
163 continue
164 }
165
166 if start != -1 {
167 addRange(inlcalls.Calls, start, p.Pc, curii, imap)
168 }
169
170 start = p.Pc
171 curii = ii
172 }
173 if start != -1 {
174 addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
175 }
176
177
178
179
180 for k, c := range inlcalls.Calls {
181 if c.Root {
182 unifyCallRanges(inlcalls, k)
183 }
184 }
185
186
187 if base.Debug.DwarfInl != 0 {
188 dumpInlCalls(inlcalls)
189 dumpInlVars(dwVars)
190 }
191
192
193
194
195
196
197 for k, c := range inlcalls.Calls {
198 if c.Root {
199 checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
200 }
201 }
202
203 return inlcalls
204 }
205
206
207
208
209
210 func AbstractFunc(fn *obj.LSym) {
211 ifn := base.Ctxt.DwFixups.GetPrecursorFunc(fn)
212 if ifn == nil {
213 base.Ctxt.Diag("failed to locate precursor fn for %v", fn)
214 return
215 }
216 _ = ifn.(*ir.Func)
217 if base.Debug.DwarfInl != 0 {
218 base.Ctxt.Logf("DwarfAbstractFunc(%v)\n", fn.Name)
219 }
220 base.Ctxt.DwarfAbstractFunc(ifn, fn, base.Ctxt.Pkgpath)
221 }
222
223
224
225 func unversion(name string) string {
226 if i := strings.Index(name, "·"); i > 0 {
227 name = name[:i]
228 }
229 return name
230 }
231
232
233
234
235
236
237
238 func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int {
239 dcl := preInliningDcls(fnsym)
240 m := make(map[varPos]int)
241 for i, n := range dcl {
242 pos := base.Ctxt.InnermostPos(n.Pos())
243 vp := varPos{
244 DeclName: unversion(n.Sym().Name),
245 DeclFile: pos.RelFilename(),
246 DeclLine: pos.RelLine(),
247 DeclCol: pos.RelCol(),
248 }
249 if _, found := m[vp]; found {
250
251 continue
252 }
253 m[vp] = i
254 }
255 return m
256 }
257
258 func insertInlCall(dwcalls *dwarf.InlCalls, inlIdx int, imap map[int]int) int {
259 callIdx, found := imap[inlIdx]
260 if found {
261 return callIdx
262 }
263
264
265
266
267 parCallIdx := -1
268 parInlIdx := base.Ctxt.InlTree.Parent(inlIdx)
269 if parInlIdx >= 0 {
270 parCallIdx = insertInlCall(dwcalls, parInlIdx, imap)
271 }
272
273
274 inlinedFn := base.Ctxt.InlTree.InlinedFunction(inlIdx)
275 callXPos := base.Ctxt.InlTree.CallPos(inlIdx)
276 absFnSym := base.Ctxt.DwFixups.AbsFuncDwarfSym(inlinedFn)
277 pb := base.Ctxt.PosTable.Pos(callXPos).Base()
278 callFileSym := base.Ctxt.Lookup(pb.SymFilename())
279 ic := dwarf.InlCall{
280 InlIndex: inlIdx,
281 CallFile: callFileSym,
282 CallLine: uint32(callXPos.Line()),
283 AbsFunSym: absFnSym,
284 Root: parCallIdx == -1,
285 }
286 dwcalls.Calls = append(dwcalls.Calls, ic)
287 callIdx = len(dwcalls.Calls) - 1
288 imap[inlIdx] = callIdx
289
290 if parCallIdx != -1 {
291
292 dwcalls.Calls[parCallIdx].Children = append(dwcalls.Calls[parCallIdx].Children, callIdx)
293 }
294
295 return callIdx
296 }
297
298
299
300
301
302
303
304
305 func posInlIndex(xpos src.XPos) int {
306 pos := base.Ctxt.PosTable.Pos(xpos)
307 if b := pos.Base(); b != nil {
308 ii := b.InliningIndex()
309 if ii >= 0 {
310 return ii
311 }
312 }
313 return -1
314 }
315
316 func addRange(calls []dwarf.InlCall, start, end int64, ii int, imap map[int]int) {
317 if start == -1 {
318 panic("bad range start")
319 }
320 if end == -1 {
321 panic("bad range end")
322 }
323 if ii == -1 {
324 return
325 }
326 if start == end {
327 return
328 }
329
330 callIdx, found := imap[ii]
331 if !found {
332 base.Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, start)
333 }
334 call := &calls[callIdx]
335 call.Ranges = append(call.Ranges, dwarf.Range{Start: start, End: end})
336 }
337
338 func dumpInlCall(inlcalls dwarf.InlCalls, idx, ilevel int) {
339 for i := 0; i < ilevel; i++ {
340 base.Ctxt.Logf(" ")
341 }
342 ic := inlcalls.Calls[idx]
343 callee := base.Ctxt.InlTree.InlinedFunction(ic.InlIndex)
344 base.Ctxt.Logf(" %d: II:%d (%s) V: (", idx, ic.InlIndex, callee.Name)
345 for _, f := range ic.InlVars {
346 base.Ctxt.Logf(" %v", f.Name)
347 }
348 base.Ctxt.Logf(" ) C: (")
349 for _, k := range ic.Children {
350 base.Ctxt.Logf(" %v", k)
351 }
352 base.Ctxt.Logf(" ) R:")
353 for _, r := range ic.Ranges {
354 base.Ctxt.Logf(" [%d,%d)", r.Start, r.End)
355 }
356 base.Ctxt.Logf("\n")
357 for _, k := range ic.Children {
358 dumpInlCall(inlcalls, k, ilevel+1)
359 }
360
361 }
362
363 func dumpInlCalls(inlcalls dwarf.InlCalls) {
364 for k, c := range inlcalls.Calls {
365 if c.Root {
366 dumpInlCall(inlcalls, k, 0)
367 }
368 }
369 }
370
371 func dumpInlVars(dwvars []*dwarf.Var) {
372 for i, dwv := range dwvars {
373 typ := "local"
374 if dwv.Abbrev == dwarf.DW_ABRV_PARAM_LOCLIST || dwv.Abbrev == dwarf.DW_ABRV_PARAM {
375 typ = "param"
376 }
377 ia := 0
378 if dwv.IsInAbstract {
379 ia = 1
380 }
381 base.Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
382 }
383 }
384
385 func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
386 for _, r := range par {
387 if rng.Start >= r.Start && rng.End <= r.End {
388 return true, ""
389 }
390 }
391 msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
392 for _, r := range par {
393 msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
394 }
395 msg += " }"
396 return false, msg
397 }
398
399 func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
400 for _, r := range child {
401 c, m := rangesContains(parent, r)
402 if !c {
403 return false, m
404 }
405 }
406 return true, ""
407 }
408
409
410
411
412
413
414 func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
415
416
417 ic := inlCalls.Calls[idx]
418 callee := base.Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
419 calleeRanges := ic.Ranges
420
421
422 caller := funcName
423 parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
424 if parentIdx != -1 {
425 pic := inlCalls.Calls[parentIdx]
426 caller = base.Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
427 parentRanges = pic.Ranges
428 }
429
430
431 c, m := rangesContainsAll(parentRanges, calleeRanges)
432 if !c {
433 base.Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
434 }
435
436
437 for _, k := range ic.Children {
438 checkInlCall(funcName, inlCalls, funcSize, k, idx)
439 }
440 }
441
442
443
444 func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
445 ic := &inlcalls.Calls[idx]
446 for _, childIdx := range ic.Children {
447
448 unifyCallRanges(inlcalls, childIdx)
449
450
451 cic := inlcalls.Calls[childIdx]
452 ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
453 }
454 }
455
View as plain text