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  }