使用gdb调试调试学习 梦里梦外; 2022-12-17 11:57 302阅读 0赞 # 例子1 # 编写程序: #include <stdio.h> int main () { unsigned long long int n, sum; n = 1; sum = 0; while (n <= 100) { sum = sum + n; n = n + 1; } return 0; } 将程序编译成可执行文件: # 使用 GDB 调试某个可执行文件,该文件中必须包含必要的调试信息(比如各行代码所在的行号、包含程序中所有变量名称的列表(又称为符号表)等)。因此必须有-g # -o main:生成可执行文件main gcc main.cpp -o main -g **启动gdb调试器**: **调试尚未执行的程序** $ gdb main GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7 Copyright (C) 2013 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-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/oceanstar/workspace/cpp/code/opencv_sln/main...(no debugging symbols found)...done. (gdb) 该指令在启动 GDB 的同时,会打印出一堆免责条款。通过添加 --silent(或者 -q、–quiet)选项,可将比部分信息屏蔽掉: $ gdb main -q Reading symbols from /home/oceanstar/workspace/cpp/code/opencv_sln/main...(no debugging symbols found)...done. (gdb) **显示带行号的源代码**:l * 默认情况下,l 选项只显示 10 行源代码,如果查看后续代码,安装 Enter 回车即可 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaXpoZW5nZ3Vhbg_size_16_color_FFFFFF_t_70_pic_center] (gdb) l No symbol table is loaded. Use the "file" command. 原因可能是工程名和实际的不一致。切记**不要将编译的二进制文件重命名** **在第 7 行源代码处打断点**: b 7 ![在这里插入图片描述][20201023165333538.png_pic_center] **运行程序,遇到断点停止**: r ![在这里插入图片描述][20201023165426795.png_pic_center] **查看代码中变量 n 的值**: p n (gdb) p n $1 = 1 # 当前 n 的值为 1,$1 表示该变量所在存储区的名称 **在第 7行的基础上,在第9行打断点**: b 7 ![在这里插入图片描述][20201023175148472.png_pic_center] # 例子2 # > 在某些情况下,我们可能想调试一个当前已经启动的程序,但又不想重启该程序,就可以借助 GDB 调试器实现。 编写程序: #include <stdio.h> int main() { int num = 1; while(1) { num++; } return 0; } 编译程序 gcc main.cpp -o main.exe -g 运行程序 ./main.exe 借助 pidof 指令即可获取它对应的进程号: ![在这里插入图片描述][20201023170842737.png_pic_center] 在此基础上,**启动gdb调试器**: **调试正在执行的程序**,调用指令有以下 3 种形式: 1. gdb attach PID 2. gdb 文件名 PID 3. gdb -p PID 其中,PID 指的就是要调取的程序对应的进程号。随便选一个: $ gdb -p 98281 -q Attaching to process 98281 Reading symbols from /home/oceanstar/桌面/main.exe...done. Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 main () at main.cpp:9 9 return 0; Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7.x86_64 (gdb) 打断点 (gdb) l 4 int num = 1; 5 while(1) 6 { 7 num++; 8 } 9 return 0; 10 } (gdb) b 7 Breakpoint 1 at 0x4004d8: file main.cpp, line 7. **令程序进行执行,其会在下一个断点处停止** (gdb) c Continuing. Breakpoint 1, main () at main.cpp:7 7 num++; 查看当前 num 的值 (gdb) p num $1 = 1549923866 注意,当调试完成后,如果想令当前程序进行执行,消除调试操作对它的影响,需手动将 GDB 调试器与程序分离,分离过程分为 2 步: * 执行 detach 指令,使 GDB 调试器和程序分离; * 执行 quit(或 q)指令,退出 GDB 调试。 ![在这里插入图片描述][20201023171553745.png_pic_center] > 问:如果我们不指定可执行文件就直接启动gdb会怎么样 我们可以通过file手动指定要调试的目标程序。如下: **启动gdb调试器**: **手动指定要调试的目标程序** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaXpoZW5nZ3Vhbg_size_16_color_FFFFFF_t_70_pic_center 1] # 例子3: # #include<stdio.h> int main(int argc,char* argv[]) { FILE * fp; if((fp = fopen(argv[1],"r")) == NULL){ printf("file open fail"); } else{ printf("file open true"); } return 0; } 编译程序 gcc main.cpp -o main.exe -g 对于上面的程序,如果想要程序正确运行,必须在启动程序的同时传递一个参数给这个程序。 **为 GDB 调试器指定的目标程序传递参数**有三种方法可以达到这个目的 (1) 方法1:在指定目标调试程序的同时,使用 --args 选项指定需要传递给该程序的数据 gdb -q --args main.exe /home/oceanstar/workspace/cpu.txt ![在这里插入图片描述][20201023173629261.png_pic_center] (2) 方法2:借助 set args 命令指定目标调试程序启动所需要的数据 set args /home/oceanstar/workspace/cpu.txt ![在这里插入图片描述][2020102317373233.png_pic_center] (3) 方法3:使用 run 或者 start 启动目标程序时,指定其所需要的数据 run /home/oceanstar/workspace/cpu.txt start /home/oceanstar/workspace/cpu.txt > 可以这样理解,使用 start 指令启动程序,完全等价于先在 main() 主函数起始位置设置一个断点,然后再使用 run 指令启动程序。另外,程序执行过程中使用 run 或者 start 指令,表示的是重新启动程序。 **输出重定向** 默认情况下,GDB 调试会将输出结果打印到屏幕上。我们可以将**执行结果**输出到文件或者某个终端上 比如下面: (gdb) r > a.txt Starting program: /home/oceanstar/桌面/main.exe > a.txt [Inferior 1 (process 100663) exited normally] 在 GDB 调试的工作目录下就会生成一个 a.txt 文件,其中存储的即为 main.exe 的执行结果。 **关于gdb的工作目录** 默认情况下,GDB 调试器的工作目录为启动时所使用的目录。当然,我们也可以切换工作目录 (gdb) pwd # 查看工作目录 Working directory /home/oceanstar/桌面. (gdb) cd /home/oceanstar/ # 切换工作目录 Working directory /home/oceanstar. > 问: 某些场景中,目标调试程序的执行需要**临时**修改 PATH 环境变量,怎么办? 答:使用path指令 **注意,此修改方式只是临时的,退出 GDB 调试后会失效。** (gdb) path /temp/demo Executable and object file path: /temp/demo:/usr/local/sbin:/usr/local/bin... # 例子4: # #include<stdio.h> int main(int argc,char* argv[]) { int num = 1; while(num<100) { num *= 2; } printf("num=%d",num); return 0; } GDB 调试器支持在被调试程序中打 3 种断点,分别为普通断点、观察断点和捕捉断点: * 普通断点用 break 命令建立 * 观察断点用 watch 命令建立 * 捕捉断点用 catch 命令建立 三者区别: * 普通断点作用于程序中的某一行,当程序运行至此行时停止执行 * 观察断点作用于某一变量或表达式,当该变量(表达式)的值发生改变时,程序暂停 * 捕捉断点的作用是,监控程序中某一事件的发生,例如程序发生某种异常时、某一动态库被加载时等等,一旦目标时间发生,则程序停止执行。 ## break ## (gdb) l 1 #include<stdio.h> 2 int main(int argc,char* argv[]) 3 { 4 int num = 1; 5 while(num<100) 6 { 7 num *= 2; 8 } 9 printf("num=%d",num); 10 return 0; (gdb) 11 } (gdb) b 4 <-- 程序第 4 行打断点 Breakpoint 1 at 0x1138: file main.c, line 4. (gdb) r <-- 运行程序,至第 4 行暂停 Starting program: /home/ubuntu64/demo/main.exe Breakpoint 1, main (argc=1, argv=0x7fffffffe078) at main.c:4 4 int num = 1; (gdb) b +1 <-- 在第 4 行的基础上,在第 5 行代码处打断点 Breakpoint 2 at 0x55555555513f: file main.c, line 5. (gdb) c <-- 继续执行程序,至第 5 行暂停 Continuing. Breakpoint 2, main (argc=1, argv=0x7fffffffe078) at main.c:5 5 while(num<100) 如果 num>10 在第 7 行打断点 (gdb) b 7 if num>10 <-- 如果 num>10 在第 7 行打断点 Breakpoint 3 at 0x555555555141: file main.c, line 7. (gdb) c <-- 继续执行 Continuing. Breakpoint 3, main (argc=1, argv=0x7fffffffe078) at main.c:7 7 num *= 2; <-- 程序在第 7 行暂停 (gdb) p num <-- p 命令查看 num 当前的值 $1 = 16 <-- num=16 ## watch ## * **watch 命令的功能是:只有当被监控变量(表达式)的值发生改变,程序才会停止运行。** * **rwatch 命令:只要程序中出现读取目标变量(表达式)的值的操作,程序就会停止运行;** * **awatch 命令:只要程序中出现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。** 对于使用 watch(rwatch、awatch)命令监控 C、C++ 程序中变量或者表达式的值,有以下几点需要注意: * 当监控的变量(表达式)为局部变量(表达式)时,一旦局部变量(表达式)失效,则监控操作也随即失效; * 如果监控的是一个指针变量(例如 \*p),则 watch \*p 和 watch p 是有区别的,前者监控的是 p 所指数据的变化情况,而后者监控的是 p 指针本身有没有改变指向; * 这 3 个监控命令还可以用于监控数组中元素值的变化情况,例如对于 a\[10\] 这个数组,watch a 表示只要 a 数组中存储的数据发生改变,程序就会停止执行。 (gdb) l <--列出要调试的程序源码 1 #include<stdio.h> 2 int main(int argc,char* argv[]) 3 { 4 int num = 1; 5 while(num<=100) 6 { 7 num *= 2; 8 } 9 printf("%d",num); 10 return 0; (gdb) 11 } (gdb) b 4 <-- 使用 break 命令打断点 Breakpoint 1 at 0x115c: file main.c, line 4. (gdb) r <-- 执行程序 Starting program: /home/ubuntu64/demo/main.exe Breakpoint 1, main (argc=1, argv=0x7fffffffe088) at main.c:4 4 int num = 1; (gdb) watch num <-- 监控程序中 num 变量的值 Hardware watchpoint 2: num (gdb) c <-- 继续执行,当 num 值发生改变时,程序才停止执行 Continuing. Hardware watchpoint 2: num Old value = 0 New value = 2 main (argc=1, argv=0x7fffffffe088) at main.c:5 5 while(num<=100) (gdb) c <-- num 值发生了改变,继续执行程序 Continuing. Hardware watchpoint 2: num Old value = 2 New value = 4 main (argc=1, argv=0x7fffffffe088) at main.c:5 5 while(num<=100) (gdb) [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaXpoZW5nZ3Vhbg_size_16_color_FFFFFF_t_70_pic_center]: /images/20221122/ac0f54c5e35945968cac152f40fca099.png [20201023165333538.png_pic_center]: /images/20221122/bd13ac726a7642f89b924e9fe697d9fd.png [20201023165426795.png_pic_center]: /images/20221122/6346646efe454be18d7bb87bccaade04.png [20201023175148472.png_pic_center]: /images/20221122/b7db00f972cc4c5aafc9df4f847f0a3b.png [20201023170842737.png_pic_center]: /images/20221122/dbb05cb3668a4ab283b51e58891437b6.png [20201023171553745.png_pic_center]: /images/20221122/dc5048d9922d41f1899c8e5bbd97d12b.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaXpoZW5nZ3Vhbg_size_16_color_FFFFFF_t_70_pic_center 1]: /images/20221122/0019762fdad746ee9ded530b81b4ae6c.png [20201023173629261.png_pic_center]: /images/20221122/2f70fa291af44ef7b8275f9103db71c1.png [2020102317373233.png_pic_center]: /images/20221122/11259cb314d64c259c4c86228a9c2e86.png
相关 GDB调试 文章目录 * * 1、gdb调试编译准备 * 2、开启gdb调试 * 3、查看程序 l * 4、断点 . b *... 痛定思痛。/ 2024年04月19日 13:17/ 0 赞/ 96 阅读
相关 gdb 调试 信息显示命令 [info address][] [info registers][] [info files][] [info functions][ 灰太狼/ 2023年06月03日 15:58/ 0 赞/ 16 阅读
相关 使用gdb调试调试学习 例子1 编写程序: include <stdio.h> int main () { unsigned long 梦里梦外;/ 2022年12月17日 11:57/ 0 赞/ 303 阅读
相关 GDB调试 一.快速进阶 1.编译生成可执行文件 gcc -g test.c -otest 2.启动gdb gdb test 3.在main函数处打断点。 bre 爱被打了一巴掌/ 2022年09月24日 11:21/ 0 赞/ 281 阅读
相关 GDB 调试 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现G 朱雀/ 2022年08月27日 04:47/ 0 赞/ 324 阅读
相关 gdb 调试 基本用法 1. gcc -g xx.c xx 2. gdb xx 基本命令 1. start 启动程序, 默认停留在main程序的第一行 2. run 启 刺骨的言语ヽ痛彻心扉/ 2022年06月09日 11:26/ 0 赞/ 346 阅读
相关 gdb调试 在用gcc编程的时候可能会出bug,这时候就可以通过gdb这个工具进行调试,gdb调试的一定是直接有\.c 文件生成的bebug版本的可执行文件,否则,进入gdb之后敲入lis Dear 丶/ 2022年06月02日 07:55/ 0 赞/ 397 阅读
相关 gdb调试 要使用gdb调试,必须在源代码生成二进制程序的时候,加上-g选项 gdb常用命令: list/l + 行号:显示源代码,接着上次的位置往下列每次10行 li Love The Way You Lie/ 2022年05月14日 04:06/ 0 赞/ 328 阅读
相关 GDB调试 [https://www.cnblogs.com/HKUI/p/8955443.html][https_www.cnblogs.com_HKUI_p_8955443.html] 曾经终败给现在/ 2022年03月29日 17:38/ 0 赞/ 383 阅读
相关 GDB调试 另外有: Gdb+core调试技术 http://zhwen.org/xlog/?p=453 一、gdb简介和安装 GDB是GNU开源组织发 谁践踏了优雅/ 2022年01月22日 04:29/ 0 赞/ 395 阅读
还没有评论,来说两句吧...