github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/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 AttrField(dwarf.Attr) *dwarf.Field 15 } 16 17 type compositeEntry []*dwarf.Entry 18 19 func (ce compositeEntry) Val(attr dwarf.Attr) interface{} { 20 if f := ce.AttrField(attr); f != nil { 21 return f.Val 22 } 23 return nil 24 } 25 26 func (ce compositeEntry) AttrField(a dwarf.Attr) *dwarf.Field { 27 for _, e := range ce { 28 if f := e.AttrField(a); f != nil { 29 return f 30 } 31 } 32 return nil 33 } 34 35 // LoadAbstractOriginAndSpecification loads the entry corresponding to the 36 // DW_AT_abstract_origin and/or DW_AT_specification of entry and returns a 37 // combination of entry and its abstract origin. If a DIE has both a 38 // specification and an abstract origin the specification will be ignored, the 39 // DWARF standard is unclear on how this should be handled 40 func LoadAbstractOriginAndSpecification(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) { 41 ao, ok := getAbstractOriginOrSpecification(entry) 42 if !ok { 43 return entry, entry.Offset 44 } 45 46 r := []*dwarf.Entry{entry} 47 48 for { 49 aordr.Seek(ao) 50 e, _ := aordr.Next() 51 if e == nil { 52 break 53 } 54 r = append(r, e) 55 56 ao, ok = getAbstractOriginOrSpecification(e) 57 if !ok { 58 break 59 } 60 } 61 62 return compositeEntry(r), entry.Offset 63 } 64 65 func getAbstractOriginOrSpecification(e *dwarf.Entry) (dwarf.Offset, bool) { 66 ao, ok := e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 67 if ok { 68 return ao, true 69 } 70 sp, ok := e.Val(dwarf.AttrSpecification).(dwarf.Offset) 71 if ok { 72 return sp, true 73 } 74 return dwarf.Offset(0), false 75 } 76 77 // Tree represents a tree of dwarf objects. 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 // LoadTree returns the tree of DIE rooted at offset 'off'. 88 // Abstract origins are automatically loaded, if present. 89 // DIE ranges are bubbled up automatically, if the child of a DIE covers a 90 // range of addresses that is not covered by its parent LoadTree will fix 91 // the parent entry. 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.resolveAbstractAndSpecificationEntries(rdr) 111 112 return r, nil 113 } 114 115 // EntryToTree converts a single entry, without children, to a *Tree object. 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 // normalizeRanges sorts rngs by starting point and fuses overlapping entries. 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 // eliminate invalid entries 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 // fuse overlapping entries 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 // fuseRanges fuses rngs2 into rngs1, it's the equivalent of 218 // 219 // normalizeRanges(append(rngs1, rngs2)) 220 // 221 // but more efficient. 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 // rangesContains checks that rngs1 is a superset of rngs2. 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 // rangeContains checks that a contains b. 249 func rangeContains(a, b [2]uint64) bool { 250 return a[0] <= b[0] && a[1] >= b[1] 251 } 252 253 func (n *Tree) resolveAbstractAndSpecificationEntries(rdr *dwarf.Reader) { 254 n.Entry, n.Offset = LoadAbstractOriginAndSpecification(n.Entry.(*dwarf.Entry), rdr) 255 for _, child := range n.Children { 256 child.resolveAbstractAndSpecificationEntries(rdr) 257 } 258 } 259 260 // ContainsPC returns true if the ranges of this DIE contains PC. 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 map[dwarf.Offset]Type) (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 }