26

编译并vscode可视化调试Linux 4.18内核

 1 year ago
source link: https://damaoooo.github.io/2022/07/04/%E7%BC%96%E8%AF%91%E5%B9%B6vscode%E5%8F%AF%E8%A7%86%E5%8C%96%E8%B0%83%E8%AF%95Linux%204.18%E5%86%85%E6%A0%B8/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

damaoooo的blog

编译并vscode可视化调试Linux 4.18内核
发表于2022-07-04|更新于2022-07-04
阅读量:4

编译并vscode可视化调试Linux 4.18内核

1. 安装必要软件

# 安装编译依赖组件。
sudo apt install -y libncurses5-dev libssl-dev bison flex libelf-dev gcc make openssl libc6-dev
sudo apt install -y flex bison make gcc libssl-dev bc libelf-dev
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v4.x/linux-4.18.tar.gz
tar -zxf linux-4.18.tar.gz
cd linux-4.18.tar.gz

# 设置调试的编译菜单
export ARCH=x86
make x86_64_defconfig
make menuconfig

# 下面选项如果没有选上的,选上(点击空格键),然后 save 保存设置,退出 exit。
##################################################################
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

Device Drivers --->
[*] Block devices --->
<*> RAM block device support
(65536) Default RAM disk size (kbytes)

Processor type and features --->
[*] Randomize the address of the kernel image (KASLR)

Kernel hacking --->
Compile-time checks and compiler options --->
[*] Compile the kernel with debug info
[*] Provide GDB scripts for kernel debugging

Device Drivers -->
Network device support -->
<*> Universal TUN/TAP device driver support

[*] Networking support -->
Networking options -->
<*> 802.1d Ethernet Bridging

# 编译内核。
make -j8

2. 编译内核

编译内核会遇见很多问题

2.1 网络库的问题

In file included from scripts/selinux/genheaders/genheaders.c:19:
# scripts/selinux/mdp/mdp.c 也会出现这种现象
./security/selinux/include/classmap.h:249:2: error: #error New address family defined, please update secclass_map.
249 | #error New address family defined, please update secclass_map.
| ^~~~~
make[3]: *** [scripts/Makefile.host:90: scripts/selinux/genheaders/genheaders] Error 1
make[2]: *** [scripts/Makefile.build:558: scripts/selinux/genheaders] Error 2
make[1]: *** [scripts/Makefile.build:558: scripts/selinux] Error 2
make: *** [Makefile:1045: scripts] Error 2

1.找到错误中提示的.c文件,genheader.c文件和mdp.c文件编辑,去掉两个文件的头部引用中的

#include <sys/socket.h>

2.找到错误提示中的classmap.h文件
a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
编辑classmap.h,在头文件中添加

#include <linux/socket.h>

重新编译即可

2.2 连接的问题

