调试利器GDB-上
Posted dengqiangjiayou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调试利器GDB-上相关的知识,希望对你有一定的参考价值。
调试利器GDB-上
-
什么是GDB?
- GNU项目中的调试器(gnu debuger)
- 能够跟踪程序的执行,也能够恢复程序崩溃前的状态
-
为什么需要GDB?
- 软件不是一次性开发完成的(是软件就有bug,是程序就有问题)
- 调试是软件开发过程中不可获取的技术(调试工具也很重要)
-
GDB的常规应用
- 自定义程序的启动方式(指定影程序运行的参数)
- 设置条件断点
- 回溯检查导致程序异常结束的原因(需要Core Dump)
- 动态改变程序的执行流(定位问题的辅助方式)
-
GDB的启动方式
-
直接启动
- gdb(在Ubuntu命令行下)
- gdb test.out
- gdb test.out core
-
动态链接
- gdb test.out pid
-
GDB应用实例
-
gdb (在目标文件夹下启动GDB)
-
file test.out (载入目标程序,.out文件是编译产生的文件)
-
set args arg1 arg2 (设置命令行参数)
-
run (执行目标文件,也可以start可以以断点的形式停止在main函数的入口处)
-
topeet@ubuntu:~/Desktop/Code$ ls a.out core func.c test.c test.i test.out topeet@ubuntu:~/Desktop/Code$ gdb GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 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-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>. (gdb) file test.out Reading symbols from /home/topeet/Desktop/Code/test.out...done. (gdb) set args HelloWorld (gdb) run Starting program: /home/topeet/Desktop/Code/test.out HelloWorld main() : begin... argv[0] = /home/topeet/Desktop/Code/test.out //传入的参数 argv[1] = HelloWorld test_1() : 0x400584 //已经开始main函数了 test_2() : 0x4005a1 ^C Program received signal SIGINT, Interrupt. 0x00007ffff7adb050 in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6 (gdb)
-
-
使用GDB进行断点调试
-
断点类型
- 软件断点:由非法指令异常实现(软件实现)运行在内存里面的程序可以用软件断点来调试
- 硬件断点:由硬件特性实现(所以数量有限)加载到flash/ROM里面的程序可以用硬件断点来调试
- 数据断点:由硬件特性实现(基于硬件断点实现,数量有限)某个设定的数据被读或被写程序就会立即停止并打印相关信息
-
软件断点的相关操作
- 通过函数名来设置断点
- break func_name [if var = value] //后面中括号可用可不用
- tbreak func_name [if var = value]
- 通过文件名行号设置断点
- break file_name:line_name [if var = value]
- tbreak file_name:line_name [if var = value]
- 通过函数名来设置断点
-
软件断点相关操作
操作 命令 断点查看 info breakpoints 断点删除 delete 1 2 n delete breakpoints //删除所有断点 断点状态改变 enable 1 2 n enable breakpoints disable 1 2 n disable breakpoints - 调试时常用的操作
操作 命令 变量查看 print name 变量设置 set var name = value 执行下一行代码 next 连续执行n行代码 next n 执行进入函数 step //执行到函数体使用step进入函数 强制当前函数返回 return [value] //强制以value值返回当前函数,当前函数可能存在错误 运行至当前函数返回 finish 执行至目标行 until line 跳转执行 jump line //强制跳转到目标行,也可以强制跳转过有问题的函数 - 硬件断点及其应用
- 当代码位于只读存储器(flash)时,只能通过硬件断点调试
- 硬件断点需要硬件支持,数量有限
- GDB通过hbreak命令支持硬件断点
- hbeak与break使用方式完全一致
第一次调试:
topeet@ubuntu:~/Desktop/Code$ ls //查看文件 a.out core func.c test.c test.i test.out topeet@ubuntu:~/Desktop/Code$ gdb test.out //执行.out文件 GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 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-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>... Reading symbols from /home/topeet/Desktop/Code/test.out...done. (gdb) set args HelloWorld //设置main参数 (gdb) start //自动设置临时断点,进入main函数的第一行就停止 Temporary breakpoint 1 at 0x4005ea: file test.c, line 25. Starting program: /home/topeet/Desktop/Code/test.out HelloWorld Temporary breakpoint 1, main (argc=2, argv=0x7fffffffe2a8) at test.c:25 25 (gdb) break test.c:37 //设置断点 Breakpoint 2 at 0x400658: file test.c, line 37. (gdb) continue //继续执行 Continuing. main() : begin... argv[0] = /home/topeet/Desktop/Code/test.out argv[1] = HelloWorld Breakpoint 2, main (argc=2, argv=0x7fffffffe2a8) at test.c:37 37 } (gdb) info breakpoints //查看断点信息 Num Type Disp Enb Address What 2 breakpoint keep y 0x0000000000400658 in main at test.c:37 breakpoint already hit 1 time (gdb) next //执行下一个程序 test_1() : 0x400584 38 (gdb) next 35 fa[i%3](); (gdb) next 3 //执行3条程序 Breakpoint 2, main (argc=2, argv=0x7fffffffe2a8) at test.c:37 37 } (gdb) print i //打印变量的信息 $1 = 1 (gdb) set var i =100 //设置变量信息 (gdb) print i $2 = 100 (gdb) next test_2() : 0x4005a1 38 (gdb) next 35 fa[i%3](); (gdb) next 41 (gdb) tbreak test.c:43 //设置临时断点 Temporary breakpoint 3 at 0x4006bb: file test.c, line 43. (gdb) info breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x0000000000400658 in main at test.c:37 breakpoint already hit 2 times 3 breakpoint del y 0x00000000004006bb in main at test.c:43 (gdb) continue Continuing. g_pointer = (nil) Temporary breakpoint 3, main (argc=2, argv=0x7fffffffe2a8) at test.c:43 43 return 0; (gdb) jump 45 //跳到程序结束位置 Continuing at 0x4006c5. main() : end... [Inferior 1 (process 4672) exited normally] (gdb) quit //退出
第二次调试:
topeet@ubuntu:~/Desktop/Code$ gdb test.out GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 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-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>... Reading symbols from /home/topeet/Desktop/Code/test.out...done. (gdb) start Temporary breakpoint 1 at 0x4005ea: file test.c, line 25. Starting program: /home/topeet/Desktop/Code/test.out Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe2a8) at test.c:25 25 (gdb) tbreak func Temporary breakpoint 2 at 0x4006dc: file func.c, line 7. (gdb) continue Continuing. main() : begin... argv[0] = /home/topeet/Desktop/Code/test.out test_1() : 0x400584 test_2() : 0x4005a1 ...... test_1() : 0x400584 g_pointer = (nil) Temporary breakpoint 2, func () at func.c:7 7 }(gdb) next Program received signal SIGSEGV, Segmentation fault. //出现错误 0x00000000004006e8 in func () at func.c:7 7 }(gdb) ^CQuit (gdb)
第三次调试:动态的改变错误以定位错误
topeet@ubuntu:~/Desktop/Code$ gdb test.out GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 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-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>... Reading symbols from /home/topeet/Desktop/Code/test.out...done. (gdb) show can-use-hw-watchpoints Debugger's willingness to use watchpoint hardware is 1. (gdb) start Temporary breakpoint 1 at 0x4005ea: file test.c, line 25. Starting program: /home/topeet/Desktop/Code/test.out Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe2a8) at test.c:25 25 (gdb) hbreak func Hardware assisted breakpoint 2 at 0x4006dc: file func.c, line 7. (gdb) info breakpoints Num Type Disp Enb Address What 2 hw breakpoint keep y 0x00000000004006dc in func at func.c:7 (gdb) continue Continuing. main() : begin... argv[0] = /home/topeet/Desktop/Code/test.out test_1() : 0x400584 test_2() : 0x4005a1 ....... test_1() : 0x400584 g_pointer = (nil) Breakpoint 2, func () at func.c:7 7 }(gdb) print g_pointer $1 = (int *) 0x0 //这个函数指针指向的地址为0,空指针 (gdb) set var g_pointer = (int*)malloc(sizeof(int)) //动态给其分配内存空间 (gdb) print g_pointer $2 = (int *) 0x602010 //得到堆空间地址 (gdb) continue Continuing. main() : end... //程序能正常结束 [Inferior 1 (process 4715) exited normally] (gdb)
上面放在Ubuntu下调试的代码如下:
test.c
#include <stdio.h> #include <unistd.h> extern int* g_pointer; extern void func(); void test_1() { printf("test_1() : %p\\n", test_1); } void test_2() { printf("test_2() : %p\\n", test_2); } void test_3() { printf("test_3() : %p\\n", test_3); } int main(int argc, char *argv[]) { typedef void(TFunc)(); TFunc* fa[] = {test_1, test_2, test_3}; int i = 0; printf("main() : begin...\\n"); for(i=0; i<argc; i++) { printf("argv[%d] = %s\\n", i, argv[i]); } for(i=0; i<100; i++) { fa[i%3](); sleep(argc > 1); } printf("g_pointer = %p\\n", g_pointer); func(); printf("main() : end...\\n"); return 0; }
func.c
#include <stdio.h> int* g_pointer; void func() { *g_pointer = (int)"HelloWorld"; return; }
-
以上是关于调试利器GDB-上的主要内容,如果未能解决你的问题,请参考以下文章