济南的网站建设公司,易居房产cms,windows10系统优化,世界500强企业排名中国名单介绍#xff1a; gdb是一个非常强大的调试工具#xff0c;在gdb下#xff0c;我们可对编写的代码进行各种调试#xff0c;找出其中的bug#xff0c;但是需注意的是#xff0c;此工具调试与VS编译器的调试道理相同#xff0c;只有在debug版本下才可以被调试#xff0c;在…介绍 gdb是一个非常强大的调试工具在gdb下我们可对编写的代码进行各种调试找出其中的bug但是需注意的是此工具调试与VS编译器的调试道理相同只有在debug版本下才可以被调试在release版本下不能被调试。因为debug版本是程序员专门开发时使用的版本要包含一切与调试相关的数据占用内存大而release版本是最终开发后给用户使用的版本也就是测试版本没有与调试相关的数据并且还将代码做了许多优化占用内存小。
版本的调用 在Linux系统的CentOS 7版本下gcc/g编译时默认的模式是release模式以下的所有演示都是在CentOS 7版本下进行的。其它版本下编译器的配置可能有些不同默认的模式可能是debug。 如果需要使用debug模式通常需要在编译命令中添加 -g 参数如 gcc -g 或 g -g等。如果想要编译为release模式需要在编译命令中添加 -O2 或 -O3 参数。 [zhuzhujunhao day11]$ g -o code-d -g code.cpp //运用debug模式进行编译 [zhuzhujunhao day11]$ g -o code-r -O2 code.cpp //运用release模式进行编译 [zhuzhujunhao day11]$ g -o code.exe code.cpp //默认模式使用release进行编译 [zhuzhujunhao day11]$ ll //下面可观察到release模式和debug模式编译形成的可执行程序占用内存大小差距很大 total 48 -rw-rw-r-- 1 zhu zhu 103 Dec 11 11:18 code.cpp -rwxrwxr-x 1 zhu zhu 19536 Dec 11 12:29 code-d -rwxrwxr-x 1 zhu zhu 8968 Dec 11 12:31 code.exe -rwxrwxr-x 1 zhu zhu 8832 Dec 11 12:30 code-r gdb调试器只能在debug编译模式下运行因为只有debug有与调试有关的数据。从上面可看出debug生成的可执行程序占用的内存大里面包含了可调试的数据。
readelf工具 readelf 工具用于读取可执行程序的格式问题。可执行程序所对应的格式在Linux中叫做ELF。通过使用 readelf 命令我们可查看ELF文件的头部信息、节区信息、符号表等等。这些信息对于理解和分析程序的组成、结构和行为非常重要。后期在gdb调试工程过程中会更加依赖使用readelf工具查看格式化问题。如使用 readelf -S [可执行文件] 只读取头部ELF信息。 [zhuzhujunhao day11]$ readelf -S code-d //显示节头 这里提醒下readelf只能用于程序的可执行文件。
gdb调试运用 首先当我们生成可执行程序时使用 gdb [可执行文件] 可进入调试阶段。当进入调试界面后l 指令可查看源文件的内容具体使用如下 1l n(n代表行号) 从第n行开始显示往后的10行源代码。 2只输入 l 将从源代码中光标所在的位置开始显示10行内容。 3l [文件]:n(n代表行号) 显示指定[文件]中10行内容其中第 n 行内容将会在中间。 若我们想往后面再观看源代码时只需直接 “回车” 键即可因为gdb会自动记录最近一次的指令。若想退出输入quit后可退出调试界面。注意gdb调试器调试的是生成的可执行文件不是源文件。 [zhuzhujunhao day11]$ gdb code.exe //进入code.exe的调试界面 GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.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/zhu/day11/code.exe...done. (gdb) l 1 //从第一行开始显示10行源代码 warning: Source file is more recent than executable. 1 #include iostream 2 using namespace std; 3 int main() 4 { 5 int i 0, n 5; 6 while (i n) 7 { 8 cout 兔子 endl; 9 i; 10 } (gdb) //直接回车继续往下显示源代码一次10行 11 cout Debug endl; 12 return 0; 13 } (gdb) Line number 14 out of range; code.cpp has 13 lines. //表示已全部展开完毕 (gdb) quit //退出调试界面 当进入调试界面后rrun的简写指令可运行程序即从头开始进行调试。 (gdb) r //启动运行这里没有设置断点直接运行完毕 Starting program: /home/zhu/day11/code.exe 兔子 兔子 Debug [Inferior 1 (process 12251) exited normally] Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64 断点功能 break(简写b)是设置断点的指令使用方法有: 1b n 在第n行处设置断点。 2b [函数名] 在指定的函数入口处设置断点。 3b [文件名]:n 在指定的文件第n行设置断点。 当设置完断点后可使用 info b 指令查看我们设置的所有断点。具体的解释如下 //使用b n 在第n行设置断点设置完之后可观察到断点的地址、文件的来源和设置的行数 (gdb) b 5 Breakpoint 1 at 0x4007e5: file code.cpp, line 5. (gdb) b 8 Breakpoint 2 at 0x4007f5: file code.cpp, line 8. (gdb) b 11 Breakpoint 3 at 0x40081d: file code.cpp, line 11. (gdb) info b //显示所有有关断点的信息 /*Num表示断点的编号。Type表示设置类型这里是断点。 Enb表示断点的功能的开闭y是yes的意思表示断点的功能正常n是no的意思表示断点的功能关闭但断点还存在。Address表示断点的地址。What表示断点在哪个函数、哪个文件、哪一行中。*/ Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007e5 in main() at code.cpp:5 2 breakpoint keep y 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 delete(简写d)是删除断点的指令。使用方法d n 删除编号为n的断点。注意这里的n代表编号不是行数。这里可使用info b指令查看Num中的标号。 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007e5 in main() at code.cpp:5 2 breakpoint keep y 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 (gdb) d 1 //删除编号1的断点 (gdb) info b Num Type Disp Enb Address What 2 breakpoint keep y 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 (gdb) d 2 //删除编号2的断点 (gdb) info b Num Type Disp Enb Address What 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 (gdb) d 3 //删除编号3的断点 (gdb) info b No breakpoints or watchpoints. //显示断点已删除完毕 当我们设置完断点时默认断点的功能是打开的。当我们使用 disable n(这里的n表示断点的编号) 指令时可将编号为n的断点功能失效但不删除。当使用 enable n(这里的n表示断点的编号) 指令时可将编号为n的断点功能打开与disable功能相反。 这里要说明的是使用disable/enable后由于调试断点的设置已被更改当使用 r(run) 运行程序时系统可能会提醒是否重新生成程序运行。 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007e5 in main() at code.cpp:5 2 breakpoint keep y 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 (gdb) disable 2 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007e5 in main() at code.cpp:5 2 breakpoint keep n 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 (gdb) enable 2 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007e5 in main() at code.cpp:5 2 breakpoint keep y 0x00000000004007f5 in main() at code.cpp:8 3 breakpoint keep y 0x000000000040081d in main() at code.cpp:11 逐过程和逐语句 逐语句是一行一行进行分析它将会进入函数内部。逐过程是一次直接执行一个过程它将一次直接执行完一个函数不会进行函数内部分析。 在gdb调试中逐过程的指令是next简写n。逐语句的指令是step简写s。当在使用一次逐过程/逐语句后下面直接按 “回车” 键即可继续往下面运行也可不断使用n/s往下面运行而在此过程中我们可使用 p [变量](print的简写) 查看变量的内容如p n 查看数据中n的值p s 查看变量s的地址。这里需注意p指令使用无法一直显示数据当再次进行操作时变量的内容将会消失。display [变量] 将会永久的显示数据。undisplay n(这里的n代表编号) 将会把编号为n的显示内容删除。 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007f3 in main() at code.cpp:6 2 breakpoint keep y 0x0000000000400839 in main() at code.cpp:13 3 breakpoint keep y 0x00000000004008fd in main() at code.cpp:20 4 breakpoint keep y 0x0000000000400a15 in main() at code.cpp:30 (gdb) r ......... (gdb) n //逐过程分析 8 cout 兔子 endl; (gdb) //回车继续运行 兔子 main () at code.cpp:9 9 i; ......... //使用p指令显示一次数据的内容 (gdb) p i $1 5 (gdb) p n $2 10 (gdb) p i $3 (int *) 0x7fffffffe4dc //可发现p指令不能永久显示 (gdb) n 8 cout 兔子 endl;//使用display指令永久显示数据内容 (gdb) display i 1: i 6 //i变量编号1 (gdb) display n 2: n 10 //n变量编号2 //逐过程继续运行还会看到数据内容 (gdb) n 兔子 9 i; 2: n 10 1: i 6//使用undisplay指令删除指定数据内容注意这里要输入编号 (gdb) undisplay n //输入变量出现错误 warning: bad display number at or near n (gdb) undisplay 2 //输入编号2删除编号2变量的内容 (gdb) n 8 cout 兔子 endl; 1: i 8 范围式查找 范围式调试常用指令有以下 continue(简写c)从一个断点运行到下一个断点或程序结束。它通常用来范围查找。 bt查看当前函数的堆栈信息根据函数栈帧发现问题。 finish运行当前所在的函数将当前所在的一个函数运行结束后就停止。但是它不会 将主函数一次运行完。 until n(n代表行号)直接将程序运行到第n行若中间出现死循环在运行中将会出现死 循环问题。 以上几个指令都是在源代码基础上进行局部分析但在调试中我们可能会想测试源代码中某些变量改变后的情况。通常使用 set var [改变内容] 指令即可完成。如set var flag0 查看将源代码中变量flag的值变为0时的测试情况。
注意 1使用set var指令改变内容时要改变的变量必须已经在内部存储过即程序已经运行到这部分时才可改变。 2set var改变内容只是在测试中改变不会影响源代码的内容在测试时可放心使用。 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004007f3 in main() at code.cpp:6 2 breakpoint keep y 0x0000000000400855 in main() at code.cpp:14 3 breakpoint keep y 0x00000000004008fd in main() at code.cpp:20 4 breakpoint keep y 0x0000000000400a15 in main() at code.cpp:30 (gdb) r //run的简写直接运行到编号1断点的位置 ............. (gdb) c //continue的简写从当前断点位置运行到编号2断点的位置 ............. (gdb) bt #0 main () at code.cpp:14 //主函数栈帧 (gdb) until 18 //将程序从当前位置直接运行到第18行 ............. (gdb) set var i6 //改变变量i的值 (gdb) p i //查看i已经改变过 $1 6 (gdb) finish //直接运行完一个函数(方法)这里程序在主函数中因此不能正常运行 finish not meaningful in the outermost frame.