Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
pubx
delve
提交
6fd1fbab
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,发现更多精彩内容 >>
提交
6fd1fbab
编写于
11月 20, 2014
作者:
D
Derek Parker
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Cleanup trapWait, include TODO for timeoutWait fix
上级
200be0e2
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
90 addition
and
88 deletion
+90
-88
proctl/proctl_linux_amd64.go
proctl/proctl_linux_amd64.go
+90
-88
未找到文件。
proctl/proctl_linux_amd64.go
浏览文件 @
6fd1fbab
...
...
@@ -285,14 +285,14 @@ func (dbp *DebuggedProcess) Continue() error {
}
}
_
,
_
,
err
:=
trapWait
(
dbp
,
-
1
,
0
)
wpid
,
_
,
err
:=
trapWait
(
dbp
,
-
1
,
0
)
if
err
!=
nil
{
if
_
,
ok
:=
err
.
(
ProcessExitedError
);
!
ok
{
return
err
return
nil
}
return
err
}
return
nil
return
handleBreakPoint
(
dbp
,
wpid
)
}
// Obtains register values from the debugged process.
...
...
@@ -390,67 +390,106 @@ func (pe ProcessExitedError) Error() string {
return
fmt
.
Sprintf
(
"process %d has exited"
,
pe
.
pid
)
}
func
trapWait
(
dbp
*
DebuggedProcess
,
p
int
,
options
int
)
(
int
,
*
syscall
.
WaitStatus
,
error
)
{
func
trapWait
(
dbp
*
DebuggedProcess
,
p
id
int
,
options
int
)
(
int
,
*
syscall
.
WaitStatus
,
error
)
{
var
status
syscall
.
WaitStatus
for
{
pid
,
err
:=
syscall
.
Wait4
(
p
,
&
status
,
syscall
.
WALL
|
options
,
nil
)
wpid
,
err
:=
syscall
.
Wait4
(
pid
,
&
status
,
syscall
.
WALL
|
options
,
nil
)
if
err
!=
nil
{
return
-
1
,
nil
,
fmt
.
Errorf
(
"wait err %s %d"
,
err
,
pid
)
}
thread
,
threadtraced
:=
dbp
.
Threads
[
pid
]
if
!
threadtraced
{
if
wpid
==
0
{
continue
}
thread
.
Status
=
&
status
if
status
.
Exited
()
{
if
pid
==
dbp
.
Pid
{
return
0
,
nil
,
ProcessExitedError
{
pid
}
if
th
,
ok
:=
dbp
.
Threads
[
wpid
];
ok
{
th
.
Status
=
&
status
}
if
status
.
Exited
()
&&
wpid
==
dbp
.
Pid
{
return
-
1
,
&
status
,
ProcessExitedError
{
wpid
}
}
if
status
.
StopSignal
()
==
syscall
.
SIGTRAP
&&
status
.
TrapCause
()
==
syscall
.
PTRACE_EVENT_CLONE
{
err
=
addNewThread
(
dbp
,
wpid
)
if
err
!=
nil
{
return
-
1
,
nil
,
err
}
delete
(
dbp
.
Threads
,
pid
)
continue
}
if
status
.
StopSignal
()
==
syscall
.
SIGTRAP
{
return
wpid
,
&
status
,
nil
}
}
}
switch
status
.
TrapCause
()
{
case
syscall
.
PTRACE_EVENT_CLONE
:
addNewThread
(
dbp
,
pid
)
default
:
pc
,
err
:=
thread
.
CurrentPC
()
func
handleBreakPoint
(
dbp
*
DebuggedProcess
,
pid
int
)
error
{
thread
:=
dbp
.
Threads
[
pid
]
if
pid
!=
dbp
.
CurrentThread
.
Id
{
fmt
.
Printf
(
"thread context changed from %d to %d
\n
"
,
dbp
.
CurrentThread
.
Id
,
pid
)
dbp
.
CurrentThread
=
thread
}
pc
,
err
:=
thread
.
CurrentPC
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"could not get current pc %s"
,
err
)
}
// Check to see if we hit a runtime.breakpoint
fn
:=
dbp
.
GoSymTable
.
PCToFunc
(
pc
)
if
fn
!=
nil
&&
fn
.
Name
==
"runtime.breakpoint"
{
// step twice to get back to user code
for
i
:=
0
;
i
<
2
;
i
++
{
err
=
thread
.
Step
()
if
err
!=
nil
{
return
-
1
,
nil
,
fmt
.
Errorf
(
"could not get current pc %s"
,
err
)
}
// Check to see if we hit a runtime.breakpoint
fn
:=
dbp
.
GoSymTable
.
PCToFunc
(
pc
)
if
fn
!=
nil
&&
fn
.
Name
==
"runtime.breakpoint"
{
// step twice to get back to user code
for
i
:=
0
;
i
<
2
;
i
++
{
err
=
thread
.
Step
()
if
err
!=
nil
{
return
-
1
,
nil
,
err
}
}
handleBreakPoint
(
dbp
,
thread
,
pid
)
return
pid
,
&
status
,
nil
return
err
}
}
stopTheWorld
(
dbp
,
thread
,
pid
)
return
nil
}
// Check to see if we have hit a user set breakpoint.
if
bp
,
ok
:=
dbp
.
BreakPoints
[
pc
-
1
];
ok
{
if
!
bp
.
temp
{
handleBreakPoint
(
dbp
,
thread
,
pid
)
}
return
pid
,
&
status
,
nil
}
// Check to see if we have hit a user set breakpoint.
if
bp
,
ok
:=
dbp
.
BreakPoints
[
pc
-
1
];
ok
{
if
!
bp
.
temp
{
stopTheWorld
(
dbp
,
thread
,
pid
)
}
return
nil
}
return
fmt
.
Errorf
(
"did not hit recognized breakpoint"
)
}
func
stopTheWorld
(
dbp
*
DebuggedProcess
,
thread
*
ThreadContext
,
pid
int
)
error
{
// Loop through all threads and ensure that we
// stop the rest of them, so that by the time
// we return control to the user, all threads
// are inactive. We send SIGSTOP and ensure all
// threads are in in signal-delivery-stop mode.
for
_
,
th
:=
range
dbp
.
Threads
{
if
th
.
Id
==
pid
{
// This thread is already stopped.
continue
}
ps
,
err
:=
parseProcessStatus
(
th
.
Id
)
if
err
!=
nil
{
return
err
}
if
ps
.
state
==
STATUS_TRACE_STOP
{
continue
}
if
status
.
Stopped
()
{
// The thread has stopped, but has not hit a breakpoint.
// Continue the thread without returning control back
// to the console.
syscall
.
PtraceCont
(
pid
,
0
)
err
=
syscall
.
Tgkill
(
dbp
.
Pid
,
th
.
Id
,
syscall
.
SIGSTOP
)
if
err
!=
nil
{
return
err
}
pid
,
err
:=
syscall
.
Wait4
(
th
.
Id
,
nil
,
syscall
.
WALL
,
nil
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"wait err %s %d"
,
err
,
pid
)
}
}
return
nil
}
func
addNewThread
(
dbp
*
DebuggedProcess
,
pid
int
)
error
{
...
...
@@ -493,8 +532,11 @@ func (err TimeoutError) Error() string {
return
fmt
.
Sprintf
(
"timeout waiting for %d"
,
err
.
pid
)
}
// timeoutwait waits the specified duration before returning
// a TimeoutError.
// TODO(dp): this is a hacky, racy implementation. Ideally this method will
// become defunct and replaced by a non-blocking incremental sleeping wait.
// The purpose is to detect whether a thread is sleeping. However, this is
// tricky because a thread can be sleeping due to being a blocked M in the
// scheduler or sleeping due to a user calling sleep.
func
timeoutWait
(
pid
int
,
options
int
)
(
int
,
*
syscall
.
WaitStatus
,
error
)
{
var
(
status
syscall
.
WaitStatus
...
...
@@ -539,43 +581,3 @@ func timeoutWait(pid int, options int) (int, *syscall.WaitStatus, error) {
return
-
1
,
nil
,
err
}
}
func
handleBreakPoint
(
dbp
*
DebuggedProcess
,
thread
*
ThreadContext
,
pid
int
)
error
{
if
pid
!=
dbp
.
CurrentThread
.
Id
{
fmt
.
Printf
(
"thread context changed from %d to %d
\n
"
,
dbp
.
CurrentThread
.
Id
,
pid
)
dbp
.
CurrentThread
=
thread
}
// Loop through all threads and ensure that we
// stop the rest of them, so that by the time
// we return control to the user, all threads
// are inactive. We send SIGSTOP and ensure all
// threads are in in signal-delivery-stop mode.
for
_
,
th
:=
range
dbp
.
Threads
{
if
th
.
Id
==
pid
{
// This thread is already stopped.
continue
}
ps
,
err
:=
parseProcessStatus
(
th
.
Id
)
if
err
!=
nil
{
return
err
}
if
ps
.
state
==
STATUS_TRACE_STOP
{
continue
}
err
=
syscall
.
Tgkill
(
dbp
.
Pid
,
th
.
Id
,
syscall
.
SIGSTOP
)
if
err
!=
nil
{
return
err
}
pid
,
err
:=
syscall
.
Wait4
(
th
.
Id
,
nil
,
syscall
.
WALL
,
nil
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"wait err %s %d"
,
err
,
pid
)
}
}
return
nil
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录