arch/x86/entry/entry_64.S: Assembler messages:
arch/x86/entry/entry_64.S:1667: Warning: no instruction mnemonic suffix given and no register operands; using default for `sysret'
AS arch/x86/entry/thunk_64.o
arch/x86/entry/thunk_64.o: warning: objtool: missing symbol table

使用这个patch

Reported-by: Nathan Chancellor <natechancellor@xxxxxxxxx>
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
tools/objtool/elf.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index be89c741ba9a..2b0f4f52f7b5 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -380,8 +380,11 @@ static int read_symbols(struct elf *elf)

symtab = find_section_by_name(elf, ".symtab");
if (!symtab) {
- WARN("missing symbol table");
- return -1;
+ /*
+ * A missing symbol table is actually possible if it's an empty
+ * .o file. This can happen for thunk_64.o.
+ */
+ return 0;
}

symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
--
2.29.2

3. 安装修改版的gdb

# 删除 gdb
gdb -v | grep gdb
apt remove gdb -y

# 安装其它组件。
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt install software-properties-common
sudo apt-get update

# 安装高版本 gcc。
gcc --version
sudo apt install gcc-9 g++-9 -y
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 --slave /usr/bin/g++ g++ /usr/bin/g++-9
gcc --version

# 下载解压 gdb
cd /root
wget http://ftp.gnu.org/gnu/gdb/gdb-8.3.tar.gz
tar zxf gdb-8.3.tar.gz

# 修改 gdb/remote.c 代码。
cd gdb-8.3
vim gdb/remote.c
#在gdb/remote.c文件下作如下修改
/* Further sanity checks, with knowledge of the architecture. */
// if (buf_len > 2 * rsa->sizeof_g_packet)
// error (_("Remote 'g' packet reply is too long (expected %ld bytes, got %d "
// "bytes): %s"),
// rsa->sizeof_g_packet, buf_len / 2,
// rs->buf.data ());
if (buf_len > 2 * rsa->sizeof_g_packet) {
rsa->sizeof_g_packet = buf_len;
for (i = 0; i < gdbarch_num_regs (gdbarch); i++){
if (rsa->regs[i].pnum == -1)
continue;
if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
rsa->regs[i].in_g_packet = 0;
else
rsa->regs[i].in_g_packet = 1;
}
}

#编译GDB
./configure
./make -j8
# 有可能会有这个报错
# error: "Please include config.h first."
# vim ./gdb/build-gnulib/import/unistd.h
# 加入 #include "../config.h"
# 总之缺啥就在哪儿加上 #include "../config.h"
# 打开GDB,看是否为新版本

sudo apt install texinfo
sudo ./make install
# makeinfo: command not found

gdb -v

4. 安装qemu并配置qemu

sudo apt install -y qemu qemu-system-x86

制作helloworld的rootfs用于测试

touch main.c

键入以下代码

#include <stdio>
int main()
{
printf("hello world!");
printf("hello world!");
printf("hello world!");
printf("hello world!");
fflush(stdout);
while(1);
return 0;
}
gcc --static -o helloworld main.c
echo helloworld | cpio -o --format=newc > rootfs

Qemu直接运行测试(非必须)

qemu-system-x86_64 \
-kernel ./arch/x86/boot/bzImage \
-initrd ./rootfs \
-append "root=/dev/ram rdinit=/helloworld console=ttyS0" \
-nographic -serial mon:stdio

但是实践证明还是有问题,最好是来一个图形化界面

Qemu 开启GDB调试

qemu-system-x86_64  \
-kernel ./arch/x86/boot/bzImage \
-initrd ./rootfs \
-append "root=/dev/ram rdinit=/helloworld" \
-smp 2 \
-s -S \
-append nokaslr

-s= -gdb tcp:1234, 这个可以改

-S 表示进入调试模式,在这个模式下已开始CPU是冻结的,在gdb中按下c来继续

这里的root=/dev/ram 因此需要在内核里面重新编译,开启对ext2的支持

进行以上会打开Qemu并进入等待调试状态,此时可以直接gdb调试,如下(非必须)

gdb ./vmLinux
#以下进行调试
target remote:1234
b start_kernel
c

可以发现内核被断点在start_kernel函数上

5. 使用vscode远程阅读linux内核源码

首先直接打开的话会发现有很多地方没法跳转,需要安装C/C++ GNU Global

在VScode远程窗口中安装C/C++ GNU Global 这个扩展

在远程机器中

sudo apt install global

在vscode设置中,写入

{
"gnuGlobal.globalExecutable": "/usr/bin/global",
"gnuGlobal.gtagsExecutable": "/usr/bin/gtags",
"gnuGlobal.objDirPrefix": "/home/damaoooo/.global"
}

shift + command + P,然后 rebuild Gtags Data

之后就可以进行Linux源代码阅读了

如果需要debug,需要安装 GDB debug 插件,随后配置launch.json

{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "kernel-debug",
"type": "cppdbg",
"request": "launch",
"miDebuggerServerAddress": "192.168.1.114:1234",
"program": "${workspaceFolder}/vmlinux",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"logging": {
"engineLogging": false
},
"MIMode": "gdb",
}
]
}

启动qemu,就可以对内核进行调试了

但是有问题,如图所示,很多的变量会被optimized out,是因为默认编译的时候开了O2,而开O0选项,直接编译不过,需要做一些修改,我懒得改了直接单步调试看内存了。

image-20220703171844616

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK