mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/dwarfgen: fix DWARF param DIE ordering
The DWARF standard requires that the DIEs in a subprogram corresponding to input and output parameters appear in declaration order; this patch adds some new code in dwarfgen to enforce this ordering (relying on the existing fn.Dcl ordering is not sufficient). Prior to the register ABI, it was easy to keep vars/decls sorted during DWARF generation since you could always rely on frame offset; with the ABI sorting by frame offset no longer gives you the original declaration order in all cases. Fixes #46055. Change-Id: I0e070cb781d6453caba896e5d3bee7cd5388050d Reviewed-on: https://go-review.googlesource.com/c/go/+/318829 Trust: Than McIntosh <thanm@google.com> Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
a63cded5e4
commit
fd4631e24f
2 changed files with 72 additions and 13 deletions
|
|
@ -222,9 +222,64 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
||||||
fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
|
fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort decls and vars.
|
||||||
|
sortDeclsAndVars(fn, decls, vars)
|
||||||
|
|
||||||
return decls, vars
|
return decls, vars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sortDeclsAndVars sorts the decl and dwarf var lists according to
|
||||||
|
// parameter declaration order, so as to insure that when a subprogram
|
||||||
|
// DIE is emitted, its parameter children appear in declaration order.
|
||||||
|
// Prior to the advent of the register ABI, sorting by frame offset
|
||||||
|
// would achieve this; with the register we now need to go back to the
|
||||||
|
// original function signature.
|
||||||
|
func sortDeclsAndVars(fn *ir.Func, decls []*ir.Name, vars []*dwarf.Var) {
|
||||||
|
paramOrder := make(map[*ir.Name]int)
|
||||||
|
idx := 1
|
||||||
|
for _, selfn := range types.RecvsParamsResults {
|
||||||
|
fsl := selfn(fn.Type()).FieldSlice()
|
||||||
|
for _, f := range fsl {
|
||||||
|
if n, ok := f.Nname.(*ir.Name); ok {
|
||||||
|
paramOrder[n] = idx
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Stable(varsAndDecls{decls, vars, paramOrder})
|
||||||
|
}
|
||||||
|
|
||||||
|
type varsAndDecls struct {
|
||||||
|
decls []*ir.Name
|
||||||
|
vars []*dwarf.Var
|
||||||
|
paramOrder map[*ir.Name]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v varsAndDecls) Len() int {
|
||||||
|
return len(v.decls)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v varsAndDecls) Less(i, j int) bool {
|
||||||
|
nameLT := func(ni, nj *ir.Name) bool {
|
||||||
|
oi, foundi := v.paramOrder[ni]
|
||||||
|
oj, foundj := v.paramOrder[nj]
|
||||||
|
if foundi {
|
||||||
|
if foundj {
|
||||||
|
return oi < oj
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return nameLT(v.decls[i], v.decls[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v varsAndDecls) Swap(i, j int) {
|
||||||
|
v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
|
||||||
|
v.decls[i], v.decls[j] = v.decls[j], v.decls[i]
|
||||||
|
}
|
||||||
|
|
||||||
// Given a function that was inlined at some point during the
|
// Given a function that was inlined at some point during the
|
||||||
// compilation, return a sorted list of nodes corresponding to the
|
// compilation, return a sorted list of nodes corresponding to the
|
||||||
// autos/locals in that function prior to inlining. If this is a
|
// autos/locals in that function prior to inlining. If this is a
|
||||||
|
|
|
||||||
|
|
@ -1660,16 +1660,16 @@ func TestOutputParamAbbrevAndAttr(t *testing.T) {
|
||||||
package main
|
package main
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func ABC(p1, p2, p3 int, f1, f2, f3 float32, b1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte) {
|
func ABC(c1, c2, c3 int, d1, d2, d3, d4 string, f1, f2, f3 float32, g1 [1024]int) (r1 int, r2 int, r3 [1024]int, r4 byte, r5 string, r6 float32) {
|
||||||
b1[0] = 6
|
g1[0] = 6
|
||||||
r1, r2, r3, r4 = p3, p2, b1, 'a'
|
r1, r2, r3, r4, r5, r6 = c3, c2+c1, g1, 'a', d1+d2+d3+d4, f1+f2+f3
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
a := [1024]int{}
|
a := [1024]int{}
|
||||||
v1, v2, v3, v4 := ABC(1, 2, 3, 1.0, 2.0, 1.0, a)
|
v1, v2, v3, v4, v5, v6 := ABC(1, 2, 3, "a", "b", "c", "d", 1.0, 2.0, 1.0, a)
|
||||||
println(v1, v2, v3[0], v4)
|
println(v1, v2, v3[0], v4, v5, v6)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
|
@ -1708,18 +1708,20 @@ func main() {
|
||||||
// OK to have it missing for input parameters, but for the moment
|
// OK to have it missing for input parameters, but for the moment
|
||||||
// we verify that the attr is present but set to false.
|
// we verify that the attr is present but set to false.
|
||||||
|
|
||||||
// Values in this map:
|
// Values in this map are of the form <order>:<varparam>
|
||||||
|
// where order is the order within the child DIE list of the param,
|
||||||
|
// and <varparam> is an integer:
|
||||||
//
|
//
|
||||||
// 0: <no param of this name>
|
|
||||||
// -1: varparm attr not found
|
// -1: varparm attr not found
|
||||||
// 1: varparm found with value false
|
// 1: varparm found with value false
|
||||||
// 2: varparm found with value true
|
// 2: varparm found with value true
|
||||||
//
|
//
|
||||||
foundParams := make(map[string]int)
|
foundParams := make(map[string]string)
|
||||||
|
|
||||||
// Walk ABCs's children looking for params.
|
// Walk ABCs's children looking for params.
|
||||||
abcIdx := ex.idxFromOffset(abcdie.Offset)
|
abcIdx := ex.idxFromOffset(abcdie.Offset)
|
||||||
childDies := ex.Children(abcIdx)
|
childDies := ex.Children(abcIdx)
|
||||||
|
idx := 0
|
||||||
for _, child := range childDies {
|
for _, child := range childDies {
|
||||||
if child.Tag == dwarf.TagFormalParameter {
|
if child.Tag == dwarf.TagFormalParameter {
|
||||||
st := -1
|
st := -1
|
||||||
|
|
@ -1731,7 +1733,8 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if name, ok := child.Val(dwarf.AttrName).(string); ok {
|
if name, ok := child.Val(dwarf.AttrName).(string); ok {
|
||||||
foundParams[name] = st
|
foundParams[name] = fmt.Sprintf("%d:%d", idx, st)
|
||||||
|
idx++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1739,13 +1742,14 @@ func main() {
|
||||||
// Digest the result.
|
// Digest the result.
|
||||||
found := make([]string, 0, len(foundParams))
|
found := make([]string, 0, len(foundParams))
|
||||||
for k, v := range foundParams {
|
for k, v := range foundParams {
|
||||||
found = append(found, fmt.Sprintf("%s:%d", k, v))
|
found = append(found, fmt.Sprintf("%s:%s", k, v))
|
||||||
}
|
}
|
||||||
sort.Strings(found)
|
sort.Strings(found)
|
||||||
|
|
||||||
// Make sure we see all of the expected params, that they have
|
// Make sure we see all of the expected params in the proper
|
||||||
// the varparam attr, and the varparm is set for the returns.
|
// order, that they have the varparam attr, and the varparm is set
|
||||||
expected := "[b1:1 f1:1 f2:1 f3:1 p1:1 p2:1 p3:1 r1:2 r2:2 r3:2 r4:2]"
|
// for the returns.
|
||||||
|
expected := "[c1:0:1 c2:1:1 c3:2:1 d1:3:1 d2:4:1 d3:5:1 d4:6:1 f1:7:1 f2:8:1 f3:9:1 g1:10:1 r1:11:2 r2:12:2 r3:13:2 r4:14:2 r5:15:2 r6:16:2]"
|
||||||
if fmt.Sprintf("%+v", found) != expected {
|
if fmt.Sprintf("%+v", found) != expected {
|
||||||
t.Errorf("param check failed, wanted %s got %s\n",
|
t.Errorf("param check failed, wanted %s got %s\n",
|
||||||
expected, found)
|
expected, found)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue