GDB详解
总结学习GDB的知识点
GDB的初始化文件
GDB会在执行的时候运行一些初始化文件。这些初始化文件或者说是配置文件有三个等级。
系统配置文件
用户配置文件
本地配置文件
系统配置文件
首先运行的是系统初始化文件:
1 |
|
其中gdbinit
这是单个系统范围的初始化文件。它的位置由 –with-system-gdbinit 配置选项指定。它在 GDB 启动时首先加载,然后再处理命令行选项。
gdbinit.d
这是系统范围的初始化目录。它的位置由 –with-system-gdbinit-dir 配置选项指定。当 GDB 启动时,在处理命令行选项之前,此目录中的文件会在 system.gdbinit (如果启用)之后立即按字母顺序加载。文件需要具有可识别的脚本语言扩展名 ( .py / .scm ) 或使用 .gdb 扩展名命名才能解释为常规 GDB 命令。GDB 不会递归到该目录的任何子目录。
用户配置文件
系统配置文件的作用范围是所有的用户,用户的配置文件是作用于单个用户。
1 |
|
其中$XDG_CONFIG_HOME
是一个gdb的环境变量。
不管是系统配置文件还是用户配置文件,都可以使用-nx
命令行选项来阻止加载系统范围的初始化文件
如果想要执行本地初始化文件,而不是系统的,或者是用户的则需要在$XDG_CONFIG_HOME/gdb/gdbinit
或者是$HOME/.config/gdb/gdbinit
中加入:add-auto-load-safe-path
/path/to/your/local/gdbinit
如果 $XDG_CONFIG_HOME 环境变量未设置,则默认路径为 $HOME/.config。
1 |
|
当然你也可以直接指定配置文件通过-x
命令
1 |
|
在 GDB 中可以使用下面这个命令查看当前的加载的初始化文件:
1 |
|
三者的执行顺序
系统初始化->用户初始化->本地初始化
并且,最后执行的初始化文件具有决定性的作用。
小细节
gdb的命令很多,gdb把之分成许多个种类。help命令只是例出gdb的命令种类,如果要看种类中的命令,可以使用 help <class>
命令,如:help breakpoints
,查看设置断点的所有命令。也可以直接help <command>
来查看命令的帮助。
参考资料
1.4 GDB启动流程
下面我们讲述一下GDB的一个启动流程:
根据命令行的指定初始化对应的命令解释器(参看上一节
GDB的执行模式
)读取系统级别的
init
文件(即在编译gdb时通过--with-system-gdbinit
选项指定的文件),并执行其中的命令读取home目录的
init
文件并执行其中的命令按顺序执行由
-iex
选项指定的命令,或-ix
选项指定的文件中的命令。你也可以使用-ex
或者-x
来替换前面的选项,但是在这种情况下其会在gdbinit之前被执行处理命令行选项和参数
如当前目录并不是
home
目录,且set auto-load local-gdbinit
值为on
时,则会读取和执行当前工作目录下的gdbinit文件。如果命令行指定了要调试的
program
,或者要attach到一个进程,或者一个core dump文件,那么gdb会加载该program
所需要的自动加载文件或共享库。假如你想要在gdb启动时禁止这个自动加载,那么类似于如下:
1 |
|
说明: 这里并不能用-ex
选项,因为这会使得关闭auto-load
太晚
执行
-ex
选项指定的命令,或-x
选项指定的文件中的命令读取
history file
中的历史命令
.gdbinit
文件的配置
基本的语法组成
1 |
|
如果输入 help user 命令,您会看到已在 .gdbinit 文件中输入的所有用户命令的摘要。.gdbinit 用户定义命令的设计者提供了一个重要特性,您在编写自己的命令时不应忽略该特性:document … end 子句。随着这些命令数量的增加,维护有关命令如何工作的功能文档将变得非常关键。
所以我们可以通过这个文件定制自己的gdb
在.gdbinit文件中定义钩子函数
钩子函数就是在某事件发生时执行这个函数,gdb中的钩子函数语法:
当运行具有钩子函数的命令foo
时,这个钩子函数会先于命令foo
运行。使用语法hook-foo
。
语法hookpost-foo
是指在foo
命令运行完之后,再运行钩子函数。
例子:
1 |
|
注意:钩子函数可以为所有的单数命令定义,但是不可以为命令的简称定义。如可以为backtrace
命令写钩子,但是不可以为bt
命令写钩子。尽管这两个命令含义是一样的。
具有多个单词的命令如何编写钩子?:
我们可以通过将hook-或hookpost-添加到命令的最后一个字来钩子多字命令,例如define target hook-remote“将钩子添加到target remote。
如果在执行钩子期间发生错误,GDB命令的执行将停止,GDB将发出提示(在您实际键入的命令有机会运行之前)。
如果尝试定义与任何已知命令都不匹配的钩子,则会从define命令得到警告。
参考资料
https://blog.csdn.net/wads23456/article/details/105064833
https://blog.csdn.net/kking_edc/article/details/114746806
gdb插件
其中gdbgui还可以。
gdb-peda
gdb的工作原理
gdb 通过系统调用 ptrace
来接管一个进程的执行。ptrace 系统调用提供了一种方法使得父进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。它主要用来实现断点调试和系统调用跟踪。ptrace 系统调用的原型如下:
1 |
|
pid_t pid:指示 ptrace 要跟踪的进程。
*_void addr_:指示要监控的内存地址。
*_void data_:存放读取出的或者要写入的数据。
enum __ptrace_request request:决定了系统调用的功能,几个主要的选项:
_PTRACE_TRACEME_:表示此进程将被父进程跟踪,任何信号(除了
SIGKILL
)都会暂停子进程,接着阻塞于wait()
等待的父进程被唤醒。子进程内部对exec()
的调用将发出SIGTRAP
信号,这可以让父进程在子进程新程序开始运行之前就完全控制它。_PTRACE_ATTACH_:attach 到一个指定的进程,使其成为当前进程跟踪的子进程,而子进程的行为等同于它进行了一次 PTRACE_TRACEME 操作。但需要注意的是,虽然当前进程成为被跟踪进程的父进程,但是子进程使用
getppid()
的到的仍将是其原始父进程的 pid。_PTRACE_CONT_:继续运行之前停止的子进程。可同时向子进程交付指定的信号。
断点的实现
断点的功能是通过内核信号实现的,在 x86
架构上,内核向某个地址打入断点,实际上就是往该地址写入断点指令 INT 3
,即 0xCC
。目标程序运行到这条指令之后会触发 SIGTRAP
信号,gdb
捕获这个信号,并根据目标程序当前停止的位置查询 gdb
维护的断点链表,若发现在该地址确实存在断点,则可判定为断点命中。