mirror of
https://github.com/go-delve/delve.git
synced 2025-10-30 10:17:03 +08:00
Genericized array reading
This commit is contained in:
@ -30,6 +30,7 @@ func foobar(baz string, bar FooBar) {
|
|||||||
a8 = FooBar2{Bur: 10, Baz: "feh"}
|
a8 = FooBar2{Bur: 10, Baz: "feh"}
|
||||||
a9 = (*FooBar)(nil)
|
a9 = (*FooBar)(nil)
|
||||||
a10 = a1[2:5]
|
a10 = a1[2:5]
|
||||||
|
a11 = [3]FooBar{{1, "a"}, {2, "b"}, {3, "c"}}
|
||||||
b1 = true
|
b1 = true
|
||||||
b2 = false
|
b2 = false
|
||||||
neg = -1
|
neg = -1
|
||||||
@ -45,7 +46,7 @@ func foobar(baz string, bar FooBar) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
barfoo()
|
barfoo()
|
||||||
fmt.Println(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, 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, b1, b2, baz, neg, i8, u8, u16, u32, u64, up, f32, i32, bar, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@ -448,7 +448,7 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, read
|
|||||||
binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr))
|
binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr))
|
||||||
|
|
||||||
parentInstructions := append([]byte{op.DW_OP_addr}, baseAddr...)
|
parentInstructions := append([]byte{op.DW_OP_addr}, baseAddr...)
|
||||||
val, err := thread.extractValue(append(parentInstructions, memberInstr...), 0, t)
|
val, err := thread.extractValue(append(parentInstructions, memberInstr...), 0, t, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -490,7 +490,7 @@ func (thread *ThreadContext) extractVariableFromEntry(entry *dwarf.Entry) (*Vari
|
|||||||
return nil, fmt.Errorf("type assertion failed")
|
return nil, fmt.Errorf("type assertion failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
val, err := thread.extractValue(instructions, 0, t)
|
val, err := thread.extractValue(instructions, 0, t, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -556,7 +556,7 @@ func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, read
|
|||||||
// Extracts the value from the instructions given in the DW_AT_location entry.
|
// Extracts the value from the instructions given in the DW_AT_location entry.
|
||||||
// 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{}) (string, error) {
|
func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if addr == 0 {
|
if addr == 0 {
|
||||||
@ -585,7 +585,7 @@ 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)
|
val, err := thread.extractValue(nil, intaddr, t.Type, printStructName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -602,18 +602,21 @@ func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ i
|
|||||||
// the value of all the members of the struct.
|
// the value of all the members of the struct.
|
||||||
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)
|
val, err := thread.extractValue(nil, field.ByteOffset+addr, field.Type, printStructName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
|
fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
|
||||||
}
|
}
|
||||||
retstr := fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", "))
|
if printStructName {
|
||||||
return retstr, nil
|
return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case *dwarf.ArrayType:
|
case *dwarf.ArrayType:
|
||||||
return thread.readIntArray(ptraddress, t)
|
return thread.readArray(ptraddress, t)
|
||||||
case *dwarf.IntType:
|
case *dwarf.IntType:
|
||||||
return thread.readInt(ptraddress, t.ByteSize)
|
return thread.readInt(ptraddress, t.ByteSize)
|
||||||
case *dwarf.UintType:
|
case *dwarf.UintType:
|
||||||
@ -681,23 +684,19 @@ func (thread *ThreadContext) readIntSlice(addr uintptr, t *dwarf.StructType) (st
|
|||||||
return "", fmt.Errorf("Could not read slice")
|
return "", fmt.Errorf("Could not read slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (thread *ThreadContext) readIntArray(addr uintptr, t *dwarf.ArrayType) (string, error) {
|
func (thread *ThreadContext) readArray(addr uintptr, t *dwarf.ArrayType) (string, error) {
|
||||||
val, err := thread.readMemory(addr, uintptr(t.ByteSize))
|
vals := make([]string, 0)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
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 {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
vals = append(vals, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t.Type.Size() {
|
return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil
|
||||||
case 4:
|
|
||||||
members := *(*[]uint32)(unsafe.Pointer(&val))
|
|
||||||
setSliceLength(unsafe.Pointer(&members), int(t.Count))
|
|
||||||
return fmt.Sprintf("%s %d", t, members), nil
|
|
||||||
case 8:
|
|
||||||
members := *(*[]uint64)(unsafe.Pointer(&val))
|
|
||||||
setSliceLength(unsafe.Pointer(&members), int(t.Count))
|
|
||||||
return fmt.Sprintf("%s %d", t, members), nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("Could not read array")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) {
|
func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) {
|
||||||
|
|||||||
@ -39,9 +39,10 @@ func TestVariableEvaluation(t *testing.T) {
|
|||||||
testcases := []varTest{
|
testcases := []varTest{
|
||||||
{"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},
|
||||||
{"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", "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},
|
||||||
@ -56,7 +57,7 @@ func TestVariableEvaluation(t *testing.T) {
|
|||||||
{"a9.Baz", "nil", "int", errors.New("a9 is nil")},
|
{"a9.Baz", "nil", "int", errors.New("a9 is nil")},
|
||||||
{"a9.NonExistent", "nil", "int", errors.New("a9 has no member NonExistent")},
|
{"a9.NonExistent", "nil", "int", errors.New("a9 has no member NonExistent")},
|
||||||
{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, // reread variable after member
|
{"a8", "main.FooBar2 {Bur: 10, Baz: feh}", "main.FooBar2", nil}, // reread variable after member
|
||||||
{"i32", "[2]int32 [1 2]", "[2]int32", nil},
|
{"i32", "[2]int32 [1,2]", "[2]int32", nil},
|
||||||
{"b1", "true", "bool", nil},
|
{"b1", "true", "bool", nil},
|
||||||
{"b2", "false", "bool", nil}, {"i8", "1", "int8", nil},
|
{"b2", "false", "bool", nil}, {"i8", "1", "int8", nil},
|
||||||
{"u16", "65535", "uint16", nil},
|
{"u16", "65535", "uint16", nil},
|
||||||
@ -69,7 +70,7 @@ func TestVariableEvaluation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
||||||
pc, _, _ := p.GoSymTable.LineToPC(fp, 47)
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 48)
|
||||||
|
|
||||||
_, err := p.Break(pc)
|
_, err := p.Break(pc)
|
||||||
assertNoError(err, t, "Break() returned an error")
|
assertNoError(err, t, "Break() returned an error")
|
||||||
@ -100,7 +101,7 @@ func TestVariableFunctionScoping(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
||||||
pc, _, _ := p.GoSymTable.LineToPC(fp, 47)
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 48)
|
||||||
|
|
||||||
_, err := p.Break(pc)
|
_, err := p.Break(pc)
|
||||||
assertNoError(err, t, "Break() returned an error")
|
assertNoError(err, t, "Break() returned an error")
|
||||||
@ -166,9 +167,10 @@ func TestLocalVariables(t *testing.T) {
|
|||||||
[]varTest{
|
[]varTest{
|
||||||
{"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},
|
||||||
{"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", "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},
|
||||||
@ -178,7 +180,7 @@ func TestLocalVariables(t *testing.T) {
|
|||||||
{"b2", "false", "bool", nil},
|
{"b2", "false", "bool", 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},
|
||||||
{"neg", "-1", "int", nil},
|
{"neg", "-1", "int", nil},
|
||||||
{"u16", "65535", "uint16", nil},
|
{"u16", "65535", "uint16", nil},
|
||||||
@ -193,7 +195,7 @@ func TestLocalVariables(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
withTestProcess(executablePath, t, func(p *DebuggedProcess) {
|
||||||
pc, _, _ := p.GoSymTable.LineToPC(fp, 47)
|
pc, _, _ := p.GoSymTable.LineToPC(fp, 48)
|
||||||
|
|
||||||
_, 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