Skip to content

Commit 05082c9

Browse files
committed
cmd/compile: clean up buggy DWARF inlined info PC ranges
Repair the code that generates PC ranges for DWARF inlined routine instances to insure that if II Y is a child of II X within the inline tree, X's ranges include the ranges from Y. This is similar to what we're already doing for DWARF scopes. Updates #33188. Change-Id: I9bb552777fcd1ae93dc01872707667ad092b1dd9 Reviewed-on: https://go-review.googlesource.com/c/go/+/248724 Run-TryBot: Than McIntosh <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> Reviewed-by: David Chase <[email protected]> Trust: Than McIntosh <[email protected]>
1 parent 01df2fe commit 05082c9

File tree

2 files changed

+110
-13
lines changed

2 files changed

+110
-13
lines changed

src/cmd/compile/internal/gc/dwinl.go

+92
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"cmd/internal/dwarf"
99
"cmd/internal/obj"
1010
"cmd/internal/src"
11+
"fmt"
1112
"strings"
1213
)
1314

@@ -170,12 +171,32 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
170171
addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
171172
}
172173

174+
// Issue 33188: if II foo is a child of II bar, then ensure that
175+
// bar's ranges include the ranges of foo (the loop above will produce
176+
// disjoint ranges).
177+
for k, c := range inlcalls.Calls {
178+
if c.Root {
179+
unifyCallRanges(inlcalls, k)
180+
}
181+
}
182+
173183
// Debugging
174184
if Debug_gendwarfinl != 0 {
175185
dumpInlCalls(inlcalls)
176186
dumpInlVars(dwVars)
177187
}
178188

189+
// Perform a consistency check on inlined routine PC ranges
190+
// produced by unifyCallRanges above. In particular, complain in
191+
// cases where you have A -> B -> C (e.g. C is inlined into B, and
192+
// B is inlined into A) and the ranges for B are not enclosed
193+
// within the ranges for A, or C within B.
194+
for k, c := range inlcalls.Calls {
195+
if c.Root {
196+
checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
197+
}
198+
}
199+
179200
return inlcalls
180201
}
181202

@@ -355,3 +376,74 @@ func dumpInlVars(dwvars []*dwarf.Var) {
355376
Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
356377
}
357378
}
379+
380+
func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
381+
for _, r := range par {
382+
if rng.Start >= r.Start && rng.End <= r.End {
383+
return true, ""
384+
}
385+
}
386+
msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
387+
for _, r := range par {
388+
msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
389+
}
390+
msg += " }"
391+
return false, msg
392+
}
393+
394+
func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
395+
for _, r := range child {
396+
c, m := rangesContains(parent, r)
397+
if !c {
398+
return false, m
399+
}
400+
}
401+
return true, ""
402+
}
403+
404+
// checkInlCall verifies that the PC ranges for inline info 'idx' are
405+
// enclosed/contained within the ranges of its parent inline (or if
406+
// this is a root/toplevel inline, checks that the ranges fall within
407+
// the extent of the top level function). A panic is issued if a
408+
// malformed range is found.
409+
func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
410+
411+
// Callee
412+
ic := inlCalls.Calls[idx]
413+
callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
414+
calleeRanges := ic.Ranges
415+
416+
// Caller
417+
caller := funcName
418+
parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
419+
if parentIdx != -1 {
420+
pic := inlCalls.Calls[parentIdx]
421+
caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
422+
parentRanges = pic.Ranges
423+
}
424+
425+
// Callee ranges contained in caller ranges?
426+
c, m := rangesContainsAll(parentRanges, calleeRanges)
427+
if !c {
428+
Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
429+
}
430+
431+
// Now visit kids
432+
for _, k := range ic.Children {
433+
checkInlCall(funcName, inlCalls, funcSize, k, idx)
434+
}
435+
}
436+
437+
// unifyCallRanges ensures that the ranges for a given inline
438+
// transitively include all of the ranges for its child inlines.
439+
func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
440+
ic := &inlcalls.Calls[idx]
441+
for _, childIdx := range ic.Children {
442+
// First make sure child ranges are unified.
443+
unifyCallRanges(inlcalls, childIdx)
444+
445+
// Then merge child ranges into ranges for this inline.
446+
cic := inlcalls.Calls[childIdx]
447+
ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
448+
}
449+
}

src/cmd/internal/dwarf/dwarf.go

+18-13
Original file line numberDiff line numberDiff line change
@@ -101,26 +101,26 @@ func EnableLogging(doit bool) {
101101
logDwarf = doit
102102
}
103103

104-
// UnifyRanges merges the list of ranges of c into the list of ranges of s
105-
func (s *Scope) UnifyRanges(c *Scope) {
106-
out := make([]Range, 0, len(s.Ranges)+len(c.Ranges))
107-
104+
// MergeRanges creates a new range list by merging the ranges from
105+
// its two arguments, then returns the new list.
106+
func MergeRanges(in1, in2 []Range) []Range {
107+
out := make([]Range, 0, len(in1)+len(in2))
108108
i, j := 0, 0
109109
for {
110110
var cur Range
111-
if i < len(s.Ranges) && j < len(c.Ranges) {
112-
if s.Ranges[i].Start < c.Ranges[j].Start {
113-
cur = s.Ranges[i]
111+
if i < len(in2) && j < len(in1) {
112+
if in2[i].Start < in1[j].Start {
113+
cur = in2[i]
114114
i++
115115
} else {
116-
cur = c.Ranges[j]
116+
cur = in1[j]
117117
j++
118118
}
119-
} else if i < len(s.Ranges) {
120-
cur = s.Ranges[i]
119+
} else if i < len(in2) {
120+
cur = in2[i]
121121
i++
122-
} else if j < len(c.Ranges) {
123-
cur = c.Ranges[j]
122+
} else if j < len(in1) {
123+
cur = in1[j]
124124
j++
125125
} else {
126126
break
@@ -133,7 +133,12 @@ func (s *Scope) UnifyRanges(c *Scope) {
133133
}
134134
}
135135

136-
s.Ranges = out
136+
return out
137+
}
138+
139+
// UnifyRanges merges the ranges from 'c' into the list of ranges for 's'.
140+
func (s *Scope) UnifyRanges(c *Scope) {
141+
s.Ranges = MergeRanges(s.Ranges, c.Ranges)
137142
}
138143

139144
// AppendRange adds r to s, if r is non-empty.

0 commit comments

Comments
 (0)