前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >gdb 调试笔记

gdb 调试笔记

原创
作者头像
De4dCr0w
修改2020-06-15 10:31:03
8390
修改2020-06-15 10:31:03
举报

一、环境安装

代码语言:txt
复制
gdb 源码下载:https://ftp.gnu.org/gnu/gdb/
gdb 源码编译:
mkdir gdb‐build‐7.7
cd gdb‐build‐7.7
../gdb‐7.7/configure
或者 ‐‐target=i686‐elf ‐‐prefix=../gdb/install
make ‐j4
make install
安装后程序在/usr/local/bin
原先的程序在/usr/bin

二、自动化处理

(1)内核调试脚本
代码语言:javascript
复制
gdb \
‐ex "add‐auto‐load‐safe‐path $(pwd)" \
‐ex "file vmlinux" \
‐ex 'set arch i386:x86‐64:intel' \
‐ex 'target remote localhost:1234' \
‐ex 'continue' \
‐ex 'disconnect' \
‐ex 'set arch i386:x86‐64:intel' \
‐ex 'target remote localhost:1234'

三、断点相关

(1)条件断点
代码语言:txt
复制
break write if $rsi == 2

(2)软件断点

代码语言:txt
复制
beak 普通
tbreak 一次性
rbreak 接受正则表达式成批设置

原理:

  • 基于CPU的断点指令,如x86的INT 3(机器码0xCC)
  • 替换断点位置的指令
  • CPU执行到此时触发断点异常
  • 没有数量限制
(3)硬件断点
代码语言:txt
复制
hbreak 普通
thbreak 一次性

原理:

  • 基于CPU的调试寄存器,如x86的DR0-DR7
  • 不需要修改程序代码,可以针对EEPROM上的代码位置
  • 有数量限制,x86上最多4个
(4)监视断点
代码语言:txt
复制
监视表达式,值变化时中断
watch a*b + c/d
watch *(int *)0x12345678
watch *global_ptr

访问监视断点:
rwatch 表达式被读时断下
awatch 表达式被读或者被写时断下

(5)catch 断点:用于捕捉事件

代码语言:txt
复制
事件包括如下:
exception [name]
exception unhandled
handlers [name]
assert
exec
syscall
syscall [name|number|group:groupname|g:groupname]
例:(gdb)catch syscall chroot
 (gdb) catch syscall group:process
 Catchpoint 1 (syscalls ’exit’ [1] ’fork’ [2] ’waitpid’ [7]
 ’execve’ [11] ’wait4’ [114] ’clone’ [120] ’vfork’ [190]
 ’exit_group’ [252] ’waitid’ [284] ’unshare’ [310])
 fork
 vfork
 load [regexp]
 unload [regexp]
 signal [signal...|'all']
 tcatch event 捕捉一次catch
(6)dprinf 遇到断点是打印信息
代码语言:txt
复制
set dprintf‐style gdb/call/agent 设置用哪里的打印函数打印信息
set dprintf‐function fprintf 设置用什么函数打印
dprintf 25,"at line 25, glob=%d\n",glob
(7)trace 跟踪点

和break命令非常相似。其参数可以是源代码行,函数名或者目标程序的某个地址,trace

命令创建跟踪点,程序在此点上短暂中断,收集数据,然后程序继续往下执行。设置跟踪点

或者改变跟踪点命令直到下个tstart命令才会生效;因此,不能在跟踪会话过程中改变跟踪

点的属性。

代码语言:txt
复制
delete tracepoint [num]
disable tracepoint [num]
enable tracepoint [num]
passcount [n [num]]
代码语言:txt
复制
(gdb) passcount 5 2 // 跟踪点2在第5次执行时中止
(gdb) passcount 12 // 最近创建的跟踪点,在第12次执行时中断
(gdb) trace foo
(gdb) pass 3
(gdb) trace bar
(gdb) pass 2
(gdb) trace baz
(gdb) pass 1 // 在foo执行过3次,或者bar执行过2次,或者baz执行过1次时,中止跟踪

