栈帧查看与切换 在使用GDB调试时可以使用以下命令对调用栈进行查看backtrace或者简写为btbt命令用于查看当前线程的调用栈信息。也可以指定只显示前几个栈帧bt 3表示只显示最靠近当前执行位置的第3个栈帧。如果想在查看调用栈时同时显示每个栈帧中的局部变量可以使用bt fullbt full比普通的bt输出更详细适合排查程序崩溃时每一层函数中的变量值。2、切换栈帧使用如下命令可以对栈帧进行切换frame n或者简写为f n其中n表示栈帧编号。在bt输出中每个栈帧前面都会有编号例如#0 add(int, int) at main.cpp:6 #1 calc(int) at main.cpp:13 #2 work(int) at main.cpp:19 #3 main() at main.cpp:25其中栈帧编号含义#0当前正在执行的函数也就是最顶层栈帧#1调用当前函数的上一层函数#2再上一层调用者#3更早的调用者如果想切换到work函数对应的栈帧可以执行f 2切换栈帧后GDB 的上下文也会切换到对应函数中。此时查看局部变量、函数参数、源码位置都是针对当前选中的栈帧而言。3、查看当前栈帧信息查看当前栈帧的详细信息info frame或者简写为i f该命令可以查看当前栈帧的地址、调用关系、保存的寄存器信息等。如果想查看某个栈帧的信息常见做法是先切换到对应栈帧f 2 i f也可以在支持的 GDB 版本中直接使用i f 2小技巧bt命令还能查看当前程序执行到哪里了查看最顶层的栈帧后面就是他当前执行所在行4、查看当前栈帧的参数与局部变量查看当前栈帧中的函数参数info args查看当前栈帧中的局部变量info locals例如当前选中的是calc函数的栈帧那么info args info locals看到的就是calc函数中的参数和局部变量而不是add或main中的变量。这也是切换栈帧的重要作用可以回到某一层函数调用现场查看当时传入了什么参数、局部变量是什么值从而分析程序为什么会执行到当前位置。三、完整示例下面通过一个包含 4 层函数调用的程序来理解调用栈。#include iostream int add(int a, int b) { int sum a b; return sum; } int calc(int x) { int y x * 2; return add(y, 10); } int work(int n) { int value n 1; return calc(value); } int main() { int data 3; int ret work(data); std::cout ret ret std::endl; return 0; }这个程序的调用关系是main - work - calc - add也就是 4 层函数调用。将程序编译完成后通过gdb启动在add函数处设置断点并通过bt命令查看当前的函数栈调用。如下图所示这个输出表示栈帧函数含义#0add(a8, b10)当前程序停在add函数中在test.cpp源文件的第5行#1calc(x4)add是由calc调用的在test.cpp源文件的第12行#2work(n3)calc是由work调用的在test.cpp源文件的第18行#3main()work是由main调用的在test.cpp源文件的第24行