File: variables.go

package info (click to toggle)
delve 1.24.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 14,092 kB
  • sloc: ansic: 111,943; sh: 169; asm: 141; makefile: 43; python: 23
file content (74 lines) | stat: -rw-r--r-- 2,719 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package reader

import (
	"debug/dwarf"

	"github.com/go-delve/delve/pkg/dwarf/godwarf"
)

type Variable struct {
	*godwarf.Tree
	// Depth represents the depth of the lexical block in which this variable
	// was declared, relative to a root scope (e.g. a function) passed to
	// Variables(). The depth is used to figure out if a variable is shadowed at
	// a particular pc by another one with the same name declared in an inner
	// block.
	Depth int
}

// VariablesFlags specifies some configuration flags for the Variables function.
type VariablesFlags uint8

const (
	VariablesOnlyVisible VariablesFlags = 1 << iota
	VariablesSkipInlinedSubroutines
	VariablesTrustDeclLine
	VariablesNoDeclLineCheck
	VariablesOnlyCaptured
)

// Variables returns a list of variables contained inside 'root'.
//
// If the VariablesOnlyVisible flag is set, only variables visible at 'pc' will be
// returned. If the VariablesSkipInlinedSubroutines is set, variables from
// inlined subroutines will be skipped.
func Variables(root *godwarf.Tree, pc uint64, line int, flags VariablesFlags) []Variable {
	return variablesInternal(nil, root, 0, pc, line, flags, true)
}

// variablesInternal appends to 'v' variables from 'root'. The function calls
// itself with an incremented scope for all sub-blocks in 'root'.
func variablesInternal(v []Variable, root *godwarf.Tree, depth int, pc uint64, line int, flags VariablesFlags, first bool) []Variable {
	switch root.Tag {
	case dwarf.TagInlinedSubroutine:
		if !first && flags&VariablesSkipInlinedSubroutines != 0 {
			return v
		}
		fallthrough
	case dwarf.TagLexDwarfBlock, dwarf.TagSubprogram:
		// Recurse into blocks and functions, if the respective block contains
		// pc (or if we don't care about visibility).
		if (flags&VariablesOnlyVisible == 0) || root.ContainsPC(pc) {
			for _, child := range root.Children {
				v = variablesInternal(v, child, depth+1, pc, line, flags, false)
			}
		}
		return v
	default:
		// Variables are considered to be visible starting on the line after the
		// line they are declared on. Function arguments are an exception - the line
		// they are declared on does not matter; they are considered to be
		// visible throughout the function.
		declLine, varHasDeclLine := root.Val(dwarf.AttrDeclLine).(int64)
		checkDeclLine :=
			root.Tag != dwarf.TagFormalParameter && // var is not a function argument
				varHasDeclLine && // we know the DeclLine
				(flags&VariablesNoDeclLineCheck == 0) // we were not explicitly instructed to ignore DeclLine

		varVisible := !checkDeclLine || (line >= int(declLine)+1) // +1 because visibility starts on the line after DeclLine
		if varVisible {
			return append(v, Variable{root, depth})
		}
		return v
	}
}