Linux源码编译、调试和阅读

下载内核源码

下载 Linux 官方 Git 仓库:

git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
# or: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

(可选)增添开发版本的远程分支

cd linux
git remote add linux-next https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
# or: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
git fetch linux-next
git fetch --tags linux-next

编译启动内核

安装工具链

与平台无关的:

sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison

与平台相关的:

sudo apt install gcc-aarch64-linux-gnu

编译配置

使用默认配置

在Linux源码目录下,执行配置程序,如下:

make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" defconfig

其中

  • defconfigdefault configuration 的意思
  • ARCH表示交叉编译的硬件架构,实际上就是arch目录下的子目录名称。在Linux中,ARM64 就是 arm64,而不是 aarch64
  • CROSS_COMPILE会拼接到 gcc,即${CROSS_COMPILE}gcc,上面的结果是 aarch64-linux-gnu-gcc

如果想输出到其它目录中,可以加O=/path/to/output-dir,然后下面的操作切换到对应的输出目录中执行,这样便将Linux源码和编译结果分离,可以在不同目录下生成不同平台的内核镜像。示例:

make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" O=/home/yuanyin/syslab/arm64-linux/linux defconfig 

!!!下文假设是在/home/yuanyin/syslab/arm64-linux/linux目录下执行编译。

配置调试信息

解决一些配置依赖的问题:

make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" menuconfig

(1)添加调试信息:
打开 DEBUG_INFO 对应选项。根据工具链决定那一项就好了。

Kernel hacking
	Compile-time checks and compiler options
		Debug information

image.png
(2)关闭RANDOMIZE_BASE
取消地址随机化:关掉RANDOMIZE_BASE选项,对应的prompt是:Randomize the address of the kernel image。

-> Processor type and features   // -> Kernel features     │
	-> Build a relocatable kernel
     [] Randomize the address of the kernel image (KASLR)

保存退出!!!

执行编译

使用 bear工具生成 compile_commands.json文件(JSON Compilation Database),用于代码分析。

sudo apt install bear

make clean # if compiled
bear -- make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" -j $(nproc)

最后会生成:

  • 包含编译参数的 compile_commands.json文件
  • 内核镜像arch/arm64/boot/Image
  • 带调试信息的镜像vmlinux
  • 符号到地址的映射System.map
yuanyin@zyynote:~/syslab/arm64-linux/linux$ ls
arch   crypto   include  kernel    mm                       modules-only.symvers  net       sound       usr      vmlinux.o
block  drivers  init     lib       modules.builtin          modules.order         scripts   source      virt     vmlinux.symvers
certs  fs       ipc      Makefile  modules.builtin.modinfo  Module.symvers        security  System.map  vmlinux

制作文件系统

请移步 制作 Linux 根文件系统,那里有详细介绍如何简单地制作一个根文件系统。

QEMU启动内核镜像

安装对应平台的QEMU

例如安装AARCH64平台的QEMU,执行下面安装:

sudo apt install qemu-system-arm

启动脚本:

qemu-system-aarch64 -machine virt -cpu cortex-a53 \
        -machine type=virt -nographic -smp 2 \
        -m 2048 \
        -kernel linux/arch/arm64/boot/Image \
        --append "console=ttyAMA0 root=/dev/vda init=/linuxrc rw" \
        -hda rootfs.ext2

其中 rootfs.ext2是ext2文件系统格式的硬盘,-hda表示硬盘。--append后面加入的是传递给内核的命令,console=ttyAMA0表示控制台输出设备,ARM64架构这里是ttyAMA0root就是跟文件系统所在的磁盘分区,而init就是Linux启动的第一个程序所在位置,可以自由定义。

注意:在 x86 中是 "console=ttyS0 root=/dev/sda init=/linuxrc rw"

调试方法

注意:首先要在启动脚本中加入-s -S选项。可以直接使用GDB命令行进行调试,也可以使用VS Code提供的图形界面进行调试。

方式一:命令行调试

安装gdb-multiarch支持跨平台调试:

sudo apt-get intall gdb-multiarch

然后执行gdb-multiarch,进入GDB界面。
执行如下连接QEMU:

set architecture aarch64
target remote localhost:1234

在 GDB 交互界面中导入调试信息:

file /path/to/vmlinux

方式二:使用 VS Code 调试和阅读

