有时候在做linux内核编程的时候会遇到内核模块使用一个内核符号symbolA,在编译的时候会遇到warning:
WARNING: "symbolA" [/home/sina/Debug/network/network-shell1/net.ko] undefined!
can't insmod xx.ko :unknown symbol in module or invalid parameter
通过内核源代码发现原来没有对内核符号 symbolA 调用 EXPORT_SYMBOL。
此时可以使用函数指针,在 /proc/kallsyms 找到内核的地址。
具体源代码如下:
int readline(char *buf,struct file *file) { static char total[512]; static int rest; char temp[128]; int len,i,cnt,count; cnt = 0; for (i = 0;i < rest;i ++ ){ if(total[i] == '\n'){ cnt ++; /// 精确的定位 /proc/kallsyms 中每条项目的地址。 break; } } if(cnt == 0){ /// 这里需要使用临时缓冲区来模拟一个seek操作 count = file->f_op->read(file, temp, sizeof(temp), &file->f_pos); if(count == 0) return 0; strncpy(total+rest,temp,count); rest += count; } len = 0; while( temp[len ] = total[len ] ){ len ++; if(total[len] == '\n') break; } temp[len] = '\n'; buf[0]='\n'; strncpy(buf+1,temp,len+1); buf[len+2] = '\0'; rest -= len+1; for (i = 0;i < rest ;i ++){ total[i] = total[i+len+1]; } return 1; } unsigned int find_kernel_symbol(char *symbol_name, char *search_file) { mm_segment_t old_fs; ssize_t bytes; struct file *file = NULL; <span style="white-space:pre"> </span>char read_buf[500]; char *p, tmp[20]; <span style="white-space:pre"> </span>unsigned int addr = 0; int i = 0; file = filp_open(search_file, O_RDONLY, 0); if (!file) return -1; if (!file->f_op->read)<span style="white-space:pre"> </span>/// ÊÇ·ñÓÐ read º¯Êý¡£ return -1; old_fs = get_fs(); /// 内核态用户态数据交换。 set_fs(get_ds());<span style="white-space:pre"> </span> /// 这里设置 fs ,kernel_read <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>while ( readline(read_buf ,file ) ){ <span style="white-space:pre"> </span>p = strstr(read_buf, symbol_name); <span style="white-space:pre"> </span>if((p != NULL) && (*(p - 1) == ' ') && ( *(p + strlen(symbol_name)) == 0xa) ) {<span style="white-space:pre"> </span>/// <span style="white-space:pre"> </span>printk("the char is:0x%x\n",*(p + strlen(symbol_name))); <span style="white-space:pre"> </span>printk("the func is:%s\n",read_buf); while (*p--) if (*p == '\n') break; <span style="white-space:pre"> </span>i = 0; while ( (tmp[i ++] = (*++ p) ) != ' '); tmp[--i] = '\0'; addr = simple_strtoul(tmp, NULL, 16); break; } } filp_close(file,NULL); <span style="white-space:pre"> </span>set_fs(old_fs); return addr; }
需要查找内核符号地址的时候可以通过 find_kernel_symbol(char *symbol_name, char *search_file)
其中 symbol_name 是符号文件,search_file 是需要寻找的文件。