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/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"
2019-01-04 18:39:25 +00:00
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
2019-04-26 17:23:43 +00:00
"github.com/go-delve/delve/pkg/goversion"
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
2019-04-26 17:23:43 +00:00
hashTophashEmptyZero = 0 // used by map reading code, indicates an empty cell
hashTophashEmptyOne = 1 // used by map reading code, indicates an empty cell in Go 1.12 and later
hashMinTopHashGo111 = 4 // used by map reading code, indicates minimum value of tophash that isn't empty or evacuated, in Go1.11
hashMinTopHashGo112 = 5 // used by map reading code, indicates minimum value of tophash that isn't empty or evacuated, in Go1.12
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
2019-07-16 20:12:16 +00:00
// VariableFakeAddress means the address of this variable is either fake
// (i.e. the variable is partially or completely stored in a CPU register
// and doesn't have a real address) or possibly no longer availabe (because
// the variable is the return value of a function call and allocated on a
// frame that no longer exists)
VariableFakeAddress
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
2019-05-30 15:08:37 +00:00
// closureAddr is the closure address for function variables (0 for non-closures)
closureAddr uint64
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
2020-01-28 14:57:21 +00:00
LocationExpr * locationExpr // location expression
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 }
2019-07-16 20:11:35 +00:00
var loadFullValueLongerStrings = LoadConfig { true , 1 , 1024 * 1024 , 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 {
2020-02-17 17:27:56 +00:00
ID int // Goroutine ID
PC uint64 // PC of goroutine when it was parked.
SP uint64 // SP of goroutine when it was parked.
BP uint64 // BP of goroutine when it was parked (go >= 1.7).
LR uint64 // LR of goroutine when it was parked.
GoPC uint64 // PC of 'go' statement that created this goroutine.
StartPC uint64 // PC of the first function run on this goroutine.
Status uint64
stkbarVar * Variable // stkbar field of g struct
stkbarPos int // stkbarPos field of g struct
2020-04-22 14:39:06 +00:00
stack stack // value of stack
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
2020-01-18 08:18:44 +00:00
2020-01-20 20:02:12 +00:00
labels * map [ string ] string // G's pprof labels, computed on demand in Labels() method
2015-04-19 22:11:33 +00:00
}
2020-04-22 14:39:06 +00:00
// stack represents a stack span in the target process.
type stack struct {
hi , lo uint64
}
2020-03-23 17:57:01 +00:00
// GetG returns information on the G (goroutine) that is executing on this thread.
//
// The G structure for a thread is stored in thread local storage. Here we simply
// calculate the address and read and parse the G struct.
//
// We cannot simply use the allg linked list in order to find the M that represents
// the given OS thread and follow its G pointer because on Darwin mach ports are not
// universal, so our port for this thread would not map to the `id` attribute of the M
// structure. Also, when linked against libc, Go prefers the libc version of clone as
// opposed to the runtime version. This has the consequence of not setting M.id for
// any thread, regardless of OS.
//
// In order to get around all this craziness, we read the address of the G structure for
// the current thread from the thread local storage area.
func GetG ( thread Thread ) ( * G , error ) {
if thread . Common ( ) . g != nil {
return thread . Common ( ) . g , nil
}
if loc , _ := thread . Location ( ) ; loc != nil && loc . Fn != nil && loc . Fn . Name == "runtime.clone" {
// When threads are executing runtime.clone the value of TLS is unreliable.
return nil , nil
}
gaddr , err := getGVariable ( thread )
if err != nil {
return nil , err
}
g , err := gaddr . parseG ( )
if err != nil {
return nil , err
}
if g . ID == 0 {
// The runtime uses a special goroutine with ID == 0 to mark that the
// current goroutine is executing on the system stack (sometimes also
// referred to as the g0 stack or scheduler stack, I'm not sure if there's
// actually any difference between those).
// For our purposes it's better if we always return the real goroutine
// since the rest of the code assumes the goroutine ID is univocal.
// The real 'current goroutine' is stored in g0.m.curg
mvar , err := g . variable . structMember ( "m" )
if err != nil {
return nil , err
}
curgvar , err := mvar . structMember ( "curg" )
if err != nil {
return nil , err
}
g , err = curgvar . parseG ( )
if err != nil {
if _ , ok := err . ( ErrNoGoroutine ) ; ok {
err = ErrNoGoroutine { thread . ThreadID ( ) }
}
return nil , err
}
g . SystemStack = true
}
g . Thread = thread
if loc , err := thread . Location ( ) ; err == nil {
g . CurrentLoc = * loc
}
thread . Common ( ) . g = g
return g , nil
}
// GoroutinesInfo searches for goroutines starting at index 'start', and
// returns an array of up to 'count' (or all found elements, if 'count' is 0)
// G structures representing the information Delve care about from the internal
// runtime G structure.
// GoroutinesInfo also returns the next index to be used as 'start' argument
// while scanning for all available goroutines, or -1 if there was an error
// or if the index already reached the last possible value.
func GoroutinesInfo ( dbp * Target , start , count int ) ( [ ] * G , int , error ) {
if _ , err := dbp . Valid ( ) ; err != nil {
return nil , - 1 , err
}
if dbp . gcache . allGCache != nil {
// We can't use the cached array to fulfill a subrange request
if start == 0 && ( count == 0 || count >= len ( dbp . gcache . allGCache ) ) {
return dbp . gcache . allGCache , - 1 , nil
}
}
var (
threadg = map [ int ] * G { }
allg [ ] * G
)
threads := dbp . ThreadList ( )
for _ , th := range threads {
if th . Blocked ( ) {
continue
}
g , _ := GetG ( th )
if g != nil {
threadg [ g . ID ] = g
}
}
allgptr , allglen , err := dbp . gcache . getRuntimeAllg ( dbp . BinInfo ( ) , dbp . CurrentThread ( ) )
if err != nil {
return nil , - 1 , err
}
for i := uint64 ( start ) ; i < allglen ; i ++ {
if count != 0 && len ( allg ) >= count {
return allg , int ( i ) , nil
}
gvar , err := newGVariable ( dbp . CurrentThread ( ) , uintptr ( allgptr + ( i * uint64 ( dbp . BinInfo ( ) . Arch . PtrSize ( ) ) ) ) , true )
if err != nil {
allg = append ( allg , & G { Unreadable : err } )
continue
}
g , err := gvar . parseG ( )
if err != nil {
allg = append ( allg , & G { Unreadable : err } )
continue
}
if thg , allocated := threadg [ g . ID ] ; allocated {
loc , err := thg . Thread . Location ( )
if err != nil {
return nil , - 1 , err
}
g . Thread = thg . Thread
// Prefer actual thread location information.
g . CurrentLoc = * loc
g . SystemStack = thg . SystemStack
}
if g . Status != Gdead {
allg = append ( allg , g )
}
dbp . gcache . addGoroutine ( g )
}
if start == 0 {
dbp . gcache . allGCache = allg
}
return allg , - 1 , nil
}
// FindGoroutine returns a G struct representing the goroutine
// specified by `gid`.
func FindGoroutine ( dbp * Target , gid int ) ( * G , error ) {
if selg := dbp . SelectedGoroutine ( ) ; ( gid == - 1 ) || ( selg != nil && selg . ID == gid ) || ( selg == nil && gid == 0 ) {
// Return the currently selected goroutine in the following circumstances:
//
// 1. if the caller asks for gid == -1 (because that's what a goroutine ID of -1 means in our API).
// 2. if gid == selg.ID.
// this serves two purposes: (a) it's an optimizations that allows us
// to avoid reading any other goroutine and, more importantly, (b) we
// could be reading an incorrect value for the goroutine ID of a thread.
// This condition usually happens when a goroutine calls runtime.clone
// and for a short period of time two threads will appear to be running
// the same goroutine.
// 3. if the caller asks for gid == 0 and the selected goroutine is
// either 0 or nil.
// Goroutine 0 is special, it either means we have no current goroutine
// (for example, running C code), or that we are running on a speical
// stack (system stack, signal handling stack) and we didn't properly
// detect it.
// Since there could be multiple goroutines '0' running simultaneously
// if the user requests it return the one that's already selected or
// nil if there isn't a selected goroutine.
return selg , nil
}
if gid == 0 {
return nil , fmt . Errorf ( "unknown goroutine %d" , gid )
}
// Calling GoroutinesInfo could be slow if there are many goroutines
// running, check if a running goroutine has been requested first.
for _ , thread := range dbp . ThreadList ( ) {
g , _ := GetG ( thread )
if g != nil && g . ID == gid {
return g , nil
}
}
if g := dbp . gcache . partialGCache [ gid ] ; g != nil {
return g , nil
}
const goroutinesInfoLimit = 10
nextg := 0
for nextg >= 0 {
var gs [ ] * G
var err error
gs , nextg , err = GoroutinesInfo ( dbp , nextg , goroutinesInfoLimit )
if err != nil {
return nil , err
}
for i := range gs {
if gs [ i ] . ID == gid {
if gs [ i ] . Unreadable != nil {
return nil , gs [ i ] . Unreadable
}
return gs [ i ] , nil
}
}
}
return nil , fmt . Errorf ( "unknown goroutine %d" , gid )
}
func getGVariable ( thread Thread ) ( * Variable , error ) {
regs , err := thread . Registers ( false )
if err != nil {
return nil , err
}
gaddr , hasgaddr := regs . GAddr ( )
if ! hasgaddr {
var err error
gaddr , err = readUintRaw ( thread , uintptr ( regs . TLS ( ) + thread . BinInfo ( ) . GStructOffset ( ) ) , int64 ( thread . BinInfo ( ) . Arch . PtrSize ( ) ) )
if err != nil {
return nil , err
}
}
2020-03-30 18:03:29 +00:00
return newGVariable ( thread , uintptr ( gaddr ) , thread . BinInfo ( ) . Arch . DerefTLS ( ) )
2020-03-23 17:57:01 +00:00
}
func newGVariable ( thread Thread , gaddr uintptr , deref bool ) ( * Variable , error ) {
typ , err := thread . BinInfo ( ) . findType ( "runtime.g" )
if err != nil {
return nil , err
}
if deref {
typ = & godwarf . PtrType {
CommonType : godwarf . CommonType {
2020-03-30 18:03:29 +00:00
ByteSize : int64 ( thread . BinInfo ( ) . Arch . PtrSize ( ) ) ,
2020-03-23 17:57:01 +00:00
Name : "" ,
ReflectKind : reflect . Ptr ,
Offset : 0 ,
} ,
Type : typ ,
}
}
2020-01-28 14:57:21 +00:00
return newVariableFromThread ( thread , "" , gaddr , typ ) , nil
2020-03-23 17:57:01 +00:00
}
2019-08-08 03:44:37 +00:00
// Defer returns the top-most defer of the goroutine.
func ( g * G ) Defer ( ) * Defer {
if g . variable . Unreadable != nil {
return nil
}
2020-02-17 17:27:56 +00:00
dvar , _ := g . variable . structMember ( "_defer" )
if dvar == nil {
return nil
}
dvar = dvar . maybeDereference ( )
2019-08-08 03:44:37 +00:00
if dvar . Addr == 0 {
return nil
}
d := & Defer { variable : dvar }
d . load ( )
return d
}
// UserCurrent returns the location the users code is at,
// or was at before entering a runtime function.
func ( g * G ) UserCurrent ( ) Location {
2019-09-25 17:21:20 +00:00
it , err := g . stackIterator ( 0 )
2019-08-08 03:44:37 +00:00
if err != nil {
return g . CurrentLoc
}
for it . Next ( ) {
frame := it . Frame ( )
if frame . Call . Fn != nil {
name := frame . Call . Fn . Name
2020-03-09 09:47:56 +00:00
if strings . Contains ( name , "." ) && ( ! strings . HasPrefix ( name , "runtime." ) || frame . Call . Fn . exportedRuntime ( ) ) {
2019-08-08 03:44:37 +00:00
return frame . Call
}
}
}
return g . CurrentLoc
}
// Go returns the location of the 'go' statement
// that spawned this goroutine.
func ( g * G ) Go ( ) Location {
pc := g . GoPC
if fn := g . variable . bi . PCToFunc ( pc ) ; fn != nil {
// Backup to CALL instruction.
// Mimics runtime/traceback.go:677.
if g . GoPC > fn . Entry {
pc --
}
}
f , l , fn := g . variable . bi . PCToLine ( pc )
return Location { PC : g . GoPC , File : f , Line : l , Fn : fn }
}
// 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 }
}
2020-01-20 20:02:12 +00:00
func ( g * G ) Labels ( ) map [ string ] string {
if g . labels != nil {
return * g . labels
}
var labels map [ string ] string
if labelsVar := g . variable . loadFieldNamed ( "labels" ) ; labelsVar != nil && len ( labelsVar . Children ) == 1 {
if address := labelsVar . Children [ 0 ] ; address . Addr != 0 {
labelMapType , _ := g . variable . bi . findType ( "runtime/pprof.labelMap" )
if labelMapType != nil {
labelMap := newVariable ( "" , address . Addr , labelMapType , g . variable . bi , g . variable . mem )
labelMap . loadValue ( loadFullValue )
labels = map [ string ] string { }
for i := range labelMap . Children {
if i % 2 == 0 {
k := labelMap . Children [ i ]
v := labelMap . Children [ i + 1 ]
labels [ constant . StringVal ( k . Value ) ] = constant . StringVal ( v . Value )
}
}
}
}
}
g . labels = & labels
return * g . labels
}
2019-03-16 13:50:18 +00:00
type Ancestor struct {
ID int64 // Goroutine ID
Unreadable error
pcsVar * Variable
}
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 )
}
2019-05-08 21:06:38 +00:00
func globalScope ( bi * BinaryInfo , image * Image , mem MemoryReadWriter ) * EvalScope {
2019-06-30 17:44:30 +00:00
return & EvalScope { Location : Location { } , Regs : op . DwarfRegisters { StaticBase : image . StaticBase } , Mem : mem , g : nil , BinInfo : bi , frameOffset : 0 }
2018-02-13 17:20:45 +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 :
2020-03-23 17:57:01 +00:00
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
}
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 )
}
2020-02-17 17:27:56 +00:00
var ErrUnreadableG = errors . New ( "could not read G struct" )
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 {
2020-02-11 01:32:50 +00:00
var err error
gaddr , err = readUintRaw ( mem , uintptr ( gaddr ) , int64 ( v . bi . Arch . PtrSize ( ) ) )
2015-06-11 20:17:56 +00:00
if err != nil {
return nil , fmt . Errorf ( "error derefing *G %s" , err )
}
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
}
2020-02-17 17:27:56 +00:00
v . mem = cacheMemory ( v . mem , v . Addr , int ( v . RealType . Size ( ) ) )
schedVar := v . loadFieldNamed ( "sched" )
if schedVar == nil {
return nil , ErrUnreadableG
2015-05-09 17:44:38 +00:00
}
2017-02-07 21:08:11 +00:00
pc , _ := constant . Int64Val ( schedVar . fieldVariable ( "pc" ) . Value )
sp , _ := constant . Int64Val ( schedVar . fieldVariable ( "sp" ) . Value )
2020-01-21 17:11:20 +00:00
var bp , lr int64
2017-10-05 07:26:19 +00:00
if bpvar := schedVar . fieldVariable ( "bp" ) ; bpvar != nil && bpvar . Value != nil {
bp , _ = constant . Int64Val ( bpvar . Value )
}
2020-01-21 17:11:20 +00:00
if bpvar := schedVar . fieldVariable ( "lr" ) ; bpvar != nil && bpvar . Value != nil {
lr , _ = constant . Int64Val ( bpvar . Value )
}
2018-05-08 13:25:17 +00:00
2020-02-17 17:27:56 +00:00
unreadable := false
loadInt64Maybe := func ( name string ) int64 {
vv := v . loadFieldNamed ( name )
if vv == nil {
unreadable = true
return 0
}
n , _ := constant . Int64Val ( vv . Value )
return n
2017-05-09 07:02:07 +00:00
}
2020-02-17 17:27:56 +00:00
id := loadInt64Maybe ( "goid" )
gopc := loadInt64Maybe ( "gopc" )
startpc := loadInt64Maybe ( "startpc" )
2018-05-04 17:31:45 +00:00
var stackhi , stacklo uint64
2020-02-17 17:27:56 +00:00
if stackVar := v . loadFieldNamed ( "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
2020-02-17 17:27:56 +00:00
stkbarVar := v . loadFieldNamed ( "stkbar" )
stkbarVarPosFld := v . loadFieldNamed ( "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 )
}
2020-02-17 17:27:56 +00:00
status := loadInt64Maybe ( "atomicstatus" )
if unreadable {
return nil , ErrUnreadableG
}
2018-08-31 18:08:18 +00:00
f , l , fn := v . bi . PCToLine ( uint64 ( pc ) )
2020-01-18 08:18:44 +00:00
2020-01-28 14:57:21 +00:00
v . Name = "runtime.curg"
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 ) ,
2020-01-21 17:11:20 +00:00
LR : uint64 ( lr ) ,
2016-01-20 21:30:47 +00:00
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 ) ,
2020-04-22 14:39:06 +00:00
stack : stack { hi : stackhi , lo : 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 {
2020-02-17 17:27:56 +00:00
if ! v . loaded {
panic ( "fieldVariable called on a variable that wasn't loaded" )
}
2017-02-07 21:08:11 +00:00
for i := range v . Children {
if child := & v . Children [ i ] ; child . Name == name {
return child
}
}
return nil
}
2019-03-16 13:50:18 +00:00
var errTracebackAncestorsDisabled = errors . New ( "tracebackancestors is disabled" )
// Ancestors returns the list of ancestors for g.
2019-06-03 17:41:33 +00:00
func Ancestors ( p Process , g * G , n int ) ( [ ] Ancestor , error ) {
scope := globalScope ( p . BinInfo ( ) , p . BinInfo ( ) . Images [ 0 ] , p . CurrentThread ( ) )
2019-03-16 13:50:18 +00:00
tbav , err := scope . EvalExpression ( "runtime.debug.tracebackancestors" , loadSingleValue )
if err == nil && tbav . Unreadable == nil && tbav . Kind == reflect . Int {
tba , _ := constant . Int64Val ( tbav . Value )
if tba == 0 {
return nil , errTracebackAncestorsDisabled
}
}
av , err := g . variable . structMember ( "ancestors" )
if err != nil {
return nil , err
}
av = av . maybeDereference ( )
av . loadValue ( LoadConfig { MaxArrayValues : n , MaxVariableRecurse : 1 , MaxStructFields : - 1 } )
if av . Unreadable != nil {
return nil , err
}
if av . Addr == 0 {
// no ancestors
return nil , nil
}
r := make ( [ ] Ancestor , len ( av . Children ) )
for i := range av . Children {
if av . Children [ i ] . Unreadable != nil {
r [ i ] . Unreadable = av . Children [ i ] . Unreadable
continue
}
goidv := av . Children [ i ] . fieldVariable ( "goid" )
if goidv . Unreadable != nil {
r [ i ] . Unreadable = goidv . Unreadable
continue
}
r [ i ] . ID , _ = constant . Int64Val ( goidv . Value )
pcsVar := av . Children [ i ] . fieldVariable ( "pcs" )
if pcsVar . Unreadable != nil {
r [ i ] . Unreadable = pcsVar . Unreadable
}
pcsVar . loaded = false
pcsVar . Children = pcsVar . Children [ : 0 ]
r [ i ] . pcsVar = pcsVar
}
return r , nil
}
// Stack returns the stack trace of ancestor 'a' as saved by the runtime.
func ( a * Ancestor ) Stack ( n int ) ( [ ] Stackframe , error ) {
if a . Unreadable != nil {
return nil , a . Unreadable
}
pcsVar := a . pcsVar . clone ( )
pcsVar . loadValue ( LoadConfig { MaxArrayValues : n } )
if pcsVar . Unreadable != nil {
return nil , pcsVar . Unreadable
}
r := make ( [ ] Stackframe , len ( pcsVar . Children ) )
for i := range pcsVar . Children {
if pcsVar . Children [ i ] . Unreadable != nil {
r [ i ] = Stackframe { Err : pcsVar . Children [ i ] . Unreadable }
continue
}
if pcsVar . Children [ i ] . Kind != reflect . Uint {
return nil , fmt . Errorf ( "wrong type for pcs item %d: %v" , i , pcsVar . Children [ i ] . Kind )
}
pc , _ := constant . Int64Val ( pcsVar . Children [ i ] . Value )
fn := a . pcsVar . bi . PCToFunc ( uint64 ( pc ) )
if fn == nil {
loc := Location { PC : uint64 ( pc ) }
r [ i ] = Stackframe { Current : loc , Call : loc }
continue
}
pc2 := uint64 ( pc )
if pc2 - 1 >= fn . Entry {
pc2 --
}
f , ln := fn . cu . lineInfo . PCToLine ( fn . Entry , pc2 )
loc := Location { PC : uint64 ( pc ) , File : f , Line : ln , Fn : fn }
r [ i ] = Stackframe { Current : loc , Call : loc }
}
r [ len ( r ) - 1 ] . Bottom = pcsVar . Len == int64 ( len ( pcsVar . Children ) )
return r , nil
}
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
}
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
}
2020-03-20 17:23:10 +00:00
func readVarEntry ( entry * godwarf . Tree , image * Image ) ( name string , typ godwarf . Type , err error ) {
2018-05-04 17:31:45 +00:00
name , ok := entry . Val ( dwarf . AttrName ) . ( string )
if ! ok {
2020-03-20 17:23:10 +00:00
return "" , nil , fmt . Errorf ( "malformed variable DIE (name)" )
2018-05-04 17:31:45 +00:00
}
2020-03-20 17:23:10 +00:00
typ , err = entry . Type ( image . dwarf , image . index , image . typeCache )
2018-05-04 17:31:45 +00:00
if err != nil {
2020-03-20 17:23:10 +00:00
return "" , nil , err
2018-05-04 17:31:45 +00:00
}
2020-03-20 17:23:10 +00:00
return name , typ , nil
2018-05-04 17:31:45 +00:00
}
2019-08-11 20:56:16 +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
2020-03-20 17:23:10 +00:00
func extractVarInfoFromEntry ( bi * BinaryInfo , image * Image , regs op . DwarfRegisters , mem MemoryReadWriter , entry * godwarf . Tree ) ( * Variable , error ) {
if entry . Tag != dwarf . TagFormalParameter && entry . Tag != dwarf . TagVariable {
return nil , fmt . Errorf ( "invalid entry tag, only supports FormalParameter and Variable, got %s" , entry . Tag . String ( ) )
2019-08-11 20:56:16 +00:00
}
2020-03-20 17:23:10 +00:00
n , t , err := readVarEntry ( entry , image )
2019-08-11 20:56:16 +00:00
if err != nil {
return nil , err
}
addr , pieces , descr , err := bi . Location ( entry , dwarf . AttrLocation , regs . PC ( ) , regs )
if pieces != nil {
addr = fakeAddress
var cmem * compositeMemory
cmem , err = newCompositeMemory ( mem , regs , pieces )
if cmem != nil {
mem = cmem
}
}
v := newVariable ( n , uintptr ( addr ) , t , bi , mem )
if pieces != nil {
v . Flags |= VariableFakeAddress
}
v . LocationExpr = descr
v . DeclLine , _ = entry . Val ( dwarf . AttrDeclLine ) . ( int64 )
if err != nil {
v . Unreadable = err
}
return v , nil
}
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 :
2018-12-03 13:53:39 +00:00
if v . Addr == 0 && len ( v . Children ) == 1 && v . loaded {
// fake pointer variable constructed by casting an integer to a pointer type
return & v . Children [ 0 ]
}
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
// 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
}
2020-03-30 18:03:29 +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
2020-02-11 01:32:50 +00:00
strlen , err := readIntRaw ( mem , addr + uintptr ( arch . PtrSize ( ) ) , int64 ( 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-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
2020-02-11 01:32:50 +00:00
val , err := readUintRaw ( mem , addr , int64 ( arch . PtrSize ( ) ) )
2014-10-25 15:48:14 +00:00
if err != nil {
2015-10-30 11:39:32 +00:00
return 0 , 0 , fmt . Errorf ( "could not read string pointer %s" , err )
2014-10-25 15:48:14 +00:00
}
2020-02-11 01:32:50 +00:00
addr = uintptr ( 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-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" {
2019-10-26 15:15:33 +00:00
field . Type = pointerTo ( fakeArrayType ( chanLen , chanType . ElemType ) , v . bi . Arch )
2017-10-26 14:14:31 +00:00
}
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
}
2019-06-17 16:51:29 +00:00
func ( v * Variable ) writeString ( len , base uint64 ) error {
writePointer ( v . bi , v . mem , uint64 ( v . Addr ) , base )
writePointer ( v . bi , v . mem , uint64 ( v . Addr ) + uint64 ( v . bi . Arch . PtrSize ( ) ) , len )
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
2019-05-30 15:08:37 +00:00
v . closureAddr = v . funcvalAddr ( )
2018-07-31 16:32:30 +00:00
if v . Unreadable != nil {
2015-10-18 17:37:13 +00:00
return
2015-01-20 04:15:40 +00:00
}
2019-05-30 15:08:37 +00:00
if v . closureAddr == 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
2020-02-11 01:32:50 +00:00
val , err := readUintRaw ( v . mem , uintptr ( v . closureAddr ) , int64 ( v . bi . Arch . PtrSize ( ) ) )
2015-01-20 04:15:40 +00:00
if err != nil {
2015-10-18 17:37:13 +00:00
v . Unreadable = err
return
2015-01-20 04:15:40 +00:00
}
2020-02-11 01:32:50 +00:00
v . Base = uintptr ( 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 {
2020-03-10 16:34:40 +00:00
val , err := readUintRaw ( v . mem , v . Addr , int64 ( v . bi . Arch . PtrSize ( ) ) )
2018-07-31 16:32:30 +00:00
if err != nil {
v . Unreadable = err
return 0
}
2020-03-10 16:34:40 +00:00
return val
2018-07-31 16:32:30 +00:00
}
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 ++
}
2020-03-18 22:45:29 +00:00
v . Children = append ( v . Children , * key , * val )
2015-11-05 17:25:52 +00:00
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
2019-04-26 17:23:43 +00:00
hashTophashEmptyOne uint64 // Go 1.12 and later has two sentinel tophash values for an empty cell, this is the second one (the first one hashTophashEmptyZero, the same as Go 1.11 and earlier)
hashMinTopHash uint64 // minimum value of tophash for a cell that isn't either evacuated or empty
2015-11-05 17:25:52 +00:00
}
// 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
}
2019-04-26 17:23:43 +00:00
it . hashTophashEmptyOne = hashTophashEmptyZero
it . hashMinTopHash = hashMinTopHashGo111
if producer := v . bi . Producer ( ) ; producer != "" && goversion . ProducerAfterOrEqual ( producer , 1 , 12 ) {
it . hashTophashEmptyOne = hashTophashEmptyOne
it . hashMinTopHash = hashMinTopHashGo112
}
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 )
2019-04-26 17:23:43 +00:00
if it . mapEvacuated ( oldb ) {
2015-11-05 17:25:52 +00:00
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 ++
2019-04-26 17:23:43 +00:00
if h != hashTophashEmptyZero && h != it . hashTophashEmptyOne {
2015-11-05 17:25:52 +00:00
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
}
2019-04-26 17:23:43 +00:00
func ( it * mapIterator ) mapEvacuated ( b * Variable ) bool {
2015-11-05 17:25:52 +00:00
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
}
2019-04-26 17:23:43 +00:00
//TODO: this needs to be > hashTophashEmptyOne for go >= 1.12
return tophash0 > it . hashTophashEmptyOne && tophash0 < it . hashMinTopHash
2015-11-05 17:25:52 +00:00
}
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 {
2019-05-08 21:06:38 +00:00
ctyp := cm [ dwarfRef { typ . Common ( ) . Index , typ . Common ( ) . Offset } ]
2017-09-08 10:31:20 +00:00
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 ""
}
2019-09-15 18:40:35 +00:00
type variablesByDepthAndDeclLine struct {
2017-05-04 14:35:31 +00:00
vars [ ] * Variable
depths [ ] int
}
2019-09-15 18:40:35 +00:00
func ( v * variablesByDepthAndDeclLine ) Len ( ) int { return len ( v . vars ) }
2017-05-04 14:35:31 +00:00
2019-09-15 18:40:35 +00:00
func ( v * variablesByDepthAndDeclLine ) Less ( i int , j int ) bool {
if v . depths [ i ] == v . depths [ j ] {
return v . vars [ i ] . DeclLine < v . vars [ j ] . DeclLine
}
return v . depths [ i ] < v . depths [ j ]
}
2017-05-04 14:35:31 +00:00
2019-09-15 18:40:35 +00:00
func ( v * variablesByDepthAndDeclLine ) Swap ( i int , j int ) {
2017-05-04 14:35:31 +00:00
v . depths [ i ] , v . depths [ j ] = v . depths [ j ] , v . depths [ i ]
v . vars [ i ] , v . vars [ j ] = v . vars [ j ] , v . vars [ i ]
}
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 ] }