For low-level iOS/Mac developers, the best way to explore the xNU kernel implementation is to debug the source code and track its implementation. Therefore, it is necessary to debug the XNU kernel. This article mainly combs the process of setting up the kernel debugging environment to start the year

An overview of the

Apple provides a kernel debugging protocolKDP(Kernel Debug Protocol)To support remote debugging, the protocol is based onUDPThe protocol allows the debugger to send commands to the kernel and receive returned results and exception notifications. This article will be based on the latest system versionOS X10.15.6, to build a kernel debugging environment to track the kernel process, the specific kernel version is as follows:

The preparatory work

Debugging the kernel will inevitably cause panic. Therefore, the best way is to run the system on a VIRTUAL machine (VM) that supports snapshot management to facilitate environment saving. Commonly used VMWare and Paralles, but the author uses Paralles to build the environment process there are some problems (will be explained later), so, it is recommended to use VMWare to install the system.

Installing a VM

You can download the latest version of the MacOS image from the App Store. The specific installation process is not described here, please Google it.

Download the toolkit and install it

Kit includes LLDB + KDK (Kernel Debug Kit), including KDK download address: developer.apple.com/download/mo… The specific version to be downloaded must meet the requirements of the latest system version. You can run the following command to view the system version

sw_vers |grep BuildVersion
Copy the code

As shown in the figure below:Or view it by “System Report -> Software”, as shown in the picture below:However, the official website did not find a fully matched version, but it has been verified that you can use the latest tool package, the specific version is:Kernel Debug Kit 10.15.6 build 19G73.

The debugging tool package must be installed to debug hosts and VMS. After the installation is complete in the/Library/Developer/KDKs/KDK_10. 15.6 _19G73. KDK/System/Library/Kernels directory to see the kernel binary files, Xcode debug symbols. DSYM, as well as the kernel. Develo Pment kernel debugging file.

downloadxnuThe source code

Run the uname -v command to check that the version 10.15.6 is XNU-6153.141.1. Therefore, download the corresponding source code from apple for subsequent debugging of the XNU source code.

Shut down the SIP

When debugging hosts and VMS, disable SIP system integrity protection as follows:

  • The system starts quicklyCommand+RUntil the Apple icon appears;
  • Open the utility’s terminal and typecsrutil disableTo disable and restart the system;

After the system restarts, it can passcsrutil statusCheck the closed status. The correct status is as follows:

debugging

The kernel to replace

The vm needs to assign the kernel debugging version in the KDK installation directory to /System/Library/Kernels:

Cp/Library/Developer/KDKs/KDK_10. 15.6 _19G73. KDK/System/Library/Kernels/kernel development/System/Library/KernelsCopy the code

However,CatalinaAfter the version, the hard disk is divided into the read-only part and the data part. Because the kernel directory is in the read-only directory, you need to change the file permissionsudo chmodIt can’t be modified. It can be passedmountTool to temporarily change the permission (the permission will be restored after the restart), as follows:

sudo mount -uw /
Copy the code

Set the NVRAM boot parameter boot-args

To set the VM to debug mode, run the following command to set boot-args using nvRAM

nvram boot-args="debug=0x141 kext-dev-mode=1 kcsuffix=development pmuflags=1 -v"
Copy the code

NVRAM: Error setting variable – ‘boot-args’; (iokit/ Common) General Error: Attempts to set recovery mode are invalid.

The following figure shows the debugging bits

For details, see the Building and Debugging Kernels

  • debug=0x145, including0x01Because the system will wait for the debugger to mount after startup,0x04Is triggered by a keyNMI (Non-Maskable Interrupt)Unmasked interrupts are used to trigger the debug state so that it can be entered at any time. But the default VM group bond to trigger unmasked interrupts asCommand-Option-Control-Shift-EscapeIt’s too long. You can go throughVMWareAs shown in the figure below:

  • kext-dev-mode=1Allowed to load unsignedkext
  • kcsuffix=developmentSpecifies to load the copy abovekernel.development
  • pmuflags=1Turn off the watchdog timer
  • -vThe kernel loading information is displayed

Network configuration pits:

  • If you are using FireWire cables through the physical FireWire port (on older Mac machines), see Debugging macOS Kernel For Fun
  • If the VM is configured with two nics, for examplehost-onlyAnd the defaultNAT, it needs to passkdp_match_nameOption to specify the nic mode, seeMac kernel extension development

Clear the Kext cache

The command is as follows:

sudo kextcache -invalidate /
Copy the code

Let the virtual machine systemkext cacheNo, use the new kernel to debug and restart the system, and you will enter debug mode, as shown below:

LLDB mounting debugging

Debug host start LLDB and set goals for kernel debugging in KDK the directory file/Library/Developer/KDKs/KDK_10. 15.6 _19G73. KDK/System/Library/Kernels/kernel. The development, As follows:

$lldb(LLDB) target the create/Library/Developer/KDKs/KDK_10 _19G73. 15.6 KDK/System/Library/Kernels/kernel developmentCopy the code

If you encounter the following problems:

Execute the following commands as prompted:

command script import "/ Library/Developer/KDKs/KDK_10. 15.6 _19G73. KDK/System/Library/Kernels/kernel development. The dSYM/Contents/Resources/Python / kernel.py"
Copy the code

The following error is encountered:instructionspythonThe version is wrong. It needs to be changedpython 2, enter the following command as prompted:

defaults write com.apple.dt.lldb DefaultPythonVersion 2
Copy the code

Note: This command is not executed in LLDB

The successes are as follows:

Connecting to a VM

Kdp-remote XXX // XXX indicates the IP address of the VMCopy the code

After success, it is shown as the picture below:

xnuThe source code to debug

Debugging, LLDB will go/Library/Caches/com. Apple. XBS/Sources/xnu (without the directory is created) corresponding to the version of the directory to find the kernel source xnu – XXX, so put this directory can download the source of support in front of the xnu source code debugging.

In actual combat

Trace application crash throwMachException conversion toSignalSignal flow, specificMachThe process of exception and signal conversion is as follows:

Test code is as follows:

#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>

#define BUF_LEN 1024

static void sig_int(int signo) {
    printf("handler signo:%d \n", signo);
}

int main(int argc, char **argv) {
    char buf[BUF_LEN] = {0};
    // Process the signal
    // The CTRL + C process terminates
    if (signal(SIGINT, sig_int) == SIG_ERR) {
        printf("signal error:%s \n", strerror(errno));
    }

	// A hardware exception is generated
    intptr_t *ptr = NULL;
    *ptr = 1;

    return 0;
}

Copy the code

throughbreakpoint set -n xxxSet the kernel functions that require breakpoints, as shown below:

The function call stack looks like this:

We can work togetherxnuSource code to further trace the invocation process, such asthreadsignalThe function is shown in the figure below:

The detailed call process is not detailed here, mainly is clear how to trace xNU source code implementation process through kernel debugging.