Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
HugeYuan
delve
提交
48e13a90
D
delve
项目概览
HugeYuan
/
delve
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
delve
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
48e13a90
编写于
11月 12, 2015
作者:
A
aarzilli
提交者:
Derek Parker
12月 15, 2015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
proc/variables: Support for interface types
上级
2deb7fba
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
198 addition
and
26 deletion
+198
-26
_fixtures/testvariables3.go
_fixtures/testvariables3.go
+14
-1
proc/eval.go
proc/eval.go
+39
-22
proc/variables.go
proc/variables.go
+110
-1
service/api/conversions.go
service/api/conversions.go
+6
-0
service/api/prettyprint.go
service/api/prettyprint.go
+15
-2
service/test/variables_test.go
service/test/variables_test.go
+14
-0
未找到文件。
_fixtures/testvariables3.go
浏览文件 @
48e13a90
...
...
@@ -26,6 +26,14 @@ func afunc(x int) int {
type
functype
func
(
int
)
int
func
(
a
*
astruct
)
Error
()
string
{
return
"not an error"
}
func
(
b
*
bstruct
)
Error
()
string
{
return
"not an error"
}
func
main
()
{
i1
:=
1
i2
:=
2
...
...
@@ -96,11 +104,16 @@ func main() {
i4
:=
800
i5
:=
-
3
i6
:=
-
500
var
err1
error
=
c1
.
sa
[
0
]
var
err2
error
=
c1
.
pb
var
errnil
error
=
nil
var
iface1
interface
{}
=
c1
.
sa
[
0
]
var
ifacenil
interface
{}
=
nil
var
amb1
=
1
runtime
.
Breakpoint
()
for
amb1
:=
0
;
amb1
<
10
;
amb1
++
{
fmt
.
Println
(
amb1
)
}
fmt
.
Println
(
i1
,
i2
,
i3
,
p1
,
amb1
,
s1
,
a1
,
p2
,
p3
,
s2
,
as1
,
str1
,
f1
,
fn1
,
fn2
,
nilslice
,
nilptr
,
ch1
,
chnil
,
m1
,
mnil
,
m2
,
m3
,
up1
,
i4
,
i5
,
i6
)
fmt
.
Println
(
i1
,
i2
,
i3
,
p1
,
amb1
,
s1
,
a1
,
p2
,
p3
,
s2
,
as1
,
str1
,
f1
,
fn1
,
fn2
,
nilslice
,
nilptr
,
ch1
,
chnil
,
m1
,
mnil
,
m2
,
m3
,
up1
,
i4
,
i5
,
i6
,
err1
,
err2
,
errnil
,
iface1
,
ifacenil
)
}
proc/eval.go
浏览文件 @
48e13a90
...
...
@@ -55,6 +55,9 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
// if it's not a package variable then it must be a struct member access
return
scope
.
evalStructSelector
(
node
)
case
*
ast
.
TypeAssertExpr
:
// <expression>.(<type>)
return
scope
.
evalTypeAssert
(
node
)
case
*
ast
.
IndexExpr
:
return
scope
.
evalIndex
(
node
)
...
...
@@ -166,26 +169,11 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) {
fnnode
=
p
.
X
}
var
styp
,
typ
dwarf
.
Type
if
snode
,
ok
:=
fnnode
.
(
*
ast
.
StarExpr
);
ok
{
// Pointer types only appear in the dwarf informations when
// a pointer to the type is used in the target program, here
// we create a pointer type on the fly so that the user can
// specify a pointer to any variable used in the target program
ptyp
,
err
:=
scope
.
findType
(
exprToString
(
snode
.
X
))
if
err
!=
nil
{
return
nil
,
err
}
typ
=
&
dwarf
.
PtrType
{
dwarf
.
CommonType
{
int64
(
scope
.
Thread
.
dbp
.
arch
.
PtrSize
()),
exprToString
(
fnnode
)},
ptyp
}
styp
=
typ
}
else
{
styp
,
err
=
scope
.
findType
(
exprToString
(
fnnode
))
if
err
!=
nil
{
return
nil
,
err
}
typ
=
resolveTypedef
(
styp
)
styp
,
err
:=
scope
.
Thread
.
dbp
.
findTypeExpr
(
fnnode
)
if
err
!=
nil
{
return
nil
,
err
}
typ
:=
resolveTypedef
(
styp
)
converr
:=
fmt
.
Errorf
(
"can not convert
\"
%s
\"
to %s"
,
exprToString
(
node
.
Args
[
0
]),
typ
.
String
())
...
...
@@ -312,6 +300,35 @@ func (scope *EvalScope) evalStructSelector(node *ast.SelectorExpr) (*Variable, e
return
xv
.
structMember
(
node
.
Sel
.
Name
)
}
// Evaluates expressions <subexpr>.(<type>)
func
(
scope
*
EvalScope
)
evalTypeAssert
(
node
*
ast
.
TypeAssertExpr
)
(
*
Variable
,
error
)
{
xv
,
err
:=
scope
.
evalAST
(
node
.
X
)
if
err
!=
nil
{
return
nil
,
err
}
if
xv
.
Kind
!=
reflect
.
Interface
{
return
nil
,
fmt
.
Errorf
(
"expression
\"
%s
\"
not an interface"
,
exprToString
(
node
.
X
))
}
xv
.
loadInterface
(
0
,
false
)
if
xv
.
Unreadable
!=
nil
{
return
nil
,
xv
.
Unreadable
}
if
xv
.
Children
[
0
]
.
Unreadable
!=
nil
{
return
nil
,
xv
.
Children
[
0
]
.
Unreadable
}
if
xv
.
Children
[
0
]
.
Addr
==
0
{
return
nil
,
fmt
.
Errorf
(
"interface conversion: %s is nil, not %s"
,
xv
.
DwarfType
.
String
(),
exprToString
(
node
.
Type
))
}
typ
,
err
:=
scope
.
Thread
.
dbp
.
findTypeExpr
(
node
.
Type
)
if
err
!=
nil
{
return
nil
,
err
}
if
xv
.
Children
[
0
]
.
DwarfType
.
String
()
!=
typ
.
String
()
{
return
nil
,
fmt
.
Errorf
(
"interface conversion: %s is %s, not %s"
,
xv
.
DwarfType
.
String
(),
xv
.
Children
[
0
]
.
TypeString
(),
typ
)
}
return
&
xv
.
Children
[
0
],
nil
}
// Evaluates expressions <subexpr>[<subexpr>] (subscript access to arrays, slices and maps)
func
(
scope
*
EvalScope
)
evalIndex
(
node
*
ast
.
IndexExpr
)
(
*
Variable
,
error
)
{
xev
,
err
:=
scope
.
evalAST
(
node
.
X
)
...
...
@@ -761,13 +778,13 @@ func equalChildren(xv, yv *Variable, shortcircuit bool) (bool, error) {
return
r
,
nil
}
func
(
scope
*
EvalScope
)
findType
(
name
string
)
(
dwarf
.
Type
,
error
)
{
reader
:=
scope
.
DwarfReader
()
func
(
dbp
*
Process
)
findType
(
name
string
)
(
dwarf
.
Type
,
error
)
{
reader
:=
dbp
.
DwarfReader
()
typentry
,
err
:=
reader
.
SeekToTypeNamed
(
name
)
if
err
!=
nil
{
return
nil
,
err
}
return
scope
.
Thread
.
dbp
.
dwarf
.
Type
(
typentry
.
Offset
)
return
dbp
.
dwarf
.
Type
(
typentry
.
Offset
)
}
func
(
v
*
Variable
)
asInt
()
(
int64
,
error
)
{
...
...
proc/variables.go
浏览文件 @
48e13a90
...
...
@@ -5,6 +5,7 @@ import (
"debug/dwarf"
"encoding/binary"
"fmt"
"go/ast"
"go/constant"
"go/parser"
"go/token"
...
...
@@ -110,6 +111,14 @@ type EvalScope struct {
CFA
int64
}
type
IsNilErr
struct
{
name
string
}
func
(
err
*
IsNilErr
)
Error
()
string
{
return
fmt
.
Sprintf
(
"%s is nil"
,
err
.
name
)
}
func
newVariable
(
name
string
,
addr
uintptr
,
dwarfType
dwarf
.
Type
,
thread
*
Thread
)
*
Variable
{
v
:=
&
Variable
{
Name
:
name
,
...
...
@@ -142,6 +151,8 @@ func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread
if
v
.
Addr
!=
0
{
v
.
base
,
v
.
Len
,
v
.
Unreadable
=
v
.
thread
.
readStringInfo
(
v
.
Addr
)
}
case
t
.
StructName
==
"runtime.iface"
||
t
.
StructName
==
"runtime.eface"
:
v
.
Kind
=
reflect
.
Interface
case
strings
.
HasPrefix
(
t
.
StructName
,
"[]"
)
:
v
.
Kind
=
reflect
.
Slice
if
v
.
Addr
!=
0
{
...
...
@@ -249,7 +260,7 @@ func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) {
return
v
.
clone
(),
nil
}
if
v
.
Addr
==
0
{
return
nil
,
fmt
.
Errorf
(
"%s is nil"
,
v
.
Name
)
return
nil
,
&
IsNilErr
{
v
.
Name
}
}
name
:=
""
...
...
@@ -770,6 +781,9 @@ func (v *Variable) loadValueInternal(recurseLevel int) {
}
}
case
reflect
.
Interface
:
v
.
loadInterface
(
recurseLevel
,
true
)
case
reflect
.
Complex64
,
reflect
.
Complex128
:
v
.
readComplex
(
v
.
RealType
.
(
*
dwarf
.
ComplexType
)
.
ByteSize
)
case
reflect
.
Int
,
reflect
.
Int8
,
reflect
.
Int16
,
reflect
.
Int32
,
reflect
.
Int64
:
...
...
@@ -1366,6 +1380,101 @@ func mapEvacuated(b *Variable) bool {
return
true
}
func
(
v
*
Variable
)
loadInterface
(
recurseLevel
int
,
loadData
bool
)
{
var
typestring
,
data
*
Variable
isnil
:=
false
for
_
,
f
:=
range
v
.
RealType
.
(
*
dwarf
.
StructType
)
.
Field
{
switch
f
.
Name
{
case
"tab"
:
// for runtime.iface
tab
,
_
:=
v
.
toField
(
f
)
_type
,
err
:=
tab
.
structMember
(
"_type"
)
if
err
!=
nil
{
_
,
isnil
=
err
.
(
*
IsNilErr
)
if
!
isnil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type: %v"
,
err
)
return
}
}
else
{
typestring
,
err
=
_type
.
structMember
(
"_string"
)
if
err
!=
nil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type: %v"
,
err
)
return
}
typestring
=
typestring
.
maybeDereference
()
}
case
"_type"
:
// for runtime.eface
var
err
error
_type
,
_
:=
v
.
toField
(
f
)
typestring
,
err
=
_type
.
structMember
(
"_string"
)
if
err
!=
nil
{
_
,
isnil
=
err
.
(
*
IsNilErr
)
if
!
isnil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type: %v"
,
err
)
return
}
}
else
{
typestring
=
typestring
.
maybeDereference
()
}
case
"data"
:
data
,
_
=
v
.
toField
(
f
)
}
}
if
isnil
{
// interface to nil
data
=
data
.
maybeDereference
()
v
.
Children
=
[]
Variable
{
*
data
}
v
.
Children
[
0
]
.
loadValue
()
return
}
if
typestring
==
nil
||
data
==
nil
||
typestring
.
Addr
==
0
||
typestring
.
Kind
!=
reflect
.
String
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type"
)
return
}
typestring
.
loadValue
()
if
typestring
.
Unreadable
!=
nil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type: %v"
,
typestring
.
Unreadable
)
return
}
t
,
err
:=
parser
.
ParseExpr
(
constant
.
StringVal
(
typestring
.
Value
))
if
err
!=
nil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type, unparsable data type: %v"
,
err
)
return
}
typ
,
err
:=
v
.
thread
.
dbp
.
findTypeExpr
(
t
)
if
err
!=
nil
{
v
.
Unreadable
=
fmt
.
Errorf
(
"invalid interface type: %v"
,
err
)
return
}
data
=
newVariable
(
"data"
,
data
.
Addr
,
typ
,
data
.
thread
)
v
.
Children
=
[]
Variable
{
*
data
}
if
loadData
{
v
.
Children
[
0
]
.
loadValue
()
}
return
}
func
(
dbp
*
Process
)
findTypeExpr
(
expr
ast
.
Expr
)
(
dwarf
.
Type
,
error
)
{
if
snode
,
ok
:=
expr
.
(
*
ast
.
StarExpr
);
ok
{
// Pointer types only appear in the dwarf informations when
// a pointer to the type is used in the target program, here
// we create a pointer type on the fly so that the user can
// specify a pointer to any variable used in the target program
ptyp
,
err
:=
dbp
.
findType
(
exprToString
(
snode
.
X
))
if
err
!=
nil
{
return
nil
,
err
}
return
&
dwarf
.
PtrType
{
dwarf
.
CommonType
{
int64
(
dbp
.
arch
.
PtrSize
()),
exprToString
(
expr
)},
ptyp
},
nil
}
return
dbp
.
findType
(
exprToString
(
expr
))
}
// Fetches all variables of a specific type in the current function scope
func
(
scope
*
EvalScope
)
variablesByTag
(
tag
dwarf
.
Tag
)
([]
*
Variable
,
error
)
{
reader
:=
scope
.
DwarfReader
()
...
...
service/api/conversions.go
浏览文件 @
48e13a90
...
...
@@ -68,10 +68,16 @@ func ConvertVar(v *proc.Variable) *Variable {
if
v
.
DwarfType
!=
nil
{
r
.
Type
=
v
.
DwarfType
.
String
()
if
r
.
Type
==
"*void"
{
r
.
Type
=
"unsafe.Pointer"
}
}
if
v
.
RealType
!=
nil
{
r
.
RealType
=
v
.
RealType
.
String
()
if
r
.
RealType
==
"*void"
{
r
.
Type
=
"unsafe.Pointer"
}
}
if
v
.
Unreadable
!=
nil
{
...
...
service/api/prettyprint.go
浏览文件 @
48e13a90
...
...
@@ -69,6 +69,19 @@ func (v *Variable) writeTo(buf *bytes.Buffer, top, newlines, includeType bool, i
}
case
reflect
.
Struct
:
v
.
writeStructTo
(
buf
,
newlines
,
includeType
,
indent
)
case
reflect
.
Interface
:
if
includeType
{
if
v
.
Children
[
0
]
.
Kind
==
reflect
.
Invalid
{
fmt
.
Fprintf
(
buf
,
"%s "
,
v
.
Type
)
if
v
.
Children
[
0
]
.
Addr
==
0
{
fmt
.
Fprintf
(
buf
,
"nil"
)
return
}
}
else
{
fmt
.
Fprintf
(
buf
,
"%s(%s) "
,
v
.
Type
,
v
.
Children
[
0
]
.
Type
)
}
}
v
.
Children
[
0
]
.
writeTo
(
buf
,
false
,
newlines
,
false
,
indent
)
case
reflect
.
Map
:
v
.
writeMapTo
(
buf
,
newlines
,
includeType
,
indent
)
case
reflect
.
Func
:
...
...
@@ -192,7 +205,7 @@ func (v *Variable) shouldNewlineArray(newlines bool) bool {
kind
,
hasptr
:=
(
&
v
.
Children
[
0
])
.
recursiveKind
()
switch
kind
{
case
reflect
.
Slice
,
reflect
.
Array
,
reflect
.
Struct
,
reflect
.
Map
:
case
reflect
.
Slice
,
reflect
.
Array
,
reflect
.
Struct
,
reflect
.
Map
,
reflect
.
Interface
:
return
true
case
reflect
.
String
:
if
hasptr
{
...
...
@@ -233,7 +246,7 @@ func (v *Variable) shouldNewlineStruct(newlines bool) bool {
kind
,
hasptr
:=
(
&
v
.
Children
[
i
])
.
recursiveKind
()
switch
kind
{
case
reflect
.
Slice
,
reflect
.
Array
,
reflect
.
Struct
,
reflect
.
Map
:
case
reflect
.
Slice
,
reflect
.
Array
,
reflect
.
Struct
,
reflect
.
Map
,
reflect
.
Interface
:
return
true
case
reflect
.
String
:
if
hasptr
{
...
...
service/test/variables_test.go
浏览文件 @
48e13a90
...
...
@@ -399,6 +399,20 @@ func TestEvalExpression(t *testing.T) {
{
"mnil[
\"
Malone
\"
]"
,
false
,
""
,
""
,
""
,
fmt
.
Errorf
(
"key not found"
)},
{
"m1[80:]"
,
false
,
""
,
""
,
""
,
fmt
.
Errorf
(
"map index out of bounds"
)},
// interfaces
{
"err1"
,
true
,
"error(*struct main.astruct) *{A: 1, B: 2}"
,
""
,
"error"
,
nil
},
{
"err2"
,
true
,
"error(*struct main.bstruct) *{a: main.astruct {A: 1, B: 2}}"
,
""
,
"error"
,
nil
},
{
"errnil"
,
true
,
"error nil"
,
""
,
"error"
,
nil
},
{
"iface1"
,
true
,
"interface {}(*struct main.astruct) *{A: 1, B: 2}"
,
""
,
"interface {}"
,
nil
},
{
"ifacenil"
,
true
,
"interface {} nil"
,
""
,
"interface {}"
,
nil
},
{
"err1 == err2"
,
false
,
"false"
,
""
,
""
,
nil
},
{
"err1 == iface1"
,
false
,
""
,
""
,
""
,
fmt
.
Errorf
(
"mismatched types
\"
error
\"
and
\"
interface {}
\"
"
)},
{
"errnil == nil"
,
false
,
"false"
,
""
,
""
,
nil
},
{
"nil == errnil"
,
false
,
"false"
,
""
,
""
,
nil
},
{
"err1.(*main.astruct)"
,
false
,
"*struct main.astruct {A: 1, B: 2}"
,
""
,
"*struct main.astruct"
,
nil
},
{
"err1.(*main.bstruct)"
,
false
,
""
,
""
,
""
,
fmt
.
Errorf
(
"interface conversion: error is *struct main.astruct, not *struct main.bstruct"
)},
{
"errnil.(*main.astruct)"
,
false
,
""
,
""
,
""
,
fmt
.
Errorf
(
"interface conversion: error is nil, not *main.astruct"
)},
// combined expressions
{
"c1.pb.a.A"
,
true
,
"1"
,
""
,
"int"
,
nil
},
{
"c1.sa[1].B"
,
false
,
"3"
,
""
,
"int"
,
nil
},
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录