最典型“停错位置”是next后跳到其他线程:因内核调度导致,需立即执行set scheduler-locking on锁定当前线程;函数名断点失效因动态符号未加载,应改用源码行号或等待dlopen后设断点。

断点停在别的线程上,不是当前调试的线程
这是最典型的“停错位置”现象:你在 thread_proc 的第 3 行设了断点,next 后却跳到了另一个线程的第 1 行或第 14 行。这不是 GDB 报错,也不是符号缺失,而是线程调度天然导致的——next 或 continue 执行后,内核可能把 CPU 切给了其他就绪线程,GDB 被迫在那个线程的任意位置中断。
解决方法只有一条硬规则:
- 进多线程调试前,立即执行
set scheduler-locking on - 该命令会让 GDB 在单步(
step)、下一行(next)或继续(continue)时,禁止调度器切换到其他线程 - 此时你始终锁定在当前选中的线程里,
next就真的一行一行走本线程代码 - 临时需要看其他线程状态?用
info threads+thread N切换,再开锁也不迟
函数名断点失效,提示 Make breakpoint pending on future shared library load?
你确认函数存在、编译加了 -g、头文件也包含了,但 break thread_proc 却弹出这个提示,输 y 后断点也不触发——常见于动态链接的函数(比如 pthread_create 回调函数、插件中加载的符号),GDB 在启动时还没看到它的实际地址。
绕过方式很直接:
- 别用函数名,改用源码位置:
break thread.c:12(假设第 12 行是thread_proc函数体第一行) - 或者先运行起来,用
info functions thread_proc确认符号是否已加载;若没列出来,说明它在某个 .so 里,得等dlopen后再设断点 - 更稳妥的做法:在函数入口处插一条无副作用语句(如
int _debug_here = 0;),然后对这行设断点
条件断点在多线程下误触发或不触发
break 42 if counter == 100 看似简单,但在多线程里容易出问题:多个线程共用同一个 counter 变量,GDB 检查条件时可能读到被其他线程刚修改过的值,导致断点在错误线程上触发;或者因为竞争,条件检查和实际执行之间 counter 已被改回,结果断点“漏掉”。
关键处理原则:
- 条件断点默认作用于所有线程,如需限定,先
thread 3切到目标线程,再设断点 - 避免依赖全局变量做条件,优先用线程局部变量(如
__thread int local_step)或传入参数(break thread_proc if (long)arg == 2) - 如果必须监控全局状态,加
set scheduler-locking on再设条件断点,能减少竞态干扰
为什么 step 进不了函数,却直接 continue 了?
这不是断点问题,而是符号缺失或内联导致的:你 step 到某行函数调用,GDB 却没进入函数体,反而像 next 一样直接执行完返回。常见原因有二:
- 函数被编译器内联(尤其
-O2下),源码里有函数调用,实际机器码里已展开,GDB 无处可“进” - 目标函数来自系统库(如
printf)且没安装对应 debuginfo 包,GDB 看不到符号和行号信息
验证方式:disassemble 看当前指令是否跳转;解决办法:
- 重新编译时加
-O0 -fno-inline关闭优化和内联 - 对系统库补装 debuginfo(如 Ubuntu 上
sudo apt install libc6-dbg) - 不想改编译选项?用
stepi单指令步进,绕过函数抽象层
run 起来了,只要还没 set scheduler-locking on,后续所有单步行为都不可预测。别等停错三次才想起来。










