github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/dwarf/godwarf/tree.go (about) 1 // The MIT License (MIT) 2 3 // Copyright (c) 2014 Derek Parker 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 // this software and associated documentation files (the "Software"), to deal in 7 // the Software without restriction, including without limitation the rights to 8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 // the Software, and to permit persons to whom the Software is furnished to do so, 10 // subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 package godwarf 23 24 import ( 25 "debug/dwarf" 26 "fmt" 27 "sort" 28 "sync" 29 ) 30 31 32 33 34 type Entry interface { 35 Val(dwarf.Attr) interface{} 36 } 37 38 type compositeEntry []*dwarf.Entry 39 40 func (ce compositeEntry) Val(attr dwarf.Attr) interface{} { 41 for _, e := range ce { 42 if r := e.Val(attr); r != nil { 43 return r 44 } 45 } 46 return nil 47 } 48 49 50 51 52 func LoadAbstractOrigin(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) { 53 ao, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 54 if !ok { 55 return entry, entry.Offset 56 } 57 58 r := []*dwarf.Entry{entry} 59 60 for { 61 aordr.Seek(ao) 62 e, _ := aordr.Next() 63 if e == nil { 64 break 65 } 66 r = append(r, e) 67 68 ao, ok = e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 69 if !ok { 70 break 71 } 72 } 73 74 return compositeEntry(r), entry.Offset 75 } 76 77 78 type Tree struct { 79 Entry 80 typ Type 81 Tag dwarf.Tag 82 Offset dwarf.Offset 83 Ranges [][2]uint64 84 Children []*Tree 85 } 86 87 88 89 90 91 92 func LoadTree(off dwarf.Offset, dw *dwarf.Data, staticBase uint64) (*Tree, error) { 93 rdr := dw.Reader() 94 rdr.Seek(off) 95 96 e, err := rdr.Next() 97 if err != nil { 98 return nil, err 99 } 100 r := entryToTreeInternal(e) 101 r.Children, err = loadTreeChildren(e, rdr) 102 if err != nil { 103 return nil, err 104 } 105 106 err = r.resolveRanges(dw, staticBase) 107 if err != nil { 108 return nil, err 109 } 110 r.resolveAbstractEntries(rdr) 111 112 return r, nil 113 } 114 115 116 func EntryToTree(entry *dwarf.Entry) *Tree { 117 if entry.Children { 118 panic(fmt.Sprintf("EntryToTree called on entry with children; "+ 119 "LoadTree should have been used instead. entry: %+v", entry)) 120 } 121 return entryToTreeInternal(entry) 122 } 123 124 func entryToTreeInternal(entry *dwarf.Entry) *Tree { 125 return &Tree{Entry: entry, Offset: entry.Offset, Tag: entry.Tag} 126 } 127 128 func loadTreeChildren(e *dwarf.Entry, rdr *dwarf.Reader) ([]*Tree, error) { 129 if !e.Children { 130 return nil, nil 131 } 132 children := []*Tree{} 133 for { 134 e, err := rdr.Next() 135 if err != nil { 136 return nil, err 137 } 138 if e.Tag == 0 { 139 break 140 } 141 child := entryToTreeInternal(e) 142 child.Children, err = loadTreeChildren(e, rdr) 143 if err != nil { 144 return nil, err 145 } 146 children = append(children, child) 147 } 148 return children, nil 149 } 150 151 func (n *Tree) resolveRanges(dw *dwarf.Data, staticBase uint64) error { 152 var err error 153 n.Ranges, err = dw.Ranges(n.Entry.(*dwarf.Entry)) 154 if err != nil { 155 return err 156 } 157 for i := range n.Ranges { 158 n.Ranges[i][0] += staticBase 159 n.Ranges[i][1] += staticBase 160 } 161 n.Ranges = normalizeRanges(n.Ranges) 162 163 for _, child := range n.Children { 164 err := child.resolveRanges(dw, staticBase) 165 if err != nil { 166 return err 167 } 168 n.Ranges = fuseRanges(n.Ranges, child.Ranges) 169 } 170 return nil 171 } 172 173 174 func normalizeRanges(rngs [][2]uint64) [][2]uint64 { 175 const ( 176 start = 0 177 end = 1 178 ) 179 180 if len(rngs) == 0 { 181 return rngs 182 } 183 184 sort.Slice(rngs, func(i, j int) bool { 185 return rngs[i][start] <= rngs[j][start] 186 }) 187 188 189 out := rngs[:0] 190 for i := range rngs { 191 if rngs[i][start] < rngs[i][end] { 192 out = append(out, rngs[i]) 193 } 194 } 195 rngs = out 196 197 198 out = rngs[:1] 199 for i := 1; i < len(rngs); i++ { 200 cur := rngs[i] 201 if cur[start] <= out[len(out)-1][end] { 202 out[len(out)-1][end] = max(cur[end], out[len(out)-1][end]) 203 } else { 204 out = append(out, cur) 205 } 206 } 207 return out 208 } 209 210 func max(a, b uint64) uint64 { 211 if a > b { 212 return a 213 } 214 return b 215 } 216 217 218 219 220 221 222 func fuseRanges(rngs1, rngs2 [][2]uint64) [][2]uint64 { 223 if rangesContains(rngs1, rngs2) { 224 return rngs1 225 } 226 227 return normalizeRanges(append(rngs1, rngs2...)) 228 } 229 230 231 func rangesContains(rngs1, rngs2 [][2]uint64) bool { 232 i, j := 0, 0 233 for { 234 if i >= len(rngs1) { 235 return false 236 } 237 if j >= len(rngs2) { 238 return true 239 } 240 if rangeContains(rngs1[i], rngs2[j]) { 241 j++ 242 } else { 243 i++ 244 } 245 } 246 } 247 248 249 func rangeContains(a, b [2]uint64) bool { 250 return a[0] <= b[0] && a[1] >= b[1] 251 } 252 253 func (n *Tree) resolveAbstractEntries(rdr *dwarf.Reader) { 254 n.Entry, n.Offset = LoadAbstractOrigin(n.Entry.(*dwarf.Entry), rdr) 255 for _, child := range n.Children { 256 child.resolveAbstractEntries(rdr) 257 } 258 } 259 260 261 func (n *Tree) ContainsPC(pc uint64) bool { 262 for _, rng := range n.Ranges { 263 if rng[0] > pc { 264 return false 265 } 266 if rng[0] <= pc && pc < rng[1] { 267 return true 268 } 269 } 270 return false 271 } 272 273 func (n *Tree) Type(dw *dwarf.Data, index int, typeCache *sync.Map) (Type, error) { 274 if n.typ == nil { 275 offset, ok := n.Val(dwarf.AttrType).(dwarf.Offset) 276 if !ok { 277 return nil, fmt.Errorf("malformed variable DIE (offset)") 278 } 279 280 var err error 281 n.typ, err = ReadType(dw, index, offset, typeCache) 282 if err != nil { 283 return nil, err 284 } 285 } 286 return n.typ, nil 287 }