1048 lines · 24.9 KB · C
RawDownload
	}	vpr_info("processed %d queries, with %d matches, %d errs\n",		 i, nfound, errs); 	if (exitcode)		return exitcode;	return nfound;} #define PREFIX_SIZE 64 static int remaining(int wrote){	if (PREFIX_SIZE - wrote > 0)		return PREFIX_SIZE - wrote;	return 0;} static char *dynamic_emit_prefix(const struct _ddebug *desc, char *buf){	int pos_after_tid;	int pos = 0; 	pos += snprintf(buf + pos, remaining(pos), "%s", KERN_DEBUG);	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {		if (in_interrupt())			pos += snprintf(buf + pos, remaining(pos), "%s ",						"<intr>");		else			pos += snprintf(buf + pos, remaining(pos), "[%d] ",						task_pid_vnr(current));	}	pos_after_tid = pos;	if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)		pos += snprintf(buf + pos, remaining(pos), "%s:",					desc->modname);	if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)		pos += snprintf(buf + pos, remaining(pos), "%s:",					desc->function);	if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)		pos += snprintf(buf + pos, remaining(pos), "%d:",					desc->lineno);	if (pos - pos_after_tid)		pos += snprintf(buf + pos, remaining(pos), " ");	if (pos >= PREFIX_SIZE)		buf[PREFIX_SIZE - 1] = '\0'; 	return buf;} int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...){	va_list args;	int res;	struct va_format vaf;	char buf[PREFIX_SIZE]; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt);	vaf.fmt = fmt;	vaf.va = &args;	res = printk("%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);	va_end(args); 	return res;}EXPORT_SYMBOL(__dynamic_pr_debug); int __dynamic_dev_dbg(struct _ddebug *descriptor,		      const struct device *dev, const char *fmt, ...){	struct va_format vaf;	va_list args;	int res;	char buf[PREFIX_SIZE]; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt);	vaf.fmt = fmt;	vaf.va = &args;	res = __dev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);	va_end(args); 	return res;}EXPORT_SYMBOL(__dynamic_dev_dbg); #ifdef CONFIG_NET int __dynamic_netdev_dbg(struct _ddebug *descriptor,		      const struct net_device *dev, const char *fmt, ...){	struct va_format vaf;	va_list args;	int res;	char buf[PREFIX_SIZE]; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt);	vaf.fmt = fmt;	vaf.va = &args;	res = __netdev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);	va_end(args); 	return res;}EXPORT_SYMBOL(__dynamic_netdev_dbg); #endif #define DDEBUG_STRING_SIZE 1024static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE]; static __init int ddebug_setup_query(char *str){	if (strlen(str) >= DDEBUG_STRING_SIZE) {		pr_warn("ddebug boot param string too large\n");		return 0;	}	strlcpy(ddebug_setup_string, str, DDEBUG_STRING_SIZE);	return 1;} __setup("ddebug_query=", ddebug_setup_query); /* * File_ops->write method for <debugfs>/dynamic_debug/conrol.  Gathers the * command text from userspace, parses and executes it. */#define USER_BUF_PAGE 4096static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,				  size_t len, loff_t *offp){	char *tmpbuf;	int ret; 	if (len == 0)		return 0;	if (len > USER_BUF_PAGE - 1) {		pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);		return -E2BIG;	}	tmpbuf = kmalloc(len + 1, GFP_KERNEL);	if (!tmpbuf)		return -ENOMEM;	if (copy_from_user(tmpbuf, ubuf, len)) {		kfree(tmpbuf);		return -EFAULT;	}	tmpbuf[len] = '\0';	vpr_info("read %d bytes from userspace\n", (int)len); 	ret = ddebug_exec_queries(tmpbuf, NULL);	kfree(tmpbuf);	if (ret < 0)		return ret; 	*offp += len;	return len;} /* * Set the iterator to point to the first _ddebug object * and return a pointer to that first object.  Returns * NULL if there are no _ddebugs at all. */static struct _ddebug *ddebug_iter_first(struct ddebug_iter *iter){	if (list_empty(&ddebug_tables)) {		iter->table = NULL;		iter->idx = 0;		return NULL;	}	iter->table = list_entry(ddebug_tables.next,				 struct ddebug_table, link);	iter->idx = 0;	return &iter->table->ddebugs[iter->idx];} /* * Advance the iterator to point to the next _ddebug * object from the one the iterator currently points at, * and returns a pointer to the new _ddebug.  Returns * NULL if the iterator has seen all the _ddebugs. */static struct _ddebug *ddebug_iter_next(struct ddebug_iter *iter){	if (iter->table == NULL)		return NULL;	if (++iter->idx == iter->table->num_ddebugs) {		/* iterate to next table */		iter->idx = 0;		if (list_is_last(&iter->table->link, &ddebug_tables)) {			iter->table = NULL;			return NULL;		}		iter->table = list_entry(iter->table->link.next,					 struct ddebug_table, link);	}	return &iter->table->ddebugs[iter->idx];} /* * Seq_ops start method.  Called at the start of every * read() call from userspace.  Takes the ddebug_lock and * seeks the seq_file's iterator to the given position. */static void *ddebug_proc_start(struct seq_file *m, loff_t *pos){	struct ddebug_iter *iter = m->private;	struct _ddebug *dp;	int n = *pos; 	vpr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos); 	mutex_lock(&ddebug_lock); 	if (!n)		return SEQ_START_TOKEN;	if (n < 0)		return NULL;	dp = ddebug_iter_first(iter);	while (dp != NULL && --n > 0)		dp = ddebug_iter_next(iter);	return dp;} /* * Seq_ops next method.  Called several times within a read() * call from userspace, with ddebug_lock held.  Walks to the * next _ddebug object with a special case for the header line. */static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos){	struct ddebug_iter *iter = m->private;	struct _ddebug *dp; 	vpr_info("called m=%p p=%p *pos=%lld\n",		m, p, (unsigned long long)*pos); 	if (p == SEQ_START_TOKEN)		dp = ddebug_iter_first(iter);	else		dp = ddebug_iter_next(iter);	++*pos;	return dp;} /* * Seq_ops show method.  Called several times within a read() * call from userspace, with ddebug_lock held.  Formats the * current _ddebug as a single human-readable line, with a * special case for the header line. */static int ddebug_proc_show(struct seq_file *m, void *p){	struct ddebug_iter *iter = m->private;	struct _ddebug *dp = p;	char flagsbuf[10]; 	vpr_info("called m=%p p=%p\n", m, p); 	if (p == SEQ_START_TOKEN) {		seq_puts(m,			"# filename:lineno [module]function flags format\n");		return 0;	} 	seq_printf(m, "%s:%u [%s]%s =%s \"",		trim_prefix(dp->filename), dp->lineno,		iter->table->mod_name, dp->function,		ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));	seq_escape(m, dp->format, "\t\r\n\"");	seq_puts(m, "\"\n"); 	return 0;} /* * Seq_ops stop method.  Called at the end of each read() * call from userspace.  Drops ddebug_lock. */static void ddebug_proc_stop(struct seq_file *m, void *p){	vpr_info("called m=%p p=%p\n", m, p);	mutex_unlock(&ddebug_lock);} static const struct seq_operations ddebug_proc_seqops = {	.start = ddebug_proc_start,	.next = ddebug_proc_next,	.show = ddebug_proc_show,	.stop = ddebug_proc_stop}; /* * File_ops->open method for <debugfs>/dynamic_debug/control.  Does * the seq_file setup dance, and also creates an iterator to walk the * _ddebugs.  Note that we create a seq_file always, even for O_WRONLY * files where it's not needed, as doing so simplifies the ->release * method. */static int ddebug_proc_open(struct inode *inode, struct file *file){	struct ddebug_iter *iter;	int err; 	vpr_info("called\n"); 	iter = kzalloc(sizeof(*iter), GFP_KERNEL);	if (iter == NULL)		return -ENOMEM; 	err = seq_open(file, &ddebug_proc_seqops);	if (err) {		kfree(iter);		return err;	}	((struct seq_file *) file->private_data)->private = iter;	return 0;} static const struct file_operations ddebug_proc_fops = {	.owner = THIS_MODULE,	.open = ddebug_proc_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release_private,	.write = ddebug_proc_write}; /* * Allocate a new ddebug_table for the given module * and add it to the global list. */int ddebug_add_module(struct _ddebug *tab, unsigned int n,			     const char *name){	struct ddebug_table *dt;	char *new_name; 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);	if (dt == NULL)		return -ENOMEM;	new_name = kstrdup(name, GFP_KERNEL);	if (new_name == NULL) {		kfree(dt);		return -ENOMEM;	}	dt->mod_name = new_name;	dt->num_ddebugs = n;	dt->ddebugs = tab; 	mutex_lock(&ddebug_lock);	list_add_tail(&dt->link, &ddebug_tables);	mutex_unlock(&ddebug_lock); 	vpr_info("%u debug prints in module %s\n", n, dt->mod_name);	return 0;}EXPORT_SYMBOL_GPL(ddebug_add_module); /* helper for ddebug_dyndbg_(boot|module)_param_cb */static int ddebug_dyndbg_param_cb(char *param, char *val,				const char *modname, int on_err){	char *sep; 	sep = strchr(param, '.');	if (sep) {		/* needed only for ddebug_dyndbg_boot_param_cb */		*sep = '\0';		modname = param;		param = sep + 1;	}	if (strcmp(param, "dyndbg"))		return on_err; /* determined by caller */ 	ddebug_exec_queries((val ? val : "+p"), modname); 	return 0; /* query failure shouldnt stop module load */} /* handle both dyndbg and $module.dyndbg params at boot */static int ddebug_dyndbg_boot_param_cb(char *param, char *val,				const char *unused){	vpr_info("%s=\"%s\"\n", param, val);	return ddebug_dyndbg_param_cb(param, val, NULL, 0);} /* * modprobe foo finds foo.params in boot-args, strips "foo.", and * passes them to load_module().  This callback gets unknown params, * processes dyndbg params, rejects others. */int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module){	vpr_info("module: %s %s=\"%s\"\n", module, param, val);	return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);} static void ddebug_table_free(struct ddebug_table *dt){	list_del_init(&dt->link);	kfree(dt->mod_name);	kfree(dt);} /* * Called in response to a module being unloaded.  Removes * any ddebug_table's which point at the module. */int ddebug_remove_module(const char *mod_name){	struct ddebug_table *dt, *nextdt;	int ret = -ENOENT; 	vpr_info("removing module \"%s\"\n", mod_name); 	mutex_lock(&ddebug_lock);	list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {		if (!strcmp(dt->mod_name, mod_name)) {			ddebug_table_free(dt);			ret = 0;		}	}	mutex_unlock(&ddebug_lock);	return ret;}EXPORT_SYMBOL_GPL(ddebug_remove_module); static void ddebug_remove_all_tables(void){	mutex_lock(&ddebug_lock);	while (!list_empty(&ddebug_tables)) {		struct ddebug_table *dt = list_entry(ddebug_tables.next,						      struct ddebug_table,						      link);		ddebug_table_free(dt);	}	mutex_unlock(&ddebug_lock);} static __initdata int ddebug_init_success; static int __init dynamic_debug_init_debugfs(void){	struct dentry *dir, *file; 	if (!ddebug_init_success)		return -ENODEV; 	dir = debugfs_create_dir("dynamic_debug", NULL);	if (!dir)		return -ENOMEM;	file = debugfs_create_file("control", 0644, dir, NULL,					&ddebug_proc_fops);	if (!file) {		debugfs_remove(dir);		return -ENOMEM;	}	return 0;} static int __init dynamic_debug_init(void){	struct _ddebug *iter, *iter_start;	const char *modname = NULL;	char *cmdline;	int ret = 0;	int n = 0, entries = 0, modct = 0;	int verbose_bytes = 0; 	if (__start___verbose == __stop___verbose) {		pr_warn("_ddebug table is empty in a "			"CONFIG_DYNAMIC_DEBUG build");		return 1;	}	iter = __start___verbose;	modname = iter->modname;	iter_start = iter;	for (; iter < __stop___verbose; iter++) {		entries++;		verbose_bytes += strlen(iter->modname) + strlen(iter->function)			+ strlen(iter->filename) + strlen(iter->format); 		if (strcmp(modname, iter->modname)) {			modct++;			ret = ddebug_add_module(iter_start, n, modname);			if (ret)				goto out_err;			n = 0;			modname = iter->modname;

Lines 501–1000 of 1048. Previous lines