mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	Genericized slice reading
This commit is contained in:
		| @ -31,6 +31,8 @@ func foobar(baz string, bar FooBar) { | |||||||
| 		a9  = (*FooBar)(nil) | 		a9  = (*FooBar)(nil) | ||||||
| 		a10 = a1[2:5] | 		a10 = a1[2:5] | ||||||
| 		a11 = [3]FooBar{{1, "a"}, {2, "b"}, {3, "c"}} | 		a11 = [3]FooBar{{1, "a"}, {2, "b"}, {3, "c"}} | ||||||
|  | 		a12 = []FooBar{{4, "d"}, {5, "e"}} | ||||||
|  | 		a13 = []*FooBar{{6, "f"}, {7, "g"}, {8, "h"}} | ||||||
| 		b1  = true | 		b1  = true | ||||||
| 		b2  = false | 		b2  = false | ||||||
| 		neg = -1 | 		neg = -1 | ||||||
| @ -46,7 +48,7 @@ func foobar(baz string, bar FooBar) { | |||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	barfoo() | 	barfoo() | ||||||
| 	fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, 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) | ||||||
| } | } | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
|  | |||||||
| @ -592,11 +592,11 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i | |||||||
|  |  | ||||||
| 		return fmt.Sprintf("*%s", val), nil | 		return fmt.Sprintf("*%s", val), nil | ||||||
| 	case *dwarf.StructType: | 	case *dwarf.StructType: | ||||||
| 		switch t.StructName { | 		switch { | ||||||
| 		case "string": | 		case t.StructName == "string": | ||||||
| 			return thread.readString(ptraddress) | 			return thread.readString(ptraddress) | ||||||
| 		case "[]int": | 		case strings.HasPrefix(t.StructName, "[]"): | ||||||
| 			return thread.readIntSlice(ptraddress, t) | 			return thread.readSlice(ptraddress, t) | ||||||
| 		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. | ||||||
| @ -660,45 +660,79 @@ func (thread *ThreadContext) readString(addr uintptr) (string, error) { | |||||||
| 	return *(*string)(unsafe.Pointer(&val)), nil | 	return *(*string)(unsafe.Pointer(&val)), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (thread *ThreadContext) readIntSlice(addr uintptr, t *dwarf.StructType) (string, error) { | func (thread *ThreadContext) readSlice(addr uintptr, t *dwarf.StructType) (string, error) { | ||||||
| 	val, err := thread.readMemory(addr, uintptr(24)) | 	var sliceLen, sliceCap int64 | ||||||
|  | 	var arrayAddr uintptr | ||||||
|  | 	var arrayType dwarf.Type | ||||||
|  | 	for _, f := range t.Field { | ||||||
|  | 		switch f.Name { | ||||||
|  | 		case "array": | ||||||
|  | 			val, err := thread.readMemory(addr+uintptr(f.ByteOffset), ptrsize) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 			arrayAddr = uintptr(binary.LittleEndian.Uint64(val)) | ||||||
|  | 			// Dereference array type to get value type | ||||||
|  | 			ptrType, ok := f.Type.(*dwarf.PtrType) | ||||||
|  | 			if !ok { | ||||||
|  | 				return "", fmt.Errorf("Invalid type %s in slice array", f.Type) | ||||||
|  | 			} | ||||||
|  | 			arrayType = ptrType.Type | ||||||
|  | 		case "len": | ||||||
|  | 			lstr, err := thread.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 			sliceLen, err = strconv.ParseInt(lstr, 10, 64) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 		case "cap": | ||||||
|  | 			cstr, err := thread.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 			sliceCap, err = strconv.ParseInt(cstr, 10, 64) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return "", err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	stride := arrayType.Size() | ||||||
|  | 	if _, ok := arrayType.(*dwarf.PtrType); ok { | ||||||
|  | 		stride = int64(ptrsize) | ||||||
|  | 	} | ||||||
|  | 	vals, err := thread.readArrayValues(arrayAddr, sliceLen, stride, arrayType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	a := binary.LittleEndian.Uint64(val[:8]) | 	return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", arrayType, sliceLen, sliceCap, strings.Join(vals, ",")), nil | ||||||
| 	l := binary.LittleEndian.Uint64(val[8:16]) |  | ||||||
| 	c := binary.LittleEndian.Uint64(val[16:24]) |  | ||||||
|  |  | ||||||
| 	val, err = thread.readMemory(uintptr(a), uintptr(uint64(ptrsize)*l)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch t.StructName { |  | ||||||
| 	case "[]int": |  | ||||||
| 		members := *(*[]int)(unsafe.Pointer(&val)) |  | ||||||
| 		setSliceLength(unsafe.Pointer(&members), int(l)) |  | ||||||
| 		return fmt.Sprintf("len: %d cap: %d %d", l, c, members), nil |  | ||||||
| 	} |  | ||||||
| 	return "", fmt.Errorf("Could not read slice") |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (thread *ThreadContext) readArray(addr uintptr, t *dwarf.ArrayType) (string, error) { | func (thread *ThreadContext) readArray(addr uintptr, t *dwarf.ArrayType) (string, error) { | ||||||
| 	vals := make([]string, 0) | 	vals, err := thread.readArrayValues(addr, t.Count, t.ByteSize/t.Count, t.Type) | ||||||
|  |  | ||||||
| 	stride := t.ByteSize / t.Count |  | ||||||
| 	for i := int64(0); i < t.Count; i++ { |  | ||||||
| 		val, err := thread.extractValue(nil, int64(addr+uintptr(i*stride)), t.Type, false) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 		vals = append(vals, val) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil | 	return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (thread *ThreadContext) readArrayValues(addr uintptr, count int64, stride int64, t dwarf.Type) ([]string, error) { | ||||||
|  | 	vals := make([]string, 0) | ||||||
|  |  | ||||||
|  | 	for i := int64(0); i < count; i++ { | ||||||
|  | 		val, err := thread.extractValue(nil, int64(addr+uintptr(i*stride)), t, false) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		vals = append(vals, val) | ||||||
|  | 	} | ||||||
|  | 	return vals, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) { | func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) { | ||||||
| 	var n int64 | 	var n int64 | ||||||
|  |  | ||||||
|  | |||||||
| @ -40,10 +40,12 @@ func TestVariableEvaluation(t *testing.T) { | |||||||
| 		{"a1", "foofoofoofoofoofoo", "struct string", nil}, | 		{"a1", "foofoofoofoofoofoo", "struct string", nil}, | ||||||
| 		{"a10", "ofo", "struct string", nil}, | 		{"a10", "ofo", "struct string", nil}, | ||||||
| 		{"a11", "[3]main.FooBar [{Baz: 1, Bur: a},{Baz: 2, Bur: b},{Baz: 3, Bur: c}]", "[3]main.FooBar", nil}, | 		{"a11", "[3]main.FooBar [{Baz: 1, Bur: a},{Baz: 2, Bur: b},{Baz: 3, Bur: c}]", "[3]main.FooBar", nil}, | ||||||
|  | 		{"a12", "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: d},{Baz: 5, Bur: e}]", "struct []main.FooBar", nil}, | ||||||
|  | 		{"a13", "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: f},*{Baz: 7, Bur: g},*{Baz: 8, Bur: h}]", "struct []*main.FooBar", nil}, | ||||||
| 		{"a2", "6", "int", nil}, | 		{"a2", "6", "int", nil}, | ||||||
| 		{"a3", "7.23", "float64", nil}, | 		{"a3", "7.23", "float64", nil}, | ||||||
| 		{"a4", "[2]int [1,2]", "[2]int", nil}, | 		{"a4", "[2]int [1,2]", "[2]int", nil}, | ||||||
| 		{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int", nil}, | 		{"a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", "struct []int", nil}, | ||||||
| 		{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil}, | 		{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil}, | ||||||
| 		{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil}, | 		{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil}, | ||||||
| 		{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, | 		{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, | ||||||
| @ -70,7 +72,7 @@ func TestVariableEvaluation(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 48) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||||
|  |  | ||||||
| 		_, err := p.Break(pc) | 		_, err := p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
| @ -101,7 +103,7 @@ func TestVariableFunctionScoping(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 48) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||||
|  |  | ||||||
| 		_, err := p.Break(pc) | 		_, err := p.Break(pc) | ||||||
| 		assertNoError(err, t, "Break() returned an error") | 		assertNoError(err, t, "Break() returned an error") | ||||||
| @ -168,10 +170,12 @@ func TestLocalVariables(t *testing.T) { | |||||||
| 				{"a1", "foofoofoofoofoofoo", "struct string", nil}, | 				{"a1", "foofoofoofoofoofoo", "struct string", nil}, | ||||||
| 				{"a10", "ofo", "struct string", nil}, | 				{"a10", "ofo", "struct string", nil}, | ||||||
| 				{"a11", "[3]main.FooBar [{Baz: 1, Bur: a},{Baz: 2, Bur: b},{Baz: 3, Bur: c}]", "[3]main.FooBar", nil}, | 				{"a11", "[3]main.FooBar [{Baz: 1, Bur: a},{Baz: 2, Bur: b},{Baz: 3, Bur: c}]", "[3]main.FooBar", nil}, | ||||||
|  | 				{"a12", "[]main.FooBar len: 2, cap: 2, [{Baz: 4, Bur: d},{Baz: 5, Bur: e}]", "struct []main.FooBar", nil}, | ||||||
|  | 				{"a13", "[]*main.FooBar len: 3, cap: 3, [*{Baz: 6, Bur: f},*{Baz: 7, Bur: g},*{Baz: 8, Bur: h}]", "struct []*main.FooBar", nil}, | ||||||
| 				{"a2", "6", "int", nil}, | 				{"a2", "6", "int", nil}, | ||||||
| 				{"a3", "7.23", "float64", nil}, | 				{"a3", "7.23", "float64", nil}, | ||||||
| 				{"a4", "[2]int [1,2]", "[2]int", nil}, | 				{"a4", "[2]int [1,2]", "[2]int", nil}, | ||||||
| 				{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int", nil}, | 				{"a5", "[]int len: 5, cap: 5, [1,2,3,4,5]", "struct []int", nil}, | ||||||
| 				{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil}, | 				{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar", nil}, | ||||||
| 				{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil}, | 				{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar", nil}, | ||||||
| 				{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, | 				{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, | ||||||
| @ -195,7 +199,7 @@ func TestLocalVariables(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | 	withTestProcess(executablePath, t, func(p *DebuggedProcess) { | ||||||
| 		pc, _, _ := p.GoSymTable.LineToPC(fp, 48) | 		pc, _, _ := p.GoSymTable.LineToPC(fp, 50) | ||||||
|  |  | ||||||
| 		_, 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