Lab3: VS Code-based Linux kernel debugging environment construction and start_kernel tracking analysis

Article directory

  • Compile the kernel
  • make root file
  • Use gdb to debug
  • Configure vscode debugging
  • reference article

Compile the kernel

  1. 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
  1. Decompress the source code: tar -xvf linux-5.4.34.tar
  2. Configure the kernel
make defconfig # Default configuration is based on 'x86_64_defconfig'
make menuconfig# Open debug related options
 Kernel hacking --->

  Compile-time checks and compiler options --->

   [*] Compile the kernel with debug info
   
   [*] Provide GDB scripts for kernel debugging
   
 [*] Kernel debugging

#Close 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)
  1. Compile 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

start kernel

Make root file

  1. Upload busybox-1.32.0.tar.bz2
  2. Decompression: tar -jxvf busybox-1.32.0.tar.bz2
  3. cut directory
  4. Configuration file: make menuconfig

Settings ->
[*] Build static binary (no shared libs) static compilation

  1. Compile and install: make -j6 & amp; & amp; make install
  2. Make a memory root file image:
  • File Directory
cd /home/song/workdir/linux-5.4.34

mkdir rootfs
 
cd rootfs
 
cp /home/song/workdir/busybox-1.32.0/_install/* ./ -rf
 
mkdir dev proc sys home
 
sudo cp -a /dev/{<!-- -->null,console,tty,tty1,tty2,tty3,tty4} dev/
  • Prepare init file
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Welcome Songlw'OS!"
echo "--------------------"
cd home
/bin/sh
  • Add permissions: chmod + x init
  • Packaged into a mirror file: find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz
  • implement
cd /home/song/workdir/linux-5.4.34
qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd rootfs.cpio.gz

Execute the init file and output Welcome Songlw’OS!

Use gdb to debug

  1. 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.
  1. Open another terminal and enter the command: gdb vmlinux
  2. Perform gdb debugging:

(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, bt, list, next, step… //Check the gdb command for details

Configure VScode debugging

  1. Install VScode

  2. Install plug-ins: plug-ins C/C ++ Intellisense and C/C ++ Themes, GDB Debug, also need to use the following command to install GNU Global. sudo apt install global.

  3. Execute the command in the Linux directory: python3 ./scripts/gen_compile_commands.py to generate a compile_commands.json file to help Intellisense prompt normally (including header files and macro definitions, etc.).

  4. Open the linux-5.4.34 folder
    !](https://img-blog.csdnimg.cn/073114e03dbe4d559c9d61ee93d89d37.png#pic_center)

  5. configuration.vscode

  6. start debugging

  • start_kernel. We saw that process 0 init_task is set as the first process of the entire system (process 0 is created manually, and other processes are created by process 0). When the kernel is booted, init_task will be created and started. It is all other The starting point of the process. 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. The end of start_kernel is arch_call_reset_init(). The definition of this function is to execute the reset_init() function, so we set a function breakpoint “reset_init”.

  • reset_init: Called kernel_thread to create a new kernel thread

  • kernel_thread creates a new kernel thread and finds that the kernel_thread function creates a process through the _do_fork function.

  • The _do_fork function mainly completes calling copy_process() to copy the parent process, calling wake_up_new_task to add the child process to the ready queue to wait for scheduling execution, etc.

  • kernel_init: Run the kernel_init() function in a new thread (process), click on the kernel_init() function, you can see that the run_init_process function is called in this. There are three ifs in total, the first two click on ramdisk_execute_command and execute_command

ramdisk_execute_command can be specified in environment variables via uboot. execute_command is also a global char pointer variable, and the value can also be passed through u-boot.

So if these two have no value, try to jump to /sbin/init, /etc/init, /bin/init, /bin/sh in order to start the init program in user space. The run_init_process function uses the do_execve function
![v

Reference article

  1. https://blog.csdn.net/double113217/article/details/129614177
  2. Course PPT