gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/dwarf/reader/variables.go (about)

     1  package reader
     2  
     3  import (
     4  	"debug/dwarf"
     5  
     6  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
     7  )
     8  
     9  type Variable struct {
    10  	*godwarf.Tree
    11  	// Depth represents the depth of the lexical block in which this variable
    12  	// was declared, relative to a root scope (e.g. a function) passed to
    13  	// Variables(). The depth is used to figure out if a variable is shadowed at
    14  	// a particular pc by another one with the same name declared in an inner
    15  	// block.
    16  	Depth int
    17  }
    18  
    19  // VariablesFlags specifies some configuration flags for the Variables function.
    20  type VariablesFlags uint8
    21  
    22  const (
    23  	VariablesOnlyVisible VariablesFlags = 1 << iota
    24  	VariablesSkipInlinedSubroutines
    25  	VariablesTrustDeclLine
    26  	VariablesNoDeclLineCheck
    27  	VariablesOnlyCaptured
    28  )
    29  
    30  // Variables returns a list of variables contained inside 'root'.
    31  //
    32  // If the VariablesOnlyVisible flag is set, only variables visible at 'pc' will be
    33  // returned. If the VariablesSkipInlinedSubroutines is set, variables from
    34  // inlined subroutines will be skipped.
    35  func Variables(root *godwarf.Tree, pc uint64, line int, flags VariablesFlags) []Variable {
    36  	return variablesInternal(nil, root, 0, pc, line, flags)
    37  }
    38  
    39  // variablesInternal appends to 'v' variables from 'root'. The function calls
    40  // itself with an incremented scope for all sub-blocks in 'root'.
    41  func variablesInternal(v []Variable, root *godwarf.Tree, depth int, pc uint64, line int, flags VariablesFlags) []Variable {
    42  	switch root.Tag {
    43  	case dwarf.TagInlinedSubroutine:
    44  		if flags&VariablesSkipInlinedSubroutines != 0 {
    45  			return v
    46  		}
    47  		fallthrough
    48  	case dwarf.TagLexDwarfBlock, dwarf.TagSubprogram:
    49  		// Recurse into blocks and functions, if the respective block contains
    50  		// pc (or if we don't care about visibility).
    51  		if (flags&VariablesOnlyVisible == 0) || root.ContainsPC(pc) {
    52  			for _, child := range root.Children {
    53  				v = variablesInternal(v, child, depth+1, pc, line, flags)
    54  			}
    55  		}
    56  		return v
    57  	default:
    58  		// Variables are considered to be visible starting on the line after the
    59  		// line they are declared on. Function arguments are an exception - the line
    60  		// they are declared on does not matter; they are considered to be
    61  		// visible throughout the function.
    62  		declLine, varHasDeclLine := root.Val(dwarf.AttrDeclLine).(int64)
    63  		checkDeclLine :=
    64  			root.Tag != dwarf.TagFormalParameter && // var is not a function argument
    65  				varHasDeclLine && // we know the DeclLine
    66  				(flags&VariablesNoDeclLineCheck == 0) // we were not explicitly instructed to ignore DeclLine
    67  
    68  		varVisible := !checkDeclLine || (line >= int(declLine)+1) // +1 because visibility starts on the line after DeclLine
    69  		if varVisible {
    70  			return append(v, Variable{root, depth})
    71  		}
    72  		return v
    73  	}
    74  }