action num 执行到跟踪点要执行的命令,只有两种:collect, while‐stepping

例:

代码语言:txt
复制
(gdb) trace foo
(gdb) actions
Enter actions for tracepoint 1, one per line:

> collect bar,baz
> collect $regs
> while‐stepping 12
	> collect $fp, $sp
	> end
 end
 collect expr1, expr2, …

 tstart 开始一次跟踪会话
 tstop 结束一次跟踪会话
 tstatus 显示当前跟踪数据收集的状态
(8)断下后执行命令

commands num(断点编号)在触发断点后执行commands,命令以end结束

用define 编写自定义的宏

(gdb) define br_info

Type commands for definition of "br_info".

End with a line saying just "end".

b $arg0

comm

i locals

i args

end

(gdb) br_info binary_search if target == 5

当if target == 5条件满足时,br_info binary_search会被执行。

br_info展开成为一系列命令,并用binary_search替换掉$arg0。

(9)管理断点
代码语言:txt
复制
info/disable/delete break

保存断点到文件中
save breakpoints [filename] 保存现在的断点到文件中
source [filename] 恢复断点,将文件中的断点打一遍, watchpoints可能会失效

四、保存现场和回溯

(1)gdb 的快照保存
代码语言:txt
复制
checkpoint: 生成当前状态的快照
info checkpoint:显示快照信息
restart checkpoint‐id:恢复到某个checkpoint
delete checkpoint checkpoint‐id:删除某个checkpoint

值得注意的是

  1. 保存快照的进程ID和之前不同
  2. 已经写入文件或者关闭设备这些操作不能撤回到原先的状态
  3. 恢复到快照后,会将快照覆盖,所以如果还想再调试一次,就要在恢复后重新建立一个快照。
  4. 快照是对原先进程的复制,所以地址相同,调试的时候可以对地址下断点,而不用管随机化
(2)逆向执行
代码语言:txt
复制
首先启动record 功能,就可以进行命令回溯
reverse‐continue 缩写rc
reverse‐step /rs
reverse‐step /rsi
reverse‐next /rn
reverse‐nexti /rni
reverse‐finish
如果嫌麻烦可以设置执行方向
set exec‐direction reverse/forward 这样执行ni就是reverse‐nexti

record stop
(3)记录功能
代码语言:txt
复制
record goto begin/start 跳转到记录的起始位置
record goto end 跳转到记录的结束位置
record goto n 跳到记录的第n条指令,默认可以记录20万条
record save filename 保存记录
record restore filename 恢复记录
(4)日志信息
代码语言:txt
复制
set logging on 开启日志记录
set logging off 关闭日志记录
set logging file file 记录日志文件,默认是gdb.txt
set logging overwrite [on|off] 是否覆盖,默认是不覆盖,以追加的方式记录日志
show logging 显示日志设置
(5)栈回溯
代码语言:txt
复制
bt 或where , info s
bt full 会打印栈里的变量

五、打印和单步调试

代码语言:txt
复制
p *&argv[0]@3:表示打印argv[0] argv[1] argv[2]
p {int}argv 以int类型显示argv变量
p/x 显示十六进制
p/d 显示有符号的十进制
p/u 显示无符号的十进制
p/o 显示八进制
p/t 显示二进制
p/a 显示地址
p/c 显示符号
p/f 显示浮点数
p/r 以上一次的格式显示
x/i 显示汇编
x/s 显示字符
x/b 单字节显示
x/h 双字节显示
x/w 四字节显示
x/g 八字节显示
disassemble/disas 显示反汇编
disassemble/r 显示反汇编前的机器码 混合
disassemble/m 显示源码 混合
disas start, end
disas start, +length
$表示上一个显示的变量
$n表示上n个显示的变量
$$表示上上个显示的变量
$$n表示上n个显示的变量的值
$_表示上一个用x显示的变量
$__表示上一个用x显示地址上存放的数据
$_thread 表示最新创建的线程


