From e2236664dd7bb8be659f5e843676c7dbbbd689b6 Mon Sep 17 00:00:00 2001 From: epipho Date: Tue, 20 Jan 2015 00:32:08 -0500 Subject: [PATCH] Genericized array reading --- _fixtures/testvariables.go | 3 ++- proctl/variables.go | 45 +++++++++++++++++++------------------- proctl/variables_test.go | 16 ++++++++------ 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/_fixtures/testvariables.go b/_fixtures/testvariables.go index 7f1ddd23..5863cf82 100644 --- a/_fixtures/testvariables.go +++ b/_fixtures/testvariables.go @@ -30,6 +30,7 @@ func foobar(baz string, bar FooBar) { a8 = FooBar2{Bur: 10, Baz: "feh"} a9 = (*FooBar)(nil) a10 = a1[2:5] + a11 = [3]FooBar{{1, "a"}, {2, "b"}, {3, "c"}} b1 = true b2 = false neg = -1 @@ -45,7 +46,7 @@ func foobar(baz string, bar FooBar) { ) 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() { diff --git a/proctl/variables.go b/proctl/variables.go index 71a15ac4..acac18b5 100644 --- a/proctl/variables.go +++ b/proctl/variables.go @@ -448,7 +448,7 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, read binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr)) 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 { return nil, err } @@ -490,7 +490,7 @@ func (thread *ThreadContext) extractVariableFromEntry(entry *dwarf.Entry) (*Vari 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 { 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. // 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{}) (string, error) { +func (thread *ThreadContext) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) { var err error 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 } - val, err := thread.extractValue(nil, intaddr, t.Type) + val, err := thread.extractValue(nil, intaddr, t.Type, printStructName) if err != nil { 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. fields := make([]string, 0, len(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 { return "", err } fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val)) } - retstr := fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")) - return retstr, nil + if printStructName { + return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil + } else { + return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil + } } case *dwarf.ArrayType: - return thread.readIntArray(ptraddress, t) + return thread.readArray(ptraddress, t) case *dwarf.IntType: return thread.readInt(ptraddress, t.ByteSize) case *dwarf.UintType: @@ -681,23 +684,19 @@ func (thread *ThreadContext) readIntSlice(addr uintptr, t *dwarf.StructType) (st return "", fmt.Errorf("Could not read slice") } -func (thread *ThreadContext) readIntArray(addr uintptr, t *dwarf.ArrayType) (string, error) { - val, err := thread.readMemory(addr, uintptr(t.ByteSize)) - if err != nil { - return "", err - } +func (thread *ThreadContext) readArray(addr uintptr, t *dwarf.ArrayType) (string, error) { + vals := make([]string, 0) - switch t.Type.Size() { - 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 + 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) } - return "", fmt.Errorf("Could not read array") + + return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil } func (thread *ThreadContext) readInt(addr uintptr, size int64) (string, error) { diff --git a/proctl/variables_test.go b/proctl/variables_test.go index 1d8517ed..e4be7297 100644 --- a/proctl/variables_test.go +++ b/proctl/variables_test.go @@ -39,9 +39,10 @@ func TestVariableEvaluation(t *testing.T) { testcases := []varTest{ {"a1", "foofoofoofoofoofoo", "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}, {"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}, {"a6", "main.FooBar {Baz: 8, Bur: word}", "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.NonExistent", "nil", "int", errors.New("a9 has no member NonExistent")}, {"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}, {"b2", "false", "bool", nil}, {"i8", "1", "int8", nil}, {"u16", "65535", "uint16", nil}, @@ -69,7 +70,7 @@ func TestVariableEvaluation(t *testing.T) { } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 47) + pc, _, _ := p.GoSymTable.LineToPC(fp, 48) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error") @@ -100,7 +101,7 @@ func TestVariableFunctionScoping(t *testing.T) { } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 47) + pc, _, _ := p.GoSymTable.LineToPC(fp, 48) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error") @@ -166,9 +167,10 @@ func TestLocalVariables(t *testing.T) { []varTest{ {"a1", "foofoofoofoofoofoo", "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}, {"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}, {"a6", "main.FooBar {Baz: 8, Bur: word}", "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}, {"f", "main.barfoo", "func()", 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}, {"neg", "-1", "int", nil}, {"u16", "65535", "uint16", nil}, @@ -193,7 +195,7 @@ func TestLocalVariables(t *testing.T) { } withTestProcess(executablePath, t, func(p *DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 47) + pc, _, _ := p.GoSymTable.LineToPC(fp, 48) _, err := p.Break(pc) assertNoError(err, t, "Break() returned an error") -- GitLab