【百度分享】基于内核模块的测试代码编写(二)

简介:

4. 用户空间和内核空间的交互 

  在解决了在内核空间置入可运行代码后,需要解决的是用户空间和内核空间的交互。具体来说,需要达到以下三个功能:用户空间的程序向内核空间下的程序控制,用户空间到内核空间的数据传递,内核空间到用户空间的数据传递。以下小节,都旨在利用系统提供给我们的各种接口,实现以上三个目标中的一个或几个。

4.1 printk

  printk是内核用来记录系统运行日志的方法。对于用户,可以通过dmesg命令查看近期的系统日志信息,或者直接访问/var/log/kernel 查看内核输出的所有历史log。在kernel module中调用printk是最简单的传递信息到用户空间的方法。printk函数的使用方法和用户态下的printf类似,区别是可以通过 KERN_INFO等宏输出从0-7的指定级别的log信息。常见的使用方式如下:
char myname[] = "chinacodec/n";
printk(KERN_INFO "Hello, world %s!/n", myname);

4.2 伪字符设备
  在linux中,用户对设备的操作往往被抽象为对文件的操作。利用这一特性,可以通过注册和实现伪字符设备到内核,来实现用户进程和内核空间的交互。当在用户空间执行对该伪设备的open/read/write/ioctl/mmap/release等操作时,这些被复用的系统调用就会使进程从用户态进入到内核态,从而在内核中完成事先注册的操作,当然可以包括对KAPI的调用等。

  具体方法是,首先,在kernel module中通过register_chrdev注册一种伪字符设备到内核,参数包括:设备的major号,需要和系统已有设备不冲突;设备的名称name;文件操作函数集fops。register_chrdev的定义如下:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

  其中,结构file_operations中包含一系列的函数指针,对应每种系统调用(包含read/write/open等),使用中,可以用如下的方式赋值(而不必为每一个元素都赋值),那些未显式赋值的元素被赋值为null。

static struct file_operations fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release
};

  register_chrdev一般在kernel module中的init函数中执行,当insmod这个module时,设备就被注册到内核中。然后,用户就可以通过mknod命令可以创建对应的字符设备文件。然后通过open/write/read/ioctl/mmap/release等系统调用以访问设备文件的方式,访问该设备。每种调用都会执行到在注册设备时注册的对应的文件操作函数。此外,对应于register_chrdev,从内核卸载该伪设备驱动的函数为 unregister_chrdev。

  以ioctl为例,当以上面的file_operations注册了伪字符设备后,当用户对伪设备文件执行ioctl后,调用会进入内核态,执行 device_ioctl函数。如果我们在自定义的device_ioctl函数中去调用KAPI,就实现了用户进程对KAPI的访问。

4.3 普通文件读写  

内核态中,可以完成对用户文件系统任意文件的访问。因此,可以在内核态将要输出的信息写入文件,写入后用户态程序直接读取文件就可以完成从内核空间向用户空间的数据传递。但是在内核态下,对文件进行访问的调用函数和用户态下的系统调用有所区别。通常的使用方法是通过filp_open打开文件,然后利用获得的文件指针得到文件操作函数,以读取和写入文件,基本代码如下:
tmp _filp = filp_open(dst_file_name, O_RDWR | O_CREAT, 00);

tmp _copied = dst_filp->f_op->write(tmp_filep, buffer, size, offset);

tmp _len = dst_filp->f_op->read(tmp _filep, buffer, size, offset);

  因为是在内核中对文件操作,所以为了通过系统调用中对缓冲区内存地址参数的检查,需要修改检查允许范围。方法是在read或write操作前通过set_fs扩大允许空间,操作后再通过setfs恢复到此前的允许范围,具体方法是:

orig_fs = get_fs();
set_fs(KERNEL_DS);
//write or read
set_fs(orig_fs);

4.4 Proc文件系统

  proc文件系统,是当前内核或内核模块,和用户交互的主要方式,它通过将虚拟的文件系统挂载在/proc下,利用虚拟文件读写在用户和内核态间传递信息。通过内核模块,可以向/proc下注册新的文件,指定用户读写该文件时的回调函数;这样,当用户读写该文件时,工作在内核态的回调函数就可以执行信息交互的有关工作。

  向内核中注册/proc下文件的调用是create_proc_entry,创建中需要指定文件名,访问权限和父节点名,返回为指向 proc_dir_entry结构的指针。通过该返回指针,可以进一步修改文件的用户id,组id,绑定的内核数据等;但最为关键的是可以指定用户读或写该文件时,在内核中被执行的回调函数。下面是一个向proc文件系统中注册新文件的示例:

