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 vp := varPos{
128 DeclName: v.Name,
129 DeclFile: v.DeclFile,
130 DeclLine: v.DeclLine,
131 DeclCol: v.DeclCol,
132 }
133 synthesized := strings.HasPrefix(v.Name, "~") || v.Name == "_"
134 if idx, found := m[vp]; found {
135 v.ChildIndex = int32(idx)
136 v.IsInAbstract = !synthesized
137 } else {
138
139
140
141
142
143
144 v.ChildIndex = int32(synthCount)
145 synthCount++
146 }
147 }
148 }
149
150
151
152 start := int64(-1)
153 curii := -1
154 var prevp *obj.Prog
155 for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
156 if prevp != nil && p.Pos == prevp.Pos {
157 continue
158 }
159 ii := posInlIndex(p.Pos)
160 if ii == curii {
161 continue
162 }
163
164 if start != -1 {
165 addRange(inlcalls.Calls, start, p.Pc, curii, imap)
166 }
167
168 start = p.Pc
169 curii = ii
170 }
171 if start != -1 {
172 addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
173 }
174
175
176
177
178 for k, c := range inlcalls.Calls {
179 if c.Root {
180 unifyCallRanges(inlcalls, k)
181 }
182 }
183
184
185 if base.Debug.DwarfInl != 0 {
186 dumpInlCalls(inlcalls)
187 dumpInlVars(dwVars)
188 }
189
190
191
192
193
194
195 for k, c := range inlcalls.Calls {
196 if c.Root {
197 checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
198 }
199 }
200
201 return inlcalls
202 }
203
204
205
206
207
208 func AbstractFunc(fn *obj.LSym) {
209 ifn := base.Ctxt.DwFixups.GetPrecursorFunc(fn)
210 if ifn == nil {
211 base.Ctxt.Diag("failed to locate precursor fn for %v", fn)
212 return
213 }
214 _ = ifn.(*ir.Func)
215 if base.Debug.DwarfInl != 0 {
216 base.Ctxt.Logf("DwarfAbstractFunc(%v)\n", fn.Name)
217 }
218 base.Ctxt.DwarfAbstractFunc(ifn, fn)
219 }
220
221
222
223
224
225
226
227 func makePreinlineDclMap(fnsym *obj.LSym) map[varPos]int {
228 dcl := preInliningDcls(fnsym)
229 m := make(map[varPos]int)
230 for i, n := range dcl {
231 pos := base.Ctxt.InnermostPos(n.Pos())
232 vp := varPos{
233 DeclName: n.Sym().Name,
234 DeclFile: pos.RelFilename(),
235 DeclLine: pos.RelLine(),
236 DeclCol: pos.RelCol(),
237 }
238 if _, found := m[vp]; found {
239
240 continue
241 }
242 m[vp] = i
243 }
244 return m
245 }
246
247 func insertInlCall(dwcalls *dwarf.InlCalls, inlIdx int, imap map[int]int) int {
248 callIdx, found := imap[inlIdx]
249 if found {
250 return callIdx
251 }
252
253
254
255
256 parCallIdx := -1
257 parInlIdx := base.Ctxt.InlTree.Parent(inlIdx)
258 if parInlIdx >= 0 {
259 parCallIdx = insertInlCall(dwcalls, parInlIdx, imap)
260 }
261
262
263 inlinedFn := base.Ctxt.InlTree.InlinedFunction(inlIdx)
264 callXPos := base.Ctxt.InlTree.CallPos(inlIdx)
265 callPos := base.Ctxt.InnermostPos(callXPos)
266 absFnSym := base.Ctxt.DwFixups.AbsFuncDwarfSym(inlinedFn)
267 ic := dwarf.InlCall{
268 InlIndex: inlIdx,
269 CallPos: callPos,
270 AbsFunSym: absFnSym,
271 Root: parCallIdx == -1,
272 }
273 dwcalls.Calls = append(dwcalls.Calls, ic)
274 callIdx = len(dwcalls.Calls) - 1
275 imap[inlIdx] = callIdx
276
277 if parCallIdx != -1 {
278
279 dwcalls.Calls[parCallIdx].Children = append(dwcalls.Calls[parCallIdx].Children, callIdx)
280 }
281
282 return callIdx
283 }
284
285
286
287
288
289
290
291
292 func posInlIndex(xpos src.XPos) int {
293 pos := base.Ctxt.PosTable.Pos(xpos)
294 if b := pos.Base(); b != nil {
295 ii := b.InliningIndex()
296 if ii >= 0 {
297 return ii
298 }
299 }
300 return -1
301 }
302
303 func addRange(calls []dwarf.InlCall, start, end int64, ii int, imap map[int]int) {
304 if start == -1 {
305 panic("bad range start")
306 }
307 if end == -1 {
308 panic("bad range end")
309 }
310 if ii == -1 {
311 return
312 }
313 if start == end {
314 return
315 }
316
317 callIdx, found := imap[ii]
318 if !found {
319 base.Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, start)
320 }
321 call := &calls[callIdx]
322 call.Ranges = append(call.Ranges, dwarf.Range{Start: start, End: end})
323 }
324
325 func dumpInlCall(inlcalls dwarf.InlCalls, idx, ilevel int) {
326 for i := 0; i < ilevel; i++ {
327 base.Ctxt.Logf(" ")
328 }
329 ic := inlcalls.Calls[idx]
330 callee := base.Ctxt.InlTree.InlinedFunction(ic.InlIndex)
331 base.Ctxt.Logf(" %d: II:%d (%s) V: (", idx, ic.InlIndex, callee.Name)
332 for _, f := range ic.InlVars {
333 base.Ctxt.Logf(" %v", f.Name)
334 }
335 base.Ctxt.Logf(" ) C: (")
336 for _, k := range ic.Children {
337 base.Ctxt.Logf(" %v", k)
338 }
339 base.Ctxt.Logf(" ) R:")
340 for _, r := range ic.Ranges {
341 base.Ctxt.Logf(" [%d,%d)", r.Start, r.End)
342 }
343 base.Ctxt.Logf("\n")
344 for _, k := range ic.Children {
345 dumpInlCall(inlcalls, k, ilevel+1)
346 }
347
348 }
349
350 func dumpInlCalls(inlcalls dwarf.InlCalls) {
351 for k, c := range inlcalls.Calls {
352 if c.Root {
353 dumpInlCall(inlcalls, k, 0)
354 }
355 }
356 }
357
358 func dumpInlVars(dwvars []*dwarf.Var) {
359 for i, dwv := range dwvars {
360 typ := "local"
361 if dwv.Tag == dwarf.DW_TAG_formal_parameter {
362 typ = "param"
363 }
364 ia := 0
365 if dwv.IsInAbstract {
366 ia = 1
367 }
368 base.Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
369 }
370 }
371
372 func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
373 for _, r := range par {
374 if rng.Start >= r.Start && rng.End <= r.End {
375 return true, ""
376 }
377 }
378 msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
379 for _, r := range par {
380 msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
381 }
382 msg += " }"
383 return false, msg
384 }
385
386 func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
387 for _, r := range child {
388 c, m := rangesContains(parent, r)
389 if !c {
390 return false, m
391 }
392 }
393 return true, ""
394 }
395
396
397
398
399
400
401 func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
402
403
404 ic := inlCalls.Calls[idx]
405 callee := base.Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
406 calleeRanges := ic.Ranges
407
408
409 caller := funcName
410 parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
411 if parentIdx != -1 {
412 pic := inlCalls.Calls[parentIdx]
413 caller = base.Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
414 parentRanges = pic.Ranges
415 }
416
417
418 c, m := rangesContainsAll(parentRanges, calleeRanges)
419 if !c {
420 base.Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
421 }
422
423
424 for _, k := range ic.Children {
425 checkInlCall(funcName, inlCalls, funcSize, k, idx)
426 }
427 }
428
429
430
431 func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
432 ic := &inlcalls.Calls[idx]
433 for _, childIdx := range ic.Children {
434
435 unifyCallRanges(inlcalls, childIdx)
436
437
438 cic := inlcalls.Calls[childIdx]
439 ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
440 }
441 }
442
View as plain text