stepi用于单步执行一条汇编指令并进入函数内部,nexti则执行当前call指令后直接停在下一条指令、不进入函数;二者均面向机器指令,适用于无源码或需精确控制流的场景。

stepi 和 nexti 都是 GDB 中面向机器指令的单步命令,选哪个取决于你当前想「跟踪函数内部逻辑」还是「跳过函数调用」——不是看汇编有多酷,而是看调试目标是否需要进入被调用函数。
什么时候必须用 stepi
当你需要逐条执行汇编指令,并且当前指令是 call、jmp 或其他可能改变控制流的指令时,stepi 会真正进入目标函数的第一条指令(哪怕没有 debug 信息),并停在那条汇编上。
常见场景包括:
• 调试内联汇编或裸函数
• 函数符号被 strip 掉,但你想确认跳转目标是否正确
• 检查寄存器/栈帧在 call 指令执行前后的变化
• step 失效(比如函数没编译 -g)但你还得跟进
-
stepi不依赖源码行号,只认 CPU 下一条要取的指令地址 - 它会显示下一条将执行的汇编语句(如
=> 0x40112a <foo>: mov %rdi,%rax</foo>),适合逆向推断行为 - 如果目标函数本身是 PLT stub 或间接跳转,
stepi后可能停在jmp *0x...(%rip),这时需配合x/2i $rip查实际地址
什么时候该用 nexti
当你只想「执行当前 call 指令,但不关心它内部干了什么」,就用 nexti。它和 next 的语义一致,只是粒度降到指令级:call 指令执行完,直接停在 call 指令后那条指令上。
典型适用点:
• 快速跳过已验证无问题的库函数(如 printf、malloc)
• 在无源码的第三方 .so 中定位 crash 前最后几条指令
• 配合 disassemble 确认某段逻辑是否被优化掉
-
nexti不会进入任何函数,哪怕你正停在call malloc上,执行后就到mov %rax,%rdi这类后续指令 - 它比
next更“确定”——不会因编译器优化导致“跳过整行”或“停在奇怪位置” - 若你误用了
stepi进入一个巨大函数(比如 libc 的strlen),可以用finish快速跳出,但nexti从一开始就不给你这个机会
stepi 和 nexti 的兼容性陷阱
它们都依赖 GDB 能正确读取当前架构的指令编码。x86-64 下基本稳定,但在以下情况容易出意外:
• 调试 ARM64 程序时,GDB 版本 bl 指令解析错误,stepi 会多走一步或少走一步
• 程序启用了 Control Flow Integrity(CFI)或 Shadow Stack,某些 call 实际被替换成间接跳转,stepi 后可能停在非法地址(需检查 $rip 是否合理)
• 使用 set architecture i386 强制切到 32 位模式调试 64 位进程,nexti 可能错解指令长度,导致跳转错乱
- 永远先用
info registers rip和x/i $rip确认当前指令再按stepi/nexti -
step-mode on对二者无效——它只影响step/next在缺失 debug 信息时的行为 - 如果你看到
Cannot find bounds of current function提示,别硬按stepi,先disassemble /r $rip看真实指令流
i 键前问自己一句:我接下来要观察的是「这条 call 里面发生了什么」,还是「call 执行完之后,程序状态变成什么样」。前者选 stepi,后者选 nexti。











