github.com/undoio/delve@v1.9.0/pkg/dwarf/godwarf/tree.go (about) 1 package godwarf 2 3 import ( 4 "debug/dwarf" 5 "fmt" 6 "sort" 7 ) 8 9 // Entry represents a debug_info entry. 10 // When calling Val, if the entry does not have the specified attribute, the 11 // entry specified by DW_AT_abstract_origin will be searched recursively. 12 type Entry interface { 13 Val(dwarf.Attr) interface{} 14 } 15 16 type compositeEntry []*dwarf.Entry 17 18 func (ce compositeEntry) Val(attr dwarf.Attr) interface{} { 19 for _, e := range ce { 20 if r := e.Val(attr); r != nil { 21 return r 22 } 23 } 24 return nil 25 } 26 27 // LoadAbstractOrigin loads the entry corresponding to the 28 // DW_AT_abstract_origin of entry and returns a combination of entry and its 29 // abstract origin. 30 func LoadAbstractOrigin(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) { 31 ao, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 32 if !ok { 33 return entry, entry.Offset 34 } 35 36 r := []*dwarf.Entry{entry} 37 38 for { 39 aordr.Seek(ao) 40 e, _ := aordr.Next() 41 if e == nil { 42 break 43 } 44 r = append(r, e) 45 46 ao, ok = e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 47 if !ok { 48 break 49 } 50 } 51 52 return compositeEntry(r), entry.Offset 53 } 54 55 // Tree represents a tree of dwarf objects. 56 type Tree struct { 57 Entry 58 typ Type 59 Tag dwarf.Tag 60 Offset dwarf.Offset 61 Ranges [][2]uint64 62 Children []*Tree 63 } 64 65 // LoadTree returns the tree of DIE rooted at offset 'off'. 66 // Abstract origins are automatically loaded, if present. 67 // DIE ranges are bubbled up automatically, if the child of a DIE covers a 68 // range of addresses that is not covered by its parent LoadTree will fix 69 // the parent entry. 70 func LoadTree(off dwarf.Offset, dw *dwarf.Data, staticBase uint64) (*Tree, error) { 71 rdr := dw.Reader() 72 rdr.Seek(off) 73 74 e, err := rdr.Next() 75 if err != nil { 76 return nil, err 77 } 78 r := entryToTreeInternal(e) 79 r.Children, err = loadTreeChildren(e, rdr) 80 if err != nil { 81 return nil, err 82 } 83 84 err = r.resolveRanges(dw, staticBase) 85 if err != nil { 86 return nil, err 87 } 88 r.resolveAbstractEntries(rdr) 89 90 return r, nil 91 } 92 93 // EntryToTree converts a single entry, without children, to a *Tree object. 94 func EntryToTree(entry *dwarf.Entry) *Tree { 95 if entry.Children { 96 panic(fmt.Sprintf("EntryToTree called on entry with children; "+ 97 "LoadTree should have been used instead. entry: %+v", entry)) 98 } 99 return entryToTreeInternal(entry) 100 } 101 102 func entryToTreeInternal(entry *dwarf.Entry) *Tree { 103 return &Tree{Entry: entry, Offset: entry.Offset, Tag: entry.Tag} 104 } 105 106 func loadTreeChildren(e *dwarf.Entry, rdr *dwarf.Reader) ([]*Tree, error) { 107 if !e.Children { 108 return nil, nil 109 } 110 children := []*Tree{} 111 for { 112 e, err := rdr.Next() 113 if err != nil { 114 return nil, err 115 } 116 if e.Tag == 0 { 117 break 118 } 119 child := entryToTreeInternal(e) 120 child.Children, err = loadTreeChildren(e, rdr) 121 if err != nil { 122 return nil, err 123 } 124 children = append(children, child) 125 } 126 return children, nil 127 } 128 129 func (n *Tree) resolveRanges(dw *dwarf.Data, staticBase uint64) error { 130 var err error 131 n.Ranges, err = dw.Ranges(n.Entry.(*dwarf.Entry)) 132 if err != nil { 133 return err 134 } 135 for i := range n.Ranges { 136 n.Ranges[i][0] += staticBase 137 n.Ranges[i][1] += staticBase 138 } 139 n.Ranges = normalizeRanges(n.Ranges) 140 141 for _, child := range n.Children { 142 err := child.resolveRanges(dw, staticBase) 143 if err != nil { 144 return err 145 } 146 n.Ranges = fuseRanges(n.Ranges, child.Ranges) 147 } 148 return nil 149 } 150 151 // normalizeRanges sorts rngs by starting point and fuses overlapping entries. 152 func normalizeRanges(rngs [][2]uint64) [][2]uint64 { 153 const ( 154 start = 0 155 end = 1 156 ) 157 158 if len(rngs) == 0 { 159 return rngs 160 } 161 162 sort.Slice(rngs, func(i, j int) bool { 163 return rngs[i][start] <= rngs[j][start] 164 }) 165 166 // eliminate invalid entries 167 out := rngs[:0] 168 for i := range rngs { 169 if rngs[i][start] < rngs[i][end] { 170 out = append(out, rngs[i]) 171 } 172 } 173 rngs = out 174 175 // fuse overlapping entries 176 out = rngs[:1] 177 for i := 1; i < len(rngs); i++ { 178 cur := rngs[i] 179 if cur[start] <= out[len(out)-1][end] { 180 out[len(out)-1][end] = max(cur[end], out[len(out)-1][end]) 181 } else { 182 out = append(out, cur) 183 } 184 } 185 return out 186 } 187 188 func max(a, b uint64) uint64 { 189 if a > b { 190 return a 191 } 192 return b 193 } 194 195 // fuseRanges fuses rngs2 into rngs1, it's the equivalent of 196 // 197 // normalizeRanges(append(rngs1, rngs2)) 198 // 199 // but more efficient. 200 func fuseRanges(rngs1, rngs2 [][2]uint64) [][2]uint64 { 201 if rangesContains(rngs1, rngs2) { 202 return rngs1 203 } 204 205 return normalizeRanges(append(rngs1, rngs2...)) 206 } 207 208 // rangesContains checks that rngs1 is a superset of rngs2. 209 func rangesContains(rngs1, rngs2 [][2]uint64) bool { 210 i, j := 0, 0 211 for { 212 if i >= len(rngs1) { 213 return false 214 } 215 if j >= len(rngs2) { 216 return true 217 } 218 if rangeContains(rngs1[i], rngs2[j]) { 219 j++ 220 } else { 221 i++ 222 } 223 } 224 } 225 226 // rangeContains checks that a contains b. 227 func rangeContains(a, b [2]uint64) bool { 228 return a[0] <= b[0] && a[1] >= b[1] 229 } 230 231 func (n *Tree) resolveAbstractEntries(rdr *dwarf.Reader) { 232 n.Entry, n.Offset = LoadAbstractOrigin(n.Entry.(*dwarf.Entry), rdr) 233 for _, child := range n.Children { 234 child.resolveAbstractEntries(rdr) 235 } 236 } 237 238 // ContainsPC returns true if the ranges of this DIE contains PC. 239 func (n *Tree) ContainsPC(pc uint64) bool { 240 for _, rng := range n.Ranges { 241 if rng[0] > pc { 242 return false 243 } 244 if rng[0] <= pc && pc < rng[1] { 245 return true 246 } 247 } 248 return false 249 } 250 251 func (n *Tree) Type(dw *dwarf.Data, index int, typeCache map[dwarf.Offset]Type) (Type, error) { 252 if n.typ == nil { 253 offset, ok := n.Val(dwarf.AttrType).(dwarf.Offset) 254 if !ok { 255 return nil, fmt.Errorf("malformed variable DIE (offset)") 256 } 257 258 var err error 259 n.typ, err = ReadType(dw, index, offset, typeCache) 260 if err != nil { 261 return nil, err 262 } 263 } 264 return n.typ, nil 265 }