static int __init proc_module_init(void){
entry = create_proc_entry("astring", 0644, myprocroot);
if (entry) {
entry->data = &string_var;
entry->read_proc = &string_read_proc;
entry->write_proc = &string_write_proc;
}
return 0
}
static void __exit procfs_exam_exit(void){
remove_proc_entry("astring", myprocroot);
remove_proc_entry("myproctest", NULL);
}
//read proc
int string_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data){
count = sprintf(page, "%s", (char *)data);
return count;
}
//write proc
int string_write_proc(struct file *file, const char __user *buffer,
unsigned long count, void *data){
if (count > STR_MAX_SIZE) {
count = 255;
}
copy_from_user(data, buffer, count);
return count;

 












本文转自百度技术51CTO博客,原文链接:http://blog.51cto.com/baidutech/744382 ,如需转载请自行联系原作者
相关文章
|
4月前
|
测试技术 开发者 Python
Python单元测试入门:3个核心断言方法,帮你快速定位代码bug
本文介绍Python单元测试基础,详解`unittest`框架中的三大核心断言方法:`assertEqual`验证值相等,`assertTrue`和`assertFalse`判断条件真假。通过实例演示其用法,帮助开发者自动化检测代码逻辑,提升测试效率与可靠性。
437 1
|
5月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
559 0
|
3月前
|
安全 Java 测试技术
《深入理解Spring》单元测试——高质量代码的守护神
Spring测试框架提供全面的单元与集成测试支持,通过`@SpringBootTest`、`@WebMvcTest`等注解实现分层测试,结合Mockito、Testcontainers和Jacoco,保障代码质量,提升开发效率与系统稳定性。
|
4月前
|
人工智能 边缘计算 搜索推荐
AI产品测试学习路径全解析:从业务场景到代码实践
本文深入解析AI测试的核心技能与学习路径,涵盖业务理解、模型指标计算与性能测试三大阶段,助力掌握分类、推荐系统、计算机视觉等多场景测试方法,提升AI产品质量保障能力。
|
6月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
232 0
|
7月前
|
测试技术 Go 开发者
如何为 gRPC Server 编写本地测试代码
本文介绍了如何使用 Go 语言中的 gRPC 测试工具 **bufconn**,通过内存连接实现 gRPC Server 的本地测试,避免端口冲突和外部依赖。结合示例代码,讲解了初始化内存监听、自定义拨号器及编写测试用例的完整流程,并借助断言库提升测试可读性与准确性。适用于单元及集成测试,助力高效开发。
164 1
|
9月前
|
存储 jenkins 测试技术
Apipost自动化测试:零代码!3步搞定!
传统手动测试耗时低效且易遗漏,全球Top 10科技公司中90%已转向自动化测试。Apipost无需代码,三步实现全流程自动化测试,支持小白快速上手。功能涵盖接口测试、性能压测与数据驱动,并提供动态数据提取、CICD集成等优势,助力高效测试全场景覆盖。通过拖拽编排、一键CLI生成,无缝对接Jenkins、GitHub Actions,提升测试效率与准确性。
785 11
|
9月前
|
人工智能 自然语言处理 测试技术
自然语言生成代码一键搞定!Codex CLI:OpenAI开源终端AI编程助手,代码重构+测试全自动
Codex CLI是OpenAI推出的轻量级AI编程智能体,基于自然语言指令帮助开发者高效生成代码、执行文件操作和进行版本控制,支持代码生成、重构、测试及数据库迁移等功能。
2061 0
自然语言生成代码一键搞定!Codex CLI:OpenAI开源终端AI编程助手,代码重构+测试全自动
|
9月前
|
数据采集 移动开发 算法
【硬件测试】基于FPGA的QPSK调制+软解调系统开发与硬件片内测试,包含信道模块,误码统计模块,可设置SNR
本文基于FPGA实现QPSK调制与软解调系统,包含Testbench、高斯信道、误码率统计模块,并支持不同SNR设置。硬件版本新增ILA在线数据采集和VIO在线SNR设置功能,提供无水印完整代码及测试结果。通过VIO分别设置SNR为6dB和12dB,验证系统性能。配套操作视频便于用户快速上手。 理论部分详细解析QPSK调制原理及其软解调实现过程,涵盖信号采样、相位估计、判决与解调等关键步骤。软解调通过概率估计(如最大似然法)提高抗噪能力,核心公式为*d = d_hat / P(d_hat|r[n])*,需考虑噪声对信号点分布的影响。 附Verilog核心程序代码及注释,助力理解与开发。
310 5