Added limit to array size (64) and struct member recursion (2) when printing

This commit is contained in:
epipho
2015-02-02 02:13:42 -05:00
committed by Derek Parker
parent fe8e85e341
commit c7fe4e3e88
3 changed files with 50 additions and 17 deletions

View File

@ -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() {

View File

@ -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,20 +615,26 @@ 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.
fields := make([]string, 0, len(t.Field)) if recurseLevel <= maxVariableRecurse {
for _, field := range t.Field { fields := make([]string, 0, len(t.Field))
val, err := thread.extractValue(nil, field.ByteOffset+addr, field.Type, printStructName) for _, field := range t.Field {
if err != nil { val, err := thread.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1)
return "", err if err != nil {
} return "", err
}
fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val)) fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
} }
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

View File

@ -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")