p $_strlen(str) 计算str字符串的长度
p $_streq(str1, str2) 比较两个字符串是否相等,相等返回1
help function 查看可使用的函数
explore val :可以显示变量的类型
(1)观察类型
代码语言:txt
复制
pt(ptype) 观察数据类型(结构)
whatis
print v@10
(2)单步跟踪
代码语言:txt
复制
next /n 代码单步步过
step/s 代码单步步入
stepi(si) 单步步入
stepi 4 执行4个指令
nexti 单步步过
skip function 始终步过指定函数
skip file [filename] 始终不进入指定文件


until 3 继续执行直到命中断点3
finish 继续执行直到当前函数返回
set print finish on 继续执行到函数后会打印返回值,本机测试不成功???
call func 执行func函数并打印返回值
return result 强制返回,返回值为result

六、实用操作

代码语言:txt
复制
gdb 重放操作 repeat
(1)启动参数
代码语言:txt
复制
gdb ‐n :可以不加载任何gdbinit文件,不想使用插件时不必去注释gdbinit文件了
gdb ‐q :不打印版本和介绍信息启动
gdb ‐write:对二进制程序可读可写启动,可对二进制程序指令进行修改,并保存到文件中,或者启动后"set write on"
gdb ‐statistics:可打印每条指令执行的时间
调试时可以通过"|"管道符对输出结果进行处理
gdb ‐‐pid=<n> 调试已经运行的程序
(2)执行系统命令
代码语言:txt
复制
 !command
(3)转储分析
代码语言:txt
复制
gdb ‐‐core=<file>
gdb program core
gcore [file] 生成一个core文件用于保存当前gdb调试的快照(默认生成core.pid文件)
(4)dump 内存
代码语言:txt
复制
dump 内存到文件中
dump [format] memory filename start_addr end_addr
format:binary/ihex
dump [format] value filename expr

追加内存到文件中
append [binary] memory filename start_addr end_addr
append [binary] value filename expr

从文件中恢复到内存
restore filename [binary] bias start end
(5)窗口调试
代码语言:txt
复制
layout 用于分割窗口,可以一边查看代码,一边测试
layout split 显示源代码和汇编窗口
layout next 显示下一个layout
layout prev 显示上一个layout
layout regs 显示源代码/汇编和寄存器窗口
focus cmd (三个窗口:cmd、asm、src)
Ctrl + L:刷新窗口
Ctrl + x,再按1:单窗口模式,显示一个窗口
Ctrl + x,再按2:双窗口模式,显示两个窗口
Ctrl + x,再按a:回到传统模式,即退出layout,回到执行layout之前的调试窗口。
(6)搜索内存:
代码语言:txt
复制
find [/sn] start_addr, +len, val1 [, val2, …]
find [/sn] start_addr, end_addr, val1 [, val2, …]
s可以为b,h,w,g等值,分别表示 字节(byte),两个字节(half words),4个字节(words),8个字节(giant words)
n表示要找的东西的最多个个数,默认是把所有的都找出来
$_ 保存着找到的最后一个地址
(7)宏处理
代码语言:txt
复制
宏展开
macro exp expression
例:macro exp __is_constexpr(1)
宏展开一次
macro exp1 expression
(8)在gdb中编译和注入代码

七、设置和显示

(1)设置操作
代码语言:txt
复制
set args 设置程序参数
show args 显示程序参数
set print vtbl on/off 开启打印虚表功能
set print union on/off 开启打印联合类型
set print symbol on/off 开启打印符号表
set print array on/off 开启打印数组类型
set print object on/off 开启打印object类型
set charset ASCII 设置字符集为ASCII
(2)显示符号
代码语言:txt
复制
info variables/var regexp 查找变量
info classes regexp
info functions/func regexp 查找函数
info types regexp
info address symbol 查找symbol所在的地址
info symbol addr 查找地址对应的symbol,如果找不到,会返回最近的symbol+偏移
directory/dir dirname 设置符号表搜索路径
info program 显示程序状态,是否在运行,程序名,为什么停止
info stack 查看栈信息
info r 查看寄存器

八、调试特定场景

(1)调试多线程
代码语言:txt
复制
info threads
thread 2 切换到线程2
thread apply [thread‐id‐list | all [‐ascending]] command
对多个线程执行命令,例如: thread apply all bt 对所有线程进行栈回溯
对当前线程命名: thread name [name]
(2)调试fork子进程
代码语言:txt
复制
set follow‐fork‐mode parent/child 默认是调试父进程,而子进程继续执行
set detach‐on‐fork mode on/off 同时调试父进程和子进程
开启后可以控制所有fork的子进程,通过info inferiors查看信息,用inferior 命令进行切换

调试exec产生的子进程
set follow‐exec‐mode new/same
new 是新建一个inferior,而父进程的inferior仍然保留,当前保留的inferior的程序状态是没有执行。
same是保持在原来的inferior,gdb默认是same模式
set schedule‐multiple on 所有进程同时运行,detach‐on‐fork开启调试一个进程时,其他进程挂起
bt 显示所有参数
set print frame‐arguments all
(3)调试信号
代码语言:txt
复制
info handle 查看各种信号的设置,设置包括如下:
print 对信号量进行通知
noprint 对信号量不打印信息,如果有信号量干扰,可以用handle xxx noprint将其屏蔽
stop 中断执行
nostop 不中断执行
pass 允许程序接管信号量
nopass 不允许程序接收信号量
handle SIGCONT 查看continued的信号量设置

九、随机化设置

代码语言:txt
复制
关闭ASLR:
set disable‐randomization on
开启ASLR:
set disable‐randomization off
查看ASLR状态:
show disable‐randomization

默认是关闭随机化的,也就是on状态。

十、调试内核时出现“Remote 'g' packet reply is too long”问题

代码语言:txt
复制
gdb源码下载:https://mirrors.ustc.edu.cn/gnu/gdb/

gdb源码根目录/gdb/remote.c里面,将
if (buf_len > 2 * rsa‐>sizeof_g_packet)
error (_(“Remote ‘g’ packet reply is too long: %s”), rs‐>buf);
修改为
if (buf_len > 2 * rsa‐>sizeof_g_packet) {
rsa‐>sizeof_g_packet = buf_len ;
for (i = 0; i < gdbarch_num_regs (gdbarch); i++) {
    if (rsa‐>regs‐>pnum == ‐1)
    continue;
    if (rsa‐>regs‐>offset >= rsa‐>sizeof_g_packet)
     rsa‐>regs‐>in_g_packet = 0;
    else
    rsa‐>regs‐>in_g_packet = 1;
    }
  }

重新编译gdb
./configure ‐‐prefix=/home/ubuntu/gdb‐8.2/install
make
sudo apt install ‐y texinfo
make install

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、环境安装
  • 二、自动化处理
    • (1)内核调试脚本
    • 三、断点相关
      • (1)条件断点
        • (3)硬件断点
          • (4)监视断点
            • (6)dprinf 遇到断点是打印信息
              • (7)trace 跟踪点
                • (8)断下后执行命令
                  • (9)管理断点
                  • 四、保存现场和回溯
                    • (1)gdb 的快照保存
                      • (2)逆向执行
                        • (3)记录功能
                          • (4)日志信息
                            • (5)栈回溯
                            • 五、打印和单步调试
                              • (1)观察类型
                                • (2)单步跟踪
                                • 六、实用操作
                                  • (1)启动参数
                                    • (2)执行系统命令
                                      • (3)转储分析
                                        • (4)dump 内存
                                          • (5)窗口调试
                                            • (6)搜索内存:
                                              • (7)宏处理
                                                • (8)在gdb中编译和注入代码
                                                • 七、设置和显示
                                                  • (1)设置操作
                                                    • (2)显示符号
                                                    • 八、调试特定场景
                                                      • (1)调试多线程
                                                        • (2)调试fork子进程
                                                          • (3)调试信号
                                                          • 九、随机化设置
                                                          • 十、调试内核时出现“Remote 'g' packet reply is too long”问题
                                                          领券
                                                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档