2015-06-12 19:49:23 +00:00
|
|
|
package proc
|
2014-10-25 15:48:14 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-05-29 13:20:01 +00:00
|
|
|
"debug/dwarf"
|
2014-10-25 15:48:14 +00:00
|
|
|
"encoding/binary"
|
2016-01-30 21:21:07 +00:00
|
|
|
"errors"
|
2014-10-25 15:48:14 +00:00
|
|
|
"fmt"
|
2015-10-21 07:06:36 +00:00
|
|
|
"go/constant"
|
2015-09-28 10:01:18 +00:00
|
|
|
"go/parser"
|
|
|
|
"go/token"
|
2017-01-20 22:22:36 +00:00
|
|
|
"math"
|
2015-10-18 17:37:13 +00:00
|
|
|
"reflect"
|
2017-05-04 14:35:31 +00:00
|
|
|
"sort"
|
2014-10-25 15:48:14 +00:00
|
|
|
"strings"
|
|
|
|
"unsafe"
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
"github.com/derekparker/delve/pkg/dwarf/godwarf"
|
2017-02-08 16:00:44 +00:00
|
|
|
"github.com/derekparker/delve/pkg/dwarf/op"
|
|
|
|
"github.com/derekparker/delve/pkg/dwarf/reader"
|
2014-10-25 15:48:14 +00:00
|
|
|
)
|
|
|
|
|
2015-02-02 07:13:42 +00:00
|
|
|
const (
|
2016-04-24 17:15:39 +00:00
|
|
|
maxErrCount = 3 // Max number of read errors to accept while evaluating slices, arrays and structs
|
2016-01-16 08:13:15 +00:00
|
|
|
|
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
|
2018-04-14 13:44:39 +00:00
|
|
|
|
|
|
|
maxFramePrefetchSize = 1 * 1024 * 1024 // Maximum prefetch size for a stack frame
|
2015-02-02 07:13:42 +00:00
|
|
|
)
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
type floatSpecial uint8
|
2017-01-20 22:22:36 +00:00
|
|
|
|
|
|
|
const (
|
2018-08-31 18:08:18 +00:00
|
|
|
// FloatIsNormal means the value is a normal float.
|
|
|
|
FloatIsNormal floatSpecial = iota
|
|
|
|
// FloatIsNaN means the float is a special NaN value.
|
2017-01-20 22:22:36 +00:00
|
|
|
FloatIsNaN
|
2018-08-31 18:08:18 +00:00
|
|
|
// FloatIsPosInf means the float is a special positive inifitiy value.
|
2017-01-20 22:22:36 +00:00
|
|
|
FloatIsPosInf
|
2018-08-31 18:08:18 +00:00
|
|
|
// FloatIsNegInf means the float is a special negative infinity value.
|
2017-01-20 22:22:36 +00:00
|
|
|
FloatIsNegInf
|
|
|
|
)
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
type variableFlags uint16
|
2017-06-13 08:38:45 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
// VariableEscaped is set for local variables that escaped to the heap
|
2017-06-13 08:38:45 +00:00
|
|
|
//
|
|
|
|
// The compiler performs escape analysis on local variables, the variables
|
|
|
|
// that may outlive the stack frame are allocated on the heap instead and
|
|
|
|
// only the address is recorded on the stack. These variables will be
|
|
|
|
// marked with this flag.
|
2018-08-31 18:08:18 +00:00
|
|
|
VariableEscaped variableFlags = (1 << iota)
|
2017-05-04 14:35:31 +00:00
|
|
|
// VariableShadowed is set for local variables that are shadowed by a
|
|
|
|
// variable with the same name in another scope
|
|
|
|
VariableShadowed
|
2017-09-08 10:31:20 +00:00
|
|
|
// VariableConstant means this variable is a constant value
|
|
|
|
VariableConstant
|
2018-04-15 12:11:27 +00:00
|
|
|
// VariableArgument means this variable is a function argument
|
|
|
|
VariableArgument
|
|
|
|
// VariableReturnArgument means this variable is a function return value
|
|
|
|
VariableReturnArgument
|
2017-06-13 08:38:45 +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
|
2017-05-29 13:20:01 +00:00
|
|
|
DwarfType godwarf.Type
|
|
|
|
RealType godwarf.Type
|
2015-10-18 17:37:13 +00:00
|
|
|
Kind reflect.Kind
|
2017-04-21 06:55:53 +00:00
|
|
|
mem MemoryReadWriter
|
2017-04-13 23:19:57 +00:00
|
|
|
bi *BinaryInfo
|
2015-09-28 09:17:27 +00:00
|
|
|
|
2017-01-20 22:22:36 +00:00
|
|
|
Value constant.Value
|
2018-08-31 18:08:18 +00:00
|
|
|
FloatSpecial floatSpecial
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
Len int64
|
|
|
|
Cap int64
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
Flags variableFlags
|
2017-06-13 08:38:45 +00:00
|
|
|
|
2016-01-10 13:08:16 +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)
|
2016-01-10 13:08:16 +00:00
|
|
|
Base uintptr
|
2015-09-28 09:17:27 +00:00
|
|
|
stride int64
|
2017-05-29 13:20:01 +00:00
|
|
|
fieldType godwarf.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
|
2017-11-21 08:50:14 +00:00
|
|
|
|
|
|
|
LocationExpr string // location expression
|
2018-06-28 09:23:39 +00:00
|
|
|
DeclLine int64 // line number of this variable's declaration
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// LoadConfig controls how variables are loaded from the targets memory.
|
2016-04-24 17:15:39 +00:00
|
|
|
type LoadConfig struct {
|
|
|
|
// FollowPointers requests pointers to be automatically dereferenced.
|
|
|
|
FollowPointers bool
|
|
|
|
// MaxVariableRecurse is how far to recurse when evaluating nested types.
|
|
|
|
MaxVariableRecurse int
|
|
|
|
// MaxStringLen is the maximum number of bytes read from a string
|
|
|
|
MaxStringLen int
|
|
|
|
// MaxArrayValues is the maximum number of elements read from an array, a slice or a map.
|
|
|
|
MaxArrayValues int
|
|
|
|
// MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields.
|
|
|
|
MaxStructFields int
|
|
|
|
}
|
|
|
|
|
|
|
|
var loadSingleValue = LoadConfig{false, 0, 64, 0, 0}
|
|
|
|
var loadFullValue = LoadConfig{true, 1, 64, 64, -1}
|
|
|
|
|
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.
|
2017-10-05 07:26:19 +00:00
|
|
|
BP uint64 // BP of goroutine when it was parked (go >= 1.7).
|
2015-04-22 13:18:25 +00:00
|
|
|
GoPC uint64 // PC of 'go' statement that created this goroutine.
|
2018-07-05 11:06:12 +00:00
|
|
|
StartPC uint64 // PC of the first function run on this goroutine.
|
2015-04-22 13:18:25 +00:00
|
|
|
WaitReason string // Reason for goroutine being parked.
|
2015-09-17 17:42:05 +00:00
|
|
|
Status uint64
|
2017-02-08 13:14:57 +00:00
|
|
|
stkbarVar *Variable // stkbar field of g struct
|
|
|
|
stkbarPos int // stkbarPos field of g struct
|
2017-05-16 18:23:33 +00:00
|
|
|
stackhi uint64 // value of stack.hi
|
2018-05-04 17:31:45 +00:00
|
|
|
stacklo uint64 // value of stack.lo
|
2015-04-22 13:18:25 +00:00
|
|
|
|
2017-09-01 13:34:13 +00:00
|
|
|
SystemStack bool // SystemStack is true if this goroutine is currently executing on a system stack.
|
|
|
|
|
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
|
|
|
|
2015-06-17 17:11:57 +00:00
|
|
|
// Thread that this goroutine is currently allocated to
|
2017-04-21 07:50:38 +00:00
|
|
|
Thread Thread
|
2015-10-16 06:42:02 +00:00
|
|
|
|
2017-02-07 21:08:11 +00:00
|
|
|
variable *Variable
|
2018-09-25 12:53:44 +00:00
|
|
|
|
|
|
|
Unreadable error // could not read the G struct
|
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 {
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
Location
|
2017-08-24 07:46:47 +00:00
|
|
|
Regs op.DwarfRegisters
|
2017-04-21 06:55:53 +00:00
|
|
|
Mem MemoryReadWriter // Target's memory
|
|
|
|
Gvar *Variable
|
|
|
|
BinInfo *BinaryInfo
|
2017-09-01 13:34:13 +00:00
|
|
|
|
|
|
|
frameOffset int64
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
|
|
|
|
aordr *dwarf.Reader // extra reader to load DW_AT_abstract_origin entries, do not initialize
|
2015-08-28 20:06:29 +00:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-02-13 17:20:45 +00:00
|
|
|
func globalScope(bi *BinaryInfo, mem MemoryReadWriter) *EvalScope {
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
return &EvalScope{Location: Location{}, Regs: op.DwarfRegisters{}, Mem: mem, Gvar: nil, BinInfo: bi, frameOffset: 0}
|
2018-02-13 17:20:45 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
|
|
|
|
return newVariable(name, addr, dwarfType, scope.BinInfo, mem)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func newVariableFromThread(t Thread, name string, addr uintptr, dwarfType godwarf.Type) *Variable {
|
2017-02-15 13:41:03 +00:00
|
|
|
return newVariable(name, addr, dwarfType, t.BinInfo(), t)
|
2016-01-10 17:29:14 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
func (v *Variable) newVariable(name string, addr uintptr, dwarfType godwarf.Type, mem MemoryReadWriter) *Variable {
|
|
|
|
return newVariable(name, addr, dwarfType, v.bi, mem)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func newVariable(name string, addr uintptr, dwarfType godwarf.Type, bi *BinaryInfo, mem MemoryReadWriter) *Variable {
|
2018-08-17 06:17:22 +00:00
|
|
|
if styp, isstruct := dwarfType.(*godwarf.StructType); isstruct && !strings.Contains(styp.Name, "<") && !strings.Contains(styp.Name, "{") {
|
|
|
|
// For named structs the compiler will emit a DW_TAG_structure_type entry
|
|
|
|
// and a DW_TAG_typedef entry.
|
|
|
|
//
|
|
|
|
// Normally variables refer to the typedef entry but sometimes global
|
|
|
|
// variables will refer to the struct entry incorrectly.
|
|
|
|
// Also the runtime type offset resolution (runtimeTypeToDIE) will return
|
|
|
|
// the struct entry directly.
|
|
|
|
//
|
|
|
|
// In both cases we prefer to have a typedef type for consistency's sake.
|
|
|
|
//
|
|
|
|
// So we wrap all struct types into a fake typedef type except for:
|
|
|
|
// a. types not defined by go
|
|
|
|
// b. anonymous struct types (they contain the '{' character)
|
|
|
|
// c. Go internal struct types used to describe maps (they contain the '<'
|
|
|
|
// character).
|
|
|
|
cu := bi.findCompileUnitForOffset(dwarfType.Common().Offset)
|
|
|
|
if cu != nil && cu.isgo {
|
|
|
|
dwarfType = &godwarf.TypedefType{
|
|
|
|
CommonType: *(dwarfType.Common()),
|
|
|
|
Type: dwarfType,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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,
|
2017-04-13 23:19:57 +00:00
|
|
|
bi: bi,
|
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) {
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.PtrType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Ptr
|
2017-05-29 13:20:01 +00:00
|
|
|
if _, isvoid := t.Type.(*godwarf.VoidType); isvoid {
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.UnsafePointer
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.ChanType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Chan
|
2017-10-26 14:14:31 +00:00
|
|
|
if v.Addr != 0 {
|
|
|
|
v.loadChanInfo()
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.MapType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Map
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.StringType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.String
|
|
|
|
v.stride = 1
|
2017-05-29 13:20:01 +00:00
|
|
|
v.fieldType = &godwarf.UintType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: 1, Name: "byte"}, BitSize: 8, BitOffset: 0}}
|
2016-01-24 09:25:54 +00:00
|
|
|
if v.Addr != 0 {
|
2017-04-21 06:55:53 +00:00
|
|
|
v.Base, v.Len, v.Unreadable = readStringInfo(v.mem, v.bi.Arch, v.Addr)
|
2016-01-24 09:25:54 +00:00
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.SliceType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Slice
|
|
|
|
if v.Addr != 0 {
|
|
|
|
v.loadSliceInfo(t)
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.InterfaceType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Interface
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.StructType:
|
2016-01-24 09:25:54 +00:00
|
|
|
v.Kind = reflect.Struct
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.ArrayType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Array
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = v.Addr
|
2015-09-28 09:17:27 +00:00
|
|
|
v.Len = t.Count
|
|
|
|
v.Cap = -1
|
|
|
|
v.fieldType = t.Type
|
|
|
|
v.stride = 0
|
|
|
|
|
|
|
|
if t.Count > 0 {
|
|
|
|
v.stride = t.ByteSize / t.Count
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.ComplexType:
|
2015-10-18 17:37:13 +00:00
|
|
|
switch t.ByteSize {
|
|
|
|
case 8:
|
|
|
|
v.Kind = reflect.Complex64
|
|
|
|
case 16:
|
|
|
|
v.Kind = reflect.Complex128
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.IntType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Int
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.UintType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Uint
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.FloatType:
|
2015-10-18 17:37:13 +00:00
|
|
|
switch t.ByteSize {
|
|
|
|
case 4:
|
|
|
|
v.Kind = reflect.Float32
|
|
|
|
case 8:
|
|
|
|
v.Kind = reflect.Float64
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.BoolType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Bool
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.FuncType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Func
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.VoidType:
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Kind = reflect.Invalid
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.UnspecifiedType:
|
2015-10-18 17:37:13 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func resolveTypedef(typ godwarf.Type) godwarf.Type {
|
2015-11-07 13:50:26 +00:00
|
|
|
for {
|
2017-05-29 13:20:01 +00:00
|
|
|
if tt, ok := typ.(*godwarf.TypedefType); ok {
|
2015-11-07 13:50:26 +00:00
|
|
|
typ = tt.Type
|
|
|
|
} else {
|
|
|
|
return typ
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func newConstant(val constant.Value, mem MemoryReadWriter) *Variable {
|
2016-01-10 12:49:03 +00:00
|
|
|
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)))
|
|
|
|
}
|
2017-09-08 10:31:20 +00:00
|
|
|
v.Flags |= VariableConstant
|
2015-10-30 11:39:32 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
var nilVariable = &Variable{
|
2016-04-24 17:15:39 +00:00
|
|
|
Name: "nil",
|
2015-10-30 11:39:32 +00:00
|
|
|
Addr: 0,
|
2016-01-10 13:08:16 +00:00
|
|
|
Base: 0,
|
2015-10-30 11:39:32 +00:00
|
|
|
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 {
|
2016-07-05 18:58:11 +00:00
|
|
|
return v.DwarfType.Common().Name
|
2015-11-12 11:29:53 +00:00
|
|
|
}
|
|
|
|
return v.Kind.String()
|
|
|
|
}
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func (v *Variable) toField(field *godwarf.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
|
|
|
}
|
2017-08-24 07:46:47 +00:00
|
|
|
return v.newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type, v.mem), 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 {
|
2017-04-21 06:55:53 +00:00
|
|
|
return scope.BinInfo.DwarfReader()
|
2015-08-28 20:06:29 +00:00
|
|
|
}
|
|
|
|
|
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 {
|
2017-04-21 06:55:53 +00:00
|
|
|
return scope.BinInfo.Arch.PtrSize()
|
2015-08-28 20:06:29 +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)
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
func (v *Variable) parseG() (*G, error) {
|
|
|
|
mem := v.mem
|
|
|
|
gaddr := uint64(v.Addr)
|
|
|
|
_, deref := v.RealType.(*godwarf.PtrType)
|
2016-01-10 17:29:14 +00:00
|
|
|
|
2015-06-11 20:17:56 +00:00
|
|
|
if deref {
|
2018-08-31 18:08:18 +00:00
|
|
|
gaddrbytes := make([]byte, v.bi.Arch.PtrSize())
|
2017-04-18 14:24:45 +00:00
|
|
|
_, err := mem.ReadMemory(gaddrbytes, uintptr(gaddr))
|
2015-06-11 20:17:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error derefing *G %s", err)
|
|
|
|
}
|
|
|
|
gaddr = binary.LittleEndian.Uint64(gaddrbytes)
|
2015-04-19 22:11:33 +00:00
|
|
|
}
|
2016-01-20 21:30:47 +00:00
|
|
|
if gaddr == 0 {
|
2016-03-23 12:40:17 +00:00
|
|
|
id := 0
|
2017-04-21 07:50:38 +00:00
|
|
|
if thread, ok := mem.(Thread); ok {
|
2017-04-21 06:55:53 +00:00
|
|
|
id = thread.ThreadID()
|
2016-03-23 12:40:17 +00:00
|
|
|
}
|
2016-05-29 19:20:09 +00:00
|
|
|
return nil, NoGError{tid: id}
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
2017-02-07 21:08:11 +00:00
|
|
|
for {
|
2018-08-31 18:08:18 +00:00
|
|
|
if _, isptr := v.RealType.(*godwarf.PtrType); !isptr {
|
2017-02-07 21:08:11 +00:00
|
|
|
break
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
v = v.maybeDereference()
|
2017-02-07 21:08:11 +00:00
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
v.loadValue(LoadConfig{false, 2, 64, 0, -1})
|
|
|
|
if v.Unreadable != nil {
|
|
|
|
return nil, v.Unreadable
|
2015-05-09 17:44:38 +00:00
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
schedVar := v.fieldVariable("sched")
|
2017-02-07 21:08:11 +00:00
|
|
|
pc, _ := constant.Int64Val(schedVar.fieldVariable("pc").Value)
|
|
|
|
sp, _ := constant.Int64Val(schedVar.fieldVariable("sp").Value)
|
2017-10-05 07:26:19 +00:00
|
|
|
var bp int64
|
|
|
|
if bpvar := schedVar.fieldVariable("bp"); bpvar != nil && bpvar.Value != nil {
|
|
|
|
bp, _ = constant.Int64Val(bpvar.Value)
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
id, _ := constant.Int64Val(v.fieldVariable("goid").Value)
|
|
|
|
gopc, _ := constant.Int64Val(v.fieldVariable("gopc").Value)
|
|
|
|
startpc, _ := constant.Int64Val(v.fieldVariable("startpc").Value)
|
2017-05-09 07:02:07 +00:00
|
|
|
waitReason := ""
|
2018-08-31 18:08:18 +00:00
|
|
|
if wrvar := v.fieldVariable("waitreason"); wrvar.Value != nil {
|
2018-05-08 13:25:17 +00:00
|
|
|
switch wrvar.Kind {
|
|
|
|
case reflect.String:
|
|
|
|
waitReason = constant.StringVal(wrvar.Value)
|
|
|
|
case reflect.Uint:
|
|
|
|
waitReason = wrvar.ConstDescr()
|
|
|
|
}
|
|
|
|
|
2017-05-09 07:02:07 +00:00
|
|
|
}
|
2018-05-04 17:31:45 +00:00
|
|
|
var stackhi, stacklo uint64
|
2018-08-31 18:08:18 +00:00
|
|
|
if stackVar := v.fieldVariable("stack"); stackVar != nil {
|
2017-05-16 18:23:33 +00:00
|
|
|
if stackhiVar := stackVar.fieldVariable("hi"); stackhiVar != nil {
|
|
|
|
stackhi, _ = constant.Uint64Val(stackhiVar.Value)
|
|
|
|
}
|
2018-05-04 17:31:45 +00:00
|
|
|
if stackloVar := stackVar.fieldVariable("lo"); stackloVar != nil {
|
|
|
|
stacklo, _ = constant.Uint64Val(stackloVar.Value)
|
|
|
|
}
|
2017-05-16 18:23:33 +00:00
|
|
|
}
|
2017-03-13 17:53:16 +00:00
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
stkbarVar, _ := v.structMember("stkbar")
|
|
|
|
stkbarVarPosFld := v.fieldVariable("stkbarPos")
|
2017-03-13 17:53:16 +00:00
|
|
|
var stkbarPos int64
|
|
|
|
if stkbarVarPosFld != nil { // stack barriers were removed in Go 1.9
|
|
|
|
stkbarPos, _ = constant.Int64Val(stkbarVarPosFld.Value)
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
status, _ := constant.Int64Val(v.fieldVariable("atomicstatus").Value)
|
|
|
|
f, l, fn := v.bi.PCToLine(uint64(pc))
|
2016-01-20 21:30:47 +00:00
|
|
|
g := &G{
|
|
|
|
ID: int(id),
|
|
|
|
GoPC: uint64(gopc),
|
2018-07-05 11:06:12 +00:00
|
|
|
StartPC: uint64(startpc),
|
2016-01-20 21:30:47 +00:00
|
|
|
PC: uint64(pc),
|
|
|
|
SP: uint64(sp),
|
2017-10-05 07:26:19 +00:00
|
|
|
BP: uint64(bp),
|
2016-01-20 21:30:47 +00:00
|
|
|
WaitReason: waitReason,
|
|
|
|
Status: uint64(status),
|
|
|
|
CurrentLoc: Location{PC: uint64(pc), File: f, Line: l, Fn: fn},
|
2018-08-31 18:08:18 +00:00
|
|
|
variable: v,
|
2017-02-08 13:14:57 +00:00
|
|
|
stkbarVar: stkbarVar,
|
|
|
|
stkbarPos: int(stkbarPos),
|
2017-05-16 18:23:33 +00:00
|
|
|
stackhi: stackhi,
|
2018-05-04 17:31:45 +00:00
|
|
|
stacklo: stacklo,
|
2015-06-11 20:17:56 +00:00
|
|
|
}
|
2016-01-20 21:30:47 +00:00
|
|
|
return g, nil
|
|
|
|
}
|
2015-06-11 20:17:56 +00:00
|
|
|
|
2017-02-07 21:08:11 +00:00
|
|
|
func (v *Variable) loadFieldNamed(name string) *Variable {
|
2016-01-20 21:30:47 +00:00
|
|
|
v, err := v.structMember(name)
|
2014-11-08 14:02:31 +00:00
|
|
|
if err != nil {
|
2016-01-20 21:30:47 +00:00
|
|
|
return nil
|
2014-11-26 02:37:43 +00:00
|
|
|
}
|
2016-04-24 17:15:39 +00:00
|
|
|
v.loadValue(loadFullValue)
|
2016-01-20 21:30:47 +00:00
|
|
|
if v.Unreadable != nil {
|
|
|
|
return nil
|
2015-04-09 14:53:02 +00:00
|
|
|
}
|
2016-01-20 21:30:47 +00:00
|
|
|
return v
|
2014-11-08 14:02:31 +00:00
|
|
|
}
|
|
|
|
|
2017-02-07 21:08:11 +00:00
|
|
|
func (v *Variable) fieldVariable(name string) *Variable {
|
|
|
|
for i := range v.Children {
|
|
|
|
if child := &v.Children[i]; child.Name == name {
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-06 07:37:31 +00:00
|
|
|
// Defer returns the top-most defer of the goroutine.
|
|
|
|
func (g *G) Defer() *Defer {
|
2017-02-07 21:08:11 +00:00
|
|
|
if g.variable.Unreadable != nil {
|
2018-07-06 07:37:31 +00:00
|
|
|
return nil
|
2017-02-07 21:08:11 +00:00
|
|
|
}
|
2018-07-06 07:37:31 +00:00
|
|
|
dvar := g.variable.fieldVariable("_defer").maybeDereference()
|
|
|
|
if dvar.Addr == 0 {
|
|
|
|
return nil
|
2017-02-07 21:08:11 +00:00
|
|
|
}
|
2018-07-06 07:37:31 +00:00
|
|
|
d := &Defer{variable: dvar}
|
|
|
|
d.load()
|
|
|
|
return d
|
2017-02-07 21:08:11 +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 {
|
2016-03-18 08:51:48 +00:00
|
|
|
it, err := g.stackIterator()
|
|
|
|
if err != nil {
|
|
|
|
return g.CurrentLoc
|
2015-10-16 06:42:02 +00:00
|
|
|
}
|
|
|
|
for it.Next() {
|
|
|
|
frame := it.Frame()
|
2016-03-18 08:32:17 +00:00
|
|
|
if frame.Call.Fn != nil {
|
|
|
|
name := frame.Call.Fn.Name
|
2017-06-29 18:15:59 +00:00
|
|
|
if strings.Contains(name, ".") && (!strings.HasPrefix(name, "runtime.") || isExportedRuntime(name)) {
|
2016-03-18 08:32:17 +00:00
|
|
|
return frame.Call
|
|
|
|
}
|
2015-10-16 06:42:02 +00:00
|
|
|
}
|
|
|
|
}
|
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 {
|
2018-03-05 09:40:42 +00:00
|
|
|
pc := g.GoPC
|
2018-05-09 08:08:49 +00:00
|
|
|
if fn := g.variable.bi.PCToFunc(pc); fn != nil {
|
|
|
|
// Backup to CALL instruction.
|
|
|
|
// Mimics runtime/traceback.go:677.
|
|
|
|
if g.GoPC > fn.Entry {
|
2018-08-31 18:08:18 +00:00
|
|
|
pc--
|
2018-05-09 08:08:49 +00:00
|
|
|
}
|
2018-03-05 09:40:42 +00:00
|
|
|
}
|
|
|
|
f, l, fn := g.variable.bi.PCToLine(pc)
|
2015-10-16 06:42:02 +00:00
|
|
|
return Location{PC: g.GoPC, File: f, Line: l, Fn: fn}
|
|
|
|
}
|
|
|
|
|
2018-07-05 11:06:12 +00:00
|
|
|
// StartLoc returns the starting location of the goroutine.
|
|
|
|
func (g *G) StartLoc() Location {
|
|
|
|
f, l, fn := g.variable.bi.PCToLine(g.StartPC)
|
|
|
|
return Location{PC: g.StartPC, File: f, Line: l, Fn: fn}
|
|
|
|
}
|
|
|
|
|
2017-02-08 13:14:57 +00:00
|
|
|
// Returns the list of saved return addresses used by stack barriers
|
|
|
|
func (g *G) stkbar() ([]savedLR, error) {
|
2017-03-13 17:53:16 +00:00
|
|
|
if g.stkbarVar == nil { // stack barriers were removed in Go 1.9
|
|
|
|
return nil, nil
|
|
|
|
}
|
2017-02-08 13:14:57 +00:00
|
|
|
g.stkbarVar.loadValue(LoadConfig{false, 1, 0, int(g.stkbarVar.Len), 3})
|
|
|
|
if g.stkbarVar.Unreadable != nil {
|
2018-08-31 18:08:18 +00:00
|
|
|
return nil, fmt.Errorf("unreadable stkbar: %v", g.stkbarVar.Unreadable)
|
2017-02-08 13:14:57 +00:00
|
|
|
}
|
|
|
|
r := make([]savedLR, len(g.stkbarVar.Children))
|
|
|
|
for i, child := range g.stkbarVar.Children {
|
|
|
|
for _, field := range child.Children {
|
|
|
|
switch field.Name {
|
|
|
|
case "savedLRPtr":
|
|
|
|
ptr, _ := constant.Int64Val(field.Value)
|
|
|
|
r[i].ptr = uint64(ptr)
|
|
|
|
case "savedLRVal":
|
|
|
|
val, _ := constant.Int64Val(field.Value)
|
|
|
|
r[i].val = uint64(val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
// EvalVariable returns the value of the given expression (backwards compatibility).
|
2016-04-24 17:15:39 +00:00
|
|
|
func (scope *EvalScope) EvalVariable(name string, cfg LoadConfig) (*Variable, error) {
|
|
|
|
return scope.EvalExpression(name, cfg)
|
2015-10-30 11:39:32 +00:00
|
|
|
}
|
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
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
return xv.setValue(yv, value)
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-04 04:20:25 +00:00
|
|
|
// LocalVariables returns all local variables from the current function scope.
|
2016-04-24 17:15:39 +00:00
|
|
|
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
2018-04-15 12:11:27 +00:00
|
|
|
vars, err := scope.Locals()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
vars = filterVariables(vars, func(v *Variable) bool {
|
|
|
|
return (v.Flags & (VariableArgument | VariableReturnArgument)) == 0
|
|
|
|
})
|
|
|
|
loadValues(vars, cfg)
|
|
|
|
return vars, nil
|
2015-02-04 04:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FunctionArguments returns the name, value, and type of all current function arguments.
|
2016-04-24 17:15:39 +00:00
|
|
|
func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) {
|
2018-04-15 12:11:27 +00:00
|
|
|
vars, err := scope.Locals()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
vars = filterVariables(vars, func(v *Variable) bool {
|
|
|
|
return (v.Flags & (VariableArgument | VariableReturnArgument)) != 0
|
|
|
|
})
|
|
|
|
loadValues(vars, cfg)
|
|
|
|
return vars, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func filterVariables(vars []*Variable, pred func(v *Variable) bool) []*Variable {
|
|
|
|
r := make([]*Variable, 0, len(vars))
|
|
|
|
for i := range vars {
|
|
|
|
if pred(vars[i]) {
|
|
|
|
r = append(r, vars[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
2015-02-04 04:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PackageVariables returns the name, value, and type of all package variables in the application.
|
2016-04-24 17:15:39 +00:00
|
|
|
func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*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
|
|
|
|
2016-02-21 16:26:13 +00:00
|
|
|
var utypoff dwarf.Offset
|
|
|
|
utypentry, err := reader.SeekToTypeNamed("<unspecified>")
|
|
|
|
if err == nil {
|
|
|
|
utypoff = utypentry.Offset
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2016-02-21 16:26:13 +00:00
|
|
|
if typoff, ok := entry.Val(dwarf.AttrType).(dwarf.Offset); !ok || typoff == utypoff {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2015-02-04 04:20:25 +00:00
|
|
|
// Ignore errors trying to extract values
|
2017-08-24 07:46:47 +00:00
|
|
|
val, err := scope.extractVarInfoFromEntry(entry)
|
2015-02-04 04:20:25 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2017-02-07 21:08:11 +00:00
|
|
|
val.loadValue(cfg)
|
2015-02-04 04:20:25 +00:00
|
|
|
vars = append(vars, val)
|
|
|
|
}
|
|
|
|
|
|
|
|
return vars, nil
|
|
|
|
}
|
|
|
|
|
2017-09-08 10:31:20 +00:00
|
|
|
func (scope *EvalScope) findGlobal(name string) (*Variable, error) {
|
2017-10-26 11:37:19 +00:00
|
|
|
for _, pkgvar := range scope.BinInfo.packageVars {
|
|
|
|
if pkgvar.name == name || strings.HasSuffix(pkgvar.name, "/"+name) {
|
2017-07-18 18:55:24 +00:00
|
|
|
reader := scope.DwarfReader()
|
2017-10-26 11:37:19 +00:00
|
|
|
reader.Seek(pkgvar.offset)
|
2017-07-18 18:55:24 +00:00
|
|
|
entry, err := reader.Next()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
return scope.extractVarInfoFromEntry(entry)
|
2015-07-23 17:08:28 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-04 17:31:45 +00:00
|
|
|
for _, fn := range scope.BinInfo.Functions {
|
|
|
|
if fn.Name == name || strings.HasSuffix(fn.Name, "/"+name) {
|
|
|
|
//TODO(aarzilli): convert function entry into a function type?
|
|
|
|
r := scope.newVariable(fn.Name, uintptr(fn.Entry), &godwarf.FuncType{}, scope.Mem)
|
|
|
|
r.Value = constant.MakeString(fn.Name)
|
|
|
|
r.Base = uintptr(fn.Entry)
|
|
|
|
r.loaded = true
|
|
|
|
return r, nil
|
|
|
|
}
|
|
|
|
}
|
2017-09-08 10:31:20 +00:00
|
|
|
for offset, ctyp := range scope.BinInfo.consts {
|
|
|
|
for _, cval := range ctyp.values {
|
2018-03-17 10:14:34 +00:00
|
|
|
if cval.fullName == name || strings.HasSuffix(cval.fullName, "/"+name) {
|
2018-05-04 17:31:45 +00:00
|
|
|
t, err := scope.BinInfo.Type(offset)
|
2017-09-08 10:31:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
v := scope.newVariable(name, 0x0, t, scope.Mem)
|
|
|
|
switch v.Kind {
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
v.Value = constant.MakeInt64(cval.value)
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
|
|
v.Value = constant.MakeUint64(uint64(cval.value))
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported constant kind %v", v.Kind)
|
|
|
|
}
|
|
|
|
v.Flags |= VariableConstant
|
|
|
|
v.loaded = true
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
}
|
2018-07-31 12:50:10 +00:00
|
|
|
vname := v.Name
|
2017-10-26 14:14:31 +00:00
|
|
|
switch v.Kind {
|
|
|
|
case reflect.Chan:
|
|
|
|
v = v.clone()
|
|
|
|
v.RealType = resolveTypedef(&(v.RealType.(*godwarf.ChanType).TypedefType))
|
2017-10-26 16:08:01 +00:00
|
|
|
case reflect.Interface:
|
|
|
|
v.loadInterface(0, false, LoadConfig{})
|
|
|
|
if len(v.Children) > 0 {
|
|
|
|
v = &v.Children[0]
|
|
|
|
}
|
2017-10-26 14:14:31 +00:00
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
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) {
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.StructType:
|
2015-09-28 09:17:27 +00:00
|
|
|
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 :=
|
2017-05-03 07:56:59 +00:00
|
|
|
field.Embedded ||
|
|
|
|
(field.Type.Common().Name == field.Name) ||
|
2015-10-07 01:21:28 +00:00
|
|
|
(len(field.Name) > 1 &&
|
|
|
|
field.Name[0] == '*' &&
|
2016-07-05 18:58:11 +00:00
|
|
|
field.Type.Common().Name[1:] == 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
|
2017-06-29 18:15:59 +00:00
|
|
|
embeddedField, _ := embeddedVar.structMember(memberName)
|
2015-10-01 00:36:36 +00:00
|
|
|
if embeddedField != nil {
|
|
|
|
return embeddedField, nil
|
2014-12-31 21:13:28 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-31 12:50:10 +00:00
|
|
|
return nil, fmt.Errorf("%s has no member %s", vname, memberName)
|
2015-09-28 09:17:27 +00:00
|
|
|
default:
|
2015-11-12 11:29:53 +00:00
|
|
|
if v.Name == "" {
|
|
|
|
return nil, fmt.Errorf("type %s is not a struct", structVar.TypeString())
|
|
|
|
}
|
2018-07-31 12:50:10 +00:00
|
|
|
return nil, fmt.Errorf("%s (type %s) is not a struct", vname, structVar.TypeString())
|
2014-12-31 21:13:28 +00:00
|
|
|
}
|
2014-12-03 05:30:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-04 17:31:45 +00:00
|
|
|
func readVarEntry(varEntry *dwarf.Entry, bi *BinaryInfo) (entry reader.Entry, name string, typ godwarf.Type, err error) {
|
|
|
|
entry, _ = reader.LoadAbstractOrigin(varEntry, bi.dwarfReader)
|
|
|
|
|
|
|
|
name, ok := entry.Val(dwarf.AttrName).(string)
|
|
|
|
if !ok {
|
|
|
|
return nil, "", nil, fmt.Errorf("malformed variable DIE (name)")
|
|
|
|
}
|
|
|
|
|
|
|
|
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
|
|
|
if !ok {
|
|
|
|
return nil, "", nil, fmt.Errorf("malformed variable DIE (offset)")
|
|
|
|
}
|
|
|
|
|
|
|
|
typ, err = bi.Type(offset)
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry, name, typ, nil
|
|
|
|
}
|
|
|
|
|
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
|
2018-02-13 17:20:45 +00:00
|
|
|
func (scope *EvalScope) extractVarInfoFromEntry(varEntry *dwarf.Entry) (*Variable, error) {
|
|
|
|
if varEntry == nil {
|
2015-05-04 22:31:13 +00:00
|
|
|
return nil, fmt.Errorf("invalid entry")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2018-02-13 17:20:45 +00:00
|
|
|
if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable {
|
|
|
|
return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", varEntry.Tag.String())
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2018-05-04 17:31:45 +00:00
|
|
|
entry, n, t, err := readVarEntry(varEntry, scope.BinInfo)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-11-21 08:50:14 +00:00
|
|
|
addr, pieces, descr, err := scope.BinInfo.Location(entry, dwarf.AttrLocation, scope.PC, scope.Regs)
|
2017-08-24 07:46:47 +00:00
|
|
|
mem := scope.Mem
|
|
|
|
if pieces != nil {
|
|
|
|
addr = fakeAddress
|
|
|
|
mem = newCompositeMemory(scope.Mem, scope.Regs, pieces)
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
v := scope.newVariable(n, uintptr(addr), t, mem)
|
2017-11-21 08:50:14 +00:00
|
|
|
v.LocationExpr = descr
|
2018-06-28 09:23:39 +00:00
|
|
|
v.DeclLine, _ = entry.Val(dwarf.AttrDeclLine).(int64)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
2017-08-22 14:40:01 +00:00
|
|
|
v.Unreadable = err
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
2017-08-22 14:40:01 +00:00
|
|
|
return v, 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) {
|
2017-05-29 13:20:01 +00:00
|
|
|
case *godwarf.PtrType:
|
2016-01-10 12:49:03 +00:00
|
|
|
ptrval, err := readUintRaw(v.mem, uintptr(v.Addr), t.ByteSize)
|
2017-08-24 07:46:47 +00:00
|
|
|
r := v.newVariable("", uintptr(ptrval), t.Type, DereferenceMemory(v.mem))
|
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
|
|
|
|
2018-04-15 12:11:27 +00:00
|
|
|
func loadValues(vars []*Variable, cfg LoadConfig) {
|
|
|
|
for i := range vars {
|
|
|
|
vars[i].loadValueInternal(0, cfg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-29 05:25:40 +00:00
|
|
|
// Extracts the value of the variable at the given address.
|
2016-04-24 17:15:39 +00:00
|
|
|
func (v *Variable) loadValue(cfg LoadConfig) {
|
|
|
|
v.loadValueInternal(0, cfg)
|
2015-09-28 09:17:27 +00:00
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) {
|
2016-01-10 13:08:16 +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()}
|
2016-04-24 17:15:39 +00:00
|
|
|
if cfg.FollowPointers {
|
|
|
|
// Don't increase the recursion level when dereferencing pointers
|
2017-02-10 00:26:38 +00:00
|
|
|
// unless this is a pointer to interface (which could cause an infinite loop)
|
|
|
|
nextLvl := recurseLevel
|
|
|
|
if v.Children[0].Kind == reflect.Interface {
|
|
|
|
nextLvl++
|
|
|
|
}
|
|
|
|
v.Children[0].loadValueInternal(nextLvl, cfg)
|
2016-04-24 17:15:39 +00:00
|
|
|
} else {
|
|
|
|
v.Children[0].OnlyAddr = true
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2015-11-03 18:11:08 +00:00
|
|
|
case reflect.Chan:
|
2016-01-24 09:25:54 +00:00
|
|
|
sv := v.clone()
|
2017-05-29 13:20:01 +00:00
|
|
|
sv.RealType = resolveTypedef(&(sv.RealType.(*godwarf.ChanType).TypedefType))
|
2016-01-24 09:25:54 +00:00
|
|
|
sv = sv.maybeDereference()
|
2016-04-24 17:15:39 +00:00
|
|
|
sv.loadValueInternal(0, loadFullValue)
|
2015-11-03 18:11:08 +00:00
|
|
|
v.Children = sv.Children
|
|
|
|
v.Len = sv.Len
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = sv.Addr
|
2015-11-03 18:11:08 +00:00
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
case reflect.Map:
|
2016-04-24 17:15:39 +00:00
|
|
|
if recurseLevel <= cfg.MaxVariableRecurse {
|
|
|
|
v.loadMap(recurseLevel, cfg)
|
2017-05-30 21:26:10 +00:00
|
|
|
} else {
|
|
|
|
// loads length so that the client knows that the map isn't empty
|
|
|
|
v.mapIterator()
|
2016-02-07 07:56:11 +00:00
|
|
|
}
|
2015-11-05 17:25:52 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.String:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val string
|
2017-08-24 07:46:47 +00:00
|
|
|
val, v.Unreadable = readStringValue(DereferenceMemory(v.mem), v.Base, v.Len, cfg)
|
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:
|
2016-04-24 17:15:39 +00:00
|
|
|
v.loadArrayValues(recurseLevel, cfg)
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
case reflect.Struct:
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size()))
|
2017-05-29 13:20:01 +00:00
|
|
|
t := v.RealType.(*godwarf.StructType)
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Len = int64(len(t.Field))
|
|
|
|
// Recursively call extractValue to grab
|
|
|
|
// the value of all the members of the struct.
|
2016-04-24 17:15:39 +00:00
|
|
|
if recurseLevel <= cfg.MaxVariableRecurse {
|
2015-10-18 17:37:13 +00:00
|
|
|
v.Children = make([]Variable, 0, len(t.Field))
|
|
|
|
for i, field := range t.Field {
|
2016-04-24 17:15:39 +00:00
|
|
|
if cfg.MaxStructFields >= 0 && len(v.Children) >= cfg.MaxStructFields {
|
|
|
|
break
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
f, _ := v.toField(field)
|
|
|
|
v.Children = append(v.Children, *f)
|
|
|
|
v.Children[i].Name = field.Name
|
2016-04-24 17:15:39 +00:00
|
|
|
v.Children[i].loadValueInternal(recurseLevel+1, cfg)
|
2015-10-18 17:37:13 +00:00
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
|
2015-11-12 11:30:41 +00:00
|
|
|
case reflect.Interface:
|
2016-04-24 17:15:39 +00:00
|
|
|
v.loadInterface(recurseLevel, true, cfg)
|
2015-11-12 11:30:41 +00:00
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Complex64, reflect.Complex128:
|
2017-05-29 13:20:01 +00:00
|
|
|
v.readComplex(v.RealType.(*godwarf.ComplexType).ByteSize)
|
2015-10-18 17:37:13 +00:00
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2015-10-21 07:06:36 +00:00
|
|
|
var val int64
|
2017-05-29 13:20:01 +00:00
|
|
|
val, v.Unreadable = readIntRaw(v.mem, v.Addr, v.RealType.(*godwarf.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
|
2017-05-29 13:20:01 +00:00
|
|
|
val, v.Unreadable = readUintRaw(v.mem, v.Addr, v.RealType.(*godwarf.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:
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, 1)
|
|
|
|
_, err := v.mem.ReadMemory(val, v.Addr)
|
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
|
2017-05-29 13:20:01 +00:00
|
|
|
val, v.Unreadable = v.readFloatRaw(v.RealType.(*godwarf.FloatType).ByteSize)
|
2015-10-21 07:06:36 +00:00
|
|
|
v.Value = constant.MakeFloat64(val)
|
2017-01-20 22:22:36 +00:00
|
|
|
switch {
|
|
|
|
case math.IsInf(val, +1):
|
|
|
|
v.FloatSpecial = FloatIsPosInf
|
|
|
|
case math.IsInf(val, -1):
|
|
|
|
v.FloatSpecial = FloatIsNegInf
|
|
|
|
case math.IsNaN(val):
|
|
|
|
v.FloatSpecial = FloatIsNaN
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
// setValue writes the value of srcv to dstv.
|
|
|
|
// * If srcv is a numerical literal constant and srcv is of a compatible type
|
|
|
|
// the necessary type conversion is performed.
|
|
|
|
// * If srcv is nil and dstv is of a nil'able type then dstv is nilled.
|
|
|
|
// * If srcv is the empty string and dstv is a string then dstv is set to the
|
|
|
|
// empty string.
|
|
|
|
// * If dstv is an "interface {}" and srcv is either an interface (possibly
|
|
|
|
// non-empty) or a pointer shaped type (map, channel, pointer or struct
|
|
|
|
// containing a single pointer field) the type conversion to "interface {}"
|
|
|
|
// is performed.
|
|
|
|
// * If srcv and dstv have the same type and are both addressable then the
|
|
|
|
// contents of srcv are copied byte-by-byte into dstv
|
2018-08-31 18:08:18 +00:00
|
|
|
func (v *Variable) setValue(srcv *Variable, srcExpr string) error {
|
2018-07-27 17:19:01 +00:00
|
|
|
srcv.loadValue(loadSingleValue)
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
typerr := srcv.isType(v.RealType, v.Kind)
|
2018-07-27 17:19:01 +00:00
|
|
|
if _, isTypeConvErr := typerr.(*typeConvErr); isTypeConvErr {
|
|
|
|
// attempt iface -> eface and ptr-shaped -> eface conversions.
|
2018-08-31 18:08:18 +00:00
|
|
|
return convertToEface(srcv, v)
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
if typerr != nil {
|
|
|
|
return typerr
|
|
|
|
}
|
|
|
|
|
|
|
|
if srcv.Unreadable != nil {
|
|
|
|
return fmt.Errorf("Expression \"%s\" is unreadable: %v", srcExpr, srcv.Unreadable)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Numerical types
|
2018-08-31 18:08:18 +00:00
|
|
|
switch v.Kind {
|
2015-10-30 11:39:32 +00:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2018-07-27 17:19:01 +00:00
|
|
|
f, _ := constant.Float64Val(srcv.Value)
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeFloatRaw(f, v.RealType.Size())
|
2015-10-30 11:39:32 +00:00
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2018-07-27 17:19:01 +00:00
|
|
|
n, _ := constant.Int64Val(srcv.Value)
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeUint(uint64(n), v.RealType.Size())
|
2015-10-30 11:39:32 +00:00
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
2018-07-27 17:19:01 +00:00
|
|
|
n, _ := constant.Uint64Val(srcv.Value)
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeUint(n, v.RealType.Size())
|
2015-10-30 11:39:32 +00:00
|
|
|
case reflect.Bool:
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeBool(constant.BoolVal(srcv.Value))
|
2015-10-30 11:39:32 +00:00
|
|
|
case reflect.Complex64, reflect.Complex128:
|
2018-07-27 17:19:01 +00:00
|
|
|
real, _ := constant.Float64Val(constant.Real(srcv.Value))
|
|
|
|
imag, _ := constant.Float64Val(constant.Imag(srcv.Value))
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeComplex(real, imag, v.RealType.Size())
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
2015-10-30 11:39:32 +00:00
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
// nilling nillable variables
|
|
|
|
if srcv == nilVariable {
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeZero()
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set a string to ""
|
|
|
|
if srcv.Kind == reflect.String && srcv.Len == 0 {
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeZero()
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// slice assignment (this is not handled by the writeCopy below so that
|
|
|
|
// results of a reslice operation can be used here).
|
|
|
|
if srcv.Kind == reflect.Slice {
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeSlice(srcv.Len, srcv.Cap, srcv.Base)
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// allow any integer to be converted to any pointer
|
2018-08-31 18:08:18 +00:00
|
|
|
if t, isptr := v.RealType.(*godwarf.PtrType); isptr {
|
|
|
|
return v.writeUint(uint64(srcv.Children[0].Addr), int64(t.ByteSize))
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// byte-by-byte copying for everything else, but the source must be addressable
|
|
|
|
if srcv.Addr != 0 {
|
2018-08-31 18:08:18 +00:00
|
|
|
return v.writeCopy(srcv)
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
return fmt.Errorf("can not set variables of type %s (not implemented)", v.Kind.String())
|
2018-07-27 17:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// convertToEface converts srcv into an "interface {}" and writes it to
|
|
|
|
// dstv.
|
2018-07-28 19:12:07 +00:00
|
|
|
// Dstv must be a variable of type "inteface {}" and srcv must either be an
|
2018-07-27 17:19:01 +00:00
|
|
|
// interface or a pointer shaped variable (map, channel, pointer or struct
|
|
|
|
// containing a single pointer)
|
|
|
|
func convertToEface(srcv, dstv *Variable) error {
|
|
|
|
if dstv.RealType.String() != "interface {}" {
|
|
|
|
return &typeConvErr{srcv.DwarfType, dstv.RealType}
|
|
|
|
}
|
|
|
|
if _, isiface := srcv.RealType.(*godwarf.InterfaceType); isiface {
|
|
|
|
// iface -> eface conversion
|
|
|
|
_type, data, _ := srcv.readInterface()
|
|
|
|
if srcv.Unreadable != nil {
|
|
|
|
return srcv.Unreadable
|
|
|
|
}
|
|
|
|
_type = _type.maybeDereference()
|
|
|
|
dstv.writeEmptyInterface(uint64(_type.Addr), data)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
typeAddr, typeKind, runtimeTypeFound, err := dwarfToRuntimeType(srcv.bi, srcv.mem, srcv.RealType)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !runtimeTypeFound || typeKind&kindDirectIface == 0 {
|
|
|
|
return &typeConvErr{srcv.DwarfType, dstv.RealType}
|
|
|
|
}
|
|
|
|
return dstv.writeEmptyInterface(typeAddr, srcv)
|
2015-09-28 10:01:18 +00:00
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +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
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, arch.PtrSize())
|
|
|
|
_, err := mem.ReadMemory(val, addr+uintptr(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
|
2017-04-18 14:24:45 +00:00
|
|
|
_, err = mem.ReadMemory(val, addr)
|
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
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func readStringValue(mem MemoryReadWriter, addr uintptr, strlen int64, cfg LoadConfig) (string, error) {
|
2018-03-08 13:17:59 +00:00
|
|
|
if strlen == 0 {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2015-10-30 11:39:32 +00:00
|
|
|
count := strlen
|
2016-04-24 17:15:39 +00:00
|
|
|
if count > int64(cfg.MaxStringLen) {
|
|
|
|
count = int64(cfg.MaxStringLen)
|
2015-10-30 11:39:32 +00:00
|
|
|
}
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, int(count))
|
|
|
|
_, err := mem.ReadMemory(val, addr)
|
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
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
const (
|
|
|
|
sliceArrayFieldName = "array"
|
|
|
|
sliceLenFieldName = "len"
|
|
|
|
sliceCapFieldName = "cap"
|
|
|
|
)
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
func (v *Variable) loadSliceInfo(t *godwarf.SliceType) {
|
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 {
|
2018-07-27 17:19:01 +00:00
|
|
|
case sliceArrayFieldName:
|
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 {
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = uintptr(base)
|
2015-09-28 09:17:27 +00:00
|
|
|
// Dereference array type to get value type
|
2017-05-29 13:20:01 +00:00
|
|
|
ptrType, ok := f.Type.(*godwarf.PtrType)
|
2015-09-28 09:17:27 +00:00
|
|
|
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
|
|
|
}
|
2018-07-27 17:19:01 +00:00
|
|
|
case sliceLenFieldName:
|
2015-10-18 17:37:13 +00:00
|
|
|
lstrAddr, _ := v.toField(f)
|
2016-04-24 17:15:39 +00:00
|
|
|
lstrAddr.loadValue(loadSingleValue)
|
2015-10-18 17:37:13 +00:00
|
|
|
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
|
|
|
}
|
2018-07-27 17:19:01 +00:00
|
|
|
case sliceCapFieldName:
|
2015-10-18 17:37:13 +00:00
|
|
|
cstrAddr, _ := v.toField(f)
|
2016-04-24 17:15:39 +00:00
|
|
|
cstrAddr.loadValue(loadSingleValue)
|
2015-10-18 17:37:13 +00:00
|
|
|
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()
|
2017-05-29 13:20:01 +00:00
|
|
|
if t, ok := v.fieldType.(*godwarf.PtrType); ok {
|
2016-01-10 12:49:03 +00:00
|
|
|
v.stride = t.ByteSize
|
2014-10-25 15:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 14:14:31 +00:00
|
|
|
// loadChanInfo loads the buffer size of the channel and changes the type of
|
|
|
|
// the buf field from unsafe.Pointer to an array of the correct type.
|
|
|
|
func (v *Variable) loadChanInfo() {
|
|
|
|
chanType, ok := v.RealType.(*godwarf.ChanType)
|
|
|
|
if !ok {
|
|
|
|
v.Unreadable = errors.New("bad channel type")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sv := v.clone()
|
|
|
|
sv.RealType = resolveTypedef(&(chanType.TypedefType))
|
|
|
|
sv = sv.maybeDereference()
|
|
|
|
if sv.Unreadable != nil || sv.Addr == 0 {
|
|
|
|
return
|
|
|
|
}
|
2018-05-04 17:31:45 +00:00
|
|
|
v.Base = sv.Addr
|
2017-10-26 14:14:31 +00:00
|
|
|
structType, ok := sv.DwarfType.(*godwarf.StructType)
|
|
|
|
if !ok {
|
|
|
|
v.Unreadable = errors.New("bad channel type")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
lenAddr, _ := sv.toField(structType.Field[1])
|
|
|
|
lenAddr.loadValue(loadSingleValue)
|
|
|
|
if lenAddr.Unreadable != nil {
|
|
|
|
v.Unreadable = fmt.Errorf("unreadable length: %v", lenAddr.Unreadable)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
chanLen, _ := constant.Uint64Val(lenAddr.Value)
|
|
|
|
|
|
|
|
newStructType := &godwarf.StructType{}
|
|
|
|
*newStructType = *structType
|
|
|
|
newStructType.Field = make([]*godwarf.StructField, len(structType.Field))
|
|
|
|
|
|
|
|
for i := range structType.Field {
|
|
|
|
field := &godwarf.StructField{}
|
|
|
|
*field = *structType.Field[i]
|
|
|
|
if field.Name == "buf" {
|
|
|
|
stride := chanType.ElemType.Common().ByteSize
|
|
|
|
atyp := &godwarf.ArrayType{
|
|
|
|
CommonType: godwarf.CommonType{
|
|
|
|
ReflectKind: reflect.Array,
|
|
|
|
ByteSize: int64(chanLen) * stride,
|
|
|
|
Name: fmt.Sprintf("[%d]%s", chanLen, chanType.ElemType.String())},
|
|
|
|
Type: chanType.ElemType,
|
|
|
|
StrideBitSize: stride * 8,
|
|
|
|
Count: int64(chanLen)}
|
|
|
|
|
|
|
|
field.Type = pointerTo(atyp, v.bi.Arch)
|
|
|
|
}
|
|
|
|
newStructType.Field[i] = field
|
|
|
|
}
|
|
|
|
|
|
|
|
v.RealType = &godwarf.ChanType{
|
|
|
|
TypedefType: godwarf.TypedefType{
|
|
|
|
CommonType: chanType.TypedefType.CommonType,
|
|
|
|
Type: pointerTo(newStructType, v.bi.Arch),
|
|
|
|
},
|
|
|
|
ElemType: chanType.ElemType,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) {
|
2015-10-18 17:37:13 +00:00
|
|
|
if v.Unreadable != nil {
|
|
|
|
return
|
|
|
|
}
|
2016-01-30 21:21:07 +00:00
|
|
|
if v.Len < 0 {
|
|
|
|
v.Unreadable = errors.New("Negative array length")
|
|
|
|
return
|
|
|
|
}
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
count := v.Len
|
|
|
|
// Cap number of elements
|
2016-04-24 17:15:39 +00:00
|
|
|
if count > int64(cfg.MaxArrayValues) {
|
|
|
|
count = int64(cfg.MaxArrayValues)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
2014-10-25 15:48:14 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
if v.stride < maxArrayStridePrefetch {
|
2016-01-10 13:08:16 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Base, int(v.stride*count))
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
2015-02-02 07:13:42 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
errcount := 0
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
mem := v.mem
|
|
|
|
if v.Kind != reflect.Array {
|
|
|
|
mem = DereferenceMemory(mem)
|
|
|
|
}
|
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
for i := int64(0); i < count; i++ {
|
2017-08-24 07:46:47 +00:00
|
|
|
fieldvar := v.newVariable("", uintptr(int64(v.Base)+(i*v.stride)), v.fieldType, mem)
|
2016-04-24 17:15:39 +00:00
|
|
|
fieldvar.loadValueInternal(recurseLevel+1, cfg)
|
2015-10-18 17:37:13 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
ftyp := &godwarf.FloatType{BasicType: godwarf.BasicType{CommonType: godwarf.CommonType{ByteSize: fs, Name: fmt.Sprintf("float%d", fs)}, BitSize: fs * 8, BitOffset: 0}}
|
2015-10-18 17:37:13 +00:00
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
realvar := v.newVariable("real", v.Addr, ftyp, v.mem)
|
|
|
|
imagvar := v.newVariable("imaginary", v.Addr+uintptr(fs), ftyp, v.mem)
|
2016-04-24 17:15:39 +00:00
|
|
|
realvar.loadValue(loadSingleValue)
|
|
|
|
imagvar.loadValue(loadSingleValue)
|
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))
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +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
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, int(size))
|
|
|
|
_, err := mem.ReadMemory(val, addr)
|
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:
|
2016-11-02 21:32:48 +00:00
|
|
|
n = int64(int8(val[0]))
|
2014-10-25 16:05:03 +00:00
|
|
|
case 2:
|
2016-11-02 21:32:48 +00:00
|
|
|
n = int64(int16(binary.LittleEndian.Uint16(val)))
|
2014-10-25 16:05:03 +00:00
|
|
|
case 4:
|
2016-11-02 21:32:48 +00:00
|
|
|
n = int64(int32(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
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
_, err := v.mem.WriteMemory(v.Addr, val)
|
2015-09-28 10:01:18 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func readUintRaw(mem MemoryReadWriter, addr uintptr, size int64) (uint64, error) {
|
2015-01-20 03:18:17 +00:00
|
|
|
var n uint64
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, int(size))
|
|
|
|
_, err := mem.ReadMemory(val, addr)
|
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) {
|
2017-04-18 14:24:45 +00:00
|
|
|
val := make([]byte, int(size))
|
|
|
|
_, err := v.mem.ReadMemory(val, v.Addr)
|
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)
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +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))
|
2017-04-21 06:55:53 +00:00
|
|
|
_, err := v.mem.WriteMemory(v.Addr, val)
|
2015-09-28 10:01:18 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
func (v *Variable) writeZero() error {
|
|
|
|
val := make([]byte, v.RealType.Size())
|
|
|
|
_, err := v.mem.WriteMemory(v.Addr, val)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeInterface writes the empty interface of type typeAddr and data as the data field.
|
|
|
|
func (v *Variable) writeEmptyInterface(typeAddr uint64, data *Variable) error {
|
|
|
|
dstType, dstData, _ := v.readInterface()
|
|
|
|
if v.Unreadable != nil {
|
|
|
|
return v.Unreadable
|
|
|
|
}
|
|
|
|
dstType.writeUint(typeAddr, dstType.RealType.Size())
|
|
|
|
dstData.writeCopy(data)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Variable) writeSlice(len, cap int64, base uintptr) error {
|
|
|
|
for _, f := range v.RealType.(*godwarf.SliceType).Field {
|
|
|
|
switch f.Name {
|
|
|
|
case sliceArrayFieldName:
|
|
|
|
arrv, _ := v.toField(f)
|
|
|
|
if err := arrv.writeUint(uint64(base), arrv.RealType.Size()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case sliceLenFieldName:
|
|
|
|
lenv, _ := v.toField(f)
|
|
|
|
if err := lenv.writeUint(uint64(len), lenv.RealType.Size()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case sliceCapFieldName:
|
|
|
|
capv, _ := v.toField(f)
|
|
|
|
if err := capv.writeUint(uint64(cap), capv.RealType.Size()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
func (v *Variable) writeCopy(srcv *Variable) error {
|
2018-07-27 17:19:01 +00:00
|
|
|
buf := make([]byte, srcv.RealType.Size())
|
|
|
|
_, err := srcv.mem.ReadMemory(buf, srcv.Addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-31 18:08:18 +00:00
|
|
|
_, err = v.mem.WriteMemory(v.Addr, buf)
|
2018-07-27 17:19:01 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-10-18 17:37:13 +00:00
|
|
|
func (v *Variable) readFunctionPtr() {
|
2018-07-31 16:32:30 +00:00
|
|
|
// dereference pointer to find function pc
|
|
|
|
fnaddr := v.funcvalAddr()
|
|
|
|
if v.Unreadable != nil {
|
2015-10-18 17:37:13 +00:00
|
|
|
return
|
2015-01-20 04:15:40 +00:00
|
|
|
}
|
2015-09-28 09:17:27 +00:00
|
|
|
if fnaddr == 0 {
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = 0
|
2015-10-30 11:39:32 +00:00
|
|
|
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
|
|
|
|
2018-07-31 16:32:30 +00:00
|
|
|
val := make([]byte, v.bi.Arch.PtrSize())
|
|
|
|
_, err := v.mem.ReadMemory(val, uintptr(fnaddr))
|
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
|
|
|
}
|
|
|
|
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = uintptr(binary.LittleEndian.Uint64(val))
|
2017-09-01 13:30:45 +00:00
|
|
|
fn := v.bi.PCToFunc(uint64(v.Base))
|
2015-05-03 19:11:17 +00:00
|
|
|
if fn == nil {
|
2016-01-10 13:08:16 +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
|
|
|
}
|
|
|
|
|
2018-07-31 16:32:30 +00:00
|
|
|
// funcvalAddr reads the address of the funcval contained in a function variable.
|
|
|
|
func (v *Variable) funcvalAddr() uint64 {
|
|
|
|
val := make([]byte, v.bi.Arch.PtrSize())
|
|
|
|
_, err := v.mem.ReadMemory(val, v.Addr)
|
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = err
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return binary.LittleEndian.Uint64(val)
|
|
|
|
}
|
|
|
|
|
2016-04-24 17:15:39 +00:00
|
|
|
func (v *Variable) loadMap(recurseLevel int, cfg LoadConfig) {
|
2015-11-05 17:25:52 +00:00
|
|
|
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() {
|
2016-04-24 17:15:39 +00:00
|
|
|
if count >= cfg.MaxArrayValues {
|
2015-11-05 17:25:52 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
key := it.key()
|
2017-05-26 18:36:28 +00:00
|
|
|
var val *Variable
|
|
|
|
if it.values.fieldType.Size() > 0 {
|
|
|
|
val = it.value()
|
|
|
|
} else {
|
2017-08-24 07:46:47 +00:00
|
|
|
val = v.newVariable("", it.values.Addr, it.values.fieldType, DereferenceMemory(v.mem))
|
2017-05-26 18:36:28 +00:00
|
|
|
}
|
2016-04-24 17:15:39 +00:00
|
|
|
key.loadValueInternal(recurseLevel+1, cfg)
|
|
|
|
val.loadValueInternal(recurseLevel+1, cfg)
|
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 {
|
2016-01-24 09:25:54 +00:00
|
|
|
sv := v.clone()
|
2017-05-29 13:20:01 +00:00
|
|
|
sv.RealType = resolveTypedef(&(sv.RealType.(*godwarf.MapType).TypedefType))
|
2016-01-24 09:25:54 +00:00
|
|
|
sv = sv.maybeDereference()
|
2016-01-10 13:08:16 +00:00
|
|
|
v.Base = sv.Addr
|
2015-11-05 17:25:52 +00:00
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
maptype, ok := sv.RealType.(*godwarf.StructType)
|
2015-11-05 17:25:52 +00:00
|
|
|
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 13:08:16 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Base, int(v.RealType.Size()))
|
2016-01-10 12:49:03 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-08 16:18:13 +00:00
|
|
|
if it.buckets.Kind != reflect.Struct || it.oldbuckets.Kind != reflect.Struct {
|
2018-08-31 18:08:18 +00:00
|
|
|
v.Unreadable = errMapBucketsNotStruct
|
2017-02-08 16:18:13 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
return it
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
var errMapBucketContentsNotArray = errors.New("malformed map type: keys, values or tophash of a bucket is not an array")
|
|
|
|
var errMapBucketContentsInconsistentLen = errors.New("malformed map type: inconsistent array length in bucket")
|
|
|
|
var errMapBucketsNotStruct = errors.New("malformed map type: buckets, oldbuckets or overflow field not a struct")
|
2017-02-08 16:18:13 +00:00
|
|
|
|
2015-11-05 17:25:52 +00:00
|
|
|
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
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
for _, f := range it.b.DwarfType.(*godwarf.StructType).Field {
|
2015-11-05 17:25:52 +00:00
|
|
|
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 {
|
2018-08-31 18:08:18 +00:00
|
|
|
it.v.Unreadable = errMapBucketContentsNotArray
|
2015-11-05 17:25:52 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-05-26 18:36:28 +00:00
|
|
|
if it.tophashes.Len != it.keys.Len {
|
2018-08-31 18:08:18 +00:00
|
|
|
it.v.Unreadable = errMapBucketContentsInconsistentLen
|
2017-05-26 18:36:28 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.values.fieldType.Size() > 0 && it.tophashes.Len != it.values.Len {
|
|
|
|
// if the type of the value is zero-sized (i.e. struct{}) then the values
|
|
|
|
// array's length is zero.
|
2018-08-31 18:08:18 +00:00
|
|
|
it.v.Unreadable = errMapBucketContentsInconsistentLen
|
2017-02-08 16:18:13 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if it.overflow.Kind != reflect.Struct {
|
2018-08-31 18:08:18 +00:00
|
|
|
it.v.Unreadable = errMapBucketsNotStruct
|
2015-11-05 17:25:52 +00:00
|
|
|
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
|
|
|
|
}
|
2017-05-29 13:20:01 +00:00
|
|
|
for _, f := range b.DwarfType.(*godwarf.StructType).Field {
|
2015-11-05 17:25:52 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-07-27 17:19:01 +00:00
|
|
|
func (v *Variable) readInterface() (_type, data *Variable, isnil bool) {
|
2016-05-29 19:20:09 +00:00
|
|
|
// An interface variable is implemented either by a runtime.iface
|
|
|
|
// struct or a runtime.eface struct. The difference being that empty
|
|
|
|
// interfaces (i.e. "interface {}") are represented by runtime.eface
|
|
|
|
// and non-empty interfaces by runtime.iface.
|
|
|
|
//
|
|
|
|
// For both runtime.ifaces and runtime.efaces the data is stored in v.data
|
|
|
|
//
|
|
|
|
// The concrete type however is stored in v.tab._type for non-empty
|
|
|
|
// interfaces and in v._type for empty interfaces.
|
|
|
|
//
|
|
|
|
// For nil empty interface variables _type will be nil, for nil
|
|
|
|
// non-empty interface variables tab will be nil
|
|
|
|
//
|
|
|
|
// In either case the _type field is a pointer to a runtime._type struct.
|
|
|
|
//
|
2018-07-27 17:19:01 +00:00
|
|
|
// The following code works for both runtime.iface and runtime.eface.
|
2016-05-29 19:20:09 +00:00
|
|
|
|
2016-01-10 12:49:03 +00:00
|
|
|
v.mem = cacheMemory(v.mem, v.Addr, int(v.RealType.Size()))
|
|
|
|
|
2017-05-29 13:20:01 +00:00
|
|
|
ityp := resolveTypedef(&v.RealType.(*godwarf.InterfaceType).TypedefType).(*godwarf.StructType)
|
2016-01-24 09:25:54 +00:00
|
|
|
|
|
|
|
for _, f := range ityp.Field {
|
2015-11-12 11:30:41 +00:00
|
|
|
switch f.Name {
|
|
|
|
case "tab": // for runtime.iface
|
|
|
|
tab, _ := v.toField(f)
|
2016-05-29 19:20:09 +00:00
|
|
|
tab = tab.maybeDereference()
|
|
|
|
isnil = tab.Addr == 0
|
|
|
|
if !isnil {
|
2018-07-27 17:19:01 +00:00
|
|
|
var err error
|
2016-05-29 19:20:09 +00:00
|
|
|
_type, err = tab.structMember("_type")
|
|
|
|
if err != nil {
|
2015-11-12 11:30:41 +00:00
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "_type": // for runtime.eface
|
2016-05-29 19:20:09 +00:00
|
|
|
_type, _ = v.toField(f)
|
2018-07-27 17:19:01 +00:00
|
|
|
isnil = _type.maybeDereference().Addr == 0
|
2015-11-12 11:30:41 +00:00
|
|
|
case "data":
|
|
|
|
data, _ = v.toField(f)
|
|
|
|
}
|
|
|
|
}
|
2018-07-27 17:19:01 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig) {
|
|
|
|
_type, data, isnil := v.readInterface()
|
2015-11-12 11:30:41 +00:00
|
|
|
|
|
|
|
if isnil {
|
|
|
|
// interface to nil
|
|
|
|
data = data.maybeDereference()
|
|
|
|
v.Children = []Variable{*data}
|
2016-02-07 07:56:11 +00:00
|
|
|
if loadData {
|
2016-04-24 17:15:39 +00:00
|
|
|
v.Children[0].loadValueInternal(recurseLevel, cfg)
|
2016-02-07 07:56:11 +00:00
|
|
|
}
|
2015-11-12 11:30:41 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-29 19:20:09 +00:00
|
|
|
if data == nil {
|
2015-11-12 11:30:41 +00:00
|
|
|
v.Unreadable = fmt.Errorf("invalid interface type")
|
|
|
|
return
|
|
|
|
}
|
2016-05-29 19:20:09 +00:00
|
|
|
|
2018-04-18 18:09:33 +00:00
|
|
|
typ, kind, err := runtimeTypeToDIE(_type, data.Addr)
|
|
|
|
if err != nil {
|
|
|
|
v.Unreadable = err
|
|
|
|
return
|
2015-11-12 11:30:41 +00:00
|
|
|
}
|
|
|
|
|
2017-06-29 18:17:52 +00:00
|
|
|
deref := false
|
2016-09-08 16:11:20 +00:00
|
|
|
if kind&kindDirectIface == 0 {
|
|
|
|
realtyp := resolveTypedef(typ)
|
2017-05-29 13:20:01 +00:00
|
|
|
if _, isptr := realtyp.(*godwarf.PtrType); !isptr {
|
2017-04-21 06:55:53 +00:00
|
|
|
typ = pointerTo(typ, v.bi.Arch)
|
2017-06-29 18:17:52 +00:00
|
|
|
deref = true
|
2016-09-08 16:11:20 +00:00
|
|
|
}
|
2015-11-26 13:10:58 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 07:46:47 +00:00
|
|
|
data = data.newVariable("data", data.Addr, typ, data.mem)
|
2017-06-29 18:17:52 +00:00
|
|
|
if deref {
|
|
|
|
data = data.maybeDereference()
|
|
|
|
data.Name = "data"
|
|
|
|
}
|
2015-11-12 11:30:41 +00:00
|
|
|
|
|
|
|
v.Children = []Variable{*data}
|
2017-02-10 00:26:38 +00:00
|
|
|
if loadData && recurseLevel <= cfg.MaxVariableRecurse {
|
2016-04-24 17:15:39 +00:00
|
|
|
v.Children[0].loadValueInternal(recurseLevel, cfg)
|
|
|
|
} else {
|
|
|
|
v.Children[0].OnlyAddr = true
|
2015-11-12 11:30:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 10:31:20 +00:00
|
|
|
// ConstDescr describes the value of v using constants.
|
|
|
|
func (v *Variable) ConstDescr() string {
|
|
|
|
if v.bi == nil || (v.Flags&VariableConstant != 0) {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
ctyp := v.bi.consts.Get(v.DwarfType)
|
|
|
|
if ctyp == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if typename := v.DwarfType.Common().Name; strings.Index(typename, ".") < 0 || strings.HasPrefix(typename, "C.") {
|
|
|
|
// only attempt to use constants for user defined type, otherwise every
|
|
|
|
// int variable with value 1 will be described with os.SEEK_CUR and other
|
|
|
|
// similar problems.
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
switch v.Kind {
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
fallthrough
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
|
|
n, _ := constant.Int64Val(v.Value)
|
|
|
|
return ctyp.describe(n)
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// popcnt is the number of bits set to 1 in x.
|
|
|
|
// It's the same as math/bits.OnesCount64, copied here so that we can build
|
|
|
|
// on versions of go that don't have math/bits.
|
|
|
|
func popcnt(x uint64) int {
|
|
|
|
const m0 = 0x5555555555555555 // 01010101 ...
|
|
|
|
const m1 = 0x3333333333333333 // 00110011 ...
|
|
|
|
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
|
|
|
|
const m = 1<<64 - 1
|
|
|
|
x = x>>1&(m0&m) + x&(m0&m)
|
|
|
|
x = x>>2&(m1&m) + x&(m1&m)
|
|
|
|
x = (x>>4 + x) & (m2 & m)
|
|
|
|
x += x >> 8
|
|
|
|
x += x >> 16
|
|
|
|
x += x >> 32
|
|
|
|
return int(x) & (1<<7 - 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cm constantsMap) Get(typ godwarf.Type) *constantType {
|
|
|
|
ctyp := cm[typ.Common().Offset]
|
|
|
|
if ctyp == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
typepkg := packageName(typ.String()) + "."
|
|
|
|
if !ctyp.initialized {
|
|
|
|
ctyp.initialized = true
|
|
|
|
sort.Sort(constantValuesByValue(ctyp.values))
|
|
|
|
for i := range ctyp.values {
|
|
|
|
if strings.HasPrefix(ctyp.values[i].name, typepkg) {
|
|
|
|
ctyp.values[i].name = ctyp.values[i].name[len(typepkg):]
|
|
|
|
}
|
|
|
|
if popcnt(uint64(ctyp.values[i].value)) == 1 {
|
|
|
|
ctyp.values[i].singleBit = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ctyp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ctyp *constantType) describe(n int64) string {
|
|
|
|
for _, val := range ctyp.values {
|
|
|
|
if val.value == n {
|
|
|
|
return val.name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// If all the values for this constant only have one bit set we try to
|
|
|
|
// represent the value as a bitwise or of constants.
|
|
|
|
|
|
|
|
fields := []string{}
|
|
|
|
for _, val := range ctyp.values {
|
|
|
|
if !val.singleBit {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if n&val.value != 0 {
|
|
|
|
fields = append(fields, val.name)
|
|
|
|
n = n & ^val.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if n == 0 {
|
|
|
|
return strings.Join(fields, "|")
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2017-05-04 14:35:31 +00:00
|
|
|
type variablesByDepth struct {
|
|
|
|
vars []*Variable
|
|
|
|
depths []int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *variablesByDepth) Len() int { return len(v.vars) }
|
|
|
|
|
|
|
|
func (v *variablesByDepth) Less(i int, j int) bool { return v.depths[i] < v.depths[j] }
|
|
|
|
|
|
|
|
func (v *variablesByDepth) Swap(i int, j int) {
|
|
|
|
v.depths[i], v.depths[j] = v.depths[j], v.depths[i]
|
|
|
|
v.vars[i], v.vars[j] = v.vars[j], v.vars[i]
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:08:18 +00:00
|
|
|
// Locals fetches all variables of a specific type in the current function scope.
|
2018-04-15 12:11:27 +00:00
|
|
|
func (scope *EvalScope) Locals() ([]*Variable, error) {
|
proc: support inlining
Go 1.10 added inlined calls to debug_info, this commit adds support
for DW_TAG_inlined_call to delve, both for stack traces (where
inlined calls will appear as normal stack frames) and to correct
the behavior of next, step and stepout.
The calls to Next and Frame of stackIterator continue to work
unchanged and only return real stack frames, after reading each line
appendInlinedCalls is called to unpacked all the inlined calls that
involve the current PC.
The fake stack frames produced by appendInlinedCalls are
distinguished from real stack frames by having the Inlined attribute
set to true. Also their Current and Call locations are treated
differently. The Call location will be changed to represent the
position inside the inlined call, while the Current location will
always reference the real stack frame. This is done because:
* next, step and stepout need to access the debug_info entry of
the real function they are stepping through
* we are already manipulating Call in different ways while Current
is just what we read from the call stack
The strategy remains mostly the same, we disassemble the function
and we set a breakpoint on each instruction corresponding to a
different file:line. The function in question will be the one
corresponding to the first real (i.e. non-inlined) stack frame.
* If the current function contains inlined calls, 'next' will not
set any breakpoints on instructions that belong to inlined calls. We
do not do this for 'step'.
* If we are inside an inlined call that makes other inlined
functions, 'next' will not set any breakpoints that belong to
inlined calls that are children of the current inlined call.
* If the current function is inlined the breakpoint on the return
address won't be set, because inlined frames don't have a return
address.
* The code we use for stepout doesn't work at all if we are inside
an inlined call, instead we call 'next' but instruct it to remove
all PCs belonging to the current inlined call.
2017-11-13 15:54:08 +00:00
|
|
|
if scope.Fn == nil {
|
2017-09-01 13:30:45 +00:00
|
|
|
return nil, errors.New("unable to find function context")
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
|
|
|
|
2016-01-10 08:57:52 +00:00
|
|
|
var vars []*Variable
|
2017-05-04 14:35:31 +00:00
|
|
|
var depths []int
|
2018-04-15 12:11:27 +00:00
|
|
|
varReader := reader.Variables(scope.BinInfo.dwarf, scope.Fn.offset, scope.PC, scope.Line, true)
|
2017-05-04 14:35:31 +00:00
|
|
|
hasScopes := false
|
|
|
|
for varReader.Next() {
|
|
|
|
entry := varReader.Entry()
|
2017-08-24 07:46:47 +00:00
|
|
|
val, err := scope.extractVarInfoFromEntry(entry)
|
2014-12-30 17:57:31 +00:00
|
|
|
if err != nil {
|
2017-05-04 14:35:31 +00:00
|
|
|
// skip variables that we can't parse yet
|
|
|
|
continue
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
vars = append(vars, val)
|
|
|
|
depth := varReader.Depth()
|
2018-04-15 12:11:27 +00:00
|
|
|
if entry.Tag == dwarf.TagFormalParameter {
|
|
|
|
if depth <= 1 {
|
|
|
|
depth = 0
|
|
|
|
}
|
|
|
|
isret, _ := entry.Val(dwarf.AttrVarParam).(bool)
|
|
|
|
if isret {
|
|
|
|
val.Flags |= VariableReturnArgument
|
|
|
|
} else {
|
|
|
|
val.Flags |= VariableArgument
|
|
|
|
}
|
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
depths = append(depths, depth)
|
|
|
|
if depth > 1 {
|
|
|
|
hasScopes = true
|
2017-02-07 21:08:11 +00:00
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
}
|
2014-12-30 17:57:31 +00:00
|
|
|
|
2017-05-04 14:35:31 +00:00
|
|
|
if err := varReader.Err(); err != nil {
|
|
|
|
return nil, err
|
2014-12-30 17:57:31 +00:00
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
|
2017-02-07 21:08:11 +00:00
|
|
|
if len(vars) <= 0 {
|
|
|
|
return vars, nil
|
|
|
|
}
|
|
|
|
|
2017-05-04 14:35:31 +00:00
|
|
|
if hasScopes {
|
|
|
|
sort.Stable(&variablesByDepth{vars, depths})
|
|
|
|
}
|
|
|
|
|
|
|
|
lvn := map[string]*Variable{} // lvn[n] is the last variable we saw named n
|
|
|
|
|
2017-06-13 08:38:45 +00:00
|
|
|
for i, v := range vars {
|
|
|
|
if name := v.Name; len(name) > 1 && name[0] == '&' {
|
|
|
|
v = v.maybeDereference()
|
2018-01-19 14:50:28 +00:00
|
|
|
if v.Addr == 0 {
|
|
|
|
v.Unreadable = fmt.Errorf("no address for escaped variable")
|
|
|
|
}
|
2017-06-13 08:38:45 +00:00
|
|
|
v.Name = name[1:]
|
|
|
|
v.Flags |= VariableEscaped
|
|
|
|
vars[i] = v
|
|
|
|
}
|
2017-05-04 14:35:31 +00:00
|
|
|
if hasScopes {
|
|
|
|
if otherv := lvn[v.Name]; otherv != nil {
|
|
|
|
otherv.Flags |= VariableShadowed
|
|
|
|
}
|
|
|
|
lvn[v.Name] = v
|
|
|
|
}
|
2017-02-07 21:08:11 +00:00
|
|
|
}
|
2014-12-30 17:57:31 +00:00
|
|
|
|
|
|
|
return vars, nil
|
|
|
|
}
|
2017-09-08 10:31:20 +00:00
|
|
|
|
|
|
|
type constantValuesByValue []constantValue
|
|
|
|
|
|
|
|
func (v constantValuesByValue) Len() int { return len(v) }
|
|
|
|
func (v constantValuesByValue) Less(i int, j int) bool { return v[i].value < v[j].value }
|
|
|
|
func (v constantValuesByValue) Swap(i int, j int) { v[i], v[j] = v[j], v[i] }
|