⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kallsyms.c

📁 linux 2.6.19 kernel source code before patching
💻 C
字号:
/* * kallsyms.c: in-kernel printing of symbolic oopses and stack traces. * * Rewritten and vastly simplified by Rusty Russell for in-kernel * module loader: *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation * * ChangeLog: * * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com> *      Changed the compression method from stem compression to "table lookup" *      compression (see scripts/kallsyms.c for a more complete description) */#include <linux/kallsyms.h>#include <linux/module.h>#include <linux/init.h>#include <linux/seq_file.h>#include <linux/fs.h>#include <linux/err.h>#include <linux/proc_fs.h>#include <linux/sched.h>	/* for cond_resched */#include <linux/mm.h>#include <linux/ctype.h>#include <asm/sections.h>#ifdef CONFIG_KALLSYMS_ALL#define all_var 1#else#define all_var 0#endif/* These will be re-linked against their real values during the second link stage */extern const unsigned long kallsyms_addresses[] __attribute__((weak));extern const unsigned long kallsyms_num_syms __attribute__((weak));extern const u8 kallsyms_names[] __attribute__((weak));extern const u8 kallsyms_token_table[] __attribute__((weak));extern const u16 kallsyms_token_index[] __attribute__((weak));extern const unsigned long kallsyms_markers[] __attribute__((weak));static inline int is_kernel_inittext(unsigned long addr){	if (addr >= (unsigned long)_sinittext	    && addr <= (unsigned long)_einittext)		return 1;	return 0;}static inline int is_kernel_extratext(unsigned long addr){	if (addr >= (unsigned long)_sextratext	    && addr <= (unsigned long)_eextratext)		return 1;	return 0;}static inline int is_kernel_text(unsigned long addr){	if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext)		return 1;	return in_gate_area_no_task(addr);}static inline int is_kernel(unsigned long addr){	if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end)		return 1;	return in_gate_area_no_task(addr);}static int is_ksym_addr(unsigned long addr){	if (all_var)		return is_kernel(addr);	return is_kernel_text(addr) || is_kernel_inittext(addr) ||		is_kernel_extratext(addr);}/* expand a compressed symbol data into the resulting uncompressed string,   given the offset to where the symbol is in the compressed stream */static unsigned int kallsyms_expand_symbol(unsigned int off, char *result){	int len, skipped_first = 0;	const u8 *tptr, *data;	/* get the compressed symbol length from the first symbol byte */	data = &kallsyms_names[off];	len = *data;	data++;	/* update the offset to return the offset for the next symbol on	 * the compressed stream */	off += len + 1;	/* for every byte on the compressed symbol data, copy the table	   entry for that byte */	while(len) {		tptr = &kallsyms_token_table[ kallsyms_token_index[*data] ];		data++;		len--;		while (*tptr) {			if(skipped_first) {				*result = *tptr;				result++;			} else				skipped_first = 1;			tptr++;		}	}	*result = '\0';	/* return to offset to the next symbol */	return off;}/* get symbol type information. This is encoded as a single char at the * begining of the symbol name */static char kallsyms_get_symbol_type(unsigned int off){	/* get just the first code, look it up in the token table, and return the	 * first char from this token */	return kallsyms_token_table[ kallsyms_token_index[ kallsyms_names[off+1] ] ];}/* find the offset on the compressed stream given and index in the * kallsyms array */static unsigned int get_symbol_offset(unsigned long pos){	const u8 *name;	int i;	/* use the closest marker we have. We have markers every 256 positions,	 * so that should be close enough */	name = &kallsyms_names[ kallsyms_markers[pos>>8] ];	/* sequentially scan all the symbols up to the point we're searching for.	 * Every symbol is stored in a [<len>][<len> bytes of data] format, so we	 * just need to add the len to the current pointer for every symbol we	 * wish to skip */	for(i = 0; i < (pos&0xFF); i++)		name = name + (*name) + 1;	return name - kallsyms_names;}/* Lookup the address for this symbol. Returns 0 if not found. */unsigned long kallsyms_lookup_name(const char *name){	char namebuf[KSYM_NAME_LEN+1];	unsigned long i;	unsigned int off;	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {		off = kallsyms_expand_symbol(off, namebuf);		if (strcmp(namebuf, name) == 0)			return kallsyms_addresses[i];	}	return module_kallsyms_lookup_name(name);}static unsigned long get_symbol_pos(unsigned long addr,				    unsigned long *symbolsize,				    unsigned long *offset){	unsigned long symbol_start = 0, symbol_end = 0;	unsigned long i, low, high, mid;	/* This kernel should never had been booted. */	BUG_ON(!kallsyms_addresses);	/* do a binary search on the sorted kallsyms_addresses array */	low = 0;	high = kallsyms_num_syms;	while (high - low > 1) {		mid = (low + high) / 2;		if (kallsyms_addresses[mid] <= addr)			low = mid;		else			high = mid;	}	/*	 * search for the first aliased symbol. Aliased	 * symbols are symbols with the same address	 */	while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])		--low;	symbol_start = kallsyms_addresses[low];	/* Search for next non-aliased symbol */	for (i = low + 1; i < kallsyms_num_syms; i++) {		if (kallsyms_addresses[i] > symbol_start) {			symbol_end = kallsyms_addresses[i];			break;		}	}	/* if we found no next symbol, we use the end of the section */	if (!symbol_end) {		if (is_kernel_inittext(addr))			symbol_end = (unsigned long)_einittext;		else if (all_var)			symbol_end = (unsigned long)_end;		else			symbol_end = (unsigned long)_etext;	}	if (symbolsize)		*symbolsize = symbol_end - symbol_start;	if (offset)		*offset = addr - symbol_start;	return low;}/* * Lookup an address but don't bother to find any names. */int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,				unsigned long *offset){	if (is_ksym_addr(addr))		return !!get_symbol_pos(addr, symbolsize, offset);	return !!module_address_lookup(addr, symbolsize, offset, NULL);}/* * Lookup an address * - modname is set to NULL if it's in the kernel * - we guarantee that the returned name is valid until we reschedule even if *   it resides in a module * - we also guarantee that modname will be valid until rescheduled */const char *kallsyms_lookup(unsigned long addr,			    unsigned long *symbolsize,			    unsigned long *offset,			    char **modname, char *namebuf){	const char *msym;	namebuf[KSYM_NAME_LEN] = 0;	namebuf[0] = 0;	if (is_ksym_addr(addr)) {		unsigned long pos;		pos = get_symbol_pos(addr, symbolsize, offset);		/* Grab name */		kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);		if (modname)			*modname = NULL;		return namebuf;	}	/* see if it's in a module */	msym = module_address_lookup(addr, symbolsize, offset, modname);	if (msym)		return strncpy(namebuf, msym, KSYM_NAME_LEN);	return NULL;}int lookup_symbol_name(unsigned long addr, char *symname){	symname[0] = '\0';	symname[KSYM_NAME_LEN] = '\0';	if (is_ksym_addr(addr)) {		unsigned long pos;		pos = get_symbol_pos(addr, NULL, NULL);		/* Grab name */		kallsyms_expand_symbol(get_symbol_offset(pos), symname);		return 0;	}	/* see if it's in a module */	return lookup_module_symbol_name(addr, symname);}int lookup_symbol_attrs(unsigned long addr, unsigned long *size,			unsigned long *offset, char *modname, char *name){	name[0] = '\0';	name[KSYM_NAME_LEN] = '\0';	if (is_ksym_addr(addr)) {		unsigned long pos;		pos = get_symbol_pos(addr, size, offset);		/* Grab name */		kallsyms_expand_symbol(get_symbol_offset(pos), name);		modname[0] = '\0';		return 0;	}	/* see if it's in a module */	return lookup_module_symbol_attrs(addr, size, offset, modname, name);}/* Look up a kernel symbol and return it in a text buffer. */int sprint_symbol(char *buffer, unsigned long address){	char *modname;	const char *name;	unsigned long offset, size;	char namebuf[KSYM_NAME_LEN+1];	name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);	if (!name)		return sprintf(buffer, "0x%lx", address);	else {		if (modname)			return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,				size, modname);		else			return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);	}}/* Look up a kernel symbol and print it to the kernel messages. */void __print_symbol(const char *fmt, unsigned long address){	char buffer[KSYM_SYMBOL_LEN];	sprint_symbol(buffer, address);	printk(fmt, buffer);}/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */struct kallsym_iter{	loff_t pos;	unsigned long value;	unsigned int nameoff; /* If iterating in core kernel symbols */	char type;	char name[KSYM_NAME_LEN+1];	char module_name[MODULE_NAME_LEN + 1];	int exported;};static int get_ksymbol_mod(struct kallsym_iter *iter){	if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,				&iter->type, iter->name, iter->module_name,				&iter->exported) < 0)		return 0;	return 1;}/* Returns space to next name. */static unsigned long get_ksymbol_core(struct kallsym_iter *iter){	unsigned off = iter->nameoff;	iter->module_name[0] = '\0';	iter->value = kallsyms_addresses[iter->pos];	iter->type = kallsyms_get_symbol_type(off);	off = kallsyms_expand_symbol(off, iter->name);	return off - iter->nameoff;}static void reset_iter(struct kallsym_iter *iter, loff_t new_pos){	iter->name[0] = '\0';	iter->nameoff = get_symbol_offset(new_pos);	iter->pos = new_pos;}/* Returns false if pos at or past end of file. */static int update_iter(struct kallsym_iter *iter, loff_t pos){	/* Module symbols can be accessed randomly. */	if (pos >= kallsyms_num_syms) {		iter->pos = pos;		return get_ksymbol_mod(iter);	}		/* If we're not on the desired position, reset to new position. */	if (pos != iter->pos)		reset_iter(iter, pos);	iter->nameoff += get_ksymbol_core(iter);	iter->pos++;	return 1;}static void *s_next(struct seq_file *m, void *p, loff_t *pos){	(*pos)++;	if (!update_iter(m->private, *pos))		return NULL;	return p;}static void *s_start(struct seq_file *m, loff_t *pos){	if (!update_iter(m->private, *pos))		return NULL;	return m->private;}static void s_stop(struct seq_file *m, void *p){}static int s_show(struct seq_file *m, void *p){	struct kallsym_iter *iter = m->private;	/* Some debugging symbols have no name.  Ignore them. */ 	if (!iter->name[0])		return 0;	if (iter->module_name[0]) {		char type;		/* Label it "global" if it is exported,		 * "local" if not exported. */		type = iter->exported ? toupper(iter->type) :					tolower(iter->type);		seq_printf(m, "%0*lx %c %s\t[%s]\n",			   (int)(2*sizeof(void*)),			   iter->value, type, iter->name, iter->module_name);	} else		seq_printf(m, "%0*lx %c %s\n",			   (int)(2*sizeof(void*)),			   iter->value, iter->type, iter->name);	return 0;}static const struct seq_operations kallsyms_op = {	.start = s_start,	.next = s_next,	.stop = s_stop,	.show = s_show};static int kallsyms_open(struct inode *inode, struct file *file){	/* We keep iterator in m->private, since normal case is to	 * s_start from where we left off, so we avoid doing	 * using get_symbol_offset for every symbol */	struct kallsym_iter *iter;	int ret;	iter = kmalloc(sizeof(*iter), GFP_KERNEL);	if (!iter)		return -ENOMEM;	reset_iter(iter, 0);	ret = seq_open(file, &kallsyms_op);	if (ret == 0)		((struct seq_file *)file->private_data)->private = iter;	else		kfree(iter);	return ret;}static const struct file_operations kallsyms_operations = {	.open = kallsyms_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release_private,};static int __init kallsyms_init(void){	struct proc_dir_entry *entry;	entry = create_proc_entry("kallsyms", 0444, NULL);	if (entry)		entry->proc_fops = &kallsyms_operations;	return 0;}__initcall(kallsyms_init);EXPORT_SYMBOL(__print_symbol);EXPORT_SYMBOL_GPL(sprint_symbol);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -