提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
内核版本:5.10
内核模块调试时候会遇到当前编译的linux内核没有导出一个函数而不能使用这个函数,比如删除文件的 do_unlinkat 函数,如何在模块中使用内核没有导出的函数呢,下面介绍下模块中使用内核没有导出的函数的方法。
提示:以下是本篇文章正文内容,下面案例可供参考
一、模块中使用内核没有导出的函数
1,查看内核函数在当前内核的地址
可以通过查看 /proc/kallsyms 节点找内核函数地址
cat /proc/kallsyms | grep do_unlinkat
或者内核编译完后会生成System.map文件,这个文件包含也是函数的地址,也可以使用,需要注意使用和当前系统配套的system.map
2,查看内核的这个函数定义,将这个地址转成函数指针然后使用
内核定义:
struct filename *
getname_kernel(const char * filename)
long do_unlinkat(int dfd, struct filename *name)
模块定义示例:
typedef struct filename* (getname_kernel_func_t)(char);
getname_kernel_func_t getname_kernel_ptr = (getname_kernel_func_t)0xffffffffb534f7a0;
typedef long (do_unlinkat_func_t)(int , struct filename);
do_unlinkat_func_t do_unlinkat_ptr = (do_unlinkat_func_t)0xffffffffb5351760;
内核中有函数可以通过地址或者函数名相互获取,但是通过函数名称获取地址的函数没有导出
int lookup_symbol_name(unsigned long addr, char *symname) //未导出
int sprint_symbol(char *buffer, unsigned long address)
{
return __sprint_symbol(buffer, address, 0, 1);
}
EXPORT_SYMBOL_GPL(sprint_symbol);
二、代码示例
使用代码前,需要将定义大的函数地址换成 当前电脑上的函数的内核地址(章节一有说明),否则可能出现异常
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sysfs.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/binfmts.h>
#include <linux/kallsyms.h>
#define DEVICE_NAME "mychardev"
#define CLASS_NAME "mychardev_class"
static dev_t dev_num; // 设备号
static struct cdev my_cdev; // cdev 结构体
static struct class *my_class; // 设备类
static struct device * my_device;
#define BUFFER_SIZE 1024 // 定义缓冲区大小
ssize_t open_read_close_file(const char *path)
{
struct file *filp;
char *buffer;
ssize_t bytes_read;
int err;
// 分配缓冲区以存储读取的数据
buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
if (!buffer) {
return -ENOMEM; // 内存分配失败
}
// 使用 vfs_open 打开文件
filp = filp_open(path, O_RDWR | O_CREAT, 0644);
if (IS_ERR(filp)) {
kfree(buffer); // 释放缓冲区
return -1;
}
// 从文件读取数据
bytes_read = kernel_read(filp, buffer, BUFFER_SIZE - 1, &filp->f_pos);
if (bytes_read >= 0) {
buffer[bytes_read] = '\0'; // 确保字符串结束符
printk(KERN_INFO "Read from file: %s\n", buffer); // 打印读取的内容
} else