Configure VSCode to track and debug the Linux kernel startup process

Configure VSCode

  1. Install the VSCode plugins C/C++ Intellisense and C/C++ Themes. Since the plug-in C/C++ Intellisense requires GNU Global, you also need to install GNUGlobal using the following command.

sudo apt install global
  1. Modify the .vscode configuration item, refer to

https://github.com/mengning/linuxkernel/tree/master/src/kerneldebuging,

  1. Since the Linux kernel is highly customized, there is no way to make Intellisense prompt normally by configuring includePath, etc. Here, a Python script is used to generate the compile_commands.json file to help Intellisense prompt normally (including header files and macro definitions, etc.). Run the following command directly in the Linux source code directory to generate compile_commands.json.

python ./scripts/gen_compile_commands.py

Install development tools

sudo apt install build-essential
 
sudo apt install qemu # install QEMU# as a virtual machine
 
sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev

Download kernel source code

Here it is recommended to go directly to the website to download, there will be some problems with axel

sudo apt install axel
axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
xz -d linux-5.4.34.tar.xz
tar -xvf linux-5.4.34.tar
cd linux-5.4.34

Configure kernel options

make defconfig # Default configuration is based on 'x86_64_defconfig'
make menuconfig

Enter the following interface

Configure as follows

Kernel hacking --->
    Compile-time checks and compiler options --->
        [*] Compile the kernel with debug info
        [*] Provide GDB scripts for kernel debugging
 [*] Kernel debugging
# Turn off KASLR (random address), otherwise the breakpoint will fail. In this way, the debugger can trace the source code. The reason why the random address is set is to prevent hacker attacks:
Processor type and features ---->
    [ ] Randomize the address of the kernel image (KASLR)

Compile and run the kernel

make -j$(nproc) # nproc gives the number of CPU cores/threads available
qemu-system-x86_64-kernel arch/x86/boot/bzImage

Kernel panics eventually due to no filesystem

Note: Here you need to comment out my_start_kernel() in the code, otherwise the system will get stuck at this step and will not execute it later

Make a memory root file system

  1. download source code

axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1
  1. compile and install

make menuconfig
make -j$(nproc) & amp; & amp; make install

Note that it should be compiled into a static link instead of a dynamic link library

Settings --->
    [*] Build static binary (no shared libs)
  1. Make a memory root file system image

mkdir rootfs
cd rootfs
cp ../busybox-1.31.1/_install/* ./ -rf
mkdir dev proc sys home
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
  1. Prepare the init script file and put it in the root file system and directory (rootfs/init), add the following content to the init file (note that the execution permission is added to the script)

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Wellcome MengningOS!"
echo "--------------------"
cd home
/bin/sh
  1. Packaged into a memory root file system image

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz 
  1. Test to mount the root file system to see if the init script is executed after the kernel boot is complete

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

If the execution is successful, it will display as follows

Trace debugging

(After doing this step, I found that there was a problem with Ubuntu22 debugging, and it was replaced by Ubuntu18 later)

  1. Put a breakpoint at start_kernel and start debugging

  1. Process number 0 is created here

  1. After process 0 is created, it is the kernel initialization work, continue to skip. start_kernel will perform some initialization operations, including initializing various important data structures, drivers, interrupt handlers, etc., and establish some necessary core data structures, such as physical memory manager, virtual memory manager, and process scheduler, etc. , until the last remaining initialization function

  1. You can enter the function to see

  1. There is another layer inside, enter and you can see that the kernel generates the first real process here (pid=1)

  1. After rest_init is executed, start_kernel is all completed

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS introductory skill tree Introduction to LinuxFirst acquaintance with Linux28824 people are studying systematically