gdb的简单使用

本例在CentOS7 64位环境下。

将用下面的例子做说明,可以跟着图片一步一步调试。

1.普通传参(例子1)

// 函数参数传递普通值
#include <stdio.h>

void change(int a,int b){
    
	int tmp = a;
    a = b;
	b = tmp;
}

int main(){
    
    int a = 5;
    int b = 3;
    
    change(a,b);
    
    printf("num a = %d \n num b=%d\n",a,b);
}

使用gdb前提:

程序是调试程序,在gcc时加-g,例如当前代码使用gcc -o main.out -g main.c进行编译。

启动程序调试:gdb 程序名

gdb的简单使用

开始运行程序:start

gdb的简单使用

展示代码:l

gdb的简单使用

运行下一行:n

gdb的简单使用

注意: 输入n之后打印的那一行代码,是之后会运行的代码,此时还没有运行。

小技巧: 在使用一次n之后,需要再运行n,可以直接按回车,可以省去输入n的麻烦。这个方法不止适用于n,其它的指令也是同样的效果(即按回车等于重复执行上一次输入的命令)。

进入函数:s

当程序运行到第16行的时候,如果使用n,会直接运行到下一行(即不会进入函数中),你看不到函数内是如何运行的。所以当运行到函数的时候,需要使用s进入函数内调试。

gdb的简单使用

获取变量值:p 变量名

前面的序号$1会一直累加,看后面的结果就好。

gdb的简单使用

显示函数堆栈:bt

在进入change函数内调试之后,使用bt显示栈堆。

gdb的简单使用

栈底是main,栈顶是change,当前正在运行change函数。

at后面是函数所在的文件和所在行数。

切换栈位置,获取栈内变量值:f 堆栈序号

gdb的简单使用

使用f 堆栈序号切换栈位置;使用bt可以获得函数栈堆,其中的堆栈序号就是这里的堆栈序号。

切换之后会显示此栈中运行到哪一行,比如图中,运行到main栈中的第16行,change函数。

之后可以用p 变量名输出当前栈中变量的值(图中有两个p a,他们代表的变量不是同一个,上面的a是change函数中的,下面的a是main函数中的)。

退出:quit或ctrl+d

2.指针传参(例子2)

// 函数参数传递指针地址
#include <stdio.h>

void change(int *a,int *b){

    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int main(){


    int a = 5;
    int b = 3;

    change(&a,&b);

    printf("num a = %d \n num b=%d\n",a,b);
}

进入函数:s

gdb的简单使用

a,b的值为他们的地址,相差4个字节。

获取指针变量的值:p *指针变量名

gdb的简单使用

注意: 我们使用n,会显示出一行代码,这行代码是将要运行的(即当前还没有运行),所以*b的值不等于tmp的值。

3.其它笔记

内存最小的单位叫字节Byte(8bit)。

经常这样:计算用二进制,显示用十进制,编程用十六进制。

内存管理:

64位操作系统,使用的内存只要有前面的48位就可以了(0x7fffffffffffffff~0x0)。

gdb的简单使用

上面是高位,下面是低位。

系统内核:

栈:保存函数运行的状态

可分配区域(绿色区域):在堆、栈之间

堆:

数据段:存放全局变量、常量或静态变量

代码段:代码编译后的二进制数据加载到内存中