linux内核断点调试入门

2020-05-18 16:27:48 浏览数 (1)

上篇文章 编译一个默认输出hello world的linux内核 中,我们已经知道如何编译一个可以自运行的linux内核,这篇文章我们来看下如何对内核进行断点调试。

1. 还是先进入内核目录,执行下面的命令,确保内核代码是干净的。

代码语言:javascript复制
$ make mrproper

2. 执行以下命令,开始对内核进行配置。

代码语言:javascript复制
$ make nconfig

3. 选中以下选项,对应选项的路径及意义如下图所示。

4. 保存上述配置后,按照上一篇文章中的方法,将我们写的hello world程序设置为内核默认使用的init程序。

代码语言:javascript复制

$ git status -s
 M usr/default_cpio_list
?? a.out
?? hello.c

$ git -P diff usr/default_cpio_list
diff --git a/usr/default_cpio_list b/usr/default_cpio_list
index 37b3864066e8..9c6b452d4c44 100644
--- a/usr/default_cpio_list
    b/usr/default_cpio_list
@@ -4,3  4,4 @@
 dir /dev 0755 0 0
 nod /dev/console 0600 0 0 c 5 1
 dir /root 0700 0 0
 file /init ./a.out 755 0 0
 No newline at end of file

$ cat hello.c
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  printf("hello world!n");
  sleep(1000);
  return 0;
}

5. 编译内核。

代码语言:javascript复制

$ make -j4
省略部分输出
Kernel: arch/x86/boot/bzImage is ready  (#1)

6. 内核编译完毕后,执行下面命令,设置方便内核调试的一些gdb脚本(如果之前执行过该命令,则不用重复执行)。

代码语言:javascript复制
$ echo "add-auto-load-safe-path $(pwd)/vmlinux-gdb.py" >> ~/.gdbinit

7. 至此,准备工作都已就绪,执行下面的命令,在qemu中运行内核,并使其处于等待调试状态。

代码语言:javascript复制
$ qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -nographic -append "console=ttyS0 nokaslr" -s -S

8. 打开另一个终端,启动gdb。

代码语言:javascript复制
$ gdb vmlinux
省略部分输出
Reading symbols from vmlinux...
(gdb)

9. 在gdb环境下,执行下面的命令,连接qemu中启动的内核。

代码语言:javascript复制
(gdb) target remote :1234
Remote debugging using :1234
0x000000000000fff0 in exception_stacks ()

10. 设置断点并使内核执行到断点处。

代码语言:javascript复制

(gdb) b start_kernel
Breakpoint 1 at 0xffffffff829e0aa8: file init/main.c, line 786.
(gdb) c
Continuing.

Breakpoint 1, start_kernel () at init/main.c:786
786  {

11. 查看堆栈信息。

代码语言:javascript复制

(gdb) bt
#0  start_kernel () at init/main.c:786
#1  0xffffffff810000e6 in secondary_startup_64 () at arch/x86/kernel/head_64.S:242
#2  0x0000000000000000 in ?? ()

12. 随便执行一些命令。

代码语言:javascript复制

(gdb) n
790    set_task_stack_end_magic(&init_task);
(gdb) n
791    smp_setup_processor_id();
(gdb) n
794    cgroup_init_early();
(gdb) n
796    local_irq_disable();
(gdb) n
797    early_boot_irqs_disabled = true;

13. 放开断点,让内核继续执行。

代码语言:javascript复制

(gdb) c
Continuing.

14. 此时在另一个终端,内核最终输出了hello world。

代码语言:javascript复制
[    2.048714] Run /init as init process
hello world!
[    2.452502] tsc: Refined TSC clocksource calibration: 2904.013 MHz

以上就是linux内核调试的大致流程,有问题欢迎讨论。


参考资料:

https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-debugging.html

http://nickdesaulniers.github.io/blog/2018/10/24/booting-a-custom-linux-kernel-in-qemu-and-debugging-it-with-gdb/

0 人点赞