gdb调试uboot与kernel

Posted by 婷 on September 8, 2024 本文总阅读量

简介

前提是搭建好环境,可以参考之前的链接

uboot

uboot目录下输入gdb-multiarch,而不是gdb-multiarch u-boot,因为uboot会重定位,而且之前这么操作总是有奇奇怪怪的问题

gdb-multiarch

image-20240903082818053

连接openocd内置的gdbserver,端口号是3333

target retmoe :3333

image-20240903083037836

然后uboot下输入bdinfo命令,找到重定位后的地址

image-20240804212309311

找到地址,输入下列命令,加载符号表,输入bt查看函数调用栈,这里连函数的第几行都显示出来了

add-symbol-file ~/raspi4b-project/uboot/u-boot 0x7f21000

image-20240903083256869

当然还有另外的方法,不用输入bdinfo也可以知道重定位后的地址,因为bd_info是在结构体gd_t中的,而gd_t的地址存放在x18寄存器中,所以我们偏移一下就可以算出来了

image-20240928164616799

bdinfo命令中的信息对上了

image-20240928164733715

kernel

如果想要gdb调试kernel,需要打开如下内核配置

CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_FRAME_POINTER=y

CONFIG_GDB_SCRIPTS=y
CONFIG_DEBUG_INFO_REDUCED=n

CONFIG_KGDB=y
CONFIG_RANDOMIZE_BASE=n /*非常重要*/

CONFIG_DEBUG_VM=y

以下为内核配置的说明

  • CONFIG_DEBUG_INFO: 在内核和内核模块中包含调试信息,这个选项在幕后为gcc使用的编译器参数增加了-g选项。
  • CONFIG_FRAME_POINTER:这个选项会将调用帧信息保存在寄存器或堆栈上的不同位置,使gdb在调试内核时可以更准确地构造堆栈回溯跟踪(stack back traces)。
  • 启用CONFIG_GDB_SCRIPTS,但要关闭CONFIG_DEBUG_INFO_REDUCED
  • CONFIG_KGDB:启用内置的内核调试器,该调试器允许进行远程调试。
  • 关闭CONFIG_RANDOMIZE_BASE设置:KASLR会更改引导时放置内核代码的基地址。如果你在内核配置中启用了KASLRCONFIG_RANDOMIZE_BASE=y),则无法从gdb设置断点。
  • CONFIG_DEBUG_VM

配置编译好kernel后,输入下列命令

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- scripts_gdb -j16

image-20240906232332681

执行gdb的时候,可能会有类似的报错

warning: File "/home/sammi/raspi4b-project/raspi_sdk/raspi_linux/scripts/gdb/vmlinux-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
        add-auto-load-safe-path /home/sammi/raspi4b-project/raspi_sdk/raspi_linux/scripts/gdb/vmlinux-gdb.py
line to your configuration file "/home/sammi/.gdbinit".

image-20240907163910308

那就按照提示语句add-auto-load-safe-path /home/sammi/raspi4b-project/raspi_sdk/raspi_linux/scripts/gdb/vmlinux-gdb.py加到文件/home/sammi/.gdbinit

image-20240907163832825

未使能MMU的kernel

kernel前期在汇编中的代码是没有开启MMU的,而vmlinux调试文件中都是虚拟地址,所以我们需要将.head.text,text ,rodata这三个段重新映射(为什么是这三个段等以后研究下kernel启动的汇编脚本)

输入下列命令获取三个段的虚拟地址,然后用kernel启动的基地址加上这三个段减去.head.text的地址的偏移量就是我们要重定位的地址了

readelf -S vmlinux

这里可以看出.head.text是最开始的第一个段,为什么.head.text是第一段呢?

image-20240904232731909

其实是由文件arch/arm64/kernel/vmlinux.lds.S 布局决定的

image-20240904232617155

通过虚拟地址跟kernel在ddr中的地址相减获取真实的物理地址,树莓派中kernel的启动地址是0x1000000,如下计算可以得到真实段的地址

.head.text = 0x1000000 + (ffffffc080000000 - ffffffc080000000) 
.text = 0x1000000 + (ffffffc080010000 - ffffffc080000000)
.rodata =  0x1000000 + (ffffffc080d30000 - ffffffc080000000) 

接着我们输入如下命令

gdb-multiarch vmlinux
target remote :3333
add-symbol-file vmlinux  -s .head.text 0x1000000 -s .text 0x1010000 -s .rodata 0x1d30000

image-20240904085645409

输入layout split即可快乐调试

image-20240904085726578

使能MMU的kernel

直接输入命令

gdb-mulitiarch vmlinux
target remote :3333

image-20240907165342192

调试ko

调试ko的话需要知道text段的地址,有两种方法可以查看

cat /proc/modules
cat /sys/module/general/sections/.text

image-20240907215450410

加载命令如下,注意这里用的是.o文件

add-symbol-file modules/general/general.o 0xffffffc0799a0000

image-20240907215310267

打断点如下

image-20240907215526792

如果需要调试静态符号,需要加载.bss

image-20240908135344077

image-20240908135500907

add-symbol-file modules/general/general.o 0xffffffc0799a0000 -s .bss 0xffffffc0799a2640

调试技巧

调用栈

这个比较常见的用法,通常想知道函数跑到什么位置

bt

断点

具体到某个文件的某一行

image-20240901204804330

其他用法

(gdb) b main         #到某个函数
(gdb) b *0x80483f    #在某个内存

查看断点

image-20240908131103890

删除断点

delete breakpoints N

image-20240908131707819

单指令调试

输入layout split命令可以列出srcasm两个框

image-20240903084009373

image-20240903084156019

可以用step(si)跳入调用函数并执行,next(ni)不跳入调用函数并执行

si 3 #执行三行
ni 3 #执行三行

退出图形界面可以按Ctrl+X 然后再按A

kernel专属

GDB提供了Python接口来扩展功能,内核基于Python接口实现了一系列辅助脚本,简化内核调试,开启CONFIG_GDB_SCRIPTS参数就可以使用了。内核中的文档信息如下

Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
Documentation/dev-tools/gdb-kernel-debugging.rst

输入apropos lx获取帮助信息

image-20240907220224497

dmesg

lx-dmesg

image-20240907221422203

virt2phy和virt2page

lx-virt_to_phys
lx-virt_to_page

image-20240907220533928

mount

lx-mount

就是不知道这些虚拟地址指的是哪个地方的,等以后研究文件系统的时候可以回头看看

image-20240907013245837

fdtdump

lx-fdtdump

image-20240907221351169

最后能找到当前目录下生成的fdtdump.dtb

image-20240908140212889

至于原理怎么实现还不了解

clk-tree

lx-clk
lx-clk-summary

image-20240908125942848

cmline

lx-cmdline

image-20240908130249332

其他

之前自己写的博客

参考链接

问题

目前调试使能MMU后使用虚拟地址的内核,无法打断点调试,会提示下列报错,还不清楚是什么问题

image-20240908140543280