Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
pubx
delve
提交
3dacc25d
D
delve
项目概览
pubx
/
delve
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
delve
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3dacc25d
编写于
2月 22, 2017
作者:
A
aarzilli
提交者:
Derek Parker
4月 18, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
proc: refactor Continue to work on any Process implementation
上级
510b7db2
变更
11
展开全部
隐藏空白更改
内联
并排
Showing
11 changed file
with
325 addition
and
283 deletion
+325
-283
pkg/proc/breakpoints.go
pkg/proc/breakpoints.go
+1
-1
pkg/proc/proc.go
pkg/proc/proc.go
+141
-96
pkg/proc/proc_test.go
pkg/proc/proc_test.go
+120
-120
pkg/proc/proc_unix_test.go
pkg/proc/proc_unix_test.go
+1
-1
pkg/proc/threads.go
pkg/proc/threads.go
+29
-34
pkg/proc/threads_darwin.go
pkg/proc/threads_darwin.go
+4
-3
pkg/proc/threads_linux.go
pkg/proc/threads_linux.go
+7
-3
pkg/proc/threads_windows.go
pkg/proc/threads_windows.go
+4
-3
pkg/target/target.go
pkg/target/target.go
+1
-5
service/debugger/debugger.go
service/debugger/debugger.go
+5
-5
service/test/variables_test.go
service/test/variables_test.go
+12
-12
未找到文件。
pkg/proc/breakpoints.go
浏览文件 @
3dacc25d
...
...
@@ -107,7 +107,7 @@ func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error {
return
err
}
func
(
bp
*
Breakpoint
)
checkCondition
(
thread
*
Thread
)
(
bool
,
error
)
{
func
(
bp
*
Breakpoint
)
checkCondition
(
thread
I
Thread
)
(
bool
,
error
)
{
if
bp
.
Cond
==
nil
{
return
true
,
nil
}
...
...
pkg/proc/proc.go
浏览文件 @
3dacc25d
package
proc
import
(
"debug/gosym"
"encoding/binary"
"errors"
"fmt"
...
...
@@ -319,17 +320,17 @@ func (dbp *Process) Status() *WaitStatus {
}
// Next continues execution until the next source line.
func
(
dbp
*
Process
)
Next
(
)
(
err
error
)
{
if
dbp
.
exited
{
func
Next
(
dbp
Continuable
)
(
err
error
)
{
if
dbp
.
Exited
()
{
return
&
ProcessExitedError
{}
}
for
i
:=
range
dbp
.
breakpoints
{
if
dbp
.
breakpoints
[
i
]
.
Internal
()
{
for
_
,
bp
:=
range
dbp
.
Breakpoints
()
{
if
bp
.
Internal
()
{
return
fmt
.
Errorf
(
"next while nexting"
)
}
}
if
err
=
dbp
.
next
(
false
);
err
!=
nil
{
if
err
=
next
(
dbp
,
false
);
err
!=
nil
{
switch
err
.
(
type
)
{
case
ThreadBlockedError
,
NoReturnAddr
:
// Noop
default
:
...
...
@@ -338,91 +339,119 @@ func (dbp *Process) Next() (err error) {
}
}
return
dbp
.
Continue
()
return
Continue
(
dbp
)
}
func
(
dbp
*
Process
)
ContinueOnce
()
(
IThread
,
error
)
{
if
dbp
.
exited
{
return
nil
,
&
ProcessExitedError
{}
}
if
err
:=
dbp
.
resume
();
err
!=
nil
{
return
nil
,
err
}
dbp
.
allGCache
=
nil
for
_
,
th
:=
range
dbp
.
threads
{
th
.
clearBreakpointState
()
}
trapthread
,
err
:=
dbp
.
trapWait
(
-
1
)
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
dbp
.
Halt
();
err
!=
nil
{
return
nil
,
dbp
.
exitGuard
(
err
)
}
if
err
:=
dbp
.
setCurrentBreakpoints
(
trapthread
);
err
!=
nil
{
return
nil
,
err
}
return
trapthread
,
err
}
// Continuable is the subinterface of target.Interface used to implement
// Continue/Next/etc.
type
Continuable
interface
{
ContinueOnce
()
(
trapthread
IThread
,
err
error
)
CurrentThread
()
IThread
SelectedGoroutine
()
*
G
Breakpoints
()
map
[
uint64
]
*
Breakpoint
ThreadList
()
[]
IThread
SwitchThread
(
int
)
error
BinInfo
()
*
BinaryInfo
ClearInternalBreakpoints
()
error
FirstPCAfterPrologue
(
fn
*
gosym
.
Func
,
sameline
bool
)
(
uint64
,
error
)
SetBreakpoint
(
addr
uint64
,
kind
BreakpointKind
,
cond
ast
.
Expr
)
(
*
Breakpoint
,
error
)
Exited
()
bool
}
// Continue continues execution of the debugged
// process. It will continue until it hits a breakpoint
// or is otherwise stopped.
func
(
dbp
*
Process
)
Continue
()
error
{
if
dbp
.
exited
{
return
&
ProcessExitedError
{}
}
func
Continue
(
dbp
Continuable
)
error
{
for
{
if
err
:=
dbp
.
resume
();
err
!=
nil
{
trapthread
,
err
:=
dbp
.
ContinueOnce
()
if
err
!=
nil
{
return
err
}
dbp
.
allGCache
=
nil
for
_
,
th
:=
range
dbp
.
threads
{
th
.
clearBreakpointState
()
}
threads
:=
dbp
.
ThreadList
()
trapthread
,
err
:=
dbp
.
trapWait
(
-
1
)
if
err
!=
nil
{
return
err
}
if
err
:=
dbp
.
Halt
();
err
!=
nil
{
return
dbp
.
exitGuard
(
err
)
}
if
err
:=
dbp
.
setCurrentBreakpoints
(
trapthread
);
err
!=
nil
{
return
err
}
if
err
:=
dbp
.
pickCurrentThread
(
trapthread
);
err
!=
nil
{
if
err
:=
pickCurrentThread
(
dbp
,
trapthread
,
threads
);
err
!=
nil
{
return
err
}
curthread
:=
dbp
.
CurrentThread
()
curbp
,
curbpActive
,
_
:=
curthread
.
Breakpoint
()
switch
{
case
dbp
.
currentThread
.
CurrentBreakpoint
==
nil
:
case
curbp
==
nil
:
// runtime.Breakpoint or manual stop
if
dbp
.
currentThread
.
onRuntimeBreakpoint
(
)
{
if
onRuntimeBreakpoint
(
curthread
)
{
// Single-step current thread until we exit runtime.breakpoint and
// runtime.Breakpoint.
// On go < 1.8 it was sufficient to single-step twice on go1.8 a change
// to the compiler requires 4 steps.
for
{
if
err
=
dbp
.
currentT
hread
.
StepInstruction
();
err
!=
nil
{
if
err
=
curt
hread
.
StepInstruction
();
err
!=
nil
{
return
err
}
loc
,
err
:=
dbp
.
currentT
hread
.
Location
()
loc
,
err
:=
curt
hread
.
Location
()
if
err
!=
nil
||
loc
.
Fn
==
nil
||
(
loc
.
Fn
.
Name
!=
"runtime.breakpoint"
&&
loc
.
Fn
.
Name
!=
"runtime.Breakpoint"
)
{
break
}
}
}
return
dbp
.
conditionErrors
(
)
case
dbp
.
currentThread
.
onTriggeredInternalBreakpoint
()
:
if
dbp
.
currentThread
.
CurrentBreakpoint
.
Kind
==
StepBreakpoint
{
return
conditionErrors
(
threads
)
case
curbpActive
&&
curbp
.
Internal
()
:
if
curbp
.
Kind
==
StepBreakpoint
{
// See description of proc.(*Process).next for the meaning of StepBreakpoints
if
err
:=
dbp
.
conditionErrors
();
err
!=
nil
{
return
err
}
pc
,
err
:=
dbp
.
currentThread
.
PC
()
if
err
!=
nil
{
if
err
:=
conditionErrors
(
threads
);
err
!=
nil
{
return
err
}
regs
,
err
:=
dbp
.
currentT
hread
.
Registers
(
false
)
regs
,
err
:=
curt
hread
.
Registers
(
false
)
if
err
!=
nil
{
return
err
}
text
,
err
:=
disassemble
(
dbp
.
currentThread
,
regs
,
dbp
.
breakpoints
,
dbp
.
BinInfo
(),
pc
,
pc
+
maxInstructionLength
)
pc
:=
regs
.
PC
()
text
,
err
:=
disassemble
(
curthread
,
regs
,
dbp
.
Breakpoints
(),
dbp
.
BinInfo
(),
pc
,
pc
+
maxInstructionLength
)
if
err
!=
nil
{
return
err
}
// here we either set a breakpoint into the destination of the CALL
// instruction or we determined that the called function is hidden,
// either way we need to resume execution
if
err
=
dbp
.
setStepIntoBreakpoint
(
text
,
sameGoroutineCondition
(
dbp
.
selectedGoroutine
));
err
!=
nil
{
if
err
=
setStepIntoBreakpoint
(
dbp
,
text
,
sameGoroutineCondition
(
dbp
.
SelectedGoroutine
()
));
err
!=
nil
{
return
err
}
}
else
{
if
err
:=
dbp
.
ClearInternalBreakpoints
();
err
!=
nil
{
return
err
}
return
dbp
.
conditionErrors
(
)
return
conditionErrors
(
threads
)
}
case
dbp
.
currentThread
.
onTriggeredBreakpoint
()
:
onNextGoroutine
,
err
:=
dbp
.
currentThread
.
onNextGoroutine
(
)
case
curbpActive
:
onNextGoroutine
,
err
:=
onNextGoroutine
(
curthread
,
dbp
.
Breakpoints
()
)
if
err
!=
nil
{
return
err
}
...
...
@@ -432,19 +461,19 @@ func (dbp *Process) Continue() error {
return
err
}
}
return
dbp
.
conditionErrors
(
)
return
conditionErrors
(
threads
)
default
:
// not a manual stop, not on runtime.Breakpoint, not on a breakpoint, just repeat
}
}
}
func
(
dbp
*
Process
)
conditionErrors
(
)
error
{
func
conditionErrors
(
threads
[]
IThread
)
error
{
var
condErr
error
for
_
,
th
:=
range
dbp
.
threads
{
if
th
.
CurrentBreakpoint
!=
nil
&&
th
.
BreakpointConditionErro
r
!=
nil
{
for
_
,
th
:=
range
threads
{
if
bp
,
_
,
bperr
:=
th
.
Breakpoint
();
bp
!=
nil
&&
bper
r
!=
nil
{
if
condErr
==
nil
{
condErr
=
th
.
BreakpointConditionErro
r
condErr
=
bper
r
}
else
{
return
fmt
.
Errorf
(
"multiple errors evaluating conditions"
)
}
...
...
@@ -457,36 +486,36 @@ func (dbp *Process) conditionErrors() error {
// - a thread with onTriggeredInternalBreakpoint() == true
// - a thread with onTriggeredBreakpoint() == true (prioritizing trapthread)
// - trapthread
func
(
dbp
*
Process
)
pickCurrentThread
(
trapthread
*
Thread
)
error
{
for
_
,
th
:=
range
dbp
.
threads
{
if
th
.
onTriggeredInternalBreakpoint
()
{
return
dbp
.
SwitchThread
(
th
.
ID
)
func
pickCurrentThread
(
dbp
Continuable
,
trapthread
IThread
,
threads
[]
I
Thread
)
error
{
for
_
,
th
:=
range
threads
{
if
bp
,
active
,
_
:=
th
.
Breakpoint
();
active
&&
bp
.
Internal
()
{
return
dbp
.
SwitchThread
(
th
.
ThreadID
()
)
}
}
if
trapthread
.
onTriggeredBreakpoint
()
{
return
dbp
.
SwitchThread
(
trapthread
.
ID
)
if
_
,
active
,
_
:=
trapthread
.
Breakpoint
();
active
{
return
dbp
.
SwitchThread
(
trapthread
.
ThreadID
()
)
}
for
_
,
th
:=
range
dbp
.
threads
{
if
th
.
onTriggeredBreakpoint
()
{
return
dbp
.
SwitchThread
(
th
.
ID
)
for
_
,
th
:=
range
threads
{
if
_
,
active
,
_
:=
th
.
Breakpoint
();
active
{
return
dbp
.
SwitchThread
(
th
.
ThreadID
()
)
}
}
return
dbp
.
SwitchThread
(
trapthread
.
ID
)
return
dbp
.
SwitchThread
(
trapthread
.
ThreadID
()
)
}
// Step will continue until another source line is reached.
// Will step into functions.
func
(
dbp
*
Process
)
Step
(
)
(
err
error
)
{
if
dbp
.
exited
{
func
Step
(
dbp
Continuable
)
(
err
error
)
{
if
dbp
.
Exited
()
{
return
&
ProcessExitedError
{}
}
for
i
:=
range
dbp
.
breakpoints
{
if
dbp
.
breakpoints
[
i
]
.
Internal
()
{
for
_
,
bp
:=
range
dbp
.
Breakpoints
()
{
if
bp
.
Internal
()
{
return
fmt
.
Errorf
(
"next while nexting"
)
}
}
if
err
=
dbp
.
next
(
true
);
err
!=
nil
{
if
err
=
next
(
dbp
,
true
);
err
!=
nil
{
switch
err
.
(
type
)
{
case
ThreadBlockedError
,
NoReturnAddr
:
// Noop
default
:
...
...
@@ -495,7 +524,7 @@ func (dbp *Process) Step() (err error) {
}
}
return
dbp
.
Continue
(
)
return
Continue
(
dbp
)
}
// Returns an expression that evaluates to true when the current goroutine is g
...
...
@@ -529,7 +558,7 @@ func (dbp *Process) StepInstruction() (err error) {
if
_
,
err
:=
dbp
.
SetBreakpoint
(
dbp
.
selectedGoroutine
.
PC
,
NextBreakpoint
,
sameGoroutineCondition
(
dbp
.
selectedGoroutine
));
err
!=
nil
{
return
err
}
return
dbp
.
Continue
(
)
return
Continue
(
dbp
)
}
dbp
.
allGCache
=
nil
if
dbp
.
exited
{
...
...
@@ -545,10 +574,12 @@ func (dbp *Process) StepInstruction() (err error) {
// StepOut will continue until the current goroutine exits the
// function currently being executed or a deferred function is executed
func
(
dbp
*
Process
)
StepOut
()
error
{
cond
:=
sameGoroutineCondition
(
dbp
.
selectedGoroutine
)
func
StepOut
(
dbp
Continuable
)
error
{
selg
:=
dbp
.
SelectedGoroutine
()
curthread
:=
dbp
.
CurrentThread
()
cond
:=
sameGoroutineCondition
(
selg
)
topframe
,
err
:=
topframe
(
dbp
.
selectedGoroutine
,
dbp
.
currentT
hread
)
topframe
,
err
:=
topframe
(
selg
,
curt
hread
)
if
err
!=
nil
{
return
err
}
...
...
@@ -557,10 +588,10 @@ func (dbp *Process) StepOut() error {
var
deferpc
uint64
=
0
if
filepath
.
Ext
(
topframe
.
Current
.
File
)
==
".go"
{
if
dbp
.
selectedGoroutine
!=
nil
{
deferPCEntry
:=
dbp
.
selectedGoroutine
.
DeferPC
()
if
selg
!=
nil
{
deferPCEntry
:=
selg
.
DeferPC
()
if
deferPCEntry
!=
0
{
_
,
_
,
deferfn
:=
dbp
.
bi
.
goSymTable
.
PCToLine
(
deferPCEntry
)
_
,
_
,
deferfn
:=
dbp
.
BinInfo
()
.
PCToLine
(
deferPCEntry
)
deferpc
,
err
=
dbp
.
FirstPCAfterPrologue
(
deferfn
,
false
)
if
err
!=
nil
{
return
err
...
...
@@ -591,12 +622,12 @@ func (dbp *Process) StepOut() error {
}
if
topframe
.
Ret
!=
0
{
if
err
:=
dbp
.
setInternalBreakpoints
(
topframe
.
Current
.
PC
,
[]
uint64
{
topframe
.
Ret
},
NextBreakpoint
,
cond
);
err
!=
nil
{
if
err
:=
setInternalBreakpoints
(
dbp
,
topframe
.
Current
.
PC
,
[]
uint64
{
topframe
.
Ret
},
NextBreakpoint
,
cond
);
err
!=
nil
{
return
err
}
}
return
dbp
.
Continue
(
)
return
Continue
(
dbp
)
}
// SwitchThread changes from current thread to the thread specified by `tid`.
...
...
@@ -633,29 +664,42 @@ func (dbp *Process) SwitchGoroutine(gid int) error {
return
nil
}
// If the argument of GoroutinesInfo implements AllGCache GoroutinesInfo
// will use the pointer returned by AllGCache as a cache.
type
AllGCache
interface
{
AllGCache
()
*
[]
*
G
}
func
(
dbp
*
Process
)
AllGCache
()
*
[]
*
G
{
return
&
dbp
.
allGCache
}
// GoroutinesInfo returns an array of G structures representing the information
// Delve cares about from the internal runtime G structure.
func
(
dbp
*
Process
)
GoroutinesInfo
(
)
([]
*
G
,
error
)
{
if
dbp
.
exited
{
func
GoroutinesInfo
(
dbp
EvalScopeConvertible
)
([]
*
G
,
error
)
{
if
dbp
.
Exited
()
{
return
nil
,
&
ProcessExitedError
{}
}
if
dbp
.
allGCache
!=
nil
{
return
dbp
.
allGCache
,
nil
if
dbp
,
ok
:=
dbp
.
(
AllGCache
);
ok
{
if
allGCache
:=
dbp
.
AllGCache
();
*
allGCache
!=
nil
{
return
*
allGCache
,
nil
}
}
var
(
threadg
=
map
[
int
]
*
Thread
{}
threadg
=
map
[
int
]
I
Thread
{}
allg
[]
*
G
rdr
=
dbp
.
bi
.
DwarfReader
()
rdr
=
dbp
.
BinInfo
()
.
DwarfReader
()
)
for
i
:=
range
dbp
.
threads
{
if
dbp
.
threads
[
i
]
.
blocked
()
{
threads
:=
dbp
.
ThreadList
()
for
_
,
th
:=
range
threads
{
if
threadBlocked
(
th
)
{
continue
}
g
,
_
:=
GetG
(
dbp
.
threads
[
i
]
)
g
,
_
:=
GetG
(
th
)
if
g
!=
nil
{
threadg
[
g
.
ID
]
=
dbp
.
threads
[
i
]
threadg
[
g
.
ID
]
=
th
}
}
...
...
@@ -663,7 +707,7 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
if
err
!=
nil
{
return
nil
,
err
}
allglenBytes
,
err
:=
dbp
.
currentThread
.
readMemory
(
uintptr
(
addr
),
8
)
allglenBytes
,
err
:=
dbp
.
CurrentThread
()
.
readMemory
(
uintptr
(
addr
),
8
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -678,11 +722,11 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
return
nil
,
err
}
}
faddr
,
err
:=
dbp
.
currentThread
.
readMemory
(
uintptr
(
allgentryaddr
),
dbp
.
bi
.
arch
.
PtrSize
())
faddr
,
err
:=
dbp
.
CurrentThread
()
.
readMemory
(
uintptr
(
allgentryaddr
),
dbp
.
BinInfo
()
.
arch
.
PtrSize
())
allgptr
:=
binary
.
LittleEndian
.
Uint64
(
faddr
)
for
i
:=
uint64
(
0
);
i
<
allglen
;
i
++
{
gvar
,
err
:=
newGVariable
(
dbp
.
currentThread
,
uintptr
(
allgptr
+
(
i
*
uint64
(
dbp
.
bi
.
arch
.
PtrSize
()))),
true
)
gvar
,
err
:=
newGVariable
(
dbp
.
CurrentThread
(),
uintptr
(
allgptr
+
(
i
*
uint64
(
dbp
.
BinInfo
()
.
arch
.
PtrSize
()))),
true
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -703,7 +747,11 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
allg
=
append
(
allg
,
g
)
}
}
dbp
.
allGCache
=
allg
if
dbp
,
ok
:=
dbp
.
(
AllGCache
);
ok
{
allGCache
:=
dbp
.
AllGCache
()
*
allGCache
=
allg
}
return
allg
,
nil
}
...
...
@@ -884,19 +932,14 @@ func (scope *EvalScope) getGoInformation() (ver GoVersion, isextld bool, err err
return
}
type
GoroutinesInfo
interface
{
SelectedGoroutine
()
*
G
GoroutinesInfo
()
([]
*
G
,
error
)
}
// FindGoroutine returns a G struct representing the goroutine
// specified by `gid`.
func
FindGoroutine
(
dbp
GoroutinesInfo
,
gid
int
)
(
*
G
,
error
)
{
func
FindGoroutine
(
dbp
EvalScopeConvertible
,
gid
int
)
(
*
G
,
error
)
{
if
gid
==
-
1
{
return
dbp
.
SelectedGoroutine
(),
nil
}
gs
,
err
:=
dbp
.
GoroutinesInfo
(
)
gs
,
err
:=
GoroutinesInfo
(
dbp
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -911,9 +954,11 @@ func FindGoroutine(dbp GoroutinesInfo, gid int) (*G, error) {
// EvalScopeConvertible is a subset of target.Interface with the methods
// used by ConvertEvalScope/GoroutinesInfo/etc.
type
EvalScopeConvertible
interface
{
GoroutinesInfo
Exited
()
bool
SelectedGoroutine
()
*
G
CurrentThread
()
IThread
BinInfo
()
*
BinaryInfo
ThreadList
()
[]
IThread
}
// ConvertEvalScope returns a new EvalScope in the context of the
...
...
pkg/proc/proc_test.go
浏览文件 @
3dacc25d
此差异已折叠。
点击以展开。
pkg/proc/proc_unix_test.go
浏览文件 @
3dacc25d
...
...
@@ -23,7 +23,7 @@ func TestIssue419(t *testing.T) {
}
}
}()
err
:=
p
.
Continue
(
)
err
:=
Continue
(
p
)
if
_
,
exited
:=
err
.
(
ProcessExitedError
);
!
exited
{
t
.
Fatalf
(
"Unexpected error after Continue(): %v
\n
"
,
err
)
}
...
...
pkg/proc/threads.go
浏览文件 @
3dacc25d
...
...
@@ -46,6 +46,7 @@ type IThread interface {
Registers
(
floatingPoint
bool
)
(
Registers
,
error
)
Arch
()
Arch
BinInfo
()
*
BinaryInfo
StepInstruction
()
error
}
// Location represents the location of a thread.
...
...
@@ -149,12 +150,12 @@ func (tbe ThreadBlockedError) Error() string {
}
// returns topmost frame of g or thread if g is nil
func
topframe
(
g
*
G
,
thread
*
Thread
)
(
Stackframe
,
error
)
{
func
topframe
(
g
*
G
,
thread
I
Thread
)
(
Stackframe
,
error
)
{
var
frames
[]
Stackframe
var
err
error
if
g
==
nil
{
if
thread
.
blocked
(
)
{
if
thread
Blocked
(
thread
)
{
return
Stackframe
{},
ThreadBlockedError
{}
}
frames
,
err
=
ThreadStacktrace
(
thread
,
0
)
...
...
@@ -177,8 +178,10 @@ func topframe(g *G, thread *Thread) (Stackframe, error) {
// a breakpoint of kind StepBreakpoint is set on the CALL instruction,
// Continue will take care of setting a breakpoint to the destination
// once the CALL is reached.
func
(
dbp
*
Process
)
next
(
stepInto
bool
)
error
{
topframe
,
err
:=
topframe
(
dbp
.
selectedGoroutine
,
dbp
.
currentThread
)
func
next
(
dbp
Continuable
,
stepInto
bool
)
error
{
selg
:=
dbp
.
SelectedGoroutine
()
curthread
:=
dbp
.
CurrentThread
()
topframe
,
err
:=
topframe
(
selg
,
curthread
)
if
err
!=
nil
{
return
err
}
...
...
@@ -191,22 +194,22 @@ func (dbp *Process) next(stepInto bool) error {
}()
csource
:=
filepath
.
Ext
(
topframe
.
Current
.
File
)
!=
".go"
var
thread
memoryReadWriter
=
dbp
.
currentT
hread
var
thread
memoryReadWriter
=
curt
hread
var
regs
Registers
if
dbp
.
selectedGoroutine
!=
nil
&&
dbp
.
selectedGoroutine
.
thread
!=
nil
{
thread
=
dbp
.
selectedGoroutine
.
thread
regs
,
err
=
dbp
.
selectedGoroutine
.
thread
.
Registers
(
false
)
if
selg
!=
nil
&&
selg
.
Thread
()
!=
nil
{
thread
=
selg
.
Thread
()
regs
,
err
=
selg
.
Thread
()
.
Registers
(
false
)
if
err
!=
nil
{
return
err
}
}
text
,
err
:=
disassemble
(
thread
,
regs
,
dbp
.
breakpoints
,
dbp
.
BinInfo
(),
topframe
.
FDE
.
Begin
(),
topframe
.
FDE
.
End
())
text
,
err
:=
disassemble
(
thread
,
regs
,
dbp
.
Breakpoints
()
,
dbp
.
BinInfo
(),
topframe
.
FDE
.
Begin
(),
topframe
.
FDE
.
End
())
if
err
!=
nil
&&
stepInto
{
return
err
}
cond
:=
sameGoroutineCondition
(
dbp
.
selectedGoroutine
)
cond
:=
sameGoroutineCondition
(
selg
)
if
stepInto
{
for
_
,
instr
:=
range
text
{
...
...
@@ -215,7 +218,7 @@ func (dbp *Process) next(stepInto bool) error {
}
if
instr
.
DestLoc
!=
nil
&&
instr
.
DestLoc
.
Fn
!=
nil
{
if
err
:=
dbp
.
setStepIntoBreakpoint
(
[]
AsmInstruction
{
instr
},
cond
);
err
!=
nil
{
if
err
:=
setStepIntoBreakpoint
(
dbp
,
[]
AsmInstruction
{
instr
},
cond
);
err
!=
nil
{
return
err
}
}
else
{
...
...
@@ -242,10 +245,10 @@ func (dbp *Process) next(stepInto bool) error {
// Set breakpoint on the most recently deferred function (if any)
var
deferpc
uint64
=
0
if
dbp
.
selectedGoroutine
!=
nil
{
deferPCEntry
:=
dbp
.
selectedGoroutine
.
DeferPC
()
if
selg
!=
nil
{
deferPCEntry
:=
selg
.
DeferPC
()
if
deferPCEntry
!=
0
{
_
,
_
,
deferfn
:=
dbp
.
bi
.
goSymTable
.
PCToLine
(
deferPCEntry
)
_
,
_
,
deferfn
:=
dbp
.
BinInfo
()
.
PCToLine
(
deferPCEntry
)
var
err
error
deferpc
,
err
=
dbp
.
FirstPCAfterPrologue
(
deferfn
,
false
)
if
err
!=
nil
{
...
...
@@ -267,7 +270,7 @@ func (dbp *Process) next(stepInto bool) error {
}
// Add breakpoints on all the lines in the current function
pcs
,
err
:=
dbp
.
bi
.
lineInfo
.
AllPCsBetween
(
topframe
.
FDE
.
Begin
(),
topframe
.
FDE
.
End
()
-
1
,
topframe
.
Current
.
File
)
pcs
,
err
:=
dbp
.
BinInfo
()
.
lineInfo
.
AllPCsBetween
(
topframe
.
FDE
.
Begin
(),
topframe
.
FDE
.
End
()
-
1
,
topframe
.
Current
.
File
)
if
err
!=
nil
{
return
err
}
...
...
@@ -282,8 +285,8 @@ func (dbp *Process) next(stepInto bool) error {
}
if
!
covered
{
fn
:=
dbp
.
bi
.
goSymTable
.
PCToFunc
(
topframe
.
Ret
)
if
dbp
.
selectedGoroutine
!=
nil
&&
fn
!=
nil
&&
fn
.
Name
==
"runtime.goexit"
{
fn
:=
dbp
.
BinInfo
()
.
goSymTable
.
PCToFunc
(
topframe
.
Ret
)
if
selg
!=
nil
&&
fn
!=
nil
&&
fn
.
Name
==
"runtime.goexit"
{
return
nil
}
}
...
...
@@ -292,10 +295,10 @@ func (dbp *Process) next(stepInto bool) error {
// Add a breakpoint on the return address for the current frame
pcs
=
append
(
pcs
,
topframe
.
Ret
)
success
=
true
return
dbp
.
setInternalBreakpoints
(
topframe
.
Current
.
PC
,
pcs
,
NextBreakpoint
,
cond
)
return
setInternalBreakpoints
(
dbp
,
topframe
.
Current
.
PC
,
pcs
,
NextBreakpoint
,
cond
)
}
func
(
dbp
*
Process
)
setStepIntoBreakpoint
(
text
[]
AsmInstruction
,
cond
ast
.
Expr
)
error
{
func
setStepIntoBreakpoint
(
dbp
Continuable
,
text
[]
AsmInstruction
,
cond
ast
.
Expr
)
error
{
if
len
(
text
)
<=
0
{
return
nil
}
...
...
@@ -337,7 +340,7 @@ func (dbp *Process) setStepIntoBreakpoint(text []AsmInstruction, cond ast.Expr)
// setInternalBreakpoints sets a breakpoint to all addresses specified in pcs
// skipping over curpc and curpc-1
func
(
dbp
*
Process
)
setInternalBreakpoints
(
curpc
uint64
,
pcs
[]
uint64
,
kind
BreakpointKind
,
cond
ast
.
Expr
)
error
{
func
setInternalBreakpoints
(
dbp
Continuable
,
curpc
uint64
,
pcs
[]
uint64
,
kind
BreakpointKind
,
cond
ast
.
Expr
)
error
{
for
i
:=
range
pcs
{
if
pcs
[
i
]
==
curpc
||
pcs
[
i
]
==
curpc
-
1
{
continue
...
...
@@ -495,7 +498,7 @@ func (thread *Thread) SetCurrentBreakpoint() error {
return
err
}
thread
.
BreakpointConditionMet
,
thread
.
BreakpointConditionError
=
bp
.
checkCondition
(
thread
)
if
thread
.
onTriggeredBreakpoint
()
{
if
thread
.
CurrentBreakpoint
!=
nil
&&
thread
.
BreakpointConditionMet
{
if
g
,
err
:=
GetG
(
thread
);
err
==
nil
{
thread
.
CurrentBreakpoint
.
HitCount
[
g
.
ID
]
++
}
...
...
@@ -511,15 +514,7 @@ func (thread *Thread) clearBreakpointState() {
thread
.
BreakpointConditionError
=
nil
}
func
(
thread
*
Thread
)
onTriggeredBreakpoint
()
bool
{
return
(
thread
.
CurrentBreakpoint
!=
nil
)
&&
thread
.
BreakpointConditionMet
}
func
(
thread
*
Thread
)
onTriggeredInternalBreakpoint
()
bool
{
return
thread
.
onTriggeredBreakpoint
()
&&
thread
.
CurrentBreakpoint
.
Internal
()
}
func
(
thread
*
Thread
)
onRuntimeBreakpoint
()
bool
{
func
onRuntimeBreakpoint
(
thread
IThread
)
bool
{
loc
,
err
:=
thread
.
Location
()
if
err
!=
nil
{
return
false
...
...
@@ -528,11 +523,11 @@ func (thread *Thread) onRuntimeBreakpoint() bool {
}
// onNextGorutine returns true if this thread is on the goroutine requested by the current 'next' command
func
(
thread
*
Thread
)
onNextGoroutine
(
)
(
bool
,
error
)
{
func
onNextGoroutine
(
thread
IThread
,
breakpoints
map
[
uint64
]
*
Breakpoint
)
(
bool
,
error
)
{
var
bp
*
Breakpoint
for
i
:=
range
thread
.
dbp
.
breakpoints
{
if
thread
.
dbp
.
breakpoints
[
i
]
.
Internal
()
{
bp
=
thread
.
dbp
.
breakpoints
[
i
]
for
i
:=
range
breakpoints
{
if
breakpoints
[
i
]
.
Internal
()
{
bp
=
breakpoints
[
i
]
break
}
}
...
...
pkg/proc/threads_darwin.go
浏览文件 @
3dacc25d
...
...
@@ -81,13 +81,14 @@ func (t *Thread) resume() error {
return
nil
}
func
(
t
*
Thread
)
blocked
(
)
bool
{
func
threadBlocked
(
t
IThread
)
bool
{
// TODO(dp) cache the func pc to remove this lookup
pc
,
err
:=
t
.
PC
(
)
regs
,
err
:=
t
.
Registers
(
false
)
if
err
!=
nil
{
return
false
}
fn
:=
t
.
dbp
.
bi
.
goSymTable
.
PCToFunc
(
pc
)
pc
:=
regs
.
PC
()
fn
:=
t
.
BinInfo
()
.
goSymTable
.
PCToFunc
(
pc
)
if
fn
==
nil
{
return
false
}
...
...
pkg/proc/threads_linux.go
浏览文件 @
3dacc25d
...
...
@@ -67,9 +67,13 @@ func (t *Thread) singleStep() (err error) {
}
}
func
(
t
*
Thread
)
blocked
()
bool
{
pc
,
_
:=
t
.
PC
()
fn
:=
t
.
dbp
.
bi
.
goSymTable
.
PCToFunc
(
pc
)
func
threadBlocked
(
t
IThread
)
bool
{
regs
,
err
:=
t
.
Registers
(
false
)
if
err
!=
nil
{
return
false
}
pc
:=
regs
.
PC
()
fn
:=
t
.
BinInfo
()
.
goSymTable
.
PCToFunc
(
pc
)
if
fn
!=
nil
&&
((
fn
.
Name
==
"runtime.futex"
)
||
(
fn
.
Name
==
"runtime.usleep"
)
||
(
fn
.
Name
==
"runtime.clone"
))
{
return
true
}
...
...
pkg/proc/threads_windows.go
浏览文件 @
3dacc25d
...
...
@@ -103,14 +103,15 @@ func (t *Thread) resume() error {
return
err
}
func
(
t
*
Thread
)
blocked
(
)
bool
{
func
threadBlocked
(
t
IThread
)
bool
{
// TODO: Probably incorrect - what are the runtime functions that
// indicate blocking on Windows?
pc
,
err
:=
t
.
PC
(
)
regs
,
err
:=
t
.
Registers
(
false
)
if
err
!=
nil
{
return
false
}
fn
:=
t
.
dbp
.
bi
.
goSymTable
.
PCToFunc
(
pc
)
pc
:=
regs
.
PC
()
fn
:=
t
.
BinInfo
()
.
goSymTable
.
PCToFunc
(
pc
)
if
fn
==
nil
{
return
false
}
...
...
pkg/target/target.go
浏览文件 @
3dacc25d
...
...
@@ -60,16 +60,12 @@ type ThreadInfo interface {
// GoroutineInfo is an interface for getting information on running goroutines.
type
GoroutineInfo
interface
{
GoroutinesInfo
()
([]
*
proc
.
G
,
error
)
SelectedGoroutine
()
*
proc
.
G
}
// ProcessManipulation is an interface for changing the execution state of a process.
type
ProcessManipulation
interface
{
Continue
()
error
Next
()
error
Step
()
error
StepOut
()
error
ContinueOnce
()
(
trapthread
proc
.
IThread
,
err
error
)
StepInstruction
()
error
SwitchThread
(
int
)
error
SwitchGoroutine
(
int
)
error
...
...
service/debugger/debugger.go
浏览文件 @
3dacc25d
...
...
@@ -412,7 +412,7 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
switch
command
.
Name
{
case
api
.
Continue
:
log
.
Print
(
"continuing"
)
err
=
d
.
target
.
Continue
(
)
err
=
proc
.
Continue
(
d
.
target
)
if
err
!=
nil
{
if
exitedErr
,
exited
:=
err
.
(
proc
.
ProcessExitedError
);
exited
{
state
:=
&
api
.
DebuggerState
{}
...
...
@@ -432,16 +432,16 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
case
api
.
Next
:
log
.
Print
(
"nexting"
)
err
=
d
.
target
.
Next
(
)
err
=
proc
.
Next
(
d
.
target
)
case
api
.
Step
:
log
.
Print
(
"stepping"
)
err
=
d
.
target
.
Step
(
)
err
=
proc
.
Step
(
d
.
target
)
case
api
.
StepInstruction
:
log
.
Print
(
"single stepping"
)
err
=
d
.
target
.
StepInstruction
()
case
api
.
StepOut
:
log
.
Print
(
"step out"
)
err
=
d
.
target
.
StepOut
(
)
err
=
proc
.
StepOut
(
d
.
target
)
case
api
.
SwitchThread
:
log
.
Printf
(
"switching to thread %d"
,
command
.
ThreadID
)
err
=
d
.
target
.
SwitchThread
(
command
.
ThreadID
)
...
...
@@ -714,7 +714,7 @@ func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
defer
d
.
processMutex
.
Unlock
()
goroutines
:=
[]
*
api
.
Goroutine
{}
gs
,
err
:=
d
.
target
.
GoroutinesInfo
(
)
gs
,
err
:=
proc
.
GoroutinesInfo
(
d
.
target
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
service/test/variables_test.go
浏览文件 @
3dacc25d
...
...
@@ -138,7 +138,7 @@ func TestVariableEvaluation(t *testing.T) {
}
withTestProcess
(
"testvariables"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
err
:=
p
.
Continue
(
)
err
:=
p
roc
.
Continue
(
p
)
assertNoError
(
err
,
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
...
...
@@ -216,7 +216,7 @@ func TestVariableEvaluationShort(t *testing.T) {
}
withTestProcess
(
"testvariables"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
err
:=
p
.
Continue
(
)
err
:=
p
roc
.
Continue
(
p
)
assertNoError
(
err
,
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
...
...
@@ -271,7 +271,7 @@ func TestMultilineVariableEvaluation(t *testing.T) {
}
withTestProcess
(
"testvariables"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
err
:=
p
.
Continue
(
)
err
:=
p
roc
.
Continue
(
p
)
assertNoError
(
err
,
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
...
...
@@ -344,7 +344,7 @@ func TestLocalVariables(t *testing.T) {
}
withTestProcess
(
"testvariables"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
err
:=
p
.
Continue
(
)
err
:=
p
roc
.
Continue
(
p
)
assertNoError
(
err
,
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
...
...
@@ -377,7 +377,7 @@ func TestEmbeddedStruct(t *testing.T) {
{
"b.s"
,
true
,
"
\"
hello
\"
"
,
"
\"
hello
\"
"
,
"string"
,
nil
},
{
"b2"
,
true
,
"main.B {main.A: main.A {val: 42}, *main.C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}"
,
"main.B {main.A: (*main.A)(0x…"
,
"main.B"
,
nil
},
}
assertNoError
(
p
.
Continue
(
),
t
,
"Continue()"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue()"
)
for
_
,
tc
:=
range
testcases
{
variable
,
err
:=
evalVariable
(
p
,
tc
.
name
,
pnormalLoadConfig
)
...
...
@@ -398,7 +398,7 @@ func TestEmbeddedStruct(t *testing.T) {
func
TestComplexSetting
(
t
*
testing
.
T
)
{
withTestProcess
(
"testvariables"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
err
:=
p
.
Continue
(
)
err
:=
p
roc
.
Continue
(
p
)
assertNoError
(
err
,
t
,
"Continue() returned an error"
)
h
:=
func
(
setExpr
,
value
string
)
{
...
...
@@ -644,7 +644,7 @@ func TestEvalExpression(t *testing.T) {
}
withTestProcess
(
"testvariables2"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
variable
,
err
:=
evalVariable
(
p
,
tc
.
name
,
pnormalLoadConfig
)
if
tc
.
err
==
nil
{
...
...
@@ -668,7 +668,7 @@ func TestEvalExpression(t *testing.T) {
func
TestEvalAddrAndCast
(
t
*
testing
.
T
)
{
withTestProcess
(
"testvariables2"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
c1addr
,
err
:=
evalVariable
(
p
,
"&c1"
,
pnormalLoadConfig
)
assertNoError
(
err
,
t
,
"EvalExpression(&c1)"
)
c1addrstr
:=
api
.
ConvertVar
(
c1addr
)
.
SinglelineString
()
...
...
@@ -694,7 +694,7 @@ func TestEvalAddrAndCast(t *testing.T) {
func
TestMapEvaluation
(
t
*
testing
.
T
)
{
withTestProcess
(
"testvariables2"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
m1v
,
err
:=
evalVariable
(
p
,
"m1"
,
pnormalLoadConfig
)
assertNoError
(
err
,
t
,
"EvalVariable()"
)
m1
:=
api
.
ConvertVar
(
m1v
)
...
...
@@ -728,7 +728,7 @@ func TestMapEvaluation(t *testing.T) {
func
TestUnsafePointer
(
t
*
testing
.
T
)
{
withTestProcess
(
"testvariables2"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
up1v
,
err
:=
evalVariable
(
p
,
"up1"
,
pnormalLoadConfig
)
assertNoError
(
err
,
t
,
"EvalVariable(up1)"
)
up1
:=
api
.
ConvertVar
(
up1v
)
...
...
@@ -765,7 +765,7 @@ func TestIssue426(t *testing.T) {
// Serialization of type expressions (go/ast.Expr) containing anonymous structs or interfaces
// differs from the serialization used by the linker to produce DWARF type information
withTestProcess
(
"testvariables2"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
for
_
,
testcase
:=
range
testcases
{
v
,
err
:=
evalVariable
(
p
,
testcase
.
name
,
pnormalLoadConfig
)
assertNoError
(
err
,
t
,
fmt
.
Sprintf
(
"EvalVariable(%s)"
,
testcase
.
name
))
...
...
@@ -816,7 +816,7 @@ func TestPackageRenames(t *testing.T) {
}
withTestProcess
(
"pkgrenames"
,
t
,
func
(
p
*
proc
.
Process
,
fixture
protest
.
Fixture
)
{
assertNoError
(
p
.
Continue
(
),
t
,
"Continue() returned an error"
)
assertNoError
(
p
roc
.
Continue
(
p
),
t
,
"Continue() returned an error"
)
for
_
,
tc
:=
range
testcases
{
variable
,
err
:=
evalVariable
(
p
,
tc
.
name
,
pnormalLoadConfig
)
if
tc
.
err
==
nil
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录