github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/dwarfgen/scope.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package dwarfgen 6 7 import ( 8 "sort" 9 10 "github.com/go-asm/go/cmd/compile/base" 11 "github.com/go-asm/go/cmd/compile/ir" 12 "github.com/go-asm/go/cmd/dwarf" 13 "github.com/go-asm/go/cmd/obj" 14 "github.com/go-asm/go/cmd/src" 15 ) 16 17 // See golang.org/issue/20390. 18 func xposBefore(p, q src.XPos) bool { 19 return base.Ctxt.PosTable.Pos(p).Before(base.Ctxt.PosTable.Pos(q)) 20 } 21 22 func findScope(marks []ir.Mark, pos src.XPos) ir.ScopeID { 23 i := sort.Search(len(marks), func(i int) bool { 24 return xposBefore(pos, marks[i].Pos) 25 }) 26 if i == 0 { 27 return 0 28 } 29 return marks[i-1].Scope 30 } 31 32 func assembleScopes(fnsym *obj.LSym, fn *ir.Func, dwarfVars []*dwarf.Var, varScopes []ir.ScopeID) []dwarf.Scope { 33 // Initialize the DWARF scope tree based on lexical scopes. 34 dwarfScopes := make([]dwarf.Scope, 1+len(fn.Parents)) 35 for i, parent := range fn.Parents { 36 dwarfScopes[i+1].Parent = int32(parent) 37 } 38 39 scopeVariables(dwarfVars, varScopes, dwarfScopes, fnsym.ABI() != obj.ABI0) 40 if fnsym.Func().Text != nil { 41 scopePCs(fnsym, fn.Marks, dwarfScopes) 42 } 43 return compactScopes(dwarfScopes) 44 } 45 46 // scopeVariables assigns DWARF variable records to their scopes. 47 func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ir.ScopeID, dwarfScopes []dwarf.Scope, regabi bool) { 48 if regabi { 49 sort.Stable(varsByScope{dwarfVars, varScopes}) 50 } else { 51 sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes}) 52 } 53 54 i0 := 0 55 for i := range dwarfVars { 56 if varScopes[i] == varScopes[i0] { 57 continue 58 } 59 dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:i] 60 i0 = i 61 } 62 if i0 < len(dwarfVars) { 63 dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:] 64 } 65 } 66 67 // scopePCs assigns PC ranges to their scopes. 68 func scopePCs(fnsym *obj.LSym, marks []ir.Mark, dwarfScopes []dwarf.Scope) { 69 // If there aren't any child scopes (in particular, when scope 70 // tracking is disabled), we can skip a whole lot of work. 71 if len(marks) == 0 { 72 return 73 } 74 p0 := fnsym.Func().Text 75 scope := findScope(marks, p0.Pos) 76 for p := p0; p != nil; p = p.Link { 77 if p.Pos == p0.Pos { 78 continue 79 } 80 dwarfScopes[scope].AppendRange(dwarf.Range{Start: p0.Pc, End: p.Pc}) 81 p0 = p 82 scope = findScope(marks, p0.Pos) 83 } 84 if p0.Pc < fnsym.Size { 85 dwarfScopes[scope].AppendRange(dwarf.Range{Start: p0.Pc, End: fnsym.Size}) 86 } 87 } 88 89 func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope { 90 // Reverse pass to propagate PC ranges to parent scopes. 91 for i := len(dwarfScopes) - 1; i > 0; i-- { 92 s := &dwarfScopes[i] 93 dwarfScopes[s.Parent].UnifyRanges(s) 94 } 95 96 return dwarfScopes 97 } 98 99 type varsByScopeAndOffset struct { 100 vars []*dwarf.Var 101 scopes []ir.ScopeID 102 } 103 104 func (v varsByScopeAndOffset) Len() int { 105 return len(v.vars) 106 } 107 108 func (v varsByScopeAndOffset) Less(i, j int) bool { 109 if v.scopes[i] != v.scopes[j] { 110 return v.scopes[i] < v.scopes[j] 111 } 112 return v.vars[i].StackOffset < v.vars[j].StackOffset 113 } 114 115 func (v varsByScopeAndOffset) Swap(i, j int) { 116 v.vars[i], v.vars[j] = v.vars[j], v.vars[i] 117 v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i] 118 } 119 120 type varsByScope struct { 121 vars []*dwarf.Var 122 scopes []ir.ScopeID 123 } 124 125 func (v varsByScope) Len() int { 126 return len(v.vars) 127 } 128 129 func (v varsByScope) Less(i, j int) bool { 130 return v.scopes[i] < v.scopes[j] 131 } 132 133 func (v varsByScope) Swap(i, j int) { 134 v.vars[i], v.vars[j] = v.vars[j], v.vars[i] 135 v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i] 136 }