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  }