mirror of
https://github.com/go-delve/delve.git
synced 2025-11-03 05:47:34 +08:00
Move variable related code to own file
This commit is contained in:
@ -234,54 +234,3 @@ func TestNext(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestVariableEvaluation(t *testing.T) {
|
||||
executablePath := "../_fixtures/testvariables"
|
||||
|
||||
fp, err := filepath.Abs(executablePath + ".go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
value string
|
||||
varType string
|
||||
}{
|
||||
{"a1", "foo", "struct string"},
|
||||
{"a2", "6", "int"},
|
||||
{"a3", "7.23", "float64"},
|
||||
{"a4", "[2]int [1 2]", "[97]int"}, // There is a weird bug in the Go dwarf parser that is grabbing the wrong size for an array.
|
||||
{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"},
|
||||
{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"},
|
||||
{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"},
|
||||
{"baz", "bazburzum", "struct string"},
|
||||
}
|
||||
|
||||
helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) {
|
||||
pc, _, _ := p.GoSymTable.LineToPC(fp, 21)
|
||||
|
||||
_, err := p.Break(uintptr(pc))
|
||||
assertNoError(err, t, "Break() returned an error")
|
||||
|
||||
err = p.Continue()
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
variable, err := p.EvalSymbol(tc.name)
|
||||
assertNoError(err, t, "Variable() returned an error")
|
||||
|
||||
if variable.Name != tc.name {
|
||||
t.Fatalf("Expected %s got %s\n", tc.name, variable.Name)
|
||||
}
|
||||
|
||||
if variable.Type != tc.varType {
|
||||
t.Fatalf("Expected %s got %s\n", tc.varType, variable.Type)
|
||||
}
|
||||
|
||||
if variable.Value != tc.value {
|
||||
t.Fatalf("Expected %#v got %#v\n", tc.value, variable.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,18 +1,12 @@
|
||||
package proctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/frame"
|
||||
"github.com/derekparker/delve/dwarf/op"
|
||||
"github.com/derekparker/delve/vendor/dwarf"
|
||||
)
|
||||
|
||||
// ThreadContext represents a single thread of execution in the
|
||||
@ -24,12 +18,6 @@ type ThreadContext struct {
|
||||
Regs *syscall.PtraceRegs
|
||||
}
|
||||
|
||||
type Variable struct {
|
||||
Name string
|
||||
Value string
|
||||
Type string
|
||||
}
|
||||
|
||||
// Obtains register values from the debugged process.
|
||||
func (thread *ThreadContext) Registers() (*syscall.PtraceRegs, error) {
|
||||
err := syscall.PtraceGetRegs(thread.Id, thread.Regs)
|
||||
@ -235,271 +223,6 @@ func (thread *ThreadContext) wait() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||
data, err := thread.Process.Executable.DWARF()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := data.Reader()
|
||||
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter {
|
||||
continue
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || n != name {
|
||||
continue
|
||||
}
|
||||
|
||||
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
t, err := data.Type(offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := thread.extractValue(instructions, 0, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Variable{Name: n, Type: t.String(), Value: val}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
|
||||
// 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, off int64, typ interface{}) (string, error) {
|
||||
regs, err := thread.Registers()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fde, err := thread.Process.FrameEntries.FDEForPC(regs.PC())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fctx := fde.EstablishFrame(regs.PC())
|
||||
cfaOffset := fctx.CFAOffset()
|
||||
|
||||
offset := off
|
||||
if off == 0 {
|
||||
offset, err = op.ExecuteStackProgram(cfaOffset, instructions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
offset = int64(regs.Rsp) + offset
|
||||
}
|
||||
|
||||
// If we have a user defined type, find the
|
||||
// underlying concrete type and use that.
|
||||
if tt, ok := typ.(*dwarf.TypedefType); ok {
|
||||
typ = tt.Type
|
||||
}
|
||||
|
||||
offaddr := uintptr(offset)
|
||||
switch t := typ.(type) {
|
||||
case *dwarf.PtrType:
|
||||
addr, err := thread.readMemory(offaddr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
adr := binary.LittleEndian.Uint64(addr)
|
||||
val, err := thread.extractValue(nil, int64(adr), t.Type)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
retstr := fmt.Sprintf("*%s", val)
|
||||
return retstr, nil
|
||||
case *dwarf.StructType:
|
||||
switch t.StructName {
|
||||
case "string":
|
||||
return thread.readString(offaddr)
|
||||
case "[]int":
|
||||
return thread.readIntSlice(offaddr)
|
||||
default:
|
||||
// Here we could 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+offset, field.Type)
|
||||
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
|
||||
}
|
||||
case *dwarf.ArrayType:
|
||||
return thread.readIntArray(offaddr, t)
|
||||
case *dwarf.IntType:
|
||||
return thread.readInt(offaddr)
|
||||
case *dwarf.FloatType:
|
||||
return thread.readFloat64(offaddr)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("could not find value for type %s", typ)
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readString(addr uintptr) (string, error) {
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// deref the pointer to the string
|
||||
addr = uintptr(binary.LittleEndian.Uint64(val))
|
||||
val, err = thread.readMemory(addr, 16)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
i := bytes.IndexByte(val, 0x0)
|
||||
val = val[:i]
|
||||
str := *(*string)(unsafe.Pointer(&val))
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readIntSlice(addr uintptr) (string, error) {
|
||||
var number uint64
|
||||
|
||||
val, err := thread.readMemory(addr, uintptr(24))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
a := binary.LittleEndian.Uint64(val[:8])
|
||||
l := binary.LittleEndian.Uint64(val[8:16])
|
||||
c := binary.LittleEndian.Uint64(val[16:24])
|
||||
|
||||
val, err = thread.readMemory(uintptr(a), uintptr(8*l))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
members := make([]uint64, 0, l)
|
||||
buf := bytes.NewBuffer(val)
|
||||
for {
|
||||
err := binary.Read(buf, binary.LittleEndian, &number)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
members = append(members, number)
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("len: %d cap: %d %d", l, c, members)
|
||||
|
||||
return str, err
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readIntArray(addr uintptr, t *dwarf.ArrayType) (string, error) {
|
||||
var (
|
||||
number uint64
|
||||
members = make([]uint64, 0, t.ByteSize)
|
||||
)
|
||||
|
||||
val, err := thread.readMemory(addr, uintptr(t.ByteSize))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(val)
|
||||
for {
|
||||
err := binary.Read(buf, binary.LittleEndian, &number)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
members = append(members, number)
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("[%d]int %d", t.ByteSize/8, members)
|
||||
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readInt(addr uintptr) (string, error) {
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
n := binary.LittleEndian.Uint64(val)
|
||||
|
||||
return strconv.Itoa(int(n)), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readFloat64(addr uintptr) (string, error) {
|
||||
var n float64
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf := bytes.NewBuffer(val)
|
||||
binary.Read(buf, binary.LittleEndian, &n)
|
||||
|
||||
return strconv.FormatFloat(n, 'f', -1, 64), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readMemory(addr uintptr, size uintptr) ([]byte, error) {
|
||||
buf := make([]byte, size)
|
||||
|
||||
_, err := syscall.PtracePeekData(thread.Id, addr, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) handleResult(err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ps, err := wait(thread.Process, thread.Id, 0)
|
||||
if err != nil && err != syscall.ECHILD {
|
||||
return err
|
||||
}
|
||||
|
||||
if ps != nil {
|
||||
thread.Status = ps
|
||||
if ps.TrapCause() == -1 && !ps.Exited() {
|
||||
regs, err := thread.Registers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("traced program %s at: %#v\n", ps.StopSignal(), regs.PC())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func threadIds(pid int) []int {
|
||||
var threads []int
|
||||
dir, err := os.Open(fmt.Sprintf("/proc/%d/task", pid))
|
||||
|
||||
285
proctl/variables_linux_amd64.go
Normal file
285
proctl/variables_linux_amd64.go
Normal file
@ -0,0 +1,285 @@
|
||||
package proctl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/derekparker/delve/dwarf/op"
|
||||
"github.com/derekparker/delve/vendor/dwarf"
|
||||
)
|
||||
|
||||
type Variable struct {
|
||||
Name string
|
||||
Value string
|
||||
Type string
|
||||
}
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||
data, err := thread.Process.Executable.DWARF()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := data.Reader()
|
||||
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter {
|
||||
continue
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || n != name {
|
||||
continue
|
||||
}
|
||||
|
||||
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
t, err := data.Type(offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := thread.extractValue(instructions, 0, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Variable{Name: n, Type: t.String(), Value: val}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
|
||||
// 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, off int64, typ interface{}) (string, error) {
|
||||
regs, err := thread.Registers()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fde, err := thread.Process.FrameEntries.FDEForPC(regs.PC())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fctx := fde.EstablishFrame(regs.PC())
|
||||
cfaOffset := fctx.CFAOffset()
|
||||
|
||||
offset := off
|
||||
if off == 0 {
|
||||
offset, err = op.ExecuteStackProgram(cfaOffset, instructions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
offset = int64(regs.Rsp) + offset
|
||||
}
|
||||
|
||||
// If we have a user defined type, find the
|
||||
// underlying concrete type and use that.
|
||||
if tt, ok := typ.(*dwarf.TypedefType); ok {
|
||||
typ = tt.Type
|
||||
}
|
||||
|
||||
offaddr := uintptr(offset)
|
||||
switch t := typ.(type) {
|
||||
case *dwarf.PtrType:
|
||||
addr, err := thread.readMemory(offaddr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
adr := binary.LittleEndian.Uint64(addr)
|
||||
val, err := thread.extractValue(nil, int64(adr), t.Type)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
retstr := fmt.Sprintf("*%s", val)
|
||||
return retstr, nil
|
||||
case *dwarf.StructType:
|
||||
switch t.StructName {
|
||||
case "string":
|
||||
return thread.readString(offaddr)
|
||||
case "[]int":
|
||||
return thread.readIntSlice(offaddr)
|
||||
default:
|
||||
// Here we could 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+offset, field.Type)
|
||||
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
|
||||
}
|
||||
case *dwarf.ArrayType:
|
||||
return thread.readIntArray(offaddr, t)
|
||||
case *dwarf.IntType:
|
||||
return thread.readInt(offaddr)
|
||||
case *dwarf.FloatType:
|
||||
return thread.readFloat64(offaddr)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("could not find value for type %s", typ)
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readString(addr uintptr) (string, error) {
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// deref the pointer to the string
|
||||
addr = uintptr(binary.LittleEndian.Uint64(val))
|
||||
val, err = thread.readMemory(addr, 16)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
i := bytes.IndexByte(val, 0x0)
|
||||
val = val[:i]
|
||||
str := *(*string)(unsafe.Pointer(&val))
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readIntSlice(addr uintptr) (string, error) {
|
||||
var number uint64
|
||||
|
||||
val, err := thread.readMemory(addr, uintptr(24))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
a := binary.LittleEndian.Uint64(val[:8])
|
||||
l := binary.LittleEndian.Uint64(val[8:16])
|
||||
c := binary.LittleEndian.Uint64(val[16:24])
|
||||
|
||||
val, err = thread.readMemory(uintptr(a), uintptr(8*l))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
members := make([]uint64, 0, l)
|
||||
buf := bytes.NewBuffer(val)
|
||||
for {
|
||||
err := binary.Read(buf, binary.LittleEndian, &number)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
members = append(members, number)
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("len: %d cap: %d %d", l, c, members)
|
||||
|
||||
return str, err
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readIntArray(addr uintptr, t *dwarf.ArrayType) (string, error) {
|
||||
var (
|
||||
number uint64
|
||||
members = make([]uint64, 0, t.ByteSize)
|
||||
)
|
||||
|
||||
val, err := thread.readMemory(addr, uintptr(t.ByteSize))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(val)
|
||||
for {
|
||||
err := binary.Read(buf, binary.LittleEndian, &number)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
members = append(members, number)
|
||||
}
|
||||
|
||||
str := fmt.Sprintf("[%d]int %d", t.ByteSize/8, members)
|
||||
|
||||
return str, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readInt(addr uintptr) (string, error) {
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
n := binary.LittleEndian.Uint64(val)
|
||||
|
||||
return strconv.Itoa(int(n)), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readFloat64(addr uintptr) (string, error) {
|
||||
var n float64
|
||||
val, err := thread.readMemory(addr, 8)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf := bytes.NewBuffer(val)
|
||||
binary.Read(buf, binary.LittleEndian, &n)
|
||||
|
||||
return strconv.FormatFloat(n, 'f', -1, 64), nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) readMemory(addr uintptr, size uintptr) ([]byte, error) {
|
||||
buf := make([]byte, size)
|
||||
|
||||
_, err := syscall.PtracePeekData(thread.Id, addr, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (thread *ThreadContext) handleResult(err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ps, err := wait(thread.Process, thread.Id, 0)
|
||||
if err != nil && err != syscall.ECHILD {
|
||||
return err
|
||||
}
|
||||
|
||||
if ps != nil {
|
||||
thread.Status = ps
|
||||
if ps.TrapCause() == -1 && !ps.Exited() {
|
||||
regs, err := thread.Registers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("traced program %s at: %#v\n", ps.StopSignal(), regs.PC())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
60
proctl/variables_test.go
Normal file
60
proctl/variables_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
package proctl_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/derekparker/delve/helper"
|
||||
"github.com/derekparker/delve/proctl"
|
||||
)
|
||||
|
||||
func TestVariableEvaluation(t *testing.T) {
|
||||
executablePath := "../_fixtures/testvariables"
|
||||
|
||||
fp, err := filepath.Abs(executablePath + ".go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
value string
|
||||
varType string
|
||||
}{
|
||||
{"a1", "foo", "struct string"},
|
||||
{"a2", "6", "int"},
|
||||
{"a3", "7.23", "float64"},
|
||||
{"a4", "[2]int [1 2]", "[97]int"},
|
||||
{"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"},
|
||||
{"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"},
|
||||
{"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"},
|
||||
{"baz", "bazburzum", "struct string"},
|
||||
}
|
||||
|
||||
helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) {
|
||||
pc, _, _ := p.GoSymTable.LineToPC(fp, 21)
|
||||
|
||||
_, err := p.Break(uintptr(pc))
|
||||
assertNoError(err, t, "Break() returned an error")
|
||||
|
||||
err = p.Continue()
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
variable, err := p.EvalSymbol(tc.name)
|
||||
assertNoError(err, t, "Variable() returned an error")
|
||||
|
||||
if variable.Name != tc.name {
|
||||
t.Fatalf("Expected %s got %s\n", tc.name, variable.Name)
|
||||
}
|
||||
|
||||
if variable.Type != tc.varType {
|
||||
t.Fatalf("Expected %s got %s\n", tc.varType, variable.Type)
|
||||
}
|
||||
|
||||
if variable.Value != tc.value {
|
||||
t.Fatalf("Expected %#v got %#v\n", tc.value, variable.Value)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user