【问题标题】:Is it possible to determine in gdb whether a thread is executing (or blocked) in kernel or user space?是否可以在 gdb 中确定线程是否在内核或用户空间中执行(或阻塞)?
【发布时间】:2018-10-26 03:02:30
【问题描述】:

考虑以下程序。

#include <unistd.h>

int main(){
    sleep(1000);
}

如果我们在这个程序上运行strace,那么在长睡眠之前出现的最后一行如下。

nanosleep({1000, 0}, 

当程序处于休眠状态时,代码正在操作系统内核中执行(可能被阻塞)。

当我在gdb下运行程序时,如果我在睡眠的中间发送SIGINT,我可以收集到关于主线程的各种信息,比如它的backtrace和各种寄存器值。

如果线程在用户空间中再次执行代码之前必须越过syscall 边界,gdb 中是否存在计算结果为true 的表达式?

理想情况下,应该有一个跨平台的解决方案,但特定于平台的解决方案也很有用。

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

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

【问题讨论】:

  • 您误解了抢先式多任务处理的工作原理。如果一个“线程”进入睡眠状态,内核在它被唤醒之前不会对该线程做任何事情,它甚至不会在内部运行任何东西。相反,它将让其他用户空间线程和进程运行。
  • @Someprogrammerdude,我很清楚这一点;这就是为什么我在内核中说“可能被阻止”。但这与问题正交;出于问题的目的,我认为内核中阻塞(未执行)的线程位于内核空间中。
  • 回答当你发送SIGINT 信号时会发生什么,是操作系统唤醒睡眠进程来处理信号,如果进程没有@987654332 的信号处理程序@ 操作系统终止进程。调试器安装特殊的处理程序来捕获所有信号,但它是在用户空间中处理的。
  • @Someprogrammerdude,SIGINT 仅用于闯入调试器,以便我们检查状态;我希望它与问题或其答案无关,但如果我弄错了,请纠正我。
  • 但是进程不在在“内核空间”中。当一个进程进入睡眠状态时,内核将它放入一个特殊的队列中等待事件的进程,然后调度另一个进程运行。睡眠进程本身不做任何事情,它不在用户空间或内核空间中运行。使用time 命令可以很容易地看到这一点,它将显示内核时间(“sys”时间)非常小。

标签: c debugging gdb kernel


【解决方案1】:

gdb 中是否有某个表达式的计算结果为 true,如果 线程在执行代码之前必须跨越系统调用边界 又是用户空间?

您可以尝试使用catch syscall nanosleep,见documentation

catch syscall nanosleep 在 2 个事件上停止:一个在调用系统调用时,一个在从系统调用返回时。你可以使用info breakpoints 来查看这个catchpoint 的命中次数。如果是偶数,那么您应该在用户空间中。如果它是奇怪的,那么你应该在内核空间:

$ 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]

【讨论】:

  • 这仅适用于 nanosleep 还是通用系统调用?
  • 它适用于任何系统调用的名称或编号,请参阅文档链接。
  • 看来我必须列举所有可能的系统调用才能使用它,这有点不幸,但很高兴知道!
  • 您可以catch syscall 一次在所有系统调用上设置捕获点。虽然我不知道它将如何用于您的最终目标。
猜你喜欢
  • 1970-01-01
  • 2016-09-26
  • 2011-12-03
  • 2019-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
相关资源
最近更新 更多