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 | ||||
| } | ||||
|  | ||||
| type Nest struct { | ||||
| 	Level int | ||||
| 	Nest  *Nest | ||||
| } | ||||
|  | ||||
| func barfoo() { | ||||
| 	a1 := "bur" | ||||
| 	fmt.Println(a1) | ||||
| @ -45,10 +50,12 @@ func foobar(baz string, bar FooBar) { | ||||
| 		f32 = float32(1.2) | ||||
| 		i32 = [2]int32{1, 2} | ||||
| 		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() | ||||
| 	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() { | ||||
|  | ||||
| @ -13,6 +13,11 @@ import ( | ||||
| 	"github.com/derekparker/delve/dwarf/reader" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	maxVariableRecurse = 1 | ||||
| 	maxArrayValues     = 64 | ||||
| ) | ||||
|  | ||||
| type Variable struct { | ||||
| 	Name  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 | ||||
| // then grab the value from the other processes memory. | ||||
| 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 | ||||
|  | ||||
| 	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 | ||||
| 		} | ||||
|  | ||||
| 		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 { | ||||
| 			return "", err | ||||
| 		} | ||||
| @ -605,20 +615,26 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i | ||||
| 		default: | ||||
| 			// Recursively call extractValue to grab | ||||
| 			// the value of all the members of the struct. | ||||
| 			fields := make([]string, 0, len(t.Field)) | ||||
| 			for _, field := range t.Field { | ||||
| 				val, err := thread.extractValue(nil, field.ByteOffset+addr, field.Type, printStructName) | ||||
| 				if err != nil { | ||||
| 					return "", err | ||||
| 				} | ||||
| 			if recurseLevel <= maxVariableRecurse { | ||||
| 				fields := make([]string, 0, len(t.Field)) | ||||
| 				for _, field := range t.Field { | ||||
| 					val, err := thread.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1) | ||||
| 					if err != nil { | ||||
| 						return "", err | ||||
| 					} | ||||
|  | ||||
| 				fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val)) | ||||
| 			} | ||||
| 			if printStructName { | ||||
| 				return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil | ||||
| 			} else { | ||||
| 					fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val)) | ||||
| 				} | ||||
| 				if printStructName { | ||||
| 					return fmt.Sprintf("%s {%s}", t.StructName, 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: | ||||
| 		return thread.readArray(ptraddress, t) | ||||
| @ -736,6 +752,12 @@ func (thread *ThreadContext) readArrayValues(addr uintptr, count int64, stride i | ||||
| 	vals := make([]string, 0) | ||||
|  | ||||
| 	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) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
|  | ||||
| @ -68,11 +68,13 @@ func TestVariableEvaluation(t *testing.T) { | ||||
| 		{"u8", "255", "uint8", nil}, | ||||
| 		{"up", "5", "uintptr", 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")}, | ||||
| 	} | ||||
|  | ||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||
|  | ||||
| 		_, err := p.Break(pc) | ||||
| 		assertNoError(err, t, "Break() returned an error") | ||||
| @ -103,7 +105,7 @@ func TestVariableFunctionScoping(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||
|  | ||||
| 		_, err := p.Break(pc) | ||||
| 		assertNoError(err, t, "Break() returned an error") | ||||
| @ -118,7 +120,7 @@ func TestVariableFunctionScoping(t *testing.T) { | ||||
| 		assertNoError(err, t, "Unable to find variable a1") | ||||
|  | ||||
| 		// 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) | ||||
| 		assertNoError(err, t, "Break() returned an error") | ||||
| @ -182,10 +184,12 @@ func TestLocalVariables(t *testing.T) { | ||||
| 				{"a9", "*main.FooBar nil", "*main.FooBar", nil}, | ||||
| 				{"b1", "true", "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}, | ||||
| 				{"f32", "1.2", "float32", nil}, | ||||
| 				{"i32", "[2]int32 [1,2]", "[2]int32", 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}, | ||||
| 				{"u16", "65535", "uint16", nil}, | ||||
| 				{"u32", "4294967295", "uint32", nil}, | ||||
| @ -199,7 +203,7 @@ func TestLocalVariables(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 57) | ||||
|  | ||||
| 		_, err := p.Break(pc) | ||||
| 		assertNoError(err, t, "Break() returned an error") | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 epipho
					epipho