有的时候只需要简单调用下别的kernel函数
或者别的模块函数没有export,而你又不想单独编译kernel重新下载的时候
或者动态去修改某个驱动的寄存器值。
首先看下效果及使用步骤:
加入kernel ,更多时候是驱动中有以下函数:
ssize_t justfortest0() { printk(KERN_ERR"[anycall] successful....justfortest 000\r\n"); return 0; } ssize_t justfortest1(int i) { printk(KERN_ERR"[anycall] successful....justfortest 111 value is %d \r\n",i); return 0; } ssize_t justfortest2(int i, int j) { printk(KERN_ERR"[anycall] successful....justfortest 222 value is %d ,%d \r\n",i,j); return 0; }
我只需要在shell 中输入:
echo "^justfortest2:1,7788,#" > /sys/kernel/debug/anycall
log 输入如下:
内核即会去执行函数:justfortest2 (参数是1 及7788)
输入字符串的协议如下:
^address:1,2,3,4,# (objdump -S vmlinux 可以通过函数名得到函数地址,注意这里输入函数地址必须是: 0X......格式)
或 ^func_name:1,2,3,4,# (func_name是你执行的函数名)
看下此内核模块:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/kprobes.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/wait.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> #include <linux/mtd/nand_ecc.h> #include <linux/dma-mapping.h> #include <linux/jiffies.h> #include <linux/platform_device.h> #include <linux/proc_fs.h> #include <linux/time.h> #include <linux/debugfs.h> #include <linux/module.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <linux/kallsyms.h> #if 0 protocol: echo "^justfortest1:1,#" > /sys/kernel/debug/anycall echo "^justfortest1:1#" > /sys/kernel/debug/anycall echo "^justfortest2:1,7788,#" > /sys/kernel/debug/anycall step: make TARGET_PRODUCT=jrdhz75_gb2 SUBDIRS=./samples/ifs modules insmod ifs.ko rmmod ifs lsmod #endif typedef char (*my_f_0)(); typedef char (*my_f_1)(int); typedef char (*my_f_2)(int,int); typedef char (*my_f_3)(int,int,int); typedef char (*my_f_4)(int,int,int,int); #define PRINT_ADDR(index) printk(KERN_ERR"func: %s address is :%p\r\n","hello"#index,hello_##index) #define define_func(index) my_f_##index pfun_##index #define select_func(index) pfun_##index #define select_func_define(index) my_f_##index define_func(0); define_func(1); define_func(2); define_func(3); define_func(4); int atoi(const char *s); static int runAny( char * buf) { int i=1; unsigned char * tempBuf; unsigned char * addr; unsigned char addrLen; unsigned long sum=0; unsigned int temp=0; unsigned char * para; unsigned char * myPara[4]={0x00,0x00,0x00,0x00}; unsigned int myPara_i[4]; unsigned char paraCount; // the input format like this : ^address:1,2,3,4,# // tempBuf=buf; if(*tempBuf!='^') { printk(KERN_ERR"[anycall]bad begin char is %02x and should be %02x \r\n",*tempBuf,'^'); return -1; } printk(KERN_ERR"[anycall] begin with ^ is right \r\n"); addr=++tempBuf; printk(KERN_ERR"[anycall]addr is %02x %02x %02x\r\n",addr[0],addr[1],addr[2]); char name[256]={0x00}; for(i=0;*tempBuf!=':';i++) { name[i]=*tempBuf; addrLen++; tempBuf++; } // 判断输入的是函数名或者直接是函数的绝对地址 if(addr[0]=='0' && (addr[1]=='x' || addr[1]=='X') ) { //get func addr addr=addr+2; //added for 0xaddress printk(KERN_ERR"[anycall]addrLen is %d \r\n",addrLen); for(i=0;i<addrLen;i++) { unsigned int ii=addr[addrLen-1-i]; // this is key!! if(ii>='0' && ii <='9') { ii=ii-'0'; } else if(ii>='a' && ii <='f') { ii=ii-'a'+10; } ii=ii<<(4*i); sum=ii+sum; } } else { // get func name printk(KERN_ERR"[anycall]get func name and name is %s\r\n",name); // 通过函数名,得到函数的地址 sum=(unsigned long)kallsyms_lookup_name(name); } printk(KERN_ERR"[anycall] finaly func addr is :%08x\r\n",sum); ////////////////////////////////////////////////////////////////////////////////// //get the func parameters //unsigned char * myPara[4]; // 获取函数的参数 para=++tempBuf; for(paraCount=0;*tempBuf!='#' && paraCount<4 ;) { if(*tempBuf==',') { *tempBuf=0X00; tempBuf++; myPara[paraCount]=para; para=tempBuf; paraCount++; continue; } tempBuf++; } // debug parameters for(i=0;i<(sizeof(myPara)/sizeof(myPara[0]));i++) { if(!myPara[i]) { break; } printk(KERN_ERR"[anycall]para %d is %s \r\n",i,myPara[i]); myPara_i[i]=atoi(myPara[i]); printk(KERN_ERR"[anycall]para %d int is %d \r\n",i,myPara_i[i]); } //////////////////////////////////////////////////// // 调用不同参数个数,目前最多只支持4个参数,且都是INT类型 switch(paraCount) { case 0: printk(KERN_ERR"[anycall]pfun_0.....\r\n"); pfun_0=(my_f_0)sum; pfun_0(); break; case 1: printk(KERN_ERR"[anycall]pfun_1.....\r\n"); pfun_1=(my_f_1)sum; pfun_1(myPara_i[0]); break; case 2: printk(KERN_ERR"[anycall]pfun_2.....\r\n"); pfun_2=(my_f_2)sum; pfun_2(myPara_i[0],myPara_i[1]); break; case 3: printk(KERN_ERR"[anycall]pfun_3.....\r\n"); pfun_3=(my_f_2)sum; pfun_3(myPara_i[0],myPara_i[1],myPara_i[2]); break; case 4: printk(KERN_ERR"[anycall]pfun_4.....\r\n"); pfun_4=(my_f_4)sum; pfun_4(myPara_i[0],myPara_i[1],myPara_i[2],myPara_i[3]); break; } return 0; } // copy from preloader int atoi(const char *s) { unsigned val=0; /* value we're accumulating */ int neg=0; /* set to true if we see a minus sign */ while (*s==' ' || *s=='\t') { s++; } if (*s=='-') { neg=1; s++; } else if (*s=='+') { s++; } while (*s) { unsigned digit; digit = (*s - '0'); val = val*10 + digit; s++; } if (neg) { return -val; } return val; } static ssize_t anycall_write(struct file *file, const char __user *user_buf, size_t size, loff_t *ppos) { char buf[64]; int buf_size; int ret=0; buf_size = min(size, (sizeof(buf) - 1)); //user拷贝数据到kernel if (strncpy_from_user(buf, user_buf, buf_size) < 0) return -EFAULT; buf[buf_size] = 0; if (ret < 0) return ret; // 逻辑处理 runAny(buf); return size; } static const struct file_operations anycall_fops = { .owner = THIS_MODULE, .write = anycall_write, }; static int __init anycall_init(void) { struct dentry *dentry; //创建debugfs文件节点 //你可以在 /sys/kernel/debug/cancall 找到它 dentry = debugfs_create_file("anycall", S_IRUGO, NULL, NULL, &anycall_fops); printk(KERN_ERR "[anycall]install anycall !!!!\n");; return 0; } static void __exit anycall_exit(void) { printk(KERN_ERR "[anycall]remove anycall !!!!\n"); } module_init(anycall_init) module_exit(anycall_exit) MODULE_LICENSE("GPL");
在简单介绍下使用步骤:
1 编译上述模块
加入上述模块名字为 : anycall.c
放在 kernel/drivers/char/anycall
kernel/drivers/char/anycall/下的makefile 中添加 : obj-m +=anycall.c
2 kernel/drivers/char/ 下makefile 中添加 : obj-m += anycall/ (注意反斜杠的意思代表目录的意思,千万不能少)
3 insmod anycall.ko
good luck !
需要完整模块代码,可以给我留邮箱地址:)