在gdb中查看某线程的sigmask需切到目标线程后,用syscall(134, 0, 0, $mask, 8)调用rt_sigprocmask读取内核task_struct->blocked字段,再以x/8xb $mask解析字节;因信号掩码是线程私有内核态状态,info signals等命令无效,且不映射到用户内存或栈帧中。

gdb里怎么看某个线程的sigmask?
不能直接用 info signals 或 print $_sigmask 查——这些命令要么作用于整个进程,要么根本不存在。信号掩码(signal mask)是每个线程独立维护的内核态属性,gdb 默认不暴露它,得靠底层寄存器和系统调用约定间接推导。
用getthreadid + call syscall手动读取
Linux 下线程信号掩码存储在内核的 task_struct->blocked 中,用户态可通过 pthread_getaffinity_np 类接口访问,但更可靠的是调用 sigprocmask(0, NULL, &oldset) 的变体:syscall(SYS_rt_sigprocmask, SIG_BLOCK, NULL, &oldset, sizeof(oldset))。在 gdb 里可以现场构造:
- 先切到目标线程:
thread <n></n>(<n></n>是info threads显示的线程编号) - 分配栈空间存
sigset_t:set $mask = (sigset_t*)malloc(sizeof(sigset_t)) - 调用系统调用读取当前掩码:
call syscall(134, 0, 0, $mask, 8)(134是x86_64上sys_rt_sigprocmask编号;8是sigset_t大小) - 打印结果:
x /8xb $mask得到原始字节,再按位解释(bit 0 对应SIGRTMIN,bit 31 对应SIGRTMAX等)
为什么info proc mappings和thread apply all bt帮不上忙?
这两条命令分别看内存布局和调用栈,都不触达线程控制块(TCB)里的信号状态字段。信号掩码不映射到用户可读内存段,也不参与栈帧保存——它纯属内核调度时检查的运行时状态。常见误操作包括:
- 在主线程上下文里执行
call sigprocmask:实际修改的是调用线程(即 gdb 当前所在线程),不是目标线程 - 用
print *(sigset_t*)$rdi猜寄存器:x86_64 ABI 中sigprocmask参数通过寄存器传,但 gdb 无法保证停在刚好能读的指令点 - 依赖
handle SIGUSR1 stop print:这只影响 gdb 自身对信号的响应策略,和线程实际掩码无关
真正能反映信号行为的替代观察点
如果只是想确认某信号是否被目标线程屏蔽/阻塞,比直接读掩码更实用的方式是看它能否被递达:
- 发一个不会终止进程的信号,比如
signal SIGUSR1(在gdb里对指定线程) - 然后
continue并观察是否进入 handler —— 如果没进,且 handler 已注册,大概率被掩码挡住 - 配合
strace -p <pid> -e trace=rt_sigprocmask</pid>外部抓取,能看到各线程调用rt_sigprocmask的实际参数
信号掩码本身没有调试符号、不存于 core dump、也不随线程切换自动同步到 gdb 视图——它是最容易被当成“全局状态”误判,实则最私密的线程级元数据之一。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











