Implement support for struct evaluation
This commit is contained in:
parent
6562b2e531
commit
f0e0d0b8fd
@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@ -131,55 +132,6 @@ func (dbp *DebuggedProcess) Registers() (*syscall.PtraceRegs, error) {
|
||||
return dbp.Regs, nil
|
||||
}
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (dbp *DebuggedProcess) EvalSymbol(name string) (*Variable, error) {
|
||||
data, err := dbp.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 {
|
||||
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 := dbp.extractValue(instructions, 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)
|
||||
}
|
||||
|
||||
// Sets a breakpoint in the running process.
|
||||
func (dbp *DebuggedProcess) Break(addr uintptr) (*BreakPoint, error) {
|
||||
var (
|
||||
@ -401,10 +353,65 @@ func (dbp *DebuggedProcess) clearTempBreakpoint(pc uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the value of the named symbol.
|
||||
func (dbp *DebuggedProcess) EvalSymbol(name string) (*Variable, error) {
|
||||
data, err := dbp.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 {
|
||||
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
|
||||
}
|
||||
|
||||
// If we have a user defined type, find the
|
||||
// underlying concrete type and use that.
|
||||
if tt, ok := t.(*dwarf.TypedefType); ok {
|
||||
t = tt.Type
|
||||
}
|
||||
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := dbp.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 (dbp *DebuggedProcess) extractValue(instructions []byte, typ interface{}) (string, error) {
|
||||
func (dbp *DebuggedProcess) extractValue(instructions []byte, off int64, typ interface{}) (string, error) {
|
||||
regs, err := dbp.Registers()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -418,27 +425,44 @@ func (dbp *DebuggedProcess) extractValue(instructions []byte, typ interface{}) (
|
||||
fctx := fde.EstablishFrame(regs.PC())
|
||||
cfaOffset := fctx.CFAOffset()
|
||||
|
||||
off, err := op.ExecuteStackProgram(cfaOffset, instructions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
offset := off
|
||||
if off == 0 {
|
||||
offset, err = op.ExecuteStackProgram(cfaOffset, instructions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
offset = int64(regs.Rsp) + offset
|
||||
}
|
||||
|
||||
offset := uintptr(int64(regs.Rsp) + off)
|
||||
|
||||
offaddr := uintptr(offset)
|
||||
switch t := typ.(type) {
|
||||
case *dwarf.StructType:
|
||||
switch t.StructName {
|
||||
case "string":
|
||||
return dbp.readString(offset)
|
||||
return dbp.readString(offaddr)
|
||||
case "[]int":
|
||||
return dbp.readIntSlice(offset)
|
||||
return dbp.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 := dbp.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 dbp.readIntArray(offset, t)
|
||||
return dbp.readIntArray(offaddr, t)
|
||||
case *dwarf.IntType:
|
||||
return dbp.readInt(offset)
|
||||
return dbp.readInt(offaddr)
|
||||
case *dwarf.FloatType:
|
||||
return dbp.readFloat64(offset)
|
||||
return dbp.readFloat64(offaddr)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("could not find value for type %s", typ)
|
||||
|
||||
@ -263,6 +263,7 @@ func TestVariableEvaluation(t *testing.T) {
|
||||
{"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}", "struct main.FooBar"},
|
||||
}
|
||||
|
||||
helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user