Software Institute of Chinese University of Science and Technology linux _la3–Building of Linux kernel debugging environment based on VS Code and start_kernel tracking analysis

Directory

1. Install development tools

2. Download the kernel source code

3. Configure kernel options

4. Compile and run the kernel

5. Make the root file system

6.gdb debugging

7. Configure vscode to debug the linux kernel

8. Trace debugging


1. Install development tools

The environment used in this experiment is ubuntu22.04. I encountered many pits and recorded some of them.

First download some 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

2. Download kernel source code

sudo apt install axel
 
axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
 
#Download the source code package

xz -d linux-5.4.34.tar.xz
 
tar -xvf linux-5.4.34.tar #Decompress the source code
 
cd linux-5.4.34

3. Configure kernel options

Here, if you configure directly according to the teacher’s instructions, the following bug will appear when compiling the kernel:

The query shows that it is because the version of the compilation tool of ubuntu22.04 is too high, and some things in the kernel are considered inappropriate. There are many solutions given on the Internet, but downgrading the compilation chain will cause other problems, or change according to mykernel. Compilation options (but when making the root file directory later, it will happen that init cannot be found, and I don’t know how to solve it). The last thing used here is to modify the kernel source code. This bug can be solved by shielding this error. Modify the following code:

Configure kernel options:

make defconfig # Default configuration is based on 'x86_64_defconfig'
make menuconfig# open debug related options

Modify the following configuration inside:

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)

4. Compile and run the kernel

make -j$(nproc) # nproc gives the number of CPU cores/threads available
# Test whether the kernel can be loaded and run normally, because there will be a kernel panic without a file system
qemu-system-x86_64-kernel arch/x86/boot/bzImage

Compilation is successful and the following results appear:

If there is no root file directory, an error will be reported

5. Make root file system

First download the busybox source code from https://www.busybox.net and decompress it. After the decompression is complete, configure, compile and install it like the kernel.

If you follow the teacher’s instructions, you will get an error:

Here you can use the patch method: busybox compilation error undefined reference to `stime make: *** [Makefile:716: busybox_unstripped] Error 1_o_alpha’s blog-CSDN Blog

Just apply a patch, here is to download the next version instead, which is simpler, the operation is as follows:

axel -n 20 https://busybox.net/downloads/busybox-1.32.0.tar.bz2 #Here changed from 31.1 to 32.0
 
tar -jxvf busybox-1.32.0.tar.bz2
 
cd busybox-1.32.0

Compile and run:

make menuconfig
#Remember to compile it into a static link instead of a dynamic link library. 

Then compile and install:

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

Then use busybox to make the root file directory:

mkdir rootfs
 
cd rootfs
 
cp ../busybox-1.32.0/_install/* ./ -rf
 
mkdir dev proc sys home
 
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

Then also need to create an init file. The content is as follows:

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo “Welcome YouYouOS!”
echo “——————–“
cd home
/bin/sh

Next, add executable permission to the script and package the root directory file:

chmod +x init
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

Run it to see the effect:

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

6.gdb debugging

implement:

qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s
#Where -S means Stopped, -s provides a debug port tcp:1234 for gdb. 

Open another terminal:

gdb vmlinux

Then you can debug with gdb

(gdb) target remote:1234 //This is to establish a connection through the previously reserved tcp:1234
(gdb) b start_kernel //This is the first breakpoint set
c

7. Configure vscode to debug linux kernel

After installing vscode on the official website, you need to install the following:

sudo apt install global

Install the extension:

Enter the command line at the kernel file:

python ./scripts/gen_compile_commands.py

You also need to create a .vscode configuration file, which contains the configuration file on this URL:

linuxkernel/src/kerneldebug at master · mengning/linuxkernel · GitHub

Among them, this place depends on where you put the file. If it is the previous command executed, it should be in the kernel file directory.

8. Trace debugging

Because the starting point of the linux kernel is the “start_kernel” function, first break the point at start_kernel: click the run and debug icon, and add a function breakpoint in the breakpoint: start_kernel

The result is a bug:

I really don’t know what the bug is here, it’s been executing, but no results, but since the gdb debugging is correct, there is a high probability that it’s a plug-in problem with vscode. ).

The final solution:

After executing qemu in the terminal, then run at the break point in vscode (by coincidence)

Here we see that process 0 init_task is set as the first process of the whole system (process 0 is created manually, other processes are created by process 0). When the kernel is booted, init_task will be created and started, it is all The starting point for other processes.

Continue to skip, start_kernel will continue to perform some initialization operations, including initializing various important data structures, drivers, interrupt handlers, etc. At this stage, the kernel will establish some necessary core data structures, such as physical memory manager, virtual memory manager, and process scheduler.

Finally, the end of start_kernel is arch_call_reset_init(). The definition of this function is to execute the reset_init() function and enter the reset_init function. This function is executed by process 0.

After entering the function, I saw kernel_init, that is, process No. 1. It is the ancestor of all user processes. It is created by the kernel_thread function. The kernel_thread function creates a new kernel thread (actually, linux does not support threads, so it is a kernel process). The entry of this thread The address is the kernel_init() function.

Next is the creation of No. 2 process, No. 2 process is the ancestor of all kernel processes, kernel_thread creates No. 2 process, and the function executed by the process is kthreadd: Tagged , , , , , , , , , , , , , , , , ,