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