proc/variables: Split address calculations from value extraction

Refactored variables.go to separate calculation of a variable's address from
reading its value. This change is useful to implement the 'set' command
as well as the evaluation of more complex expressions (in the future).
This commit is contained in:
aarzilli
2015-09-28 11:17:27 +02:00
parent bba999b985
commit 8d920931e1
2 changed files with 261 additions and 232 deletions

View File

@ -23,11 +23,20 @@ const (
ChanSend = "chan send" ChanSend = "chan send"
) )
// Represents an evaluated variable. // Represents a variable.
type Variable struct { type Variable struct {
Addr uintptr
Name string Name string
Value string Value string
Type string Type string
dwarfType dwarf.Type
thread *Thread
Len int64
Cap int64
base uintptr
stride int64
fieldType dwarf.Type
} }
// Represents a runtime M (OS thread) structure. // Represents a runtime M (OS thread) structure.
@ -80,6 +89,46 @@ type EvalScope struct {
CFA int64 CFA int64
} }
func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread) (*Variable, error) {
v := &Variable{
Name: name,
Addr: addr,
dwarfType: dwarfType,
thread: thread,
Type: dwarfType.String(),
}
switch t := dwarfType.(type) {
case *dwarf.StructType:
if strings.HasPrefix(t.StructName, "[]") {
err := v.loadSliceInfo(t)
if err != nil {
return nil, err
}
}
case *dwarf.ArrayType:
v.base = v.Addr
v.Len = t.Count
v.Cap = -1
v.fieldType = t.Type
v.stride = 0
if t.Count > 0 {
v.stride = t.ByteSize / t.Count
}
}
return v, nil
}
func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) {
name := ""
if v.Name != "" {
name = fmt.Sprintf("%s.%s", v.Name, field.Name)
}
return newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type, v.thread)
}
func (scope *EvalScope) DwarfReader() *reader.Reader { func (scope *EvalScope) DwarfReader() *reader.Reader {
return scope.Thread.dbp.DwarfReader() return scope.Thread.dbp.DwarfReader()
} }
@ -241,15 +290,8 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) {
return g, nil return g, nil
} }
// Returns the value of the named variable. // Returns the address of the named variable
func (scope *EvalScope) EvalVariable(name string) (*Variable, error) { func (scope *EvalScope) ExtractVariableInfo(name string) (*Variable, error) {
reader := scope.DwarfReader()
_, err := reader.SeekToFunction(scope.PC)
if err != nil {
return nil, err
}
varName := name varName := name
memberName := "" memberName := ""
if strings.Contains(name, ".") { if strings.Contains(name, ".") {
@ -258,6 +300,61 @@ func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
memberName = name[idx+1:] memberName = name[idx+1:]
} }
addr, err := scope.extractVarInfo(varName)
if err != nil {
origErr := err
// Attempt to evaluate name as a package variable.
if memberName != "" {
addr, err = scope.packageVarAddr(name)
} else {
_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
if fn != nil {
addr, err = scope.packageVarAddr(fn.PackageName() + "." + name)
}
}
if err != nil {
return nil, origErr
}
addr.Name = name
} else {
if len(memberName) > 0 {
addr, err = addr.structMember(memberName)
if err != nil {
return nil, err
}
}
}
return addr, nil
}
// Returns the value of the named variable.
func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
addr, err := scope.ExtractVariableInfo(name)
if err != nil {
return nil, err
}
err = addr.loadValue(true)
return addr, err
}
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
rdr := scope.DwarfReader()
addr, err := scope.extractVarInfoFromEntry(entry, rdr)
if err != nil {
return nil, err
}
err = addr.loadValue(true)
return addr, err
}
func (scope *EvalScope) extractVarInfo(varName string) (*Variable, error) {
reader := scope.DwarfReader()
_, err := reader.SeekToFunction(scope.PC)
if err != nil {
return nil, err
}
for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() { for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
if err != nil { if err != nil {
return nil, err return nil, err
@ -269,28 +366,10 @@ func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
} }
if n == varName { if n == varName {
if len(memberName) == 0 { return scope.extractVarInfoFromEntry(entry, reader)
return scope.extractVariableFromEntry(entry)
}
return scope.evaluateStructMember(entry, reader, memberName)
} }
} }
return nil, fmt.Errorf("could not find symbol value for %s", varName)
// Attempt to evaluate name as a package variable.
if memberName != "" {
return scope.Thread.dbp.EvalPackageVariable(name)
} else {
_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
if fn != nil {
v, err := scope.Thread.dbp.EvalPackageVariable(fn.PackageName() + "." + name)
if err == nil {
v.Name = name
return v, nil
}
}
}
return nil, fmt.Errorf("could not find symbol value for %s", name)
} }
// LocalVariables returns all local variables from the current function scope. // LocalVariables returns all local variables from the current function scope.
@ -326,9 +405,18 @@ func (scope *EvalScope) PackageVariables() ([]*Variable, error) {
} }
func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) { func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) {
reader := dbp.DwarfReader()
scope := &EvalScope{Thread: dbp.CurrentThread, PC: 0, CFA: 0} scope := &EvalScope{Thread: dbp.CurrentThread, PC: 0, CFA: 0}
addr, err := scope.packageVarAddr(name)
if err != nil {
return nil, err
}
err = addr.loadValue(true)
return addr, err
}
func (scope *EvalScope) packageVarAddr(name string) (*Variable, error) {
reader := scope.DwarfReader()
for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() { for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
if err != nil { if err != nil {
return nil, err return nil, err
@ -340,80 +428,40 @@ func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) {
} }
if n == name { if n == name {
return scope.extractVariableFromEntry(entry) return scope.extractVarInfoFromEntry(entry, reader)
} }
} }
return nil, fmt.Errorf("could not find symbol value for %s", name) return nil, fmt.Errorf("could not find symbol value for %s", name)
} }
func (scope *EvalScope) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) { func (v *Variable) structMember(memberName string) (*Variable, error) {
parentAddr, err := scope.extractVariableDataAddress(parentEntry, rdr) structVar, err := v.maybeDereference()
structVar.Name = v.Name
if err != nil { if err != nil {
return nil, err return nil, err
} }
structVar = structVar.resolveTypedefs()
// Get parent variable name switch t := structVar.dwarfType.(type) {
parentName, ok := parentEntry.Val(dwarf.AttrName).(string) case *dwarf.StructType:
if !ok { for _, field := range t.Field {
return nil, fmt.Errorf("unable to retrive variable name") if field.Name != memberName {
}
// Seek reader to the type information so members can be iterated
_, err = rdr.SeekToType(parentEntry, true, true)
if err != nil {
return nil, err
}
// Iterate to find member by name
for memberEntry, err := rdr.NextMemberVariable(); memberEntry != nil; memberEntry, err = rdr.NextMemberVariable() {
if err != nil {
return nil, err
}
name, ok := memberEntry.Val(dwarf.AttrName).(string)
if !ok {
continue continue
} }
if structVar.Addr == 0 {
if name == memberName { return nil, fmt.Errorf("%s is nil", v.Name)
// Nil ptr, wait until here to throw a nil pointer error to prioritize no such member error
if parentAddr == 0 {
return nil, fmt.Errorf("%s is nil", parentName)
} }
return structVar.toField(field)
memberInstr, err := rdr.InstructionsForEntry(memberEntry)
if err != nil {
return nil, err
} }
return nil, fmt.Errorf("%s has no member %s", v.Name, memberName)
offset, ok := memberEntry.Val(dwarf.AttrType).(dwarf.Offset) default:
if !ok { return nil, fmt.Errorf("%s type %s is not a struct", v.Name, structVar.dwarfType)
return nil, fmt.Errorf("type assertion failed")
} }
t, err := scope.Type(offset)
if err != nil {
return nil, err
}
baseAddr := make([]byte, 8)
binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr))
parentInstructions := append([]byte{op.DW_OP_addr}, baseAddr...)
val, err := scope.extractValue(append(parentInstructions, memberInstr...), 0, t, true)
if err != nil {
return nil, err
}
return &Variable{Name: strings.Join([]string{parentName, memberName}, "."), Type: t.String(), Value: val}, nil
}
}
return nil, fmt.Errorf("%s has no member %s", parentName, memberName)
} }
// Extracts the name, type, and value of a variable from a dwarf entry // Extracts the name and type of a variable from a dwarf entry
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) { // then executes the instructions given in the DW_AT_location attribute to grab the variable's address
func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry, rdr *reader.Reader) (*Variable, error) {
if entry == nil { if entry == nil {
return nil, fmt.Errorf("invalid entry") return nil, fmt.Errorf("invalid entry")
} }
@ -442,67 +490,34 @@ func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable,
return nil, fmt.Errorf("type assertion failed") return nil, fmt.Errorf("type assertion failed")
} }
val, err := scope.extractValue(instructions, 0, t, true) addr, err := op.ExecuteStackProgram(scope.CFA, instructions)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Variable{Name: n, Type: t.String(), Value: val}, nil return newVariable(n, uintptr(addr), t, scope.Thread)
} }
// Extracts the address of a variable, dereferencing any pointers // If addr is a pointer a new variable is returned containing the value pointed by addr
func (scope *EvalScope) extractVariableDataAddress(entry *dwarf.Entry, rdr *reader.Reader) (int64, error) { func (v *Variable) maybeDereference() (*Variable, error) {
instructions, err := rdr.InstructionsForEntry(entry) v = v.resolveTypedefs()
switch t := v.dwarfType.(type) {
case *dwarf.PtrType:
ptrval, err := v.thread.readUintRaw(uintptr(v.Addr), int64(v.thread.dbp.arch.PtrSize()))
if err != nil { if err != nil {
return 0, err return nil, err
} }
address, err := op.ExecuteStackProgram(scope.CFA, instructions) return newVariable("", uintptr(ptrval), t.Type, v.thread)
if err != nil { default:
return 0, err return v, nil
} }
// Dereference pointers to get down the concrete type
for typeEntry, err := rdr.SeekToType(entry, true, false); typeEntry != nil; typeEntry, err = rdr.SeekToType(typeEntry, true, false) {
if err != nil {
return 0, err
}
if typeEntry.Tag != dwarf.TagPointerType {
break
}
ptraddress := uintptr(address)
ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize())
if err != nil {
return 0, err
}
address = int64(binary.LittleEndian.Uint64(ptr))
}
return address, nil
} }
// Extracts the value from the instructions given in the DW_AT_location entry. // Returns a VarAddr with the same address but a concrete dwarfType
// We execute the stack program described in the DW_OP_* instruction stream, and func (v *Variable) resolveTypedefs() *Variable {
// then grab the value from the other processes memory. typ := v.dwarfType
func (scope *EvalScope) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) {
return scope.extractValueInternal(instructions, addr, typ, printStructName, 0)
}
func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, typ interface{}, printStructName bool, recurseLevel int) (string, error) {
var err error
if addr == 0 {
addr, err = op.ExecuteStackProgram(scope.CFA, instructions)
if err != nil {
return "", err
}
}
// If we have a user defined type, find the
// underlying concrete type and use that.
for { for {
if tt, ok := typ.(*dwarf.TypedefType); ok { if tt, ok := typ.(*dwarf.TypedefType); ok {
typ = tt.Type typ = tt.Type
@ -510,22 +525,33 @@ func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, ty
break break
} }
} }
r := *v
r.dwarfType = typ
return &r
}
ptraddress := uintptr(addr) // Extracts the value of the given address
switch t := typ.(type) { func (v *Variable) loadValue(printStructName bool) (err error) {
v.Value, err = v.loadValueInternal(printStructName, 0)
return
}
func (v *Variable) loadValueInternal(printStructName bool, recurseLevel int) (string, error) {
v = v.resolveTypedefs()
switch t := v.dwarfType.(type) {
case *dwarf.PtrType: case *dwarf.PtrType:
ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize()) ptrv, err := v.maybeDereference()
if err != nil { if err != nil {
return "", err return "", err
} }
intaddr := int64(binary.LittleEndian.Uint64(ptr)) if ptrv.Addr == 0 {
if intaddr == 0 {
return fmt.Sprintf("%s nil", t.String()), nil return fmt.Sprintf("%s nil", t.String()), nil
} }
// Don't increase the recursion level when dereferencing pointers // Don't increase the recursion level when dereferencing pointers
val, err := scope.extractValueInternal(nil, intaddr, t.Type, printStructName, recurseLevel) val, err := ptrv.loadValueInternal(printStructName, recurseLevel)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -534,9 +560,9 @@ func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, ty
case *dwarf.StructType: case *dwarf.StructType:
switch { switch {
case t.StructName == "string": case t.StructName == "string":
return scope.Thread.readString(ptraddress) return v.thread.readString(uintptr(v.Addr))
case strings.HasPrefix(t.StructName, "[]"): case strings.HasPrefix(t.StructName, "[]"):
return scope.readSlice(ptraddress, t, recurseLevel) return v.loadArrayValues(recurseLevel)
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.
@ -544,7 +570,14 @@ func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, ty
errcount := 0 errcount := 0
fields := make([]string, 0, len(t.Field)) fields := make([]string, 0, len(t.Field))
for i, field := range t.Field { for i, field := range t.Field {
val, err := scope.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1) var err error
var val string
var fieldvar *Variable
fieldvar, err = v.toField(field)
if err == nil {
val, err = fieldvar.loadValueInternal(printStructName, recurseLevel+1)
}
if err != nil { if err != nil {
errcount++ errcount++
val = fmt.Sprintf("<unreadable: %s>", err.Error()) val = fmt.Sprintf("<unreadable: %s>", err.Error())
@ -568,19 +601,19 @@ func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, ty
return "{...}", nil return "{...}", nil
} }
case *dwarf.ArrayType: case *dwarf.ArrayType:
return scope.readArray(ptraddress, t, recurseLevel) return v.loadArrayValues(recurseLevel)
case *dwarf.ComplexType: case *dwarf.ComplexType:
return scope.Thread.readComplex(ptraddress, t.ByteSize) return v.readComplex(t.ByteSize)
case *dwarf.IntType: case *dwarf.IntType:
return scope.Thread.readInt(ptraddress, t.ByteSize) return v.readInt(t.ByteSize)
case *dwarf.UintType: case *dwarf.UintType:
return scope.Thread.readUint(ptraddress, t.ByteSize) return v.readUint(t.ByteSize)
case *dwarf.FloatType: case *dwarf.FloatType:
return scope.Thread.readFloat(ptraddress, t.ByteSize) return v.readFloat(t.ByteSize)
case *dwarf.BoolType: case *dwarf.BoolType:
return scope.Thread.readBool(ptraddress) return v.readBool()
case *dwarf.FuncType: case *dwarf.FuncType:
return scope.Thread.readFunctionPtr(ptraddress) return v.readFunctionPtr()
case *dwarf.VoidType: case *dwarf.VoidType:
return "(void)", nil return "(void)", nil
case *dwarf.UnspecifiedType: case *dwarf.UnspecifiedType:
@ -589,7 +622,7 @@ func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, ty
fmt.Printf("Unknown type: %T\n", t) fmt.Printf("Unknown type: %T\n", t)
} }
return "", fmt.Errorf("could not find value for type %s", typ) return "", fmt.Errorf("could not find value for type %s", v.dwarfType)
} }
func (thread *Thread) readString(addr uintptr) (string, error) { func (thread *Thread) readString(addr uintptr) (string, error) {
@ -635,95 +668,89 @@ func (thread *Thread) readString(addr uintptr) (string, error) {
return retstr, nil return retstr, nil
} }
func (scope *EvalScope) readSlice(addr uintptr, t *dwarf.StructType, recurseLevel int) (string, error) { func (v *Variable) loadSliceInfo(t *dwarf.StructType) error {
var sliceLen, sliceCap int64 var err error
var arrayAddr uintptr
var arrayType dwarf.Type
for _, f := range t.Field { for _, f := range t.Field {
switch f.Name { switch f.Name {
case "array": case "array":
val, err := scope.Thread.readMemory(addr+uintptr(f.ByteOffset), scope.PtrSize()) var base uint64
if err != nil { base, err = v.thread.readUintRaw(uintptr(int64(v.Addr)+f.ByteOffset), int64(v.thread.dbp.arch.PtrSize()))
return "", err if err == nil {
} v.base = uintptr(base)
arrayAddr = uintptr(binary.LittleEndian.Uint64(val))
// Dereference array type to get value type // Dereference array type to get value type
ptrType, ok := f.Type.(*dwarf.PtrType) ptrType, ok := f.Type.(*dwarf.PtrType)
if !ok { if !ok {
return "", fmt.Errorf("Invalid type %s in slice array", f.Type) return fmt.Errorf("Invalid type %s in slice array", f.Type)
}
v.fieldType = ptrType.Type
} }
arrayType = ptrType.Type
case "len": case "len":
lstr, err := scope.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) lstrAddr, err := v.toField(f)
if err != nil { if err == nil {
return "", err err = lstrAddr.loadValue(true)
} }
sliceLen, err = strconv.ParseInt(lstr, 10, 64) if err == nil {
if err != nil { v.Len, err = strconv.ParseInt(lstrAddr.Value, 10, 64)
return "", err
} }
case "cap": case "cap":
cstr, err := scope.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true) cstrAddr, err := v.toField(f)
if err != nil { if err == nil {
return "", err err = cstrAddr.loadValue(true)
} }
sliceCap, err = strconv.ParseInt(cstr, 10, 64) if err == nil {
if err != nil { v.Cap, err = strconv.ParseInt(cstrAddr.Value, 10, 64)
return "", err
} }
} }
} }
stride := arrayType.Size()
if _, ok := arrayType.(*dwarf.PtrType); ok {
stride = int64(scope.PtrSize())
}
vals, err := scope.readArrayValues(arrayAddr, sliceLen, stride, arrayType, recurseLevel)
if err != nil { if err != nil {
return "", err return nil
} }
return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", arrayType, sliceLen, sliceCap, strings.Join(vals, ",")), nil v.stride = v.fieldType.Size()
if _, ok := v.fieldType.(*dwarf.PtrType); ok {
v.stride = int64(v.thread.dbp.arch.PtrSize())
}
return nil
} }
func (scope *EvalScope) readArray(addr uintptr, t *dwarf.ArrayType, recurseLevel int) (string, error) { func (v *Variable) loadArrayValues(recurseLevel int) (string, error) {
if t.Count > 0 {
vals, err := scope.readArrayValues(addr, t.Count, t.ByteSize/t.Count, t.Type, recurseLevel)
if err != nil {
return "", err
}
return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil
}
// because you can declare a zero-size array
return fmt.Sprintf("%s []", t), nil
}
func (scope *EvalScope) readArrayValues(addr uintptr, count int64, stride int64, t dwarf.Type, recurseLevel int) ([]string, error) {
vals := make([]string, 0) vals := make([]string, 0)
errcount := 0 errcount := 0
for i := int64(0); i < count; i++ { for i := int64(0); i < v.Len; i++ {
// Cap number of elements // Cap number of elements
if i >= maxArrayValues { if i >= maxArrayValues {
vals = append(vals, fmt.Sprintf("...+%d more", count-maxArrayValues)) vals = append(vals, fmt.Sprintf("...+%d more", v.Len-maxArrayValues))
break break
} }
val, err := scope.extractValueInternal(nil, int64(addr+uintptr(i*stride)), t, false, recurseLevel+1) var val string
fieldvar, err := newVariable("", uintptr(int64(v.base)+(i*v.stride)), v.fieldType, v.thread)
if err == nil {
val, err = fieldvar.loadValueInternal(false, recurseLevel+1)
}
if err != nil { if err != nil {
errcount++ errcount++
val = fmt.Sprintf("<unreadable: %s>", err.Error()) val = fmt.Sprintf("<unreadable: %s>", err.Error())
} }
vals = append(vals, val) vals = append(vals, val)
if errcount > maxErrCount { if errcount > maxErrCount {
vals = append(vals, fmt.Sprintf("...+%d more", count-i)) vals = append(vals, fmt.Sprintf("...+%d more", v.Len-i))
break break
} }
} }
return vals, nil
if v.Cap < 0 {
return fmt.Sprintf("%s [%s]", v.dwarfType, strings.Join(vals, ",")), nil
} else {
return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", v.fieldType, v.Len, v.Cap, strings.Join(vals, ",")), nil
}
} }
func (thread *Thread) readComplex(addr uintptr, size int64) (string, error) { func (v *Variable) readComplex(size int64) (string, error) {
var fs int64 var fs int64
switch size { switch size {
case 8: case 8:
@ -733,19 +760,21 @@ func (thread *Thread) readComplex(addr uintptr, size int64) (string, error) {
default: default:
return "", fmt.Errorf("invalid size (%d) for complex type", size) return "", fmt.Errorf("invalid size (%d) for complex type", size)
} }
r, err := thread.readFloat(addr, fs) r, err := v.readFloat(fs)
if err != nil { if err != nil {
return "", err return "", err
} }
i, err := thread.readFloat(addr+uintptr(fs), fs) imagvar := *v
imagvar.Addr += uintptr(fs)
i, err := imagvar.readFloat(fs)
if err != nil { if err != nil {
return "", err return "", err
} }
return fmt.Sprintf("(%s, %si)", r, i), nil return fmt.Sprintf("(%s + %si)", r, i), nil
} }
func (thread *Thread) readInt(addr uintptr, size int64) (string, error) { func (v *Variable) readInt(size int64) (string, error) {
n, err := thread.readIntRaw(addr, size) n, err := v.thread.readIntRaw(v.Addr, size)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -774,8 +803,8 @@ func (thread *Thread) readIntRaw(addr uintptr, size int64) (int64, error) {
return n, nil return n, nil
} }
func (thread *Thread) readUint(addr uintptr, size int64) (string, error) { func (v *Variable) readUint(size int64) (string, error) {
n, err := thread.readUintRaw(addr, size) n, err := v.thread.readUintRaw(v.Addr, size)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -804,8 +833,8 @@ func (thread *Thread) readUintRaw(addr uintptr, size int64) (uint64, error) {
return n, nil return n, nil
} }
func (thread *Thread) readFloat(addr uintptr, size int64) (string, error) { func (v *Variable) readFloat(size int64) (string, error) {
val, err := thread.readMemory(addr, int(size)) val, err := v.thread.readMemory(v.Addr, int(size))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -825,8 +854,8 @@ func (thread *Thread) readFloat(addr uintptr, size int64) (string, error) {
return "", fmt.Errorf("could not read float") return "", fmt.Errorf("could not read float")
} }
func (thread *Thread) readBool(addr uintptr) (string, error) { func (v *Variable) readBool() (string, error) {
val, err := thread.readMemory(addr, 1) val, err := v.thread.readMemory(v.Addr, 1)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -838,25 +867,25 @@ func (thread *Thread) readBool(addr uintptr) (string, error) {
return "true", nil return "true", nil
} }
func (thread *Thread) readFunctionPtr(addr uintptr) (string, error) { func (v *Variable) readFunctionPtr() (string, error) {
val, err := thread.readMemory(addr, thread.dbp.arch.PtrSize()) val, err := v.thread.readMemory(v.Addr, v.thread.dbp.arch.PtrSize())
if err != nil { if err != nil {
return "", err return "", err
} }
// dereference pointer to find function pc // dereference pointer to find function pc
addr = uintptr(binary.LittleEndian.Uint64(val)) fnaddr := uintptr(binary.LittleEndian.Uint64(val))
if addr == 0 { if fnaddr == 0 {
return "nil", nil return "nil", nil
} }
val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize()) val, err = v.thread.readMemory(fnaddr, v.thread.dbp.arch.PtrSize())
if err != nil { if err != nil {
return "", err return "", err
} }
funcAddr := binary.LittleEndian.Uint64(val) funcAddr := binary.LittleEndian.Uint64(val)
fn := thread.dbp.goSymTable.PCToFunc(uint64(funcAddr)) fn := v.thread.dbp.goSymTable.PCToFunc(uint64(funcAddr))
if fn == nil { if fn == nil {
return "", fmt.Errorf("could not find function for %#v", funcAddr) return "", fmt.Errorf("could not find function for %#v", funcAddr)
} }

View File

@ -58,8 +58,8 @@ func TestVariableEvaluation(t *testing.T) {
{"baz", "bazburzum", "struct string", nil}, {"baz", "bazburzum", "struct string", nil},
{"neg", "-1", "int", nil}, {"neg", "-1", "int", nil},
{"f32", "1.2", "float32", nil}, {"f32", "1.2", "float32", nil},
{"c64", "(1, 2i)", "complex64", nil}, {"c64", "(1 + 2i)", "complex64", nil},
{"c128", "(2, 3i)", "complex128", nil}, {"c128", "(2 + 3i)", "complex128", nil},
{"a6.Baz", "8", "int", nil}, {"a6.Baz", "8", "int", nil},
{"a7.Baz", "5", "int", nil}, {"a7.Baz", "5", "int", nil},
{"a8.Baz", "feh", "struct string", nil}, {"a8.Baz", "feh", "struct string", nil},
@ -181,8 +181,8 @@ func TestLocalVariables(t *testing.T) {
{"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}, {"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},
{"c128", "(2, 3i)", "complex128", nil}, {"c128", "(2 + 3i)", "complex128", nil},
{"c64", "(1, 2i)", "complex64", nil}, {"c64", "(1 + 2i)", "complex64", 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},