1.GDB调试1.1GDB简介
GDB(GNU调试器)是一个功能强悍的、跨平台的源代码调试器。它支持多种编程语言(如C、C++、Go等)和许多处理器构架。GDB准许开发人员对程序执行进行深入了解,以查找并修补错误。GDB调试环境一般包括以下组件:
GDB调试器:这是GDB的核心组件,它与目标程序进行交互,控制程序的执行,并搜集关于程序状态的信息。您须要依照目标处理器构架(比如ARM、x86、MIPS等)安装合适的GDB版本。
目标程序:您希望调试的程序。在我们之前的事例中,这是TF-A(TrustedFirmware-A)。确保目标程序是使用调试信息编译的,这样GDB能够获取有关源代码和符号的详尽信息。
调试服务器:在个别情况下,我们须要一个调试服务器与目标程序进行通讯。比如,在远程调试或使用QEMU进行硬件仿真。当前我们计划让QEMU充当调试服务器,使用GDB联接到它以控制目标程序。
源代码和符号:为了便捷调试,我们须要访问目标程序的源代码和符号。这种信息包含在目标程序的ELF文件中。在我们当前的事例中,就是TF-A源代码经过编译生成的bl31.elf文件。
终端/控制台:用于与GDB进行交互的界面。我们可以使用命令行终端中运行GDB,或则使用支持GDB的集成开发环境(IDE)。
1.2设置GDB调试环境
要设置GDB调试环境,请根据以下步骤操作:
sudo apt-get update
sudo apt-get install gdb-multiarch
1.3常用的GDB命令
如今,您的GDB调试环境已打算就绪。您可以使用GDB的各类功能,比如,设置断点、单步执行、检查和更改变量、寄存器和显存等,以调试目标程序。通过熟练把握这种命令,您可以更有效地使用GDB调试环境找到并解决程序中的问题。以下是一些常用的GDB调试命令:
GDB断点命令
使用break命令在特定的源代码行或函数上设置断点。
breakmain.c:42
breakmy_function
断点命令:break,也可以缩写为b
某一行进行打断点(第3行):b3;
多个文件,对某个文件的某一行打断点:bdemo.c:4,表示对demo.c文件4行打断点;
对函数打断点:bfun,表示对fun()函数打断点
多个文件,对某个函数打断点:bdemo.c:fun;查询所有断点:infob
查询第n个断点:infobnbdemo.c:8ifValue=10delete,缩写d删掉某个断点n为断点号:deletebreakn
删掉设在n行的断点(多个文件与打断点一样):clearn
en/enable启用某个断点
dis/disable禁用某个断点
下边是相关命令以及对应的作用说明:
break[file]:function在文件file的function函数入口设置断点
break[file]:line在文件file的第line行设置断点
infobreakpoints查看断点列表
break[±]offset在当前位置偏斜量为[±]offset处设置断点
break*addr在地址addr处设置断点
break…ifexpr设置条件断点,仅仅在条件满足时
ignorencount接出来对于编号为n的断点忽视count次
clear删掉所有断点
clearfunction删掉所有坐落function内的断点
deleten删掉指定编号的断点
enablen启用指定编号的断点
disablen禁用指定编号的断点
savebreakpointsfile保存断点信息到指定文件
sourcefile导出文件中保存的断点信息
break在下一个指令处设置断点
clear[file:]line删掉第line行的断点GDB监视点使用watch命令在特定变量或显存地址上设置监视点。当变量或显存地址的值发生修改时,程序将停止执行。
watchmy_variableGDB控制执行run:启动程序执行
continue:从当前断点处继续执行
next:执行下一行源代码(不步入函数)
step:执行下一行源代码(步入函数)
finish:继续执行,直至当前函数返回
quit命令退出GDBnext,缩写为n,一条一条简单句子执行step,缩写slinux 关机命令,若在某个函数断点处qemu调试linux内核,则步入此函数步入下一个断点,或继续运行
命令:continue,缩写c退出步入的函数
但是复印函数返回时的堆栈地址和返回值及参数值等信息,回到上一层调用函数在一个循环体内单步跟踪时,这个命令可以运行程序直至退出循环体,可缩写为u
until+行号运行至某行
call+行数+(参数)调用程序中可见的函数雨林木风linux,并传递参数
如:callgdb_test(66)GDB的复印和输出
一般情况下,在调试的过程中,我们须要查看某个变量的值,以剖析其是否符合预期,这个时侯就须要复印输出变量值。
info命令可以查看很多信息
info all-registers --Dump所有寄存器的信息
info threads -- Display currently known threads.
info register
info register TTBR0_EL1
查看变量
whatisvariable查看变量的类型
ptypevariable查看变量详尽的类型信息
infovariablesvar查看定义该变量的文件,不支持局部变量检测变量和寄存器:使用print命令查看变量和寄存器的值。
printmy_variable
print$rax
如复印TTBR0_EL1寄存器的值
(gdb) p /x $TTBR0_EL1
$5 = 0x418b6000
更改变量
更改变量和寄存器:使用set命令更改变量和寄存器的值。
setmy_variable=42
set$rax=0xdeadbeef
使用x命令来复印显存的值,格式为x/nfuaddr,以f格式复印从addr开始的n个宽度单元为u的显存值。
n:输出单元的个数
f:输出格式,如x表示以16补码输出,o表示以8补码输出,默认为x
u:一个单元的宽度,b表示1个byte,h表示2个byte(halfword),w表示4个byte,g表示8个byte(giantword)
x/8xbarray以16补码复印链表array的前8个byte的值
x/8xwarray以16补码复印链表array的前16个word的值使用x命令检测显存。比如,要检测以16补码表示的地址0x1000处的4个字(32位),可以执行:
x/4x0x1000
更改显存:使用set命令更改显存。比如,要将以16补码表示的地址0x1000处的一个字设置为0xdeadbeef,可以执行:
set*(unsignedint*)0x1000=0xdeadbeef
使用x/s命令复印ASCII字符串,若果是宽字符字符串,须要先看宽字符的宽度printsizeof(str)。
假如厚度为2,则使用x/hs复印;假如厚度为4,则使用x/ws复印。
x/sstr复印字符串
setprintelements0复印不限制字符串宽度/或不限制字段宽度
callprintf("%sn",xxx)这时复印出的字符串不会富含多余的通配符符
printf“%sn”,xxx同上print*array@10复印从字段开头连续10个元素的值
printarray[60]@10复印array字段下标从60开始的10个元素,即第60~69个元素
setprintarray-indexeson复印链表元素时,同时复印字段的下标printptr查看该表针指向的类型及表针地址
print*(structxxx*)ptr查看指向的结构体的内容GDB程序栈查看当程序崩溃可以使用,where命令,查看死在哪个位置。
bt,查看函数栈
f/frame切换到当前调用线程的指定堆栈
f2步入第2栈
backtrace[n]复印栈帧
frame[n]选择第n个栈帧,假若不存在,则复印当前栈帧
upn选择当前栈帧编号+n的栈帧
downn选择当前栈帧编号-n的栈帧
infoframe[addr]描述当前选择的栈帧
infoargs当前栈帧的参数列表
infolocals当前栈帧的局部变量GDB图形化查看
tui为terminaluserinterface的简写,在启动时侯指定-tui参数,或则调试时使用ctrl+x+a组合键,可步入或退出图形化界面。
layoutsrc显示源码窗口
layoutasm显示汇编窗口
layoutsplit显示源码+汇编窗口
layoutregs显示寄存器+源码或汇编窗口
winheightsrc+5源码窗口高度降低5行
winheightasm-5汇编窗口高度降低5行
winheightcmd+5控制台窗口高度降低5行
winheightregs-5寄存器窗口高度降低5行
查看源码:list(l),默认显示10行l函数名l字段
GDB查看汇编
disassemblefunction查看函数的汇编代码
disassemble/mrfunction同时比较函数源代码和汇编代码
GDB查看线程
ithreads查看所有线程
tnum步入num线程
thread查当前线程
thread2切换到第二个线程
参考GDB调试-从入门实践到原理_高性能构架探求的博客-CSDN博客
参考GDB调试_深深生生的博客-CSDN博客
2.QEMUgdb调试环境搭建2.1配置内核
打开kerneldebug的内核配置选项CONFIG_DEBUG_INFO=y,而且重新编译内核
2.2编译配置busybox
见busybox章节
2.3qemu启动内核gdb调试
qemu-system-aarch64
-machine virt,virtualization=true,gic-version=3
-m size=1024M
-cpu cortex-a72
-smp 4
-kernel ./Image
-initrd rootfs.img
--append "nokaslr console=ttyAMA0"
-nographic
-s
-S
-gdb tcp::1234
启动qemu后挂起
加上-s和-S后,qemu启动会挂起,此时在另外个终端输入gdb-multiarchvmlinux,启动gdb并加载内核符号表
targetremotelocalhost:1234联接到gdb的窃听端口
添加断点start_kernel后qemu调试linux内核,按c执行程序,命中断点
3.QEMUGDB调试汇编代码
在gdb窗口输入layoutasm打开汇编窗口,但是输入stepi或si单步调试