mirror of
https://github.com/golang/go
synced 2024-11-11 20:30:22 -07:00
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 <thanm@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: David Chase <drchase@google.com> Trust: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
01df2febf5
commit
05082c90d5
@ -8,6 +8,7 @@ import (
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -170,12 +171,32 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
||||
addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
|
||||
}
|
||||
|
||||
// Issue 33188: if II foo is a child of II bar, then ensure that
|
||||
// bar's ranges include the ranges of foo (the loop above will produce
|
||||
// disjoint ranges).
|
||||
for k, c := range inlcalls.Calls {
|
||||
if c.Root {
|
||||
unifyCallRanges(inlcalls, k)
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging
|
||||
if Debug_gendwarfinl != 0 {
|
||||
dumpInlCalls(inlcalls)
|
||||
dumpInlVars(dwVars)
|
||||
}
|
||||
|
||||
// Perform a consistency check on inlined routine PC ranges
|
||||
// produced by unifyCallRanges above. In particular, complain in
|
||||
// cases where you have A -> B -> C (e.g. C is inlined into B, and
|
||||
// B is inlined into A) and the ranges for B are not enclosed
|
||||
// within the ranges for A, or C within B.
|
||||
for k, c := range inlcalls.Calls {
|
||||
if c.Root {
|
||||
checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
|
||||
}
|
||||
}
|
||||
|
||||
return inlcalls
|
||||
}
|
||||
|
||||
@ -355,3 +376,74 @@ func dumpInlVars(dwvars []*dwarf.Var) {
|
||||
Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
|
||||
}
|
||||
}
|
||||
|
||||
func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
|
||||
for _, r := range par {
|
||||
if rng.Start >= r.Start && rng.End <= r.End {
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
|
||||
for _, r := range par {
|
||||
msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
|
||||
}
|
||||
msg += " }"
|
||||
return false, msg
|
||||
}
|
||||
|
||||
func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
|
||||
for _, r := range child {
|
||||
c, m := rangesContains(parent, r)
|
||||
if !c {
|
||||
return false, m
|
||||
}
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// checkInlCall verifies that the PC ranges for inline info 'idx' are
|
||||
// enclosed/contained within the ranges of its parent inline (or if
|
||||
// this is a root/toplevel inline, checks that the ranges fall within
|
||||
// the extent of the top level function). A panic is issued if a
|
||||
// malformed range is found.
|
||||
func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
|
||||
|
||||
// Callee
|
||||
ic := inlCalls.Calls[idx]
|
||||
callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
|
||||
calleeRanges := ic.Ranges
|
||||
|
||||
// Caller
|
||||
caller := funcName
|
||||
parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
|
||||
if parentIdx != -1 {
|
||||
pic := inlCalls.Calls[parentIdx]
|
||||
caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
|
||||
parentRanges = pic.Ranges
|
||||
}
|
||||
|
||||
// Callee ranges contained in caller ranges?
|
||||
c, m := rangesContainsAll(parentRanges, calleeRanges)
|
||||
if !c {
|
||||
Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
|
||||
}
|
||||
|
||||
// Now visit kids
|
||||
for _, k := range ic.Children {
|
||||
checkInlCall(funcName, inlCalls, funcSize, k, idx)
|
||||
}
|
||||
}
|
||||
|
||||
// unifyCallRanges ensures that the ranges for a given inline
|
||||
// transitively include all of the ranges for its child inlines.
|
||||
func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
|
||||
ic := &inlcalls.Calls[idx]
|
||||
for _, childIdx := range ic.Children {
|
||||
// First make sure child ranges are unified.
|
||||
unifyCallRanges(inlcalls, childIdx)
|
||||
|
||||
// Then merge child ranges into ranges for this inline.
|
||||
cic := inlcalls.Calls[childIdx]
|
||||
ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
|
||||
}
|
||||
}
|
||||
|
@ -101,26 +101,26 @@ func EnableLogging(doit bool) {
|
||||
logDwarf = doit
|
||||
}
|
||||
|
||||
// UnifyRanges merges the list of ranges of c into the list of ranges of s
|
||||
func (s *Scope) UnifyRanges(c *Scope) {
|
||||
out := make([]Range, 0, len(s.Ranges)+len(c.Ranges))
|
||||
|
||||
// MergeRanges creates a new range list by merging the ranges from
|
||||
// its two arguments, then returns the new list.
|
||||
func MergeRanges(in1, in2 []Range) []Range {
|
||||
out := make([]Range, 0, len(in1)+len(in2))
|
||||
i, j := 0, 0
|
||||
for {
|
||||
var cur Range
|
||||
if i < len(s.Ranges) && j < len(c.Ranges) {
|
||||
if s.Ranges[i].Start < c.Ranges[j].Start {
|
||||
cur = s.Ranges[i]
|
||||
if i < len(in2) && j < len(in1) {
|
||||
if in2[i].Start < in1[j].Start {
|
||||
cur = in2[i]
|
||||
i++
|
||||
} else {
|
||||
cur = c.Ranges[j]
|
||||
cur = in1[j]
|
||||
j++
|
||||
}
|
||||
} else if i < len(s.Ranges) {
|
||||
cur = s.Ranges[i]
|
||||
} else if i < len(in2) {
|
||||
cur = in2[i]
|
||||
i++
|
||||
} else if j < len(c.Ranges) {
|
||||
cur = c.Ranges[j]
|
||||
} else if j < len(in1) {
|
||||
cur = in1[j]
|
||||
j++
|
||||
} else {
|
||||
break
|
||||
@ -133,7 +133,12 @@ func (s *Scope) UnifyRanges(c *Scope) {
|
||||
}
|
||||
}
|
||||
|
||||
s.Ranges = out
|
||||
return out
|
||||
}
|
||||
|
||||
// UnifyRanges merges the ranges from 'c' into the list of ranges for 's'.
|
||||
func (s *Scope) UnifyRanges(c *Scope) {
|
||||
s.Ranges = MergeRanges(s.Ranges, c.Ranges)
|
||||
}
|
||||
|
||||
// AppendRange adds r to s, if r is non-empty.
|
||||
|
Loading…
Reference in New Issue
Block a user