最直接可控的线程诞生跟踪方式是在 pthread_create 函数入口设断点,停住后用 next 执行完调用再 info threads 查看新线程 ID。

用 break pthread_create 拦住线程诞生瞬间
线程创建不是魔法,本质就是调用 pthread_create。GDB 无法“自动感知”线程何时诞生,但可以在该函数入口打断点,强制程序在新线程真正启动前停住。这是最直接、最可控的跟踪起点。
注意:必须确保编译时加了 -g,且链接了 pthread 库(-lpthread),否则 GDB 可能找不到符号或跳转到汇编层。
- 启动调试:
gdb ./your_program - 设断点:
break pthread_create(不要写成break pthread_create(),括号会报错) - 运行:
run,程序会在每次调用pthread_create前停下 - 此时还没生成新线程,
info threads仍只显示主线程
next 和 step 的区别决定你能否看到线程 ID 出现
在 pthread_create 断点处,用 next 会直接执行完该函数调用(返回成功后继续),这时新线程已启动,info threads 就能看到新增线程;而用 step 会跳进 pthread_create 内部实现(通常是 glibc 汇编或 C 实现),对理解业务逻辑帮助小,还容易卡在系统层。
- 推荐操作:停在
pthread_create后,先print $rax(x86_64 下返回值在$rax)确认是否为 0(成功) - 再执行
next,然后立刻info threads—— 新线程 ID 会出现在列表里,带(LWP xxx)标识 - 如果
next后没看到新线程,说明pthread_create失败了,检查传入的attr或栈大小等参数
为什么 info threads 有时看不到刚创建的线程?
不是 GDB 漏了,而是线程对象虽已分配,但内核线程(LWP)尚未完全初始化或调度。常见于以下情况:
- 断点设在
pthread_create返回之后,但新线程函数还没开始执行第一行代码(比如它开头是sleep(1)) - 程序用了自定义线程池或延迟启动逻辑,
pthread_create成功但线程体被挂起 - GDB 版本较老(
- 你正在调试的是
clone系统调用直连的线程(非 pthread 封装),此时pthread_create断点无效,得用break clone或catch syscall clone
想看线程函数里第一行就断住?用 thread apply all break 不现实
别试图在所有线程上统一打同一个函数断点——新线程还没存在,thread apply all 对它无效。正确做法是:在 pthread_create 断点触发后,记下即将传入的线程函数指针(如 arg 参数里的函数地址),然后手动对那个函数设断点。
- 例如:
print *(void**)($rdi + 8)(x86_64,$rdi是第一个参数,函数指针通常在结构体偏移 8 字节) - 拿到地址后:
break *0x7ffff7bcb123(把地址换成实际值) - 再
continue,新线程一执行就会停在它自己的第一行 - 这个过程没法自动化,必须人工介入一次,因为函数地址在 ASLR 开启时每次不同
线程创建过程本身极快,GDB 的介入点只有两个可靠位置:pthread_create 入口和线程函数入口。中间那段“线程已创建但未执行”的空白期,靠 info threads 刷新频率或 thread 切换是抓不住的——它根本不在用户可控的代码路径上。


















