1134 lines · 27.3 KB · C
RawDownload
	char *words[MAXWORDS]; 	nwords = ddebug_tokenize(query_string, words, MAXWORDS);	if (nwords <= 0) {		pr_err("tokenize failed\n");		return -EINVAL;	}	/* check flags 1st (last arg) so query is pairs of spec,val */	if (ddebug_parse_flags(words[nwords-1], &modifiers)) {		pr_err("flags parse failed\n");		return -EINVAL;	}	if (ddebug_parse_query(words, nwords-1, &query, modname)) {		pr_err("query parse failed\n");		return -EINVAL;	}	/* actually go and implement the change */	nfound = ddebug_change(&query, &modifiers);	vpr_info_dq(&query, nfound ? "applied" : "no-match"); 	return nfound;} /* handle multiple queries in query string, continue on error, return   last error or number of matching callsites.  Module name is either   in param (for boot arg) or perhaps in query string.*/int ddebug_exec_queries(char *query, const char *modname){	char *split;	int i, errs = 0, exitcode = 0, rc, nfound = 0; 	for (i = 0; query; query = split) {		split = strpbrk(query, ";\n");		if (split)			*split++ = '\0'; 		query = skip_spaces(query);		if (!query || !*query || *query == '#')			continue; 		vpr_info("query %d: \"%s\"\n", i, query); 		rc = ddebug_exec_query(query, modname);		if (rc < 0) {			errs++;			exitcode = rc;		} else {			nfound += rc;		}		i++;	}	vpr_info("processed %d queries, with %d matches, %d errs\n",		 i, nfound, errs); 	if (exitcode)		return exitcode;	return nfound;}EXPORT_SYMBOL_GPL(ddebug_exec_queries); #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; 	*buf = '\0'; 	if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {		if (in_interrupt())			pos += snprintf(buf + pos, remaining(pos), "<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;} void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...){	va_list args;	struct va_format vaf;	char buf[PREFIX_SIZE]; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf); 	va_end(args);}EXPORT_SYMBOL(__dynamic_pr_debug); void __dynamic_dev_dbg(struct _ddebug *descriptor,		      const struct device *dev, const char *fmt, ...){	struct va_format vaf;	va_list args; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	if (!dev) {		printk(KERN_DEBUG "(NULL device *): %pV", &vaf);	} else {		char buf[PREFIX_SIZE]; 		dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",				dynamic_emit_prefix(descriptor, buf),				dev_driver_string(dev), dev_name(dev),				&vaf);	} 	va_end(args);}EXPORT_SYMBOL(__dynamic_dev_dbg); #ifdef CONFIG_NET void __dynamic_netdev_dbg(struct _ddebug *descriptor,			  const struct net_device *dev, const char *fmt, ...){	struct va_format vaf;	va_list args; 	BUG_ON(!descriptor);	BUG_ON(!fmt); 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	if (dev && dev->dev.parent) {		char buf[PREFIX_SIZE]; 		dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,				"%s%s %s %s%s: %pV",				dynamic_emit_prefix(descriptor, buf),				dev_driver_string(dev->dev.parent),				dev_name(dev->dev.parent),				netdev_name(dev), netdev_reg_state(dev),				&vaf);	} else if (dev) {		printk(KERN_DEBUG "%s%s: %pV", netdev_name(dev),		       netdev_reg_state(dev), &vaf);	} else {		printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);	} 	va_end(args);}EXPORT_SYMBOL(__dynamic_netdev_dbg); #endif #if IS_ENABLED(CONFIG_INFINIBAND) void __dynamic_ibdev_dbg(struct _ddebug *descriptor,			 const struct ib_device *ibdev, const char *fmt, ...){	struct va_format vaf;	va_list args; 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	if (ibdev && ibdev->dev.parent) {		char buf[PREFIX_SIZE]; 		dev_printk_emit(LOGLEVEL_DEBUG, ibdev->dev.parent,				"%s%s %s %s: %pV",				dynamic_emit_prefix(descriptor, buf),				dev_driver_string(ibdev->dev.parent),				dev_name(ibdev->dev.parent),				dev_name(&ibdev->dev),				&vaf);	} else if (ibdev) {		printk(KERN_DEBUG "%s: %pV", dev_name(&ibdev->dev), &vaf);	} else {		printk(KERN_DEBUG "(NULL ib_device): %pV", &vaf);	} 	va_end(args);}EXPORT_SYMBOL(__dynamic_ibdev_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/control.  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 = memdup_user_nul(ubuf, len);	if (IS_ERR(tmpbuf))		return PTR_ERR(tmpbuf);	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; 	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; 	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;	struct flagsbuf flags; 	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->flags, &flags));	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){	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}; static int ddebug_proc_open(struct inode *inode, struct file *file){	vpr_info("called\n");	return seq_open_private(file, &ddebug_proc_seqops,				sizeof(struct ddebug_iter));} 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}; static const struct proc_ops proc_fops = {	.proc_open = ddebug_proc_open,	.proc_read = seq_read,	.proc_lseek = seq_lseek,	.proc_release = seq_release_private,	.proc_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; 	dt = kzalloc(sizeof(*dt), GFP_KERNEL);	if (dt == NULL) {		pr_err("error adding module: %s\n", name);		return -ENOMEM;	}	/*	 * For built-in modules, name lives in .rodata and is	 * immortal. For loaded modules, name points at the name[]	 * member of struct module, which lives at least as long as	 * this struct ddebug_table.	 */	dt->mod_name = name;	dt->num_ddebugs = n;	dt->ddebugs = tab; 	mutex_lock(&ddebug_lock);	list_add(&dt->link, &ddebug_tables);	mutex_unlock(&ddebug_lock); 	v2pr_info("%u debug prints in module %s\n", n, dt->mod_name);	return 0;} /* 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, void *arg){	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);} /*

Lines 501–1000 of 1134. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t