文章目录
- 前言
- 第一讲 什么是GDB
- 第二讲 搭建实验环境
- 第三讲 快速开始
- 第四讲 举例说明如何查看变量信息——print、step
- 第五讲 使用GDB的技巧(只在此展开观察点)
- 第六讲 调试core文件(针对UNIX,程序崩溃时)
- 第七讲 调试一个正在运行的程序
前言
学习资源来自B站【小神仙讲 GDB】 通俗易懂版教程 | 一小时入门GDB | Debug | c/c++程序员必备 | 佩雨小神仙_哔哩哔哩_bilibili
第一讲 什么是GDB
GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes – or what another program was doing at the moment it crashed.
GDB 调试器,帮助你检查程序运行时的内部情况
GDB 可以做以下4件事:
- Start your program, specifying anything that might affect its behavior.启动并设置程序运行的参数
- Make your program stop on specified conditions.使程序在确定情况下停止(打断点)
- Examine what has happened, when your program has stopped.程序停止时,检查发生了什么
- Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.修改程序,纠正错误
Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on macOS.这些程序可以本地、远程或仿真器上运行,GDB可以在UNIX、Windows、macOS上运行
GDB支持以下语言:
- Ada
- Assembly(汇编)
- C
- C++
- D
- Fortran
- Go
- Objective-C
- OpenCL
- Modula-2
- Pascal
- Rust
第二讲 搭建实验环境
-
命令行检查电脑是否已经安装GDB
GDB --version
有版本信息即已经安装
-
如果未安装,则命令行执行
yum install gdb
-
检查是否已经成功安装GDB
GDB --version
有版本信息即安装成功
第三讲 快速开始
-
写一个程序test.c
#include <stdio.h>int main() {int arr[4] = {1, 2, 3, 4};int i;for(i = 0; i < 4;i++){printf("%d\n", arr[i]);}return 0; }
-
命令行编译该文件,生成可执行文件a.exe(Windows),记得加上-g,否则无法调试
gcc -g test.c
-
开始调试
gdb a.exe
终端显示gdb的内容:
GNU gdb (GDB) 8.1 Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-w64-mingw32". Type "show configuration" for configuration details. For bug reporting instructions, please see: http://www.gnu.org/software/gdb/bugs/. Find the GDB manual and other documentation resources online at: http://www.gnu.org/software/gdb/documentation/. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from a.exe...done. (gdb)
-
让程序跑起来:命令”run”,run也可简写为r
**(gdb) run** Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 22268.0x27d0] [New Thread 22268.0x4928] 1 2 3 4 [Thread 22268.0x4928 exited with code 0] [Inferior 1 (process 22268) exited normally] (gdb)
-
退出程序:命令“quit”
-
查看源代码:命令“list”
-
在某函数处打断点:
-
命令“break 函数名”
**(gdb) break main** Breakpoint 1 at 0x40155d: file ./caogao.c, line 5. (gdb)
-
命令“break 第几行”,break也可简写为b
-
查看断点:命令“info b”
-
运行下一行:命令“next”,也可简写为n(运行到下一个断点:n 6)
**(gdb) list** 1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() { 5 int arr[4] = {1, 2, 3, 4}; 6 for(int i = 0; i < 4;i++){ 7 printf("%d\n", arr[i]); 8 } 9 10 return 0; **(gdb) break 6** Breakpoint 2 at 0x401579: file ./caogao.c, line 6. **(gdb) b 9** Breakpoint 3 at 0x4015a3: file ./caogao.c, line 9. **(gdb) info b** Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000040155d in main at ./caogao.c:5 2 breakpoint keep y 0x0000000000401579 in main at ./caogao.c:6 3 breakpoint keep y 0x00000000004015a3 in main at ./caogao.c:9 **(gdb) r** Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 4288.0x5b8c] [New Thread 4288.0x54f0]Thread 1 hit Breakpoint 1, main () at ./caogao.c:5 5 int arr[4] = {1, 2, 3, 4}; **(gdb) r** Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 4288.0x5b8c] [New Thread 4288.0x54f0]Thread 1 hit Breakpoint 1, main () at ./caogao.c:5 5 int arr[4] = {1, 2, 3, 4}; **(gdb) n**Thread 1 hit Breakpoint 2, main () at ./caogao.c:6 6 for(int i = 0; i < 4;i++){ **(gdb) n** 7 printf("%d\n", arr[i]); (gdb)
-
第四讲 举例说明如何查看变量信息——print、step
-
命令“print”:可简写为p,打印变量
**(gdb) list** 1 #include <stdio.h> 2 3 int main() { 4 int arr[4] = {1, 2, 3, 4}; 5 int i = 0; 6 for(i = 0; i < 4;i++){ 7 printf("%d\n", arr[i]); 8 } 9 10 return 0; **(gdb) b 4(在第4行打断点,运行到第4行,此时已经声明并初始化数组arr)** Breakpoint 1 at 0x40155d: file .\caogao.c, line 4. **(gdb) r** Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 7940.0x5990] [New Thread 7940.0x4a14]Thread 1 hit Breakpoint 1, main () at .\caogao.c:4 4 int arr[4] = {1, 2, 3, 4}; **(gdb) n(再执行n,运行到下一行)** 5 int i = 0; **(gdb) p arr[0](打印arr[0]的位置,发现被赋值为1)** $1 = 1 **(gdb) p arr[3](发现被赋值为4)** $2 = 4 **(gdb) p &arr(得到这个数组的地址)** $3 = (int (*)[4]) 0x61fe00 **(gdb) p &arr[0](得到第1个元素的地址)** $4 = (int *) 0x61fe00 **(gdb) p &arr[1](得到第2个元素的地址,比上一个地址多4字节,为int的大小)** $5 = (int *) 0x61fe04
-
命令“step”:简写为s,进某一个具体的函数调试(要先打函数被调用处的断点)
#include <stdio.h>void hello(){printf("hello echo\n"); }int main() {int arr[4] = {1, 2, 3, 4};int i = 0;for(i = 0; i < 4;i++){printf("%d\n", arr[i]);}hello();return 0; }
(gdb) list 1 #include <stdio.h> 2 3 void hello(){ 4 printf("hello echo\n"); 5 } 6 7 int main() { 8 int arr[4] = {1, 2, 3, 4}; 9 int i = 0; 10 for(i = 0; i < 4;i++){ (gdb) list(一次list看不完就再list) 11 printf("%d\n", arr[i]); 12 } 13 hello(); 14 15 return 0; 16 } 17 (gdb) r Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 4432.0x5f00] [New Thread 4432.0x4bbc] 1 2 3 4 hello echo [Inferior 1 (process 4432) exited normally] (gdb) b 15 Breakpoint 1 at 0x4015ca: file .\caogao1.c, line 15. (gdb) clear 15(断点打错,删除断点) Deleted breakpoint 1 (gdb) b 13 Breakpoint 2 at 0x4015c5: file .\caogao1.c, line 13. (gdb) r(到13行就停下) Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 24652.0x3644] [New Thread 24652.0x55c8] 1 2 3 4Thread 1 hit Breakpoint 2, main () at .\caogao1.c:13 13 hello(); (gdb) s(进入hello函数) hello () at .\caogao1.c:4 4 printf("hello echo\n"); (gdb) n hello echo 5 } (gdb) n main () at .\caogao1.c:15 15 return 0; (gdb) n 16 } (gdb) n(结束) 0x00000000004013c7 in __tmainCRTStartup () (gdb)
第五讲 使用GDB的技巧(只在此展开观察点)
-
shell在gdb中的使用
-
日志功能set logging on
-
catch point
-
观察点:watchpoints,观察变量是否变化
(gdb) list 1 #include <stdio.h> 2 3 void hello(){ 4 printf("hello echo\n"); 5 } 6 7 int main() { 8 int arr[4] = {1, 2, 3, 4}; 9 int i = 0; 10 for(i = 0; i < 4;i++){ (gdb) list 11 printf("%d\n", arr[i]); 12 } 13 hello(); 14 15 return 0; 16 } 17 (gdb) b 9 Breakpoint 2 at 0x401594: file .\caogao1.c, line 9. (gdb) r Starting program: C:\Users\xlay\Desktop\MATLAB-C\a.exe [New Thread 12436.0x651c] [New Thread 12436.0x2164]Thread 1 hit Breakpoint 2, main () at .\caogao1.c:9 9 int i = 0; (gdb) p &i $1 = (int *) 0x61fe1c **(gdb) watch *0x61fe1c(把i(即*0x61fe1c)作为观察点)** Hardware watchpoint 3: *0x61fe1c (gdb) info watchpoints Num Type Disp Enb Address What 3 hw watchpoint keep y *0x61fe1c (gdb) n 10 for(i = 0; i < 4;i++){ (gdb) n 11 printf("%d\n", arr[i]); (gdb) n 1 10 for(i = 0; i < 4;i++){ **(gdb) n(i发生了变化)**Thread 1 hit Hardware watchpoint 3: *0x61fe1cOld value = 0 New value = 1 0x00000000004015bf in main () at .\caogao1.c:10 10 for(i = 0; i < 4;i++){ (gdb)
第六讲 调试core文件(针对UNIX,程序崩溃时)
本讲内容讲如何调试挂掉的程序、正在运行的程序
-
核心文件(core file),也称磁芯倾印(core dump),是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写入一个磁盘文件。这种信息往往用于调试。——来自维基百科
-
写一个会挂掉的程序
#include <stdio.h>int main() {int* temp = NULL;*temp = 10;return 0; }
-
命令行gcc -g编译得a.out文件,运行./a.out,出现段错误segment fault
-
命令行ll,没有生成core文件,因为这个主机是多人共享的,会给每个用户一些使用限制的使用,而core文件比较大,不会默认生成,需要自行调整系统资源的设置
-
命令行ulimit -a查看当前shell的限制,发现core file size默认为0
-
命令行ulimit -c unlimited,再gcc -g编译.c文件,再执行./a.out,会出现错误segment fault(core dumped)
-
命令行ll,生成一个core文件“core.19761”
-
使用gdb进行debug:gdb ./a.out core.19761,即gdb 二进制文件 core文件
-
会直接走到出问题的地方
- 总结:
- gdb 二进制文件 core文件
- 如果core文件没有生成,则需要查看自己的限制
第七讲 调试一个正在运行的程序
-
写一个可以一直运行的程序
#include <stdio.h>void test(){} void test1(){int i = 0;i++; } int main() {while(1){test();test1();}return 0; }
-
命令行 gcc -g 编译,./a.out & 后台执行(Linux才有,Windows不行),因为程序是死循环,会占用现在的终端导致待会没法使用这么终端进行演示,所以选择后台进行
-
执行./a.out &后,显示程序的pid(进程标识符process identifier,又略称为进程ID、process ID、PID——来自维基百科):21528
-
GDB调试:命令行执行gdb -p 21528
-
发现此时执行到test()
-
命令行执行n,执行下一行,到test1()
-
命令行执行s,进入test1(),i=0,继续n,执行到i++
-
命令行执行p i,得到$1 = 0,符合预期
-
命令行执行n,执行下一行,到 }
-
命令行执行p i,得到$2 = 1,符合预期
结束