一些内核模块API (2)

//【内核符号表】,就是在内核的内部函数或变量中,可供外部引用的函数和变量的符号表。
//其实说白了就是一个索引文件,它存在的目的就是让外部软件可以知道kernel文件内部实际分配的位置。


//给一个内存地址address,查找一个内核符号,并将该符号的基本信息,符号名name,偏移offset
//大小size,所属模块名,保存在 fmt 的%s中
void __print_symbol(const char *fmt, unsigned long address)
{
char buffer[KSYM_SYMBOL_LEN];


sprint_symbol(buffer, address);


printk(fmt, buffer);
}
static int __sprint_symbol(char *buffer,        unsigned long address,
               int   symbol_offset, int           add_offset)
{
char *modname;
const char *name;
unsigned long offset, size;
int len;


address += symbol_offset;
name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
if (!name)
return sprintf(buffer, "0x%lx", address - symbol_offset);


if (name != buffer)
strcpy(buffer, name);
len = strlen(buffer);
offset -= symbol_offset;


if (add_offset)
len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);


if (modname)
len += sprintf(buffer + len, " [%s]", modname);


return len;
}


//给一个内核符号名symbol,获得该符号的内存地址,找到其所在的内核模块,并会给该模块的引用计数
//加1
void *__symbol_get(const char *symbol)
{
struct module *owner;
const struct kernel_symbol *sym;


preempt_disable();
sym = find_symbol(symbol, &owner, NULL, true, true);
if (sym && strong_try_module_get(owner))
sym = NULL;
preempt_enable();


return sym ? (void *)sym->value : NULL;
}


//给一个内核符号名symbol,获得该符号的内存地址,找到其所在的内核模块,并会给该模块的引用计数
//减1 【此处即是内核态下,部分API成双成对的使用,有+就要有-】
void __symbol_put(const char *symbol)
{
struct module *owner;


preempt_disable();
if (!find_symbol(symbol, &owner, NULL, true, false))
BUG();
module_put(owner);
preempt_enable();
}


//给一个给定的模块名 name ,由于模块名不允许有重复,是一一对应的,所以可以通过模块名找到模块
struct module *find_module(const char *name)
{
return find_module_all(name, strlen(name), false);
}
static struct module *find_module_all(const char *name, size_t len, bool even_unformed)
{
struct module *mod;


list_for_each_entry(mod, &modules, list) {
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
continue;
if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
return mod;
}
return NULL;
}


//这个函数有点复杂,主要是通过内核名name,bool型参数gplok,warn来查找内核符号,并返回该符号
//的结构体指针。如果
const struct kernel_symbol *find_symbol(const char *name,          struct module **owner,
                    const unsigned long **crc, bool gplok, bool warn)
{
struct find_symbol_arg fsa;


fsa.name = name;
fsa.gplok = gplok;
fsa.warn = warn;


if (each_symbol_section(find_symbol_in_section, &fsa)) {
if (owner)
*owner = fsa.owner;
if (crc)
*crc = fsa.crc;
return fsa.sym;
}


pr_debug("Failed to find symbol %s\n", name);
return NULL;
}

猜你喜欢

转载自blog.csdn.net/dummkopfer/article/details/80378524