Skip to content

Latest commit

 

History

History
277 lines (193 loc) · 6.68 KB

bin_GDB.md

File metadata and controls

277 lines (193 loc) · 6.68 KB

GDB 简介

linux下基于命令行的程序调试工具

主要调试对象为C/C++程序

被调试的C/C++的程序,在编译时必须把调试信息加到可执行文件中

命令:

# 使用编译器(cc/gcc/g++)的 -g 参数 增加调试信息到可执行文件中 (不加-g就看不见程序的函数名、变量名,代替它们的全是运行时的内存地址)

# 例如
$ gcc -g hello.c -o hello
$ g++ -g hello.cpp -o hello

启动gdb的方式

# 1 可执行文件
gdb program
# 2 核心转储后产生的文件
gdb core
用gdb同时调试一个运行程序和core文件,core是程序非法执行后,core dump后产生的文件。
# 3 指定进程
gdb 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID。
gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。

gdb启动时,可以加一些gdb的启动开关,常用的参数:

-symbols -s 从指定文件中读取【符号表】。
-se file 从指定文件中读取符号表信息,并把它用在可执行文件中。
-core -c 调试时core dump的core文件。
-directory -d 加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径


# 查看 所有 详细的开关
gdb -help

基本流程

GDB中的命令虽然很多,但只要掌握最常用的10个命令,就可以完成基本的程序调试。

GDB主要帮忙你完成下面四个方面的功能:

1、启动你的程序,可以按照你自定义的要求来运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。断点可以是条件表达式
3、当程序被停住时,可以检查此时你的程序中所发生的情况
4、动态的改变该程序的执行环境

可见GDB和其他调试工具都是是完成这些功能。不过GDB在一些细节上很强大。

命令行的调试工具 有时能够完成 图形化工具"不能完成的功能"。

基本命令

#启动gdb调试环境
gdb
#退出GDB调试环境
q
Quit的简写
#加载同目录下的 被调试的可执行程序文件
file <文件名>
# GDB帮助命令 提供对GDB名种命令的解释说明
help [命令名称]

#指定了“命令名称”参数,则显示该命令的详细说明
(gdb) help display


#如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。

断点

断点必须位于源代码中【可执行代码】的那一行。 (无效断点:源代码中的 注释、空白行、变量说明 这些所在的行)

被调试程序处于什么情况下可以设置断点:

  • 未运行状态
  • 运行调试(已运行状态)

根据断点调试找到错误处。 在程序开发中,为了找到程序的bug,通常采用的一种调试手段,一步一步跟踪程序执行的流程,根据变量的值,找到错误的原因。 在需要调试的代码断设置断点,然后按预设的快捷键步进。调试状态运行程序,程序执行到有断点的地方会停下来。

#下断点
b <行号>
b <函数名称>
b *<函数名称>
b *<代码地址>
d [编号]

如
(gdb) b 8
(gdb) b main
(gdb) b *main
(gdb) b *0x804835c
(gdb) d

b: Breakpoint的简写,设置断点 指定断点位置。
在函数名称前面加“*”符号,(汇编有关)表示将断点设置在“由编译器生成的prolog代码处”。


#删除断点
d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。



#关闭所有断点
 (gdb)disable
 
#启动所有断点
 (gdb)enable
 
#关闭指定断点
 (gdb)info breakpoints
 (gdb)disable "num"
 
#开启指定断点
 (gdb)info breakpoints
 (gdb)enable "num"

#断点被执行一次然后关闭
 (gdb)enable once "num"
 
#断点被执行一次后删除
 (gdb)enable delete "num"

运行r 继续调试c

#运行被调试的程序。
r
Run的简写,如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处


可以重定向符号 传入参数
r < xxxpayload.txt

#继续执行被调试程序(执行到下一断点 或 程序结束)
c
Continue的简写

有源代码

必须在有源代码调试信息,才可以使用 s和n 这两个命令

也就是:GCC编译源代码时,使用了“-g”参数编译出来的程序。

单步跟踪:s和n,即step和next

单步跟踪:一行一行地执行程序,每执行一行语句后就停下来等待指示。 这样能够仔细了解程序的执行顺序,以及当时的各种状况。

s和n 二者相同点: 都会【执行1行源程序代码】

s和n的区别

n 单步调试【但不进入子函数内部】 此行代码中的函数调用直接执行。 next 相当于其它调试器中的“Step Over (单步跟踪)”。 (gdb)next

s 进入调试【进入子函数内部】 如果此行代码中有函数调用,则进入该函数; step 相当于其它调试器中的“Step Into (单步跟踪进入)”; (gdb) step

#执行到函数结束
(gdb) finish

#执行到下一个断点
 (gdb)continue
#执行到源代码的某一行
 (gdb)until "num"

汇编指令下的si和ni

si, ni
si命令类似于s命令,ni命令类似于n命令。
不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。

(gdb) si
(gdb) ni

打印变量的值

p <变量名称>	Print的简写,显示指定变量(临时变量/全局变量)的值
(gdb) p i
(gdb) p nGlobalVar


# it will print the value of $EBP.
p $ebp 

# I wish to show 4 bytes after the address pointed by ebp, and display an int.
(gdb) x/x $EBP+4
(gdb) x/d $EBP+4
(gdb) p *(int*)($EBP+4)

中断 显示此刻数据及格式

display ...
undisplay <编号>

display,设置程序中断后欲显示的数据及其格式。
例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令
“display /i $pc”
其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。



#必须在程序已经 运行起来 的状态下才能执行!
#一般完全相同的display命令只需要执行一次,否则会显示完全相同的内容,用undisplay 取消即可。
(gdb) display /i $pc

#取消先前的display设置,编号从1开始递增。
(gdb) undisplay 1
i
Info的简写,用于显示各类信息,详情请查阅“help i”。
如
(gdb) i r

GDB函数栈

#查看进程内存结构
(gdb)info proc mappings
#查看函数调用栈情况
(gdb)backtrace
(gdb)where
(gdb)info stack
#查看某个栈详细信息
(gdb)info frame "num"