配置启动文件

.vscode/launch.json文件配置如下:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "arm64-linux debug",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/../arm64-linux/linux/vmlinux",
      "args": [],
      "stopAtEntry": true,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb-multiarch",
      "targetArchitecture": "arm64",
      "miDebuggerServerAddress": "127.0.0.1:1234",
    }
  ]
}

配置C/C++属性文件

用于阅读源码:增加 compile_commands.json配置项,如下:

{
  "configurations": [
    {
      "name": "Linux",
      "forcedInclude": [],
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "gnu11",
      "intelliSenseMode": "linux-gcc-x64",
      "compileCommands": "${workspaceFolder}/../arm64-linux/linux/compile_commands.json"
    }
  ],
  "version": 4
}

注意:符号定义跳转的时候可能会比较卡。

网络配置

User mode networking

image.png
缺点:不允许从外面连接进来,不推荐。

TAP interfaces

!!!不需要操作,直接看综合配置小节。

查看当前工作主机的路由表,可以看到
(1)所有Destination为0.0.0.0这一项,表示所有的IP都通过网卡eth0到网关172.18.144.1去。
(2)所有符合IP为172.18.144.0掩码 255.255.240.0的报文无效,参考链接
匹配的时候以匹配最长的IP字段为准。

$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.144.1    0.0.0.0         UG    0      0        0 eth0
172.18.144.0    0.0.0.0         255.255.240.0   U     0      0        0 eth0

(1)打开主机的转发功能

先查看主机是否转发报文:

 $ cat /proc/sys/net/ipv4/ip_forward
0
# 或者

$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0

开启主机的转发功能:

sudo sysctl net.ipv4.ip_forward=1

(2)创建虚拟交换机

$ sudo ip link add zyybr0 type bridge
$ sudo ip link set zyybr0 up
# or
# brctl addbr zyybr0 (deprecated)
# ifconfig zyybr0 up

给交换机分配地址:

$ sudo ifconfig zyybr0 192.168.1.1/24

使用主机转发交换机内容

$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

(3)创建交换机网口

$ sudo ip tuntap add zyytap0 mode tap
$ sudo ip link set dev zyytap0 up
# or tunctl command (deprecated)

将网口和交换机绑定

$ sudo ip link set zyytap0 master zyybr0

(4)QEMU配置

...
-netdev tap,id=zyynet0,script=no,downscript=no,ifname=zyytap0 \
-device virtio-net-device,netdev=zyynet0 \
...

(5)配置客户端系统

ifconfig eth0 192.168.1.20
route add default gw 192.168.1.1

配置DNS服务器

# cat /etc/resolv.conf
nameserver 8.8.8.8

综合配置

QEMU启动脚本

sh ifup.sh

qemu-system-aarch64 -machine virt -cpu cortex-a53 \
        -machine type=virt -nographic -smp 2 \
        -m 2048 \
        -kernel linux/arch/arm64/boot/Image \
        --append "console=ttyAMA0 root=/dev/vda init=/linuxrc rw" \
        -netdev tap,id=zyynet0,script=no,downscript=no,ifname=zyytap0 \
        -device virtio-net-device,netdev=zyynet0 \
        -hda rootfs.ext2

sh ifdown.sh

先执行启动脚本

sudo sysctl net.ipv4.ip_forward=1 > /dev/null

sudo ip link add zyybr0 type bridge
sudo ip link set zyybr0 up

sudo ip tuntap add zyytap0 mode tap
sudo ip link set dev zyytap0 up

sudo ip link set zyytap0 master zyybr0

sudo ifconfig zyybr0 192.168.1.1/24
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

在根文件系统的/etc/init.d/rcS或者其它配置文件中加入:

ifconfig eth0 192.168.1.20
route add default gw 192.168.1.1

echo "nameserver 8.8.8.8" > /etc/resolv.conf

关掉qemu后执行

sudo iptables -t nat --flush

sudo ip addr flush dev zyybr0

sudo ip link set dev zyytap0 down
sudo ip tuntap del zyytap0 mode tap

sudo ip link set zyybr0 down
sudo ip link del dev zyybr0 type bridge

sudo sysctl net.ipv4.ip_forward=0 > /dev/null

参考:

posted @   爱吃饭的胖胖熊  阅读(824)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示