基于Openwrt + Qemu进行内核源码级调试

本文介绍了如何基于Openwrt和Qemu搭建内核源码级调试环境,详细讲解了Openwrt的编译过程、Qemu仿真Openwrt的步骤,并通过Netlink通信机制展示了自定义package和Kernel module的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于Openwrt + Qemu进行内核源码级调试

上篇文章—利用Qemu + Buildroot 进行内核源码级调试中介绍了通过Qemu + Buildroot 搭建Linux内核源码级调试,但是后面在使用,学习过程中感觉有点不方便的一点就是在Buildroot中添加自己的应用或者内核模块的时候,添加应用相对来说算比较简单方便的,但是添加内核模块的时候,由于Buildroot的根目录下面的make menuconfig选项中没有针对Kernel modules的选项, 相对来说Openwrt中增加自己的应用和内核模块相对比较方便,所以这里首先针对Openwrt + Qemu 搭建内核源码级调试环境,然后通过对Linux内核中Netlink通信机制的简单学习,实现一个简单应用程序和一个简单的内核模块,最后简单介绍往Openwrt中添加自己的应用程序和内核模块的方法。

一、Openwrt编译

1. 下载Openwrt源码

git clone https://github.com/openwrt/openwrt.git

2. 下载安装拓展包

$ ./scripts/feeds update -a
$ ./scripts/feeds install -a

3. 配置环境

我PC系统是Centos7,下面是预装的可能缺少的工具和库
sudo yum -y install gcc binutils patch bzip2 flex bison make autoconf gettext texinfo unzip sharutils libncurses5-dev ncurses-term zlib1g-dev wget perl-Thread-Queue openssl-devel zlib-static ncurses-devel gcc-c++
可能所列出的不全,可以在后面根据运行make menuconfig的时候出现的报错所显示的内容对应的再去一一的安装。

4. 编译

运行如下命令:

$ make menuconfig

图1
将会出现如上图所示的对话框,进行编译选项配置,我直接选择的x86平台,其他先默认配置,后续根据自己的需求可以增加删除软件包,修改配置选项。然后保存配置直接编译。

$ make V=s

二、通过Qemu仿真Openwt

现在qemu对Openwrt的支持很好,通过如下命令既可以直接运行Openwrt生成的固件。

qemu-system-x86_64 -m 5120 -smp 4 -M pc -drive file=openwrt-x86-64-combined-ext4.img,if=none,id=openwrtdisk –device ich9-ahci,id=ahci -device ide-drive,drive=openwrtdisk,bus=ahci.0 -net nic,vlan=0,macaddr=52:54:00:AF:53:81,model=virtio -net user,vlan=0 -redir tcp:10023::23 -redir tcp:10080::80 –localtime

可能默认编译出来是没有这个文件openwrt-x86-64-combined-ext4.img,要修改编译选项,取消“GZip images”选项,即不通过gzip打包,如下图所示。
图2
图3
上图串口打印还是一样熟悉的配方。为方便调试,可修改网络配置为自动分配。可直接修改Openwrt根目录下target/linux/x86/base-files/etc/config/network文件按照如下方式修改即可。
图4
可以通过在主机上Telnet到虚拟机进行操作,这样比较方便,当然也可以通过ssh,自己调试学习用,没考虑安全所以直接选择Telnet,因为在启动qemu-system-x86_64的时候已经把虚拟机的23端口直接映射到主机10023端口,所以可以通过如下方式来访问:
图5
同样通过访问主机的10080端口,可以访问虚拟机的80端口,如下图所示:
图6
为方便调试,可以在主机上配置httpd服务,然后在虚拟机就可以通过wget来进行操作,如下图所示:
图7
这样就不用每次编译都重启虚拟机。

三、Netlink通信机制

Netlink是linux提供的用于内核和用户态进程之间的通信方式。但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式,一般不用Netlink。除非需要用到Netlink的广播特性时。
一般来说用户空间和内核空间的通信方式有三种:/proc、ioctl、Netlink。而前两种都是单向的,但是Netlink可以实现双工通信。
Netlink协议基于BSD socket和AF_NETLINK地址簇(address family),使用32位的端口号寻址(以前称作PID),每个Netlink协议(或称作总线,man手册中则称之为netlink family),通常与一个或一组内核服务/组件相关联,如NETLINK_ROUTE用于获取和设置路由与链路信息、NETLINK_KOBJECT_UEVENT用于内核向用户空间的udev进程发送通知等。netlink具有以下特点:
① 支持全双工、异步通信(当然同步也支持)
② 用户空间可使用标准的BSD socket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)
③ 在内核空间使用专用的内核API接口
④ 支持多播(因此支持“总线”式通信,可实现消息订阅)
⑤ 在内核端可用于进程上下文与中断上下文

下面是一个简单的例子(例子摘自网上,自己修改了一点错误,主要在于理解Netlink通讯的机制)
客户端代码:

#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include <errno.h>


#define MAX_PAYLOAD  1024 // maximum payload size
#define NETLINK_TEST 25    //自定义的协议

int main(int argc, char* argv[])
{
    int state;
    struct sockaddr_nl src_addr, dest_addr;
    struct nlmsghdr *nlh = NULL; //Netlink数据包头
    struct iovec iov;
    struct msghdr msg;
    int sock_fd, retval;
    int state_smg = 0;
    // Create a socket
    sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if(sock_fd == -1){
        printf("error getting socket: %s", strerror(errno));
        return -1;
    }
    // To prepare binding
    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = 100; //A:设置源端端口号
    src_addr.nl_groups = 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值