七、基础 | linux内核调试

环境

在坑里很久,用的64位的ubuntu桌面版,一直出问题,很烦,最后换成32位的了,最后发现,问题出在cp /boot/config-xxxx .config上,不要执行!!不要执行!!直接make defconfig然后make menuconfig,不要cp!!!

QEMU+GDB+busybox

QEMU

sudo apt-get install qemu

busybox

源码下载

busybox的作用就是生成一个简单的根文件系统

下载源码后执行:

make defconfig
make menuconfig

设置下配置,采用静态编译的方式,否则程序运行期间会动态加载库文件。

-> Busybox Setting -> Build Options
[*] Build BusyBox as a static binary (no shared libs)

保存后可以再确认下,出现的是CONFIG_STATIC=y则没什么问题了

cat .config| grep STATIC

接着就开始编译安装

make
make install

文件都会生成到_install文件夹下,后面的内容借鉴下QEMU+gdb调试Linux内核全过程,生成initramfs.img留备用

内核

内核的编译主要得开启CONFIG_DEBUG_INFO(有CONFIG_GDB_SCRIPTS就也开启,没有就算)

Kernel hacking -->
  [*] Kernel debug
  [*] Compile the kernel with debug info


Kernel hacking -->

  [*] compile the kernel with frame pointers


Kernel hacking -->
  [*] KGDB: kernel debugging with remote gdb

这样可以看一下.config中是否为CONFIG_DEBUG_INFO=yCONFIG_FRAME_POINTER=y,之后编译安装内核,会用到生成的arch/x86_64/boot/bzImage

要注意只设置上面两个,其余全都不选择,否则会出现断点没拦截的情况,也可以尝试取消Write protect kernel read-only data structures这个选项,不过没有实验过,还有b start_kernel的问题,这个参照下硬件断点

调试

GEF插件

执行命令先把内核运行起来:

qemu-system-i386 -kernel /usr/src/linux-2.6.32.1/arch/x86/boot/bzImage -initrd initramfs.img -S -s

挂起状态等待gdb连接,端口是默认的1234 然后开启gdb连接,到编译的内核文件目录下执行:

gdb vmlinux
(gdb)target remote:1234
(gdb)b cmdline_proc_show   //下个测试断点
(gdb)c

此时在qemu中执行cat /proc/cmdline即可看到断点信息

VMware+gdb双机调试

这个调试方式比qemu更实用,上面一样的,调试配置都打开,然后可能还涉及一个CONFIG_DEBUG_RODATA,低版本可能是CONFIG_DEBUG_RODATA_TEST的关闭,不然你的断点没有用。

生成内核镜像后,复制到宿主机的相同路径下,开启GDB:

(gdb)>file vmlinux
(gdb)>target remote localhost:8864

修改要调试的虚拟机的配置文件

vim /tools/centos7/CentOS7/CentOS7.vmx

然后添加如下内容:

debugStub.listen.guest64 = "TRUE"
debugStub.listen.guest64.remote = "TRUE"
debugStub.hideBreakpoints = "FALSE"
monitor.debugOnStartGuest64 = "TRUE"

接着就按照正常的调试方式下断点调试就行,可以先看看b start_kernel,但是会存在编译优化的问题,导致断点断错位,因此要降低编译优化,修改Makefile

ifeq ($(DEBUG),y)
    DEBFLAGS = -O -g3 -DSBULL_DEBUG
else
    DEBFLAGS = -O0
endif
EXTRA_CFLAGS += $(DEBFLAGS)

最后就是随机化的问题,kernel加载到内存后起始地址随机化,因此调试地址和真实地址不太相同,会导致断点失败,所以需要禁用随机化kaslr。 然而内核编译优化的问题依然没有得到解决,在-O0的情况下内核无法编译通过,因为kernel本身的设计思想中就包含了编译优化的假想,这就导致不优化的情况下大量底层汇编代码根本无法编译通过,那么只能通过__attribute__((optimize("O0")))修饰函数来跳过优化了,不过这个方法我没有去尝试,不过编译时候好像有报错,最后还是用打patch的方式。

参考

#嵌入式##面经#
Linux嵌入式必考必会 文章被收录于专栏

"《Linux嵌入式必考必会》专栏,专为嵌入式开发者量身打造,聚焦Linux环境下嵌入式系统面试高频考点。涵盖基础架构、内核原理、驱动开发、系统优化等核心技能,实战案例与理论解析并重。助你快速掌握面试关键,提升竞争力。

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务