2015-06-12 19:49:23 +00:00
|
|
|
package proc
|
2014-10-25 15:48:14 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-11-24 23:27:56 +00:00
|
|
|
"debug/dwarf"
|
2014-10-25 15:48:14 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
2015-10-21 07:06:36 +00:00
|
|
|
"go/constant"
|
2015-09-28 10:01:18 +00:00
|
|
|
"go/parser"
|
|
|
|
"go/token"
|
2015-10-18 17:37:13 +00:00
|
|
|
"reflect"
|
2014-10-25 15:48:14 +00:00
|
|
|
"strings"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/derekparker/delve/dwarf/op"
|
2014-12-31 21:13:28 +00:00
|
|
|
"github.com/derekparker/delve/dwarf/reader"
|
2014-10-25 15:48:14 +00:00
|
|
|
)
|
|
|
|
|
2015-02-02 07:13:42 +00:00
|
|
|
const (
|
2015-04-22 13:18:25 +00:00
|
|
|
maxVariableRecurse = 1 // How far to recurse when evaluating nested types.
|
|
|
|
maxArrayValues = 64 // Max value for reading large arrays.
|
2015-09-20 06:27:25 +00:00
|
|
|
maxErrCount = 3 // Max number of read errors to accept while evaluating slices, arrays and structs
|
2016-01-10 12:49:03 +00:00
|
|
|
|
|
|
|
maxArrayStridePrefetch = 1024 // Maximum size of array stride for which we will prefetch the array contents
|
2015-04-19 22:11:33 +00:00
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
chanRecv = "chan receive"
|
|
|
|
chanSend = "chan send"
|
2015-11-05 17:25:52 +00:00
|
|
|
|
|
|
|
hashTophashEmpty = 0 // used by map reading code, indicates an empty bucket
|
|
|
|
hashMinTopHash = 4 // used by map reading code, indicates minimum value of tophash that isn't empty or evacuated
|
2015-02-02 07:13:42 +00:00
|
|
|
)
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// Variable represents a variable. It contains the address, name,
|
|
|
|
// type and other information parsed from both the Dwarf information
|
|
|
|
// and the memory of the debugged process.
|
|
|
|
// If OnlyAddr is true, the variables value has not been loaded.
|
2014-10-25 15:48:14 +00:00
|
|
|
type Variable struct {
|
2015-09-28 09:17:27 +00:00
|
|
|
Addr uintptr
|
2015-10-30 11:39:32 +00:00
|
|
|
OnlyAddr bool
|
2015-09-28 09:17:27 +00:00
|
|
|
Name string
|
2015-10-18 17:37:13 +00:00
|
|
|
DwarfType dwarf.Type
|
|
|
|
RealType dwarf.Type
|
|
|
|
Kind reflect.Kind
|
2016-01-10 12:49:03 +00:00
|
|
|
mem memoryReadWriter
|
|
|
|
dbp *Process
|
2015-09-28 09:17:27 +00:00
|
|
|
|
2015-10-21 07:06:36 +00:00
|
|
|
Value constant.Value
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
Len int64
|
|
|
|
Cap int64
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
// base address of arrays, base address of the backing array for slices (0 for nil slices)
|
|
|
|
// base address of the backing byte array for strings
|
2015-11-05 17:25:52 +00:00
|
|
|
// address of the struct backing chan and map variables
|
2015-10-30 11:39:32 +00:00
|
|
|
// address of the function entry point for function variables (0 for nil function pointers)
|
2015-09-28 09:17:27 +00:00
|
|
|
base uintptr
|
|
|
|
stride int64
|
|
|
|
fieldType dwarf.Type
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
// number of elements to skip when loading a map
|
|
|
|
mapSkip int
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
Children []Variable
|
|
|
|
|
|
|
|
loaded bool
|
|
|
|
Unreadable error
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// M represents a runtime M (OS thread) structure.
|
2014-11-27 02:35:53 +00:00
|
|
|
type M struct {
|
2015-04-22 13:18:25 +00:00
|
|
|
procid int // Thread ID or port.
|
|
|
|
spinning uint8 // Busy looping.
|
|
|
|
blocked uint8 // Waiting on futex / semaphore.
|
|
|
|
curg uintptr // Current G running on this thread.
|
2014-11-27 02:35:53 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// G status, from: src/runtime/runtime2.go
|
2015-09-17 17:42:05 +00:00
|
|
|
const (
|
2016-01-10 08:57:52 +00:00
|
|
|
Gidle uint64 = iota // 0
|
|
|
|
Grunnable // 1 runnable and on a run queue
|
|
|
|
Grunning // 2
|
|
|
|
Gsyscall // 3
|
|
|
|
Gwaiting // 4
|
|
|
|
GmoribundUnused // 5 currently unused, but hardcoded in gdb scripts
|
|
|
|
Gdead // 6
|
|
|
|
Genqueue // 7 Only the Gscanenqueue is used.
|
|
|
|
Gcopystack // 8 in this state when newstack is moving the stack
|
2015-09-17 17:42:05 +00:00
|
|
|
)
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// G represents a runtime G (goroutine) structure (at least the
|
2015-04-22 13:18:25 +00:00
|
|
|
// fields that Delve is interested in).
|
2015-03-28 01:12:07 +00:00
|
|
|
type G struct {
|
2016-01-10 08:57:52 +00:00
|
|
|
ID int // Goroutine ID
|
2015-04-22 13:18:25 +00:00
|
|
|
PC uint64 // PC of goroutine when it was parked.
|
|
|
|
SP uint64 // SP of goroutine when it was parked.
|
|
|
|
GoPC uint64 // PC of 'go' statement that created this goroutine.
|
|
|
|
WaitReason string // Reason for goroutine being parked.
|
2015-09-17 17:42:05 +00:00
|
|
|
Status uint64
|
2015-04-22 13:18:25 +00:00
|
|
|
|
2015-10-16 06:42:02 +00:00
|
|
|
// Information on goroutine location
|
2015-10-18 22:02:14 +00:00
|
|
|
CurrentLoc Location
|
2015-05-09 17:44:38 +00:00
|
|
|
|
|
|
|
// PC of entry to top-most deferred function.
|
|
|
|
DeferPC uint64
|
2015-06-17 17:11:57 +00:00
|
|
|
|
|
|
|
// Thread that this goroutine is currently allocated to
|
|
|
|
thread *Thread
|
2015-10-16 06:42:02 +00:00
|
|
|
|
|
|
|
dbp *Process
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// EvalScope is the scope for variable evaluation. Contains the thread,
|
|
|
|
// current location (PC), and canonical frame address.
|
2015-08-28 20:06:29 +00:00
|
|
|
type EvalScope struct {
|
|
|
|
Thread *Thread
|
|
|
|
PC uint64
|
|
|
|
CFA int64
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// IsNilErr is returned when a variable is nil.
|
2015-11-12 11:30:41 +00:00
|
|
|
type IsNilErr struct {
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (err *IsNilErr) Error() string {
|
|
|
|
return fmt.Sprintf("%s is nil", err.name)
|
|
|
|
}
|
|
|
|
|
2015-11-25 13:20:07 +00:00
|
|
|
func ptrTypeKind(t *dwarf.PtrType) reflect.Kind {
|
|
|
|
structtyp, isstruct := t.Type.(*dwarf.StructType)
|
|
|
|
_, isvoid := t.Type.(*dwarf.VoidType)
|
|
|
|
if isstruct && strings.HasPrefix(structtyp.StructName, "hchan<") {
|
|
|
|
return reflect.Chan
|
|
|
|
} else if isstruct && strings.HasPrefix(structtyp.StructName, "hash<") {
|
|
|
|
return reflect.Map
|
|
|
|
} else if isvoid {
|
|
|
|
return reflect.UnsafePointer
|
|
|
|
}
|
2016-01-10 08:57:52 +00:00
|
|
|
return reflect.Ptr
|
2015-11-25 13:20:07 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable {
|
|
|
|
return newVariable(name, addr, dwarfType, scope.Thread.dbp, scope.Thread)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Variable) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable {
|
|
|
|
return newVariable(name, addr, dwarfType, v.dbp, v.mem)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newVariable(name string, addr uintptr, dwarfType dwarf.Type, dbp *Process, mem memoryReadWriter) *Variable {
|
2015-09-28 09:17:27 +00:00
|
|
|
v := &Variable{
|
|
|
|
Name: name,
|
|
|
|
Addr: addr,
|
2015-10-18 17:37:13 +00:00
|
|
|
DwarfType: dwarfType,
|
2016-01-10 12:49:03 +00:00
|
|
|
mem: mem,
|
|
|
|
dbp: dbp,
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2015-11-07 13:50:26 +00:00
|
|
|
v.RealType = resolveTypedef(v.DwarfType)
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
switch t := v.RealType.(type) {
|
|
|
|
case *dwarf.PtrType:
|
2015-11-25 13:20:07 +00:00
|
|
|
v.Kind = ptrTypeKind(t)
|
2015-09-28 09:17:27 +00:00
|
|
|
case *dwarf.StructType:
|
2015-10-18 17:37:13 +00:00
|
|
|
switch {
|
|
|
|
case t.StructName == "string":
|
|
|
|
v.Kind = reflect.String
|
2015-10-30 11:39:32 +00:00
|
|
|
v.stride = 1
|
2016-01-10 08:57:52 +00:00
|
|
|
v.fieldType = &dwarf.UintType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: 1, Name: "byte"}, BitSize: 8, BitOffset: 0}}
|
2015-10-30 11:39:32 +00:00
|
|
|
if v.Addr != 0 {
|
2016-01-10 12:49:03 +00:00
|
|
|
v.base, v.Len, v.Unreadable = readStringInfo(v.mem, v.dbp.arch, v.Addr)
|
2015-10-30 11:39:32 +00:00
|
|
|
}
|
2015-11-12 11:30:41 +00:00
|
|
|
case t.StructName == "runtime.iface" || t.StructName == "runtime.eface":
|
|
|
|
v.Kind = reflect.Interface
|
2015-10-18 17:37:13 +00:00
|
|
|
case strings.HasPrefix(t.StructName, "[]"):
|
|
|
|
v.Kind = reflect.Slice
|
|
|
|
if v.Addr != 0 {
|
|
|
|
v.loadSliceInfo(t)
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
default:
|
|
|
|
v.Kind = reflect.Struct
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
case *dwarf.ArrayType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Array
|
2015-09-28 09:17:27 +00:00
|
|
|
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
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
case *dwarf.ComplexType:
|
|
|
|
switch t.ByteSize {
|
|
|
|
case 8:
|
|
|
|
v.Kind = reflect.Complex64
|
|
|
|
case 16:
|
|
|
|
v.Kind = reflect.Complex128
|
|
|
|
}
|
|
|
|
case *dwarf.IntType:
|
|
|
|
v.Kind = reflect.Int
|
|
|
|
case *dwarf.UintType:
|
|
|
|
v.Kind = reflect.Uint
|
|
|
|
case *dwarf.FloatType:
|
|
|
|
switch t.ByteSize {
|
|
|
|
case 4:
|
|
|
|
v.Kind = reflect.Float32
|
|
|
|
case 8:
|
|
|
|
v.Kind = reflect.Float64
|
|
|
|
}
|
|
|
|
case *dwarf.BoolType:
|
|
|
|
v.Kind = reflect.Bool
|
|
|
|
case *dwarf.FuncType:
|
|
|
|
v.Kind = reflect.Func
|
|
|
|
case *dwarf.VoidType:
|
|
|
|
v.Kind = reflect.Invalid
|
|
|
|
case *dwarf.UnspecifiedType:
|
|
|
|
v.Kind = reflect.Invalid
|
|
|
|
default:
|
|
|
|
v.Unreadable = fmt.Errorf("Unknown type: %T", t)
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2015-11-07 13:50:26 +00:00
|
|
|
func resolveTypedef(typ dwarf.Type) dwarf.Type {
|
|
|
|
for {
|
|
|
|
if tt, ok := typ.(*dwarf.TypedefType); ok {
|
|
|
|
typ = tt.Type
|
|
|
|
} else {
|
|
|
|
return typ
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func newConstant(val constant.Value, mem memoryReadWriter) *Variable {
|
|
|
|
v := &Variable{Value: val, mem: mem, loaded: true}
|
2015-10-30 11:39:32 +00:00
|
|
|
switch val.Kind() {
|
|
|
|
case constant.Int:
|
|
|
|
v.Kind = reflect.Int
|
|
|
|
case constant.Float:
|
|
|
|
v.Kind = reflect.Float64
|
|
|
|
case constant.Bool:
|
|
|
|
v.Kind = reflect.Bool
|
|
|
|
case constant.Complex:
|
|
|
|
v.Kind = reflect.Complex128
|
|
|
|
case constant.String:
|
|
|
|
v.Kind = reflect.String
|
|
|
|
v.Len = int64(len(constant.StringVal(val)))
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
var nilVariable = &Variable{
|
|
|
|
Addr: 0,
|
|
|
|
base: 0,
|
|
|
|
Kind: reflect.Ptr,
|
|
|
|
Children: []Variable{{Addr: 0, OnlyAddr: true}},
|
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) clone() *Variable {
|
|
|
|
r := *v
|
|
|
|
return &r
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// TypeString returns the string representation
|
|
|
|
// of the type of this variable.
|
2015-11-12 11:29:53 +00:00
|
|
|
func (v *Variable) TypeString() string {
|
|
|
|
if v == nilVariable {
|
|
|
|
return "nil"
|
|
|
|
}
|
|
|
|
if v.DwarfType != nil {
|
|
|
|
return v.DwarfType.String()
|
|
|
|
}
|
|
|
|
return v.Kind.String()
|
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) {
|
2015-10-18 17:37:13 +00:00
|
|
|
if v.Unreadable != nil {
|
|
|
|
return v.clone(), nil
|
|
|
|
}
|
2015-10-07 01:21:28 +00:00
|
|
|
if v.Addr == 0 {
|
2015-11-12 11:30:41 +00:00
|
|
|
return nil, &IsNilErr{v.Name}
|
2015-10-07 01:21:28 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
name := ""
|
|
|
|
if v.Name != "" {
|
2015-10-01 00:36:36 +00:00
|
|
|
parts := strings.Split(field.Name, ".")
|
|
|
|
if len(parts) > 1 {
|
|
|
|
name = fmt.Sprintf("%s.%s", v.Name, parts[1])
|
|
|
|
} else {
|
2015-10-07 01:21:28 +00:00
|
|
|
name = fmt.Sprintf("%s.%s", v.Name, field.Name)
|
2015-10-01 00:36:36 +00:00
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
return v.newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type), nil
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// DwarfReader returns the DwarfReader containing the
|
|
|
|
// Dwarf information for the target process.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) DwarfReader() *reader.Reader {
|
|
|
|
return scope.Thread.dbp.DwarfReader()
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// Type returns the Dwarf type entry at `offset`.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) Type(offset dwarf.Offset) (dwarf.Type, error) {
|
|
|
|
return scope.Thread.dbp.dwarf.Type(offset)
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// PtrSize returns the size of a pointer.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) PtrSize() int {
|
|
|
|
return scope.Thread.dbp.arch.PtrSize()
|
|
|
|
}
|
|
|
|
|
2016-01-10 11:47:54 +00:00
|
|
|
// ChanRecvBlocked returns whether the goroutine is blocked on
|
2015-04-22 13:18:25 +00:00
|
|
|
// a channel read operation.
|
2015-04-19 22:11:33 +00:00
|
|
|
func (g *G) ChanRecvBlocked() bool {
|
2016-01-10 08:57:52 +00:00
|
|
|
return g.WaitReason == chanRecv
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// chanRecvReturnAddr returns the address of the return from a channel read.
|
2015-06-20 22:54:52 +00:00
|
|
|
func (g *G) chanRecvReturnAddr(dbp *Process) (uint64, error) {
|
2015-10-02 11:09:41 +00:00
|
|
|
locs, err := dbp.GoroutineStacktrace(g, 4)
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
topLoc := locs[len(locs)-1]
|
2015-09-17 08:42:34 +00:00
|
|
|
return topLoc.Current.PC, nil
|
2015-03-28 01:12:07 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 18:55:42 +00:00
|
|
|
// NoGError returned when a G could not be found
|
|
|
|
// for a specific thread.
|
2015-04-19 22:11:33 +00:00
|
|
|
type NoGError struct {
|
|
|
|
tid int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ng NoGError) Error() string {
|
|
|
|
return fmt.Sprintf("no G executing on thread %d", ng.tid)
|
|
|
|
}
|
|
|
|
|
2015-06-12 19:51:23 +00:00
|
|
|
func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) {
|
2015-06-11 20:17:56 +00:00
|
|
|
initialInstructions := make([]byte, thread.dbp.arch.PtrSize()+1)
|
|
|
|
initialInstructions[0] = op.DW_OP_addr
|
|
|
|
binary.LittleEndian.PutUint64(initialInstructions[1:], gaddr)
|
|
|
|
if deref {
|
|
|
|
gaddrbytes, err := thread.readMemory(uintptr(gaddr), thread.dbp.arch.PtrSize())
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error derefing *G %s", err)
|
|
|
|
}
|
|
|
|
initialInstructions = append([]byte{op.DW_OP_addr}, gaddrbytes...)
|
|
|
|
gaddr = binary.LittleEndian.Uint64(gaddrbytes)
|
|
|
|
if gaddr == 0 {
|
2016-01-10 08:57:52 +00:00
|
|
|
return nil, NoGError{tid: thread.ID}
|
2015-06-11 20:17:56 +00:00
|
|
|
}
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
2014-11-08 14:02:31 +00:00
|
|
|
|
2015-05-27 17:16:45 +00:00
|
|
|
rdr := thread.dbp.DwarfReader()
|
2015-05-09 15:27:06 +00:00
|
|
|
rdr.Seek(0)
|
2015-05-09 17:44:38 +00:00
|
|
|
entry, err := rdr.SeekToTypeNamed("runtime.g")
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-05-09 15:27:06 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
var mem memoryReadWriter = thread
|
|
|
|
if gtype, err := thread.dbp.dwarf.Type(entry.Offset); err == nil {
|
|
|
|
mem = cacheMemory(thread, uintptr(gaddr), int(gtype.Size()))
|
|
|
|
}
|
|
|
|
|
2015-05-09 17:44:38 +00:00
|
|
|
// Parse defer
|
|
|
|
deferAddr, err := rdr.AddrForMember("_defer", initialInstructions)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var deferPC uint64
|
|
|
|
// Dereference *defer pointer
|
2016-01-10 12:49:03 +00:00
|
|
|
deferAddrBytes, err := mem.readMemory(uintptr(deferAddr), thread.dbp.arch.PtrSize())
|
2015-05-09 17:44:38 +00:00
|
|
|
if err != nil {
|
2015-06-11 20:17:56 +00:00
|
|
|
return nil, fmt.Errorf("error derefing defer %s", err)
|
2015-05-09 17:44:38 +00:00
|
|
|
}
|
|
|
|
if binary.LittleEndian.Uint64(deferAddrBytes) != 0 {
|
|
|
|
initialDeferInstructions := append([]byte{op.DW_OP_addr}, deferAddrBytes...)
|
|
|
|
_, err = rdr.SeekToTypeNamed("runtime._defer")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
deferPCAddr, err := rdr.AddrForMember("fn", initialDeferInstructions)
|
2016-01-10 12:49:03 +00:00
|
|
|
deferPC, err = readUintRaw(mem, uintptr(deferPCAddr), 8)
|
2015-05-09 17:44:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
deferPC, err = readUintRaw(mem, uintptr(deferPC), 8)
|
2015-05-09 17:44:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2015-06-11 20:17:56 +00:00
|
|
|
|
|
|
|
// Let's parse all of the members we care about in order so that
|
|
|
|
// we don't have to spend any extra time seeking.
|
|
|
|
|
|
|
|
err = rdr.SeekToEntry(entry)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-05-09 15:27:06 +00:00
|
|
|
// Parse sched
|
|
|
|
schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return nil, err
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
2015-05-09 15:27:06 +00:00
|
|
|
// From sched, let's parse PC and SP.
|
2016-01-10 12:49:03 +00:00
|
|
|
sp, err := readUintRaw(mem, uintptr(schedAddr), 8)
|
2014-11-08 14:02:31 +00:00
|
|
|
if err != nil {
|
2015-03-28 01:12:07 +00:00
|
|
|
return nil, err
|
2014-11-26 02:37:43 +00:00
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
pc, err := readUintRaw(mem, uintptr(schedAddr+uint64(thread.dbp.arch.PtrSize())), 8)
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return nil, err
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
2015-09-17 17:42:05 +00:00
|
|
|
// Parse atomicstatus
|
|
|
|
atomicStatusAddr, err := rdr.AddrForMember("atomicstatus", initialInstructions)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
atomicStatus, err := readUintRaw(mem, uintptr(atomicStatusAddr), 4)
|
2015-05-09 15:27:06 +00:00
|
|
|
// Parse goid
|
|
|
|
goidAddr, err := rdr.AddrForMember("goid", initialInstructions)
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
goid, err := readIntRaw(mem, uintptr(goidAddr), 8)
|
2015-04-19 22:11:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-05-09 15:27:06 +00:00
|
|
|
// Parse waitreason
|
|
|
|
waitReasonAddr, err := rdr.AddrForMember("waitreason", initialInstructions)
|
2014-11-26 02:37:43 +00:00
|
|
|
if err != nil {
|
2015-03-28 01:12:07 +00:00
|
|
|
return nil, err
|
2014-11-08 14:02:31 +00:00
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
waitreason, _, err := readString(mem, thread.dbp.arch, uintptr(waitReasonAddr))
|
2014-11-08 14:02:31 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return nil, err
|
2014-11-08 14:02:31 +00:00
|
|
|
}
|
2015-05-09 15:27:06 +00:00
|
|
|
// Parse gopc
|
|
|
|
gopcAddr, err := rdr.AddrForMember("gopc", initialInstructions)
|
2014-11-26 02:37:43 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
gopc, err := readUintRaw(mem, uintptr(gopcAddr), 8)
|
2015-05-09 15:27:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2014-11-26 02:37:43 +00:00
|
|
|
}
|
2015-04-19 22:11:33 +00:00
|
|
|
|
2015-09-17 03:59:30 +00:00
|
|
|
f, l, fn := thread.dbp.goSymTable.PCToLine(pc)
|
2015-04-09 14:53:02 +00:00
|
|
|
g := &G{
|
2016-01-10 08:57:52 +00:00
|
|
|
ID: int(goid),
|
2015-05-09 15:27:06 +00:00
|
|
|
GoPC: gopc,
|
|
|
|
PC: pc,
|
|
|
|
SP: sp,
|
2015-10-18 22:02:14 +00:00
|
|
|
CurrentLoc: Location{PC: pc, File: f, Line: l, Fn: fn},
|
2015-04-19 22:11:33 +00:00
|
|
|
WaitReason: waitreason,
|
2015-05-09 17:44:38 +00:00
|
|
|
DeferPC: deferPC,
|
2015-09-17 17:42:05 +00:00
|
|
|
Status: atomicStatus,
|
2015-10-16 06:42:02 +00:00
|
|
|
dbp: thread.dbp,
|
2015-04-09 14:53:02 +00:00
|
|
|
}
|
|
|
|
return g, nil
|
2014-11-08 14:02:31 +00:00
|
|
|
}
|
|
|
|
|
2015-10-16 06:42:02 +00:00
|
|
|
// From $GOROOT/src/runtime/traceback.go:597
|
|
|
|
// isExportedRuntime reports whether name is an exported runtime function.
|
|
|
|
// It is only for runtime functions, so ASCII A-Z is fine.
|
|
|
|
func isExportedRuntime(name string) bool {
|
|
|
|
const n = len("runtime.")
|
|
|
|
return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// UserCurrent returns the location the users code is at,
|
|
|
|
// or was at before entering a runtime function.
|
2015-10-16 06:42:02 +00:00
|
|
|
func (g *G) UserCurrent() Location {
|
|
|
|
pc, sp := g.PC, g.SP
|
|
|
|
if g.thread != nil {
|
|
|
|
regs, err := g.thread.Registers()
|
|
|
|
if err != nil {
|
2015-10-18 22:02:14 +00:00
|
|
|
return g.CurrentLoc
|
2015-10-16 06:42:02 +00:00
|
|
|
}
|
|
|
|
pc, sp = regs.PC(), regs.SP()
|
|
|
|
}
|
|
|
|
it := newStackIterator(g.dbp, pc, sp)
|
|
|
|
for it.Next() {
|
|
|
|
frame := it.Frame()
|
|
|
|
name := frame.Call.Fn.Name
|
|
|
|
if (strings.Index(name, ".") >= 0) && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) {
|
|
|
|
return frame.Call
|
|
|
|
}
|
|
|
|
}
|
2015-10-18 22:02:14 +00:00
|
|
|
return g.CurrentLoc
|
2015-10-16 06:42:02 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// Go returns the location of the 'go' statement
|
|
|
|
// that spawned this goroutine.
|
2015-10-16 06:42:02 +00:00
|
|
|
func (g *G) Go() Location {
|
|
|
|
f, l, fn := g.dbp.goSymTable.PCToLine(g.GoPC)
|
|
|
|
return Location{PC: g.GoPC, File: f, Line: l, Fn: fn}
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// EvalVariable returns the value of the given expression (backwards compatibility).
|
2015-10-30 11:39:32 +00:00
|
|
|
func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
|
|
|
|
return scope.EvalExpression(name)
|
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// SetVariable sets the value of the named variable
|
2015-10-30 11:39:32 +00:00
|
|
|
func (scope *EvalScope) SetVariable(name, value string) error {
|
|
|
|
t, err := parser.ParseExpr(name)
|
2015-09-28 09:17:27 +00:00
|
|
|
if err != nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
return err
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
xv, err := scope.evalAST(t)
|
2015-09-28 09:17:27 +00:00
|
|
|
if err != nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
return err
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
2014-12-03 05:30:39 +00:00
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
if xv.Addr == 0 {
|
|
|
|
return fmt.Errorf("Can not assign to \"%s\"", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
if xv.Unreadable != nil {
|
|
|
|
return fmt.Errorf("Expression \"%s\" is unreadable: %v", name, xv.Unreadable)
|
|
|
|
}
|
|
|
|
|
|
|
|
t, err = parser.ParseExpr(value)
|
2015-09-28 10:01:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-10-30 11:39:32 +00:00
|
|
|
|
|
|
|
yv, err := scope.evalAST(t)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
yv.loadValue()
|
|
|
|
|
|
|
|
if err := yv.isType(xv.RealType, xv.Kind); err != nil {
|
|
|
|
return err
|
2015-10-18 17:37:13 +00:00
|
|
|
}
|
2015-10-30 11:39:32 +00:00
|
|
|
|
|
|
|
if yv.Unreadable != nil {
|
|
|
|
return fmt.Errorf("Expression \"%s\" is unreadable: %v", value, yv.Unreadable)
|
|
|
|
}
|
|
|
|
|
|
|
|
return xv.setValue(yv)
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
|
|
|
|
rdr := scope.DwarfReader()
|
2015-09-29 05:25:40 +00:00
|
|
|
v, err := scope.extractVarInfoFromEntry(entry, rdr)
|
2014-12-31 13:34:41 +00:00
|
|
|
if err != nil {
|
2014-12-02 22:42:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
v.loadValue()
|
|
|
|
return v, nil
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
2014-11-11 03:26:13 +00:00
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
func (scope *EvalScope) extractVarInfo(varName string) (*Variable, error) {
|
|
|
|
reader := scope.DwarfReader()
|
|
|
|
|
|
|
|
_, err := reader.SeekToFunction(scope.PC)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2014-12-03 05:30:39 +00:00
|
|
|
}
|
|
|
|
|
2014-12-31 13:34:41 +00:00
|
|
|
for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
|
2014-11-11 03:26:13 +00:00
|
|
|
if err != nil {
|
2014-12-31 13:34:41 +00:00
|
|
|
return nil, err
|
2014-11-11 03:26:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
n, ok := entry.Val(dwarf.AttrName).(string)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2014-12-31 21:13:28 +00:00
|
|
|
if n == varName {
|
2015-09-28 09:17:27 +00:00
|
|
|
return scope.extractVarInfoFromEntry(entry, reader)
|
2014-11-11 03:26:13 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
return nil, fmt.Errorf("could not find symbol value for %s", varName)
|
2014-11-11 03:26:13 +00:00
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2015-02-04 04:20:25 +00:00
|
|
|
// LocalVariables returns all local variables from the current function scope.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) LocalVariables() ([]*Variable, error) {
|
|
|
|
return scope.variablesByTag(dwarf.TagVariable)
|
2015-02-04 04:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FunctionArguments returns the name, value, and type of all current function arguments.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) FunctionArguments() ([]*Variable, error) {
|
|
|
|
return scope.variablesByTag(dwarf.TagFormalParameter)
|
2015-02-04 04:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PackageVariables returns the name, value, and type of all package variables in the application.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) PackageVariables() ([]*Variable, error) {
|
2016-01-10 08:57:52 +00:00
|
|
|
var vars []*Variable
|
2015-08-28 20:06:29 +00:00
|
|
|
reader := scope.DwarfReader()
|
2015-02-04 04:20:25 +00:00
|
|
|
|
|
|
|
for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore errors trying to extract values
|
2015-08-28 20:06:29 +00:00
|
|
|
val, err := scope.extractVariableFromEntry(entry)
|
2015-02-04 04:20:25 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
vars = append(vars, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
return vars, nil
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// EvalPackageVariable will evaluate the package level variable
|
|
|
|
// specified by 'name'.
|
2015-08-28 20:06:29 +00:00
|
|
|
func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) {
|
|
|
|
scope := &EvalScope{Thread: dbp.CurrentThread, PC: 0, CFA: 0}
|
2015-07-23 17:08:28 +00:00
|
|
|
|
2015-09-29 05:25:40 +00:00
|
|
|
v, err := scope.packageVarAddr(name)
|
2015-09-28 09:17:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
v.loadValue()
|
|
|
|
return v, nil
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (scope *EvalScope) packageVarAddr(name string) (*Variable, error) {
|
|
|
|
reader := scope.DwarfReader()
|
2015-07-23 17:08:28 +00:00
|
|
|
for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
n, ok := entry.Val(dwarf.AttrName).(string)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == name {
|
2015-09-28 09:17:27 +00:00
|
|
|
return scope.extractVarInfoFromEntry(entry, reader)
|
2015-07-23 17:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
func (v *Variable) structMember(memberName string) (*Variable, error) {
|
2015-10-18 17:37:13 +00:00
|
|
|
if v.Unreadable != nil {
|
|
|
|
return v.clone(), nil
|
|
|
|
}
|
|
|
|
structVar := v.maybeDereference()
|
2015-09-28 09:17:27 +00:00
|
|
|
structVar.Name = v.Name
|
2015-10-18 17:37:13 +00:00
|
|
|
if structVar.Unreadable != nil {
|
|
|
|
return structVar, nil
|
2014-12-03 05:30:39 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
switch t := structVar.RealType.(type) {
|
2015-09-28 09:17:27 +00:00
|
|
|
case *dwarf.StructType:
|
|
|
|
for _, field := range t.Field {
|
|
|
|
if field.Name != memberName {
|
|
|
|
continue
|
2014-12-31 21:13:28 +00:00
|
|
|
}
|
2015-10-06 23:34:18 +00:00
|
|
|
return structVar.toField(field)
|
2015-10-01 00:36:36 +00:00
|
|
|
}
|
|
|
|
// Check for embedded field only if field was
|
|
|
|
// not a regular struct member
|
|
|
|
for _, field := range t.Field {
|
|
|
|
isEmbeddedStructMember :=
|
|
|
|
(field.Type.String() == ("struct " + field.Name)) ||
|
2015-10-07 01:21:28 +00:00
|
|
|
(len(field.Name) > 1 &&
|
|
|
|
field.Name[0] == '*' &&
|
|
|
|
field.Type.String()[1:] == ("struct "+field.Name[1:]))
|
2015-10-01 00:36:36 +00:00
|
|
|
if !isEmbeddedStructMember {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// Check for embedded field referenced by type name
|
|
|
|
parts := strings.Split(field.Name, ".")
|
|
|
|
if len(parts) > 1 && parts[1] == memberName {
|
2015-10-06 23:34:18 +00:00
|
|
|
embeddedVar, err := structVar.toField(field)
|
2015-10-01 00:36:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return embeddedVar, nil
|
|
|
|
}
|
|
|
|
// Recursively check for promoted fields on the embedded field
|
2015-10-06 23:34:18 +00:00
|
|
|
embeddedVar, err := structVar.toField(field)
|
2015-10-01 00:36:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
embeddedVar.Name = structVar.Name
|
|
|
|
embeddedField, err := embeddedVar.structMember(memberName)
|
|
|
|
if embeddedField != nil {
|
|
|
|
return embeddedField, nil
|
2014-12-31 21:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
return nil, fmt.Errorf("%s has no member %s", v.Name, memberName)
|
|
|
|
default:
|
2015-11-12 11:29:53 +00:00
|
|
|
if v.Name == "" {
|
|
|
|
return nil, fmt.Errorf("type %s is not a struct", structVar.TypeString())
|
|
|
|
}
|
2016-01-10 08:57:52 +00:00
|
|
|
return nil, fmt.Errorf("%s (type %s) is not a struct", v.Name, structVar.TypeString())
|
2014-12-31 21:13:28 +00:00
|
|
|
}
|
2014-12-03 05:30:39 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
// Extracts the name and type of a variable from a dwarf entry
|
|
|
|
// 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) {
|
2014-12-30 17:57:31 +00:00
|
|
|
if entry == nil {
|
2015-05-04 22:31:13 +00:00
|
|
|
return nil, fmt.Errorf("invalid entry")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable {
|
|
|
|
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
n, ok := entry.Val(dwarf.AttrName).(string)
|
|
|
|
if !ok {
|
2015-05-04 22:31:13 +00:00
|
|
|
return nil, fmt.Errorf("type assertion failed")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
|
|
|
if !ok {
|
2015-05-04 22:31:13 +00:00
|
|
|
return nil, fmt.Errorf("type assertion failed")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2015-08-28 20:06:29 +00:00
|
|
|
t, err := scope.Type(offset)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
|
|
|
if !ok {
|
2015-05-04 22:31:13 +00:00
|
|
|
return nil, fmt.Errorf("type assertion failed")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
addr, err := op.ExecuteStackProgram(scope.CFA, instructions)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
return scope.newVariable(n, uintptr(addr), t), nil
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2015-09-29 05:25:40 +00:00
|
|
|
// If v is a pointer a new variable is returned containing the value pointed by v.
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) maybeDereference() *Variable {
|
|
|
|
if v.Unreadable != nil {
|
|
|
|
return v
|
|
|
|
}
|
2015-01-01 09:00:44 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
switch t := v.RealType.(type) {
|
2015-09-28 09:17:27 +00:00
|
|
|
case *dwarf.PtrType:
|
2016-01-10 12:49:03 +00:00
|
|
|
ptrval, err := readUintRaw(v.mem, uintptr(v.Addr), t.ByteSize)
|
|
|
|
r := v.newVariable("", uintptr(ptrval), t.Type)
|
2014-12-31 07:37:27 +00:00
|
|
|
if err != nil {
|
2015-10-18 17:37:13 +00:00
|
|
|
r.Unreadable = err
|
2015-01-01 09:00:44 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
return r
|
2015-09-28 09:17:27 +00:00
|
|
|
default:
|
2015-10-18 17:37:13 +00:00
|
|
|
return v
|
2015-01-01 09:00:44 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2015-09-29 05:25:40 +00:00
|
|
|
// Extracts the value of the variable at the given address.
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) loadValue() {
|
|
|
|
v.loadValueInternal(0)
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) loadValueInternal(recurseLevel int) {
|
2015-10-30 11:39:32 +00:00
|
|
|
if v.Unreadable != nil || v.loaded || (v.Addr == 0 && v.base == 0) {
|
2015-10-18 17:37:13 +00:00
|
|
|
return
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
v.loaded = true
|
|
|
|
switch v.Kind {
|
2015-11-05 17:27:50 +00:00
|
|
|
case reflect.Ptr, reflect.UnsafePointer:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Len = 1
|
|
|
|
v.Children = []Variable{*v.maybeDereference()}
|
2015-02-02 07:13:42 +00:00
|
|
|
// Don't increase the recursion level when dereferencing pointers
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Children[0].loadValueInternal(recurseLevel)
|
|
|
|
|
2015-11-03 18:11:08 +00:00
|
|
|
case reflect.Chan:
|
|
|
|
sv := v.maybeDereference()
|
|
|
|
sv.loadValueInternal(recurseLevel)
|
|
|
|
v.Children = sv.Children
|
|
|
|
v.Len = sv.Len
|
|
|
|
v.base = sv.Addr
|
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
case reflect.Map:
|
|
|
|
v.loadMap(recurseLevel)
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.String:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val string
|
2016-01-10 12:49:03 +00:00
|
|
|
val, v.Unreadable = readStringValue(v.mem, v.base, v.Len)
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeString(val)
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
case reflect.Slice, reflect.Array:
|
|
|
|
v.loadArrayValues(recurseLevel)
|
|
|
|
|
|
|
|
case reflect.Struct:
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size()))
|
2015-10-18 17:37:13 +00:00
|
|
|
t := v.RealType.(*dwarf.StructType)
|
|
|
|
v.Len = int64(len(t.Field))
|
|
|
|
// Recursively call extractValue to grab
|
|
|
|
// the value of all the members of the struct.
|
|
|
|
if recurseLevel <= maxVariableRecurse {
|
|
|
|
v.Children = make([]Variable, 0, len(t.Field))
|
|
|
|
for i, field := range t.Field {
|
|
|
|
f, _ := v.toField(field)
|
|
|
|
v.Children = append(v.Children, *f)
|
|
|
|
v.Children[i].Name = field.Name
|
|
|
|
v.Children[i].loadValueInternal(recurseLevel + 1)
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 11:30:41 +00:00
|
|
|
case reflect.Interface:
|
|
|
|
v.loadInterface(recurseLevel, true)
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Complex64, reflect.Complex128:
|
|
|
|
v.readComplex(v.RealType.(*dwarf.ComplexType).ByteSize)
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val int64
|
2016-01-10 12:49:03 +00:00
|
|
|
val, v.Unreadable = readIntRaw(v.mem, v.Addr, v.RealType.(*dwarf.IntType).ByteSize)
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeInt64(val)
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val uint64
|
2016-01-10 12:49:03 +00:00
|
|
|
val, v.Unreadable = readUintRaw(v.mem, v.Addr, v.RealType.(*dwarf.UintType).ByteSize)
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeUint64(val)
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Bool:
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := v.mem.readMemory(v.Addr, 1)
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = err
|
|
|
|
if err == nil {
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeBool(val[0] != 0)
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val float64
|
|
|
|
val, v.Unreadable = v.readFloatRaw(v.RealType.(*dwarf.FloatType).ByteSize)
|
|
|
|
v.Value = constant.MakeFloat64(val)
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Func:
|
|
|
|
v.readFunctionPtr()
|
2015-01-20 04:15:40 +00:00
|
|
|
default:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = fmt.Errorf("unknown or unsupported kind: \"%s\"", v.Kind.String())
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
func (v *Variable) setValue(y *Variable) error {
|
|
|
|
var err error
|
|
|
|
switch v.Kind {
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
f, _ := constant.Float64Val(y.Value)
|
|
|
|
err = v.writeFloatRaw(f, v.RealType.Size())
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
n, _ := constant.Int64Val(y.Value)
|
|
|
|
err = v.writeUint(uint64(n), v.RealType.Size())
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
|
|
n, _ := constant.Uint64Val(y.Value)
|
|
|
|
err = v.writeUint(n, v.RealType.Size())
|
|
|
|
case reflect.Bool:
|
|
|
|
err = v.writeBool(constant.BoolVal(y.Value))
|
|
|
|
case reflect.Complex64, reflect.Complex128:
|
|
|
|
real, _ := constant.Float64Val(constant.Real(y.Value))
|
|
|
|
imag, _ := constant.Float64Val(constant.Imag(y.Value))
|
|
|
|
err = v.writeComplex(real, imag, v.RealType.Size())
|
2015-09-28 10:01:18 +00:00
|
|
|
default:
|
2015-10-30 11:39:32 +00:00
|
|
|
fmt.Printf("default\n")
|
2016-01-10 12:49:03 +00:00
|
|
|
if t, isptr := v.RealType.(*dwarf.PtrType); isptr {
|
|
|
|
err = v.writeUint(uint64(y.Children[0].Addr), int64(t.ByteSize))
|
2015-10-30 11:39:32 +00:00
|
|
|
} else {
|
|
|
|
return fmt.Errorf("can not set variables of type %s (not implemented)", v.Kind.String())
|
|
|
|
}
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
2015-10-30 11:39:32 +00:00
|
|
|
|
|
|
|
return err
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func readStringInfo(mem memoryReadWriter, arch Arch, addr uintptr) (uintptr, int64, error) {
|
2015-01-19 23:25:08 +00:00
|
|
|
// string data structure is always two ptrs in size. Addr, followed by len
|
|
|
|
// http://research.swtch.com/godata
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
mem = cacheMemory(mem, addr, arch.PtrSize()*2)
|
|
|
|
|
2015-01-19 23:25:08 +00:00
|
|
|
// read len
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := mem.readMemory(addr+uintptr(arch.PtrSize()), arch.PtrSize())
|
2015-01-19 23:25:08 +00:00
|
|
|
if err != nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
return 0, 0, fmt.Errorf("could not read string len %s", err)
|
2015-01-19 23:25:08 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
strlen := int64(binary.LittleEndian.Uint64(val))
|
2015-09-20 06:27:25 +00:00
|
|
|
if strlen < 0 {
|
2015-10-30 11:39:32 +00:00
|
|
|
return 0, 0, fmt.Errorf("invalid length: %d", strlen)
|
2015-09-20 06:27:25 +00:00
|
|
|
}
|
2015-01-19 23:25:08 +00:00
|
|
|
|
|
|
|
// read addr
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err = mem.readMemory(addr, arch.PtrSize())
|
2014-10-25 15:48:14 +00:00
|
|
|
if err != nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
return 0, 0, fmt.Errorf("could not read string pointer %s", err)
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
addr = uintptr(binary.LittleEndian.Uint64(val))
|
2015-05-07 14:34:34 +00:00
|
|
|
if addr == 0 {
|
2015-10-30 11:39:32 +00:00
|
|
|
return 0, 0, nil
|
2015-05-07 14:34:34 +00:00
|
|
|
}
|
2015-01-16 21:30:22 +00:00
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
return addr, strlen, nil
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func readStringValue(mem memoryReadWriter, addr uintptr, strlen int64) (string, error) {
|
2015-10-30 11:39:32 +00:00
|
|
|
count := strlen
|
|
|
|
if count > maxArrayValues {
|
|
|
|
count = maxArrayValues
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := mem.readMemory(addr, int(count))
|
2014-10-25 15:48:14 +00:00
|
|
|
if err != nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
return "", fmt.Errorf("could not read string at %#v due to %s", addr, err)
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-09-20 06:27:25 +00:00
|
|
|
retstr := *(*string)(unsafe.Pointer(&val))
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
return retstr, nil
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func readString(mem memoryReadWriter, arch Arch, addr uintptr) (string, int64, error) {
|
|
|
|
addr, strlen, err := readStringInfo(mem, arch, addr)
|
2015-10-30 11:39:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", 0, err
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
retstr, err := readStringValue(mem, addr, strlen)
|
2015-10-30 11:39:32 +00:00
|
|
|
return retstr, strlen, err
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) loadSliceInfo(t *dwarf.StructType) {
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Addr, int(t.Size()))
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
var err error
|
2015-01-20 06:37:52 +00:00
|
|
|
for _, f := range t.Field {
|
|
|
|
switch f.Name {
|
|
|
|
case "array":
|
2015-09-28 09:17:27 +00:00
|
|
|
var base uint64
|
2016-01-10 12:49:03 +00:00
|
|
|
base, err = readUintRaw(v.mem, uintptr(int64(v.Addr)+f.ByteOffset), f.Type.Size())
|
2015-09-28 09:17:27 +00:00
|
|
|
if err == nil {
|
|
|
|
v.base = uintptr(base)
|
|
|
|
// Dereference array type to get value type
|
|
|
|
ptrType, ok := f.Type.(*dwarf.PtrType)
|
|
|
|
if !ok {
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = fmt.Errorf("Invalid type %s in slice array", f.Type)
|
|
|
|
return
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
v.fieldType = ptrType.Type
|
2015-01-20 06:37:52 +00:00
|
|
|
}
|
|
|
|
case "len":
|
2015-10-18 17:37:13 +00:00
|
|
|
lstrAddr, _ := v.toField(f)
|
|
|
|
lstrAddr.loadValue()
|
|
|
|
err = lstrAddr.Unreadable
|
2015-09-28 09:17:27 +00:00
|
|
|
if err == nil {
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Len, _ = constant.Int64Val(lstrAddr.Value)
|
2015-01-20 06:37:52 +00:00
|
|
|
}
|
|
|
|
case "cap":
|
2015-10-18 17:37:13 +00:00
|
|
|
cstrAddr, _ := v.toField(f)
|
|
|
|
cstrAddr.loadValue()
|
|
|
|
err = cstrAddr.Unreadable
|
2015-09-28 09:17:27 +00:00
|
|
|
if err == nil {
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Cap, _ = constant.Int64Val(cstrAddr.Value)
|
2015-01-20 06:37:52 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = err
|
|
|
|
return
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 09:17:27 +00:00
|
|
|
v.stride = v.fieldType.Size()
|
2016-01-10 12:49:03 +00:00
|
|
|
if t, ok := v.fieldType.(*dwarf.PtrType); ok {
|
|
|
|
v.stride = t.ByteSize
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
return
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) loadArrayValues(recurseLevel int) {
|
|
|
|
if v.Unreadable != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
count := v.Len
|
|
|
|
// Cap number of elements
|
|
|
|
if count > maxArrayValues {
|
|
|
|
count = maxArrayValues
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
if v.stride < maxArrayStridePrefetch {
|
|
|
|
v.mem = cacheMemory(v.mem, v.base, int(v.stride*count))
|
|
|
|
}
|
2015-02-02 07:13:42 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
errcount := 0
|
|
|
|
|
|
|
|
for i := int64(0); i < count; i++ {
|
|
|
|
fieldvar := v.newVariable("", uintptr(int64(v.base)+(i*v.stride)), v.fieldType)
|
2015-10-18 17:37:13 +00:00
|
|
|
fieldvar.loadValueInternal(recurseLevel + 1)
|
|
|
|
|
|
|
|
if fieldvar.Unreadable != nil {
|
2015-09-20 06:27:25 +00:00
|
|
|
errcount++
|
2015-01-20 05:32:08 +00:00
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Children = append(v.Children, *fieldvar)
|
2015-09-20 06:27:25 +00:00
|
|
|
if errcount > maxErrCount {
|
|
|
|
break
|
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) readComplex(size int64) {
|
2015-07-30 15:07:08 +00:00
|
|
|
var fs int64
|
|
|
|
switch size {
|
|
|
|
case 8:
|
|
|
|
fs = 4
|
|
|
|
case 16:
|
|
|
|
fs = 8
|
|
|
|
default:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = fmt.Errorf("invalid size (%d) for complex type", size)
|
|
|
|
return
|
2015-07-30 15:07:08 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
ftyp := &dwarf.FloatType{BasicType: dwarf.BasicType{CommonType: dwarf.CommonType{ByteSize: fs, Name: fmt.Sprintf("float%d", fs)}, BitSize: fs * 8, BitOffset: 0}}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
realvar := v.newVariable("real", v.Addr, ftyp)
|
|
|
|
imagvar := v.newVariable("imaginary", v.Addr+uintptr(fs), ftyp)
|
2015-10-18 17:37:13 +00:00
|
|
|
realvar.loadValue()
|
|
|
|
imagvar.loadValue()
|
2015-10-30 11:39:32 +00:00
|
|
|
v.Value = constant.BinaryOp(realvar.Value, token.ADD, constant.MakeImag(imagvar.Value))
|
2015-07-30 15:07:08 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
func (v *Variable) writeComplex(real, imag float64, size int64) error {
|
|
|
|
err := v.writeFloatRaw(real, int64(size/2))
|
2015-09-28 10:01:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
imagaddr := *v
|
|
|
|
imagaddr.Addr += uintptr(size / 2)
|
|
|
|
return imagaddr.writeFloatRaw(imag, int64(size/2))
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func readIntRaw(mem memoryReadWriter, addr uintptr, size int64) (int64, error) {
|
2015-01-20 03:18:17 +00:00
|
|
|
var n int64
|
2014-10-25 16:05:03 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := mem.readMemory(addr, int(size))
|
2014-10-25 15:48:14 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return 0, err
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2014-10-25 16:05:03 +00:00
|
|
|
switch size {
|
|
|
|
case 1:
|
2015-01-20 03:18:17 +00:00
|
|
|
n = int64(val[0])
|
2014-10-25 16:05:03 +00:00
|
|
|
case 2:
|
2015-01-20 03:18:17 +00:00
|
|
|
n = int64(binary.LittleEndian.Uint16(val))
|
2014-10-25 16:05:03 +00:00
|
|
|
case 4:
|
2015-01-20 03:18:17 +00:00
|
|
|
n = int64(binary.LittleEndian.Uint32(val))
|
2014-10-25 16:05:03 +00:00
|
|
|
case 8:
|
2015-01-20 03:18:17 +00:00
|
|
|
n = int64(binary.LittleEndian.Uint64(val))
|
2014-10-25 16:05:03 +00:00
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2015-05-09 15:27:06 +00:00
|
|
|
return n, nil
|
2015-01-20 03:18:17 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
func (v *Variable) writeUint(value uint64, size int64) error {
|
2015-09-28 10:01:18 +00:00
|
|
|
val := make([]byte, size)
|
|
|
|
|
|
|
|
switch size {
|
|
|
|
case 1:
|
2015-10-30 11:39:32 +00:00
|
|
|
val[0] = byte(value)
|
2015-09-28 10:01:18 +00:00
|
|
|
case 2:
|
2015-10-30 11:39:32 +00:00
|
|
|
binary.LittleEndian.PutUint16(val, uint16(value))
|
2015-09-28 10:01:18 +00:00
|
|
|
case 4:
|
2015-10-30 11:39:32 +00:00
|
|
|
binary.LittleEndian.PutUint32(val, uint32(value))
|
2015-09-28 10:01:18 +00:00
|
|
|
case 8:
|
2015-10-30 11:39:32 +00:00
|
|
|
binary.LittleEndian.PutUint64(val, uint64(value))
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
_, err := v.mem.writeMemory(v.Addr, val)
|
2015-09-28 10:01:18 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
func readUintRaw(mem memoryReadWriter, addr uintptr, size int64) (uint64, error) {
|
2015-01-20 03:18:17 +00:00
|
|
|
var n uint64
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := mem.readMemory(addr, int(size))
|
2015-01-20 03:18:17 +00:00
|
|
|
if err != nil {
|
2015-05-09 15:27:06 +00:00
|
|
|
return 0, err
|
2015-01-20 03:18:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch size {
|
|
|
|
case 1:
|
|
|
|
n = uint64(val[0])
|
|
|
|
case 2:
|
|
|
|
n = uint64(binary.LittleEndian.Uint16(val))
|
|
|
|
case 4:
|
|
|
|
n = uint64(binary.LittleEndian.Uint32(val))
|
|
|
|
case 8:
|
|
|
|
n = uint64(binary.LittleEndian.Uint64(val))
|
|
|
|
}
|
|
|
|
|
2015-05-09 15:27:06 +00:00
|
|
|
return n, nil
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) readFloatRaw(size int64) (float64, error) {
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := v.mem.readMemory(v.Addr, int(size))
|
2014-10-25 15:48:14 +00:00
|
|
|
if err != nil {
|
2015-10-18 17:37:13 +00:00
|
|
|
return 0.0, err
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
buf := bytes.NewBuffer(val)
|
|
|
|
|
2014-10-26 17:44:26 +00:00
|
|
|
switch size {
|
|
|
|
case 4:
|
|
|
|
n := float32(0)
|
|
|
|
binary.Read(buf, binary.LittleEndian, &n)
|
2015-10-18 17:37:13 +00:00
|
|
|
return float64(n), nil
|
2014-10-26 17:44:26 +00:00
|
|
|
case 8:
|
|
|
|
n := float64(0)
|
|
|
|
binary.Read(buf, binary.LittleEndian, &n)
|
2015-10-18 17:37:13 +00:00
|
|
|
return n, nil
|
2014-10-26 17:44:26 +00:00
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
return 0.0, fmt.Errorf("could not read float")
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-09-28 10:01:18 +00:00
|
|
|
func (v *Variable) writeFloatRaw(f float64, size int64) error {
|
|
|
|
buf := bytes.NewBuffer(make([]byte, 0, size))
|
|
|
|
|
|
|
|
switch size {
|
|
|
|
case 4:
|
|
|
|
n := float32(f)
|
|
|
|
binary.Write(buf, binary.LittleEndian, n)
|
|
|
|
case 8:
|
|
|
|
n := float64(f)
|
|
|
|
binary.Write(buf, binary.LittleEndian, n)
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
_, err := v.mem.writeMemory(v.Addr, buf.Bytes())
|
2015-09-28 10:01:18 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
func (v *Variable) writeBool(value bool) error {
|
2015-09-28 10:01:18 +00:00
|
|
|
val := []byte{0}
|
2015-10-30 11:39:32 +00:00
|
|
|
val[0] = *(*byte)(unsafe.Pointer(&value))
|
2016-01-10 12:49:03 +00:00
|
|
|
_, err := v.mem.writeMemory(v.Addr, val)
|
2015-09-28 10:01:18 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) readFunctionPtr() {
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err := v.mem.readMemory(v.Addr, v.dbp.arch.PtrSize())
|
2015-01-20 04:15:40 +00:00
|
|
|
if err != nil {
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = err
|
|
|
|
return
|
2015-01-20 04:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// dereference pointer to find function pc
|
2015-09-28 09:17:27 +00:00
|
|
|
fnaddr := uintptr(binary.LittleEndian.Uint64(val))
|
|
|
|
if fnaddr == 0 {
|
2015-10-30 11:39:32 +00:00
|
|
|
v.base = 0
|
|
|
|
v.Value = constant.MakeString("")
|
2015-10-18 17:37:13 +00:00
|
|
|
return
|
2015-01-21 05:47:59 +00:00
|
|
|
}
|
2015-01-20 04:15:40 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
val, err = v.mem.readMemory(fnaddr, v.dbp.arch.PtrSize())
|
2015-01-20 04:15:40 +00:00
|
|
|
if err != nil {
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Unreadable = err
|
|
|
|
return
|
2015-01-20 04:15:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
v.base = uintptr(binary.LittleEndian.Uint64(val))
|
2016-01-10 12:49:03 +00:00
|
|
|
fn := v.dbp.goSymTable.PCToFunc(uint64(v.base))
|
2015-05-03 19:11:17 +00:00
|
|
|
if fn == nil {
|
2015-10-30 11:39:32 +00:00
|
|
|
v.Unreadable = fmt.Errorf("could not find function for %#v", v.base)
|
2015-10-18 17:37:13 +00:00
|
|
|
return
|
2015-01-20 04:15:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeString(fn.Name)
|
2015-01-20 04:15:40 +00:00
|
|
|
}
|
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
func (v *Variable) loadMap(recurseLevel int) {
|
|
|
|
it := v.mapIterator()
|
|
|
|
if it == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for skip := 0; skip < v.mapSkip; skip++ {
|
|
|
|
if ok := it.next(); !ok {
|
2015-11-07 10:48:33 +00:00
|
|
|
v.Unreadable = fmt.Errorf("map index out of bounds")
|
2015-11-05 17:25:52 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
errcount := 0
|
|
|
|
for it.next() {
|
|
|
|
if count >= maxArrayValues {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
key := it.key()
|
|
|
|
val := it.value()
|
2016-01-10 09:04:14 +00:00
|
|
|
if recurseLevel <= maxVariableRecurse {
|
|
|
|
key.loadValueInternal(recurseLevel + 1)
|
|
|
|
val.loadValueInternal(recurseLevel + 1)
|
|
|
|
}
|
2015-11-05 17:25:52 +00:00
|
|
|
if key.Unreadable != nil || val.Unreadable != nil {
|
|
|
|
errcount++
|
|
|
|
}
|
|
|
|
v.Children = append(v.Children, *key)
|
|
|
|
v.Children = append(v.Children, *val)
|
|
|
|
count++
|
|
|
|
if errcount > maxErrCount {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type mapIterator struct {
|
|
|
|
v *Variable
|
|
|
|
numbuckets uint64
|
|
|
|
oldmask uint64
|
|
|
|
buckets *Variable
|
|
|
|
oldbuckets *Variable
|
|
|
|
b *Variable
|
|
|
|
bidx uint64
|
|
|
|
|
|
|
|
tophashes *Variable
|
|
|
|
keys *Variable
|
|
|
|
values *Variable
|
|
|
|
overflow *Variable
|
|
|
|
|
|
|
|
idx int64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Code derived from go/src/runtime/hashmap.go
|
|
|
|
func (v *Variable) mapIterator() *mapIterator {
|
|
|
|
sv := v.maybeDereference()
|
|
|
|
v.base = sv.Addr
|
|
|
|
|
|
|
|
maptype, ok := sv.RealType.(*dwarf.StructType)
|
|
|
|
if !ok {
|
|
|
|
v.Unreadable = fmt.Errorf("wrong real type for map")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
it := &mapIterator{v: v, bidx: 0, b: nil, idx: 0}
|
|
|
|
|
|
|
|
if sv.Addr == 0 {
|
|
|
|
it.numbuckets = 0
|
|
|
|
return it
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.base, int(v.RealType.Size()))
|
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
for _, f := range maptype.Field {
|
|
|
|
var err error
|
|
|
|
field, _ := sv.toField(f)
|
|
|
|
switch f.Name {
|
|
|
|
case "count":
|
|
|
|
v.Len, err = field.asInt()
|
|
|
|
case "B":
|
|
|
|
var b uint64
|
|
|
|
b, err = field.asUint()
|
|
|
|
it.numbuckets = 1 << b
|
|
|
|
it.oldmask = (1 << (b - 1)) - 1
|
|
|
|
case "buckets":
|
|
|
|
it.buckets = field.maybeDereference()
|
|
|
|
case "oldbuckets":
|
|
|
|
it.oldbuckets = field.maybeDereference()
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = err
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return it
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *mapIterator) nextBucket() bool {
|
|
|
|
if it.overflow != nil && it.overflow.Addr > 0 {
|
|
|
|
it.b = it.overflow
|
|
|
|
} else {
|
|
|
|
it.b = nil
|
|
|
|
|
|
|
|
for it.bidx < it.numbuckets {
|
|
|
|
it.b = it.buckets.clone()
|
|
|
|
it.b.Addr += uintptr(uint64(it.buckets.DwarfType.Size()) * it.bidx)
|
|
|
|
|
|
|
|
if it.oldbuckets.Addr <= 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// if oldbuckets is not nil we are iterating through a map that is in
|
|
|
|
// the middle of a grow.
|
|
|
|
// if the bucket we are looking at hasn't been filled in we iterate
|
|
|
|
// instead through its corresponding "oldbucket" (i.e. the bucket the
|
|
|
|
// elements of this bucket are coming from) but only if this is the first
|
|
|
|
// of the two buckets being created from the same oldbucket (otherwise we
|
|
|
|
// would print some keys twice)
|
|
|
|
|
|
|
|
oldbidx := it.bidx & it.oldmask
|
|
|
|
oldb := it.oldbuckets.clone()
|
|
|
|
oldb.Addr += uintptr(uint64(it.oldbuckets.DwarfType.Size()) * oldbidx)
|
|
|
|
|
|
|
|
if mapEvacuated(oldb) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if oldbidx == it.bidx {
|
|
|
|
it.b = oldb
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// oldbucket origin for current bucket has not been evacuated but we have already
|
|
|
|
// iterated over it so we should just skip it
|
|
|
|
it.b = nil
|
|
|
|
it.bidx++
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.b == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
it.bidx++
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.b.Addr <= 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
it.b.mem = cacheMemory(it.b.mem, it.b.Addr, int(it.b.RealType.Size()))
|
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
it.tophashes = nil
|
|
|
|
it.keys = nil
|
|
|
|
it.values = nil
|
|
|
|
it.overflow = nil
|
|
|
|
|
|
|
|
for _, f := range it.b.DwarfType.(*dwarf.StructType).Field {
|
|
|
|
field, err := it.b.toField(f)
|
|
|
|
if err != nil {
|
|
|
|
it.v.Unreadable = err
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if field.Unreadable != nil {
|
|
|
|
it.v.Unreadable = field.Unreadable
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
switch f.Name {
|
|
|
|
case "tophash":
|
|
|
|
it.tophashes = field
|
|
|
|
case "keys":
|
|
|
|
it.keys = field
|
|
|
|
case "values":
|
|
|
|
it.values = field
|
|
|
|
case "overflow":
|
|
|
|
it.overflow = field.maybeDereference()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// sanity checks
|
|
|
|
if it.tophashes == nil || it.keys == nil || it.values == nil {
|
|
|
|
it.v.Unreadable = fmt.Errorf("malformed map type")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.tophashes.Kind != reflect.Array || it.keys.Kind != reflect.Array || it.values.Kind != reflect.Array {
|
|
|
|
it.v.Unreadable = fmt.Errorf("malformed map type: keys, values or tophash of a bucket is not an array")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.tophashes.Len != it.keys.Len || it.tophashes.Len != it.values.Len {
|
|
|
|
it.v.Unreadable = fmt.Errorf("malformed map type: inconsistent array length in bucket")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *mapIterator) next() bool {
|
|
|
|
for {
|
|
|
|
if it.b == nil || it.idx >= it.tophashes.Len {
|
|
|
|
r := it.nextBucket()
|
|
|
|
if !r {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
it.idx = 0
|
|
|
|
}
|
|
|
|
tophash, _ := it.tophashes.sliceAccess(int(it.idx))
|
|
|
|
h, err := tophash.asUint()
|
|
|
|
if err != nil {
|
|
|
|
it.v.Unreadable = fmt.Errorf("unreadable tophash: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
it.idx++
|
|
|
|
if h != hashTophashEmpty {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *mapIterator) key() *Variable {
|
|
|
|
k, _ := it.keys.sliceAccess(int(it.idx - 1))
|
|
|
|
return k
|
|
|
|
}
|
|
|
|
|
|
|
|
func (it *mapIterator) value() *Variable {
|
|
|
|
v, _ := it.values.sliceAccess(int(it.idx - 1))
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func mapEvacuated(b *Variable) bool {
|
|
|
|
if b.Addr == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
for _, f := range b.DwarfType.(*dwarf.StructType).Field {
|
|
|
|
if f.Name != "tophash" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
tophashes, _ := b.toField(f)
|
|
|
|
tophash0var, _ := tophashes.sliceAccess(0)
|
|
|
|
tophash0, err := tophash0var.asUint()
|
|
|
|
if err != nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return tophash0 > hashTophashEmpty && tophash0 < hashMinTopHash
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:30:41 +00:00
|
|
|
func (v *Variable) loadInterface(recurseLevel int, loadData bool) {
|
|
|
|
var typestring, data *Variable
|
|
|
|
isnil := false
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size()))
|
|
|
|
|
2015-11-12 11:30:41 +00:00
|
|
|
for _, f := range v.RealType.(*dwarf.StructType).Field {
|
|
|
|
switch f.Name {
|
|
|
|
case "tab": // for runtime.iface
|
|
|
|
tab, _ := v.toField(f)
|
|
|
|
_type, err := tab.structMember("_type")
|
|
|
|
if err != nil {
|
|
|
|
_, isnil = err.(*IsNilErr)
|
|
|
|
if !isnil {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
typestring, err = _type.structMember("_string")
|
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
typestring = typestring.maybeDereference()
|
|
|
|
}
|
|
|
|
case "_type": // for runtime.eface
|
|
|
|
var err error
|
|
|
|
_type, _ := v.toField(f)
|
|
|
|
typestring, err = _type.structMember("_string")
|
|
|
|
if err != nil {
|
|
|
|
_, isnil = err.(*IsNilErr)
|
|
|
|
if !isnil {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
typestring = typestring.maybeDereference()
|
|
|
|
}
|
|
|
|
case "data":
|
|
|
|
data, _ = v.toField(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if isnil {
|
|
|
|
// interface to nil
|
|
|
|
data = data.maybeDereference()
|
|
|
|
v.Children = []Variable{*data}
|
2016-01-10 09:04:14 +00:00
|
|
|
v.Children[0].loadValueInternal(recurseLevel)
|
2015-11-12 11:30:41 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if typestring == nil || data == nil || typestring.Addr == 0 || typestring.Kind != reflect.String {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
typestring.loadValue()
|
|
|
|
if typestring.Unreadable != nil {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type: %v", typestring.Unreadable)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
t, err := parser.ParseExpr(constant.StringVal(typestring.Value))
|
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type, unparsable data type: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
typ, err := v.dbp.findTypeExpr(t)
|
2015-11-12 11:30:41 +00:00
|
|
|
if err != nil {
|
2015-11-26 13:10:58 +00:00
|
|
|
v.Unreadable = fmt.Errorf("interface type \"%s\" not found for 0x%x: %v", constant.StringVal(typestring.Value), data.Addr, err)
|
2015-11-12 11:30:41 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-11-26 13:10:58 +00:00
|
|
|
realtyp := resolveTypedef(typ)
|
|
|
|
if _, isptr := realtyp.(*dwarf.PtrType); !isptr {
|
|
|
|
// interface to non-pointer types are pointers even if the type says otherwise
|
2016-01-10 12:49:03 +00:00
|
|
|
typ = v.dbp.pointerTo(typ)
|
2015-11-26 13:10:58 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
data = data.newVariable("data", data.Addr, typ)
|
2015-11-12 11:30:41 +00:00
|
|
|
|
|
|
|
v.Children = []Variable{*data}
|
|
|
|
if loadData {
|
2015-12-19 13:57:48 +00:00
|
|
|
v.Children[0].loadValueInternal(recurseLevel)
|
2015-11-12 11:30:41 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-12-30 17:57:31 +00:00
|
|
|
// Fetches all variables of a specific type in the current function scope
|
2015-08-28 20:06:29 +00:00
|
|
|
func (scope *EvalScope) variablesByTag(tag dwarf.Tag) ([]*Variable, error) {
|
|
|
|
reader := scope.DwarfReader()
|
2014-12-30 17:57:31 +00:00
|
|
|
|
2015-08-28 20:06:29 +00:00
|
|
|
_, err := reader.SeekToFunction(scope.PC)
|
2014-12-31 13:34:41 +00:00
|
|
|
if err != nil {
|
2014-12-30 17:57:31 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
var vars []*Variable
|
2014-12-31 13:34:41 +00:00
|
|
|
for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if entry.Tag == tag {
|
2015-08-28 20:06:29 +00:00
|
|
|
val, err := scope.extractVariableFromEntry(entry)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
2015-01-20 03:18:17 +00:00
|
|
|
// skip variables that we can't parse yet
|
|
|
|
continue
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vars = append(vars, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return vars, nil
|
|
|
|
}
|