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  }