mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	 bbcea6b9f4
			
		
	
	bbcea6b9f4
	
	
	
		
			
			Supports showing captured variables for function closures on versions of Go that export informations about the closure struct (Go >= 1.23) Fixes #3612
		
			
				
	
	
		
			75 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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)
 | |
| }
 | |
| 
 | |
| // 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) []Variable {
 | |
| 	switch root.Tag {
 | |
| 	case dwarf.TagInlinedSubroutine:
 | |
| 		if 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)
 | |
| 			}
 | |
| 		}
 | |
| 		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
 | |
| 	}
 | |
| }
 |