gdb个人总结

GDB调试文件

假设当前目录下共有以下3个文件,接下来会利用以下代码来演示GDB的调试过程。

├── main.cpp

├── tool.h

└── tools.cpp

文件内容分别为:

tool.h:函数声明

void greeting();
int sum(int a,int b);
int sum(int a, int b);

tools.cpp:函数定义

#include <iostream>
#include "tool.h"

using namespace std;

void greeting(){
    cout<<"Hello World"<<endl;
}

int sum(int a, int b){
    return a+b;
}

main.cpp:主函数

#include <iostream>
#include <string.h>
#include "tool.h"
using namespace std;

#include <iostream>
#include <string.h>
#include "tool.h"
using namespace std;

void greeting();
int main(int argc, char* argv[]){
    int s = 0;
    int m=0;
    int n=0;
    for(int i=1; i<=atoi(argv[1]); i++){
        s+=i;
        m++;
        n++;
    }
    printf("sum=%d\n",s);
    greeting();
    cout<<sum(12,12)<<endl;
    print_num();
    return 0;
}

以上代码只是为了演示之用,并无特别之处。

编译方式

// -g 添加调试信息    -Wall 输出所有警告信息,例如定义了从未使用过的变量
$ gcc main.cpp -o main -g -Wall  

一、启动

gdb main

设置和获取参数

有时需要在执行程序时输入额外的参数,例如:像下面这样执行程序test

$ ./main 5

调试时,往往直接执行$ gdb main

那么怎么在gdb中输入该程序的参数呢?

(gdb) set args 5

还可以查看程序的参数

(gdb) show args
Argument list to give program being debugged when it is started is "5".

二、查看代码

GDB提供了两种查看源码的方式,分别是根据行号和函数名查看。除了可以查看本文件源码,还可以查看其他文件的源码。

①本文件查看

本文件指的是该程序对应的main函数所在文件,即main.cpp

(gdb) l        # 每执行1次显示10行,再执行1次显示次10
(gdb) l 15     # 显示第15行,此时会将15行显示在屏幕窗口中央,方便查看前后的代码
(gdb) l main   # 显示本文件的main函数

②其他文件

共同编译的所有文件中,除了main函数所在文件的其它文件。在这里,除了main.cpp即tools.cpp

(gdb) l tools.cpp:15         # 在tools.cpp中,显示第15行附近的代码
(gdb) l tools.cpp:sum        # 在tools.cpp中,查看sum函数的代码

③设置和获取显示行数

(gdb) show list        # 显示行数
(gdb) set list 20      # 设置行数

三、断点

可以在一次调试中设置1个或多个断点,下一次只需让程序自动运行到设置断点位置,便可在上次设置断点的位置中断下来,极大的方便了操作,同时节省了时间。

可以根据行号,函数名设置断点,还可根据条件设置断点(一般用于循环中)

①本文件

(gdb) b 10              # 将第10行设置为断点
(gdb) b main            # 将main函数设置为断点
(gdb) l                 # 可以看到在main.cpp中含有greeting函数的声明


void greeting();
int main(int argc, char* argv[]){
   int s = 0;
   int m=0;
   int n=0;
   for(int i=1; i<=atoi(argv[1]); i++){
       s+=i;
       m++;
       n++;
    }


(gdb) b greeting        # 此时设置的断点并不是函数的声明处,而是函数的定义处,greeting函数定义在tools.cpp文件中
Breakpoint 1 at 0xaa2: file tools.cpp, line 13.

②其他文件

b tools.cpp:12            # 将tools.cpp的第12行设置为断点
b tools.cpp:sum           # 将tools.cpp的sum函数设置为断点

三、设置条件断点

条件断点一般用于循环中

①本文件

设置i==2时,第18行为断点

行号必须在变量的作用域范围内

(gdb) b 18 if i==2                              
Breakpoint 1 at 0x9d8: file main.cpp, line 18.

②其他文件

# 设置tools.cpp文件内,i==5时,第22行为断点
22必须在i的作用域范围
(gdb) b tools.cpp:22 if i==5                  
Breakpoint 2 at 0xafb: file tools.cpp, line 22.

四、查看和删除断点

(gdb) i b            # 显示所有断点
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000009a4 in main(intchar**) at main.cpp:14
2       breakpoint     keep y   0x00000000000009ec in main(intchar**) at main.cpp:22
3       breakpoint     keep y   0x0000000000000a39 in main(intchar**) at main.cpp:25

d 1                  # 删除第1个断点                               

设置断点无效和有效

dis 2               # 将第2个断点设置为无效
ena 2               # 将第2个断点设置有效     

五、运行

有两种运行方式,一种是从主函数开始运行,一种是运行到第1个断点处

1 从主函数运行 程序从main函数开始

(gdb) run

2 运行到第1个断点处

程序停在第一个断点处

(gdb) start

六、执行流控制

c/continue         # 向下运行到下一个断点处
n/next             # 执行下一行代码,不进入调用的函数,直接返回结果
s/step             # 执行下一行代码,进入调用的函数
finish             # 跳出函数体
until         # 跳出当前循环 在执行完循环体内的最后一条语句之后执行 until,才可以跳出循环

打印变量

p  变量名                      # 打印变量值,可以答应在当前作用域之内的变量名
ptype 变量名                   # 打印变量类型

自动变量操作

可以在每次执行时都打印该变量的值,常用于循环体中

display 变量名                 # 自动打印指定变量的值
i display               # 查看所有设置自动打印的变量值
undisplay 编号            # 取消自动打印变量值

设置变量值

set var 变量名=变量值           # 可以临时改变该变量的值  

GDB调试运行中的程序

通过命令:

$ ps -aux | grep main 

获取执行main的进程(pid),执行main的进程为18786

启动gdb attach,执行gdb attach pid即可调试正在运行的程序,执行:

$ gdb attach 18786

若执行gdb attach时提示:” ptrace: Operation not permitted”,则执行:$ sudo gdb attach 18786 也可执行:$ gdb main 18786,与gdb attach 18786相同。

常用的命令如下:

  1. bt:查看函数调用栈的所有信息,当程序执行异常时,可通过此命令查看程序的调用过程;

  2. info threads:显示当前进程中的线程;

  3. thread id:切换到具体的线程id,一般切换到具体的线程后再执行bt等操作。

  4. sharedlibrary:将动态库的符号读入gdb,为了找到变量和函数名

posted @ 2022-04-15 23:31  mengchao  阅读(61)  评论(0编辑  收藏  举报