是否有可能在gdb中确定线程是在内核还是用户空间中执行(或阻塞)?

考虑以下程序.

#include <unistd.h>

int main(){
    sleep(1000);
}

如果我们对此程序运行strace,则在长时间睡眠之前出现的最后一行如下.

nanosleep({1000, 0}, 

程序处于睡眠状态时,代码正在OS内核中执行(可能被阻止).

当我在gdb下运行程序时,如果我在睡眠中间发送SIGINT,我可以收集有关主线程的各种信息,例如它的回溯和各种寄存器值.

如果在再次在用户空间中执行代码之前线程必须越过系统调用边界,那么gdb中是否有一些表达式求值为true?

理想情况下,会有跨平台解决方案,但特定于平台的解决方案也很有用.

澄清:我不关心线程是否实际执行;只是它的最新程序计数器值是在内核代码还是用户代码中.

换句话说,gdb可以告诉我们特定线程是否已进入内核但尚未退出内核?

最佳答案

Is there is some expression in gdb that evaluates to true if the
thread must cross a syscall boundary before executing code in
userspace again?

您可以尝试使用catch syscall nanosleep,请参阅documentation.

catch syscall nanosleep在2个事件上停止:一个调用系统调用,另一个调用系统调用.您可以使用信息断点查看此捕获点的命中次数.如果它是偶数,那么你应该在用户空间.如果它是奇数,那么你应该在内核空间:

$gdb -q a.out 
Reading symbols from a.out...done.
(gdb) catch syscall nanosleep 
Catchpoint 1 (syscall 'nanosleep' [35])
(gdb) i b
Num     Type           Disp Enb Address            What
1       catchpoint     keep y                      syscall "nanosleep" 
(gdb) r
Starting program: /home/ks1322/a.out 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.27-8.fc28.x86_64

Catchpoint 1 (call to syscall nanosleep), 0x00007ffff7adeb54 in nanosleep () from /lib64/libc.so.6
(gdb) i b
Num     Type           Disp Enb Address            What
1       catchpoint     keep y                      syscall "nanosleep" 
    catchpoint already hit 1 time
(gdb) c
Continuing.

Catchpoint 1 (returned from syscall nanosleep), 0x00007ffff7adeb54 in nanosleep () from /lib64/libc.so.6
(gdb) i b
Num     Type           Disp Enb Address            What
1       catchpoint     keep y                      syscall "nanosleep" 
    catchpoint already hit 2 times
(gdb) c
Continuing.
[Inferior 1 (process 19515) exited normally]
点赞