github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/dwarf/reader/reader.go (about)

     1  package reader
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/go-delve/delve/pkg/dwarf/godwarf"
     9  	"github.com/go-delve/delve/pkg/dwarf/op"
    10  )
    11  
    12  type Reader struct {
    13  	*dwarf.Reader
    14  	depth int
    15  }
    16  
    17  // New returns a reader for the specified dwarf data.
    18  func New(data *dwarf.Data) *Reader {
    19  	return &Reader{data.Reader(), 0}
    20  }
    21  
    22  // Seek moves the reader to an arbitrary offset.
    23  func (reader *Reader) Seek(off dwarf.Offset) {
    24  	reader.depth = 0
    25  	reader.Reader.Seek(off)
    26  }
    27  
    28  // SeekToEntry moves the reader to an arbitrary entry.
    29  func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
    30  	reader.Seek(entry.Offset)
    31  	// Consume the current entry so .Next works as intended
    32  	_, err := reader.Next()
    33  	return err
    34  }
    35  
    36  // AddrFor returns the address for the named entry.
    37  func (reader *Reader) AddrFor(name string, staticBase uint64, ptrSize int) (uint64, error) {
    38  	entry, err := reader.FindEntryNamed(name, false)
    39  	if err != nil {
    40  		return 0, err
    41  	}
    42  	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
    43  	if !ok {
    44  		return 0, fmt.Errorf("type assertion failed")
    45  	}
    46  	addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{StaticBase: staticBase}, instructions, ptrSize, nil)
    47  	if err != nil {
    48  		return 0, err
    49  	}
    50  	return uint64(addr), nil
    51  }
    52  
    53  var ErrTypeNotFound = errors.New("no type entry found, use 'types' for a list of valid types")
    54  
    55  // SeekToType moves the reader to the type specified by the entry,
    56  // optionally resolving typedefs and pointer types. If the reader is set
    57  // to a struct type the NextMemberVariable call can be used to walk all member data.
    58  func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) {
    59  	offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
    60  	if !ok {
    61  		return nil, fmt.Errorf("entry does not have a type attribute")
    62  	}
    63  
    64  	// Seek to the first type offset
    65  	reader.Seek(offset)
    66  
    67  	// Walk the types to the base
    68  	for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() {
    69  		if err != nil {
    70  			return nil, err
    71  		}
    72  
    73  		if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs {
    74  			return typeEntry, nil
    75  		}
    76  
    77  		if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes {
    78  			return typeEntry, nil
    79  		}
    80  
    81  		offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset)
    82  		if !ok {
    83  			return typeEntry, nil
    84  		}
    85  
    86  		reader.Seek(offset)
    87  	}
    88  
    89  	return nil, ErrTypeNotFound
    90  }
    91  
    92  func (reader *Reader) NextType() (*dwarf.Entry, error) {
    93  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  
    98  		switch entry.Tag {
    99  		case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
   100  			return entry, nil
   101  		}
   102  	}
   103  
   104  	return nil, nil
   105  }
   106  
   107  // SeekToTypeNamed moves the reader to the type specified by the name.
   108  // If the reader is set to a struct type the NextMemberVariable call
   109  // can be used to walk all member data.
   110  func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
   111  	// Walk the types to the base
   112  	for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  
   117  		n, ok := entry.Val(dwarf.AttrName).(string)
   118  		if !ok {
   119  			continue
   120  		}
   121  
   122  		if n == name {
   123  			return entry, nil
   124  		}
   125  	}
   126  
   127  	return nil, ErrTypeNotFound
   128  }
   129  
   130  // FindEntryNamed finds the entry for 'name'.
   131  func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) {
   132  	depth := 1
   133  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   134  		if err != nil {
   135  			return nil, err
   136  		}
   137  
   138  		if entry.Children {
   139  			depth++
   140  		}
   141  
   142  		if entry.Tag == 0 {
   143  			depth--
   144  			if depth <= 0 {
   145  				return nil, fmt.Errorf("could not find symbol value for %s", name)
   146  			}
   147  		}
   148  
   149  		if member {
   150  			if entry.Tag != dwarf.TagMember {
   151  				continue
   152  			}
   153  		} else {
   154  			if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType {
   155  				continue
   156  			}
   157  		}
   158  
   159  		n, ok := entry.Val(dwarf.AttrName).(string)
   160  		if !ok || n != name {
   161  			continue
   162  		}
   163  		return entry, nil
   164  	}
   165  	return nil, fmt.Errorf("could not find symbol value for %s", name)
   166  }
   167  
   168  func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) {
   169  	entry, err := reader.FindEntryNamed(name, member)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	var attr dwarf.Attr
   174  	if member {
   175  		attr = dwarf.AttrDataMemberLoc
   176  	} else {
   177  		attr = dwarf.AttrLocation
   178  	}
   179  	instr, ok := entry.Val(attr).([]byte)
   180  	if !ok {
   181  		return nil, errors.New("invalid typecast for Dwarf instructions")
   182  	}
   183  	return instr, nil
   184  }
   185  
   186  func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) {
   187  	if entry.Tag == dwarf.TagMember {
   188  		instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
   189  		if !ok {
   190  			return nil, fmt.Errorf("member data has no data member location attribute")
   191  		}
   192  		// clone slice to prevent stomping on the dwarf data
   193  		return append([]byte{}, instructions...), nil
   194  	}
   195  
   196  	// non-member
   197  	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
   198  	if !ok {
   199  		return nil, fmt.Errorf("entry has no location attribute")
   200  	}
   201  
   202  	// clone slice to prevent stomping on the dwarf data
   203  	return append([]byte{}, instructions...), nil
   204  }
   205  
   206  // NextMemberVariable moves the reader to the next debug entry that describes a member variable and returns the entry.
   207  func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) {
   208  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   209  		if err != nil {
   210  			return nil, err
   211  		}
   212  
   213  		// All member variables will be at the same depth
   214  		reader.SkipChildren()
   215  
   216  		// End of the current depth
   217  		if entry.Tag == 0 {
   218  			break
   219  		}
   220  
   221  		if entry.Tag == dwarf.TagMember {
   222  			return entry, nil
   223  		}
   224  	}
   225  
   226  	// No more items
   227  	return nil, nil
   228  }
   229  
   230  // NextPackageVariable moves the reader to the next debug entry that describes a package variable.
   231  // Any TagVariable entry that is not inside a sub program entry and is marked external is considered a package variable.
   232  func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
   233  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   234  		if err != nil {
   235  			return nil, err
   236  		}
   237  
   238  		if entry.Tag == dwarf.TagVariable {
   239  			ext, ok := entry.Val(dwarf.AttrExternal).(bool)
   240  			if ok && ext {
   241  				return entry, nil
   242  			}
   243  		}
   244  
   245  		// Ignore everything inside sub programs
   246  		if entry.Tag == dwarf.TagSubprogram {
   247  			reader.SkipChildren()
   248  		}
   249  	}
   250  
   251  	// No more items
   252  	return nil, nil
   253  }
   254  
   255  func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
   256  	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
   257  		if err != nil {
   258  			return nil, err
   259  		}
   260  
   261  		if entry.Tag == dwarf.TagCompileUnit {
   262  			return entry, nil
   263  		}
   264  	}
   265  
   266  	return nil, nil
   267  }
   268  
   269  // InlineStack returns the stack of inlined calls for the specified function
   270  // and PC address.
   271  // If pc is 0 then all inlined calls will be returned.
   272  func InlineStack(root *godwarf.Tree, pc uint64) []*godwarf.Tree {
   273  	v := []*godwarf.Tree{}
   274  	for _, child := range root.Children {
   275  		v = inlineStackInternal(v, child, pc)
   276  	}
   277  	return v
   278  }
   279  
   280  // inlineStackInternal precalculates the inlined call stack for pc
   281  // If pc == 0 then all inlined calls will be returned
   282  // Otherwise an inlined call will be returned if its range, or
   283  // the range of one of its child entries contains irdr.pc.
   284  // The recursive calculation of range inclusion is necessary because
   285  // sometimes when doing midstack inlining the Go compiler emits the toplevel
   286  // inlined call with ranges that do not cover the inlining of nested inlined
   287  // calls.
   288  // For example if a function A calls B which calls C and both the calls to
   289  // B and C are inlined the DW_AT_inlined_subroutine entry for A might have
   290  // ranges that do not cover the ranges of the inlined call to C.
   291  // This is probably a violation of the DWARF standard (it's unclear) but we
   292  // might as well support it as best as possible anyway.
   293  func inlineStackInternal(stack []*godwarf.Tree, n *godwarf.Tree, pc uint64) []*godwarf.Tree {
   294  	switch n.Tag {
   295  	case dwarf.TagSubprogram, dwarf.TagInlinedSubroutine, dwarf.TagLexDwarfBlock:
   296  		if pc == 0 || n.ContainsPC(pc) {
   297  			for _, child := range n.Children {
   298  				stack = inlineStackInternal(stack, child, pc)
   299  			}
   300  			if n.Tag == dwarf.TagInlinedSubroutine {
   301  				stack = append(stack, n)
   302  			}
   303  		}
   304  	}
   305  	return stack
   306  }