mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	Improve variable evaluation scope
Properly scope variable evaluation to the function the traced process is currently stopped in.
This commit is contained in:
		| @ -7,6 +7,11 @@ type FooBar struct { | |||||||
| 	Bur string | 	Bur string | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func barfoo() { | ||||||
|  | 	a1 := "bur" | ||||||
|  | 	fmt.Println(a1) | ||||||
|  | } | ||||||
|  |  | ||||||
| func foobar(baz string) { | func foobar(baz string) { | ||||||
| 	var ( | 	var ( | ||||||
| 		a1  = "foo" | 		a1  = "foo" | ||||||
| @ -21,6 +26,7 @@ func foobar(baz string) { | |||||||
| 		f32 = float32(1.2) | 		f32 = float32(1.2) | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
|  | 	barfoo() | ||||||
| 	fmt.Println(a1, a2, a3, a4, a5, a6, a7, baz, neg, i8, f32) | 	fmt.Println(a1, a2, a3, a4, a5, a6, a7, baz, neg, i8, f32) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -24,20 +24,21 @@ func (dbp *DebuggedProcess) PrintGoroutinesInfo() error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	reader := data.Reader() | ||||||
|  |  | ||||||
| 	allglen, err := allglenval(dbp, data) | 	allglen, err := allglenval(dbp, reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	goidoffset, err := parsegoidoffset(dbp, data) | 	goidoffset, err := parsegoidoffset(dbp, reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	schedoffset, err := parseschedoffset(dbp, data) | 	schedoffset, err := parseschedoffset(dbp, reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	allgentryaddr, err := allgentryptr(dbp, data) | 	allgentryaddr, err := allgentryptr(dbp, reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -76,8 +77,8 @@ func printGoroutineInfo(dbp *DebuggedProcess, addr uint64, goidoffset, schedoffs | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func allglenval(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | func allglenval(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { | ||||||
| 	entry, err := findDwarfEntry("runtime.allglen", data) | 	entry, err := findDwarfEntry("runtime.allglen", reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| @ -97,8 +98,8 @@ func allglenval(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | |||||||
| 	return binary.LittleEndian.Uint64(val), nil | 	return binary.LittleEndian.Uint64(val), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func allgentryptr(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | func allgentryptr(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { | ||||||
| 	entry, err := findDwarfEntry("runtime.allg", data) | 	entry, err := findDwarfEntry("runtime.allg", reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| @ -115,8 +116,8 @@ func allgentryptr(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | |||||||
| 	return uint64(addr), nil | 	return uint64(addr), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func parsegoidoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | func parsegoidoffset(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { | ||||||
| 	entry, err := findDwarfEntry("goid", data) | 	entry, err := findDwarfEntry("goid", reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| @ -132,8 +133,8 @@ func parsegoidoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | |||||||
| 	return uint64(offset), nil | 	return uint64(offset), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func parseschedoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { | func parseschedoffset(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { | ||||||
| 	entry, err := findDwarfEntry("sched", data) | 	entry, err := findDwarfEntry("sched", reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| @ -156,7 +157,18 @@ func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	entry, err := findDwarfEntry(name, data) | 	pc, err := thread.CurrentPC() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	fn := thread.Process.GoSymTable.PCToFunc(pc) | ||||||
|  | 	if fn == nil { | ||||||
|  | 		return nil, fmt.Errorf("could not func function scope") | ||||||
|  | 	} | ||||||
|  | 	reader := data.Reader() | ||||||
|  | 	err = findFunction(fn.Name, reader) | ||||||
|  |  | ||||||
|  | 	entry, err := findDwarfEntry(name, reader) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -184,9 +196,34 @@ func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { | |||||||
| 	return &Variable{Name: name, Type: t.String(), Value: val}, nil | 	return &Variable{Name: name, Type: t.String(), Value: val}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func findDwarfEntry(name string, data *dwarf.Data) (*dwarf.Entry, error) { | // findFunction is basically used to seek the dwarf.Reader to | ||||||
| 	reader := data.Reader() | // the function entry that represents our current scope. From there | ||||||
|  | // we can find the first child entry that matches the var name and | ||||||
|  | // use it to determine the value of the variable. | ||||||
|  | func findFunction(name string, reader *dwarf.Reader) error { | ||||||
|  | 	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if entry.Tag != dwarf.TagSubprogram { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		n, ok := entry.Val(dwarf.AttrName).(string) | ||||||
|  | 		if !ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if n == name { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findDwarfEntry(name string, reader *dwarf.Reader) (*dwarf.Entry, error) { | ||||||
| 	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { | 	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ func TestVariableEvaluation(t *testing.T) { | |||||||
| 		{"a1", "foo", "struct string"}, | 		{"a1", "foo", "struct string"}, | ||||||
| 		{"a2", "6", "int"}, | 		{"a2", "6", "int"}, | ||||||
| 		{"a3", "7.23", "float64"}, | 		{"a3", "7.23", "float64"}, | ||||||
| 		{"a4", "[2]int [1 2]", "[97]int"}, | 		{"a4", "[2]int [1 2]", "[65]int"}, | ||||||
| 		{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"}, | 		{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"}, | ||||||
| 		{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"}, | 		{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"}, | ||||||
| 		{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"}, | 		{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"}, | ||||||
| @ -35,7 +35,7 @@ func TestVariableEvaluation(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) { | 	helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 24) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 29) | ||||||
|  |  | ||||||
| 		_, err := p.Break(uintptr(pc)) | 		_, err := p.Break(uintptr(pc)) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Derek Parker
					Derek Parker