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
2018-10-29 11:22:03 +00:00
maxMapBucketsFactor = 100 // Maximum numbers of map buckets to read for every requested map entry when loading variables through (*EvalScope).LocalVariables and (*EvalScope).FunctionArguments.
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
2018-10-29 11:22:03 +00:00
// MaxMapBuckets is the maximum number of map buckets to read before giving up.
// A value of 0 will read as many buckets as necessary until the entire map
// is read or MaxArrayValues is reached.
//
// Loading a map is an operation that issues O(num_buckets) operations.
// Normally the number of buckets is proportional to the number of elements
// in the map, since the runtime tries to keep the load factor of maps
// between 40% and 80%.
//
// It is possible, however, to create very sparse maps either by:
// a) adding lots of entries to a map and then deleting most of them, or
// b) using the make(mapType, N) expression with a very large N
//
// When this happens delve will have to scan many empty buckets to find the
// few entries in the map.
// MaxMapBuckets can be set to avoid annoying slowdowns␣while reading
// very sparse maps.
//
// Since there is no good way for a user of delve to specify the value of
// MaxMapBuckets, this field is not actually exposed through the API.
// Instead (*EvalScope).LocalVariables and (*EvalScope).FunctionArguments
// set this field automatically to MaxArrayValues * maxMapBucketsFactor.
// Every other invocation uses the default value of 0, obtaining the old behavior.
// In practice this means that debuggers using the ListLocalVars or
// ListFunctionArgs API will not experience a massive slowdown when a very
// sparse map is in scope, but evaluating a single variable will still work
// correctly, even if the variable in question is a very sparse map.
MaxMapBuckets int
2016-04-24 17:15:39 +00:00
}
2018-10-29 11:22:03 +00:00
var loadSingleValue = LoadConfig { false , 0 , 64 , 0 , 0 , 0 }
var loadFullValue = LoadConfig { true , 1 , 64 , 64 , - 1 , 0 }
2016-04-24 17:15:39 +00:00
2016-01-10 08:57:52 +00:00
// G status, from: src/runtime/runtime2.go
2015-09-17 17:42:05 +00:00
const (
2016-01-10 08:57:52 +00:00
Gidle uint64 = iota // 0
Grunnable // 1 runnable and on a run queue
Grunning // 2
Gsyscall // 3
Gwaiting // 4
GmoribundUnused // 5 currently unused, but hardcoded in gdb scripts
Gdead // 6
Genqueue // 7 Only the Gscanenqueue is used.
Gcopystack // 8 in this state when newstack is moving the stack
2015-09-17 17:42:05 +00:00
)
2016-01-10 08:57:52 +00:00
// G represents a runtime G (goroutine) structure (at least the
2015-04-22 13:18:25 +00:00
// fields that Delve is interested in).
2015-03-28 01:12:07 +00:00
type G struct {
2016-01-10 08:57:52 +00:00
ID int // Goroutine ID
2015-04-22 13:18:25 +00:00
PC uint64 // PC of goroutine when it was parked.
SP uint64 // SP of goroutine when it was parked.
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 {
2018-05-29 15:01:51 +00:00
return & EvalScope { Location : Location { } , Regs : op . DwarfRegisters { StaticBase : bi . staticBase } , 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 {
2018-05-29 15:01:51 +00:00
switch tt := typ . ( type ) {
case * godwarf . TypedefType :
2015-11-07 13:50:26 +00:00
typ = tt . Type
2018-05-29 15:01:51 +00:00
case * godwarf . QualType :
typ = tt . Type
default :
2015-11-07 13:50:26 +00:00
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
}
2018-10-16 15:49:20 +00:00
// ErrNoGoroutine returned when a G could not be found
2015-06-12 18:55:42 +00:00
// for a specific thread.
2018-10-16 15:49:20 +00:00
type ErrNoGoroutine struct {
2015-04-19 22:11:33 +00:00
tid int
}
2018-10-16 15:49:20 +00:00
func ( ng ErrNoGoroutine ) Error ( ) string {
2015-04-19 22:11:33 +00:00
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
}
2018-10-16 15:49:20 +00:00
return nil , ErrNoGoroutine { 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-10-29 11:22:03 +00:00
v . loadValue ( LoadConfig { false , 2 , 64 , 0 , - 1 , 0 } )
2018-08-31 18:08:18 +00:00
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
}
2018-10-29 11:22:03 +00:00
g . stkbarVar . loadValue ( LoadConfig { false , 1 , 0 , int ( g . stkbarVar . Len ) , 3 , 0 } )
2017-02-08 13:14:57 +00:00
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
} )
2018-10-29 11:22:03 +00:00
cfg . MaxMapBuckets = maxMapBucketsFactor * cfg . MaxArrayValues
2018-04-15 12:11:27 +00:00
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
} )
2018-10-29 11:22:03 +00:00
cfg . MaxMapBuckets = maxMapBucketsFactor * cfg . MaxArrayValues
2018-04-15 12:11:27 +00:00
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
2018-11-22 13:42:11 +00:00
var cmem * compositeMemory
cmem , err = newCompositeMemory ( scope . Mem , scope . Regs , pieces )
if cmem != nil {
mem = cmem
2018-11-19 13:22:43 +00:00
}
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
}
2018-10-29 11:22:03 +00:00
it . maxNumBuckets = uint64 ( cfg . MaxMapBuckets )
if v . Len == 0 || int64 ( v . mapSkip ) >= v . Len || cfg . MaxArrayValues == 0 {
return
}
2015-11-05 17:25:52 +00:00
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 ( ) {
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
}
2018-10-29 11:22:03 +00:00
if count >= cfg . MaxArrayValues || int64 ( count ) >= v . Len {
break
}
2015-11-05 17:25:52 +00:00
}
}
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
2018-10-29 11:22:03 +00:00
maxNumBuckets uint64 // maximum number of buckets to scan
2015-11-05 17:25:52 +00:00
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
2018-10-29 11:22:03 +00:00
if it . maxNumBuckets > 0 && it . bidx >= it . maxNumBuckets {
return false
}
2015-11-05 17:25:52 +00:00
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-05-29 15:01:51 +00:00
varReader := reader . Variables ( scope . BinInfo . dwarf , scope . Fn . offset , reader . ToRelAddr ( scope . PC , scope . BinInfo . staticBase ) , 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 ] }