mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	Added limit to array size (64) and struct member recursion (2) when printing
This commit is contained in:
		| @ -13,6 +13,11 @@ type FooBar2 struct { | |||||||
| 	Baz string | 	Baz string | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type Nest struct { | ||||||
|  | 	Level int | ||||||
|  | 	Nest  *Nest | ||||||
|  | } | ||||||
|  |  | ||||||
| func barfoo() { | func barfoo() { | ||||||
| 	a1 := "bur" | 	a1 := "bur" | ||||||
| 	fmt.Println(a1) | 	fmt.Println(a1) | ||||||
| @ -45,10 +50,12 @@ func foobar(baz string, bar FooBar) { | |||||||
| 		f32 = float32(1.2) | 		f32 = float32(1.2) | ||||||
| 		i32 = [2]int32{1, 2} | 		i32 = [2]int32{1, 2} | ||||||
| 		f   = barfoo | 		f   = barfoo | ||||||
|  | 		ms  = Nest{0, &Nest{1, &Nest{2, &Nest{3, &Nest{4, nil}}}}} // Test recursion capping | ||||||
|  | 		ba  = make([]int, 200, 200)                                // Test array size capping | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	barfoo() | 	barfoo() | ||||||
| 	fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, b1, b2, baz, neg, i8, u8, u16, u32, u64, up, f32, i32, bar, f) | 	fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, b1, b2, baz, neg, i8, u8, u16, u32, u64, up, f32, i32, bar, f, ms, ba) | ||||||
| } | } | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
|  | |||||||
| @ -13,6 +13,11 @@ import ( | |||||||
| 	"github.com/derekparker/delve/dwarf/reader" | 	"github.com/derekparker/delve/dwarf/reader" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	maxVariableRecurse = 1 | ||||||
|  | 	maxArrayValues     = 64 | ||||||
|  | ) | ||||||
|  |  | ||||||
| type Variable struct { | type Variable struct { | ||||||
| 	Name  string | 	Name  string | ||||||
| 	Value string | 	Value string | ||||||
| @ -558,6 +563,10 @@ func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, read | |||||||
| // We execute the stack program described in the DW_OP_* instruction stream, and | // We execute the stack program described in the DW_OP_* instruction stream, and | ||||||
| // then grab the value from the other processes memory. | // then grab the value from the other processes memory. | ||||||
| func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) { | func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) { | ||||||
|  | 	return thread.extractValueInternal(instructions, addr, typ, printStructName, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (thread *ThreadContext) extractValueInternal(instructions []byte, addr int64, typ interface{}, printStructName bool, recurseLevel int) (string, error) { | ||||||
| 	var err error | 	var err error | ||||||
|  |  | ||||||
| 	if addr == 0 { | 	if addr == 0 { | ||||||
| @ -590,7 +599,8 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i | |||||||
| 			return fmt.Sprintf("%s nil", t.String()), nil | 			return fmt.Sprintf("%s nil", t.String()), nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		val, err := thread.extractValue(nil, intaddr, t.Type, printStructName) | 		// Don't increase the recursion level when dereferencing pointers | ||||||
|  | 		val, err := thread.extractValueInternal(nil, intaddr, t.Type, printStructName, recurseLevel) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", err | 			return "", err | ||||||
| 		} | 		} | ||||||
| @ -605,9 +615,10 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i | |||||||
| 		default: | 		default: | ||||||
| 			// Recursively call extractValue to grab | 			// Recursively call extractValue to grab | ||||||
| 			// the value of all the members of the struct. | 			// the value of all the members of the struct. | ||||||
|  | 			if recurseLevel <= maxVariableRecurse { | ||||||
| 				fields := make([]string, 0, len(t.Field)) | 				fields := make([]string, 0, len(t.Field)) | ||||||
| 				for _, field := range t.Field { | 				for _, field := range t.Field { | ||||||
| 				val, err := thread.extractValue(nil, field.ByteOffset+addr, field.Type, printStructName) | 					val, err := thread.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1) | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						return "", err | 						return "", err | ||||||
| 					} | 					} | ||||||
| @ -616,9 +627,14 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i | |||||||
| 				} | 				} | ||||||
| 				if printStructName { | 				if printStructName { | ||||||
| 					return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil | 					return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil | ||||||
| 			} else { | 				} | ||||||
| 				return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil | 				return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil | ||||||
| 			} | 			} | ||||||
|  | 			// no fields | ||||||
|  | 			if printStructName { | ||||||
|  | 				return fmt.Sprintf("%s {...}", t.StructName), nil | ||||||
|  | 			} | ||||||
|  | 			return "{...}", nil | ||||||
| 		} | 		} | ||||||
| 	case *dwarf.ArrayType: | 	case *dwarf.ArrayType: | ||||||
| 		return thread.readArray(ptraddress, t) | 		return thread.readArray(ptraddress, t) | ||||||
| @ -736,6 +752,12 @@ func (thread *ThreadContext) readArrayValues(addr uintptr, count int64, stride i | |||||||
| 	vals := make([]string, 0) | 	vals := make([]string, 0) | ||||||
|  |  | ||||||
| 	for i := int64(0); i < count; i++ { | 	for i := int64(0); i < count; i++ { | ||||||
|  | 		// Cap number of elements | ||||||
|  | 		if i >= maxArrayValues { | ||||||
|  | 			vals = append(vals, fmt.Sprintf("...+%d more", count-maxArrayValues)) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		val, err := thread.extractValue(nil, int64(addr+uintptr(i*stride)), t, false) | 		val, err := thread.extractValue(nil, int64(addr+uintptr(i*stride)), t, false) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
|  | |||||||
| @ -68,11 +68,13 @@ func TestVariableEvaluation(t *testing.T) { | |||||||
| 		{"u8", "255", "uint8", nil}, | 		{"u8", "255", "uint8", nil}, | ||||||
| 		{"up", "5", "uintptr", nil}, | 		{"up", "5", "uintptr", nil}, | ||||||
| 		{"f", "main.barfoo", "func()", nil}, | 		{"f", "main.barfoo", "func()", nil}, | ||||||
|  | 		{"ba", "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", "struct []int", nil}, | ||||||
|  | 		{"ms", "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *main.Nest {...}}}", "main.Nest", nil}, | ||||||
| 		{"NonExistent", "", "", errors.New("could not find symbol value for NonExistent")}, | 		{"NonExistent", "", "", errors.New("could not find symbol value for NonExistent")}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||||
|  |  | ||||||
| 		_, err := p.Break(pc) | 		_, err := p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
| @ -103,7 +105,7 @@ func TestVariableFunctionScoping(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||||
|  |  | ||||||
| 		_, err := p.Break(pc) | 		_, err := p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
| @ -118,7 +120,7 @@ func TestVariableFunctionScoping(t *testing.T) { | |||||||
| 		assertNoError(err, t, "Unable to find variable a1") | 		assertNoError(err, t, "Unable to find variable a1") | ||||||
|  |  | ||||||
| 		// Move scopes, a1 exists here by a2 does not | 		// Move scopes, a1 exists here by a2 does not | ||||||
| 		pc, _, _ = p.GoSymTable.LineToPC(fp, 18) | 		pc, _, _ = p.GoSymTable.LineToPC(fp, 23) | ||||||
|  |  | ||||||
| 		_, err = p.Break(pc) | 		_, err = p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
| @ -182,10 +184,12 @@ func TestLocalVariables(t *testing.T) { | |||||||
| 				{"a9", "*main.FooBar nil", "*main.FooBar", nil}, | 				{"a9", "*main.FooBar nil", "*main.FooBar", nil}, | ||||||
| 				{"b1", "true", "bool", nil}, | 				{"b1", "true", "bool", nil}, | ||||||
| 				{"b2", "false", "bool", nil}, | 				{"b2", "false", "bool", nil}, | ||||||
|  | 				{"ba", "[]int len: 200, cap: 200, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,...+136 more]", "struct []int", nil}, | ||||||
| 				{"f", "main.barfoo", "func()", nil}, | 				{"f", "main.barfoo", "func()", nil}, | ||||||
| 				{"f32", "1.2", "float32", nil}, | 				{"f32", "1.2", "float32", nil}, | ||||||
| 				{"i32", "[2]int32 [1,2]", "[2]int32", nil}, | 				{"i32", "[2]int32 [1,2]", "[2]int32", nil}, | ||||||
| 				{"i8", "1", "int8", nil}, | 				{"i8", "1", "int8", nil}, | ||||||
|  | 				{"ms", "main.Nest {Level: 0, Nest: *main.Nest {Level: 1, Nest: *main.Nest {...}}}", "main.Nest", nil}, | ||||||
| 				{"neg", "-1", "int", nil}, | 				{"neg", "-1", "int", nil}, | ||||||
| 				{"u16", "65535", "uint16", nil}, | 				{"u16", "65535", "uint16", nil}, | ||||||
| 				{"u32", "4294967295", "uint32", nil}, | 				{"u32", "4294967295", "uint32", nil}, | ||||||
| @ -199,7 +203,7 @@ func TestLocalVariables(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||||
|  |  | ||||||
| 		_, err := p.Break(pc) | 		_, err := p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 epipho
					epipho