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

📄 trace.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 5 页
字号:
	entry = iter->ent;	SEQ_PUT_HEX_FIELD_RET(s, entry->pid);	SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);	SEQ_PUT_HEX_FIELD_RET(s, entry->t);	switch (entry->type) {	case TRACE_FN:		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.ip);		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.parent_ip);		break;	case TRACE_CTX:	case TRACE_WAKE:		S = entry->ctx.prev_state < sizeof(state_to_char) ?			state_to_char[entry->ctx.prev_state] : 'X';		T = entry->ctx.next_state < sizeof(state_to_char) ?			state_to_char[entry->ctx.next_state] : 'X';		if (entry->type == TRACE_WAKE)			S = '+';		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_pid);		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.prev_prio);		SEQ_PUT_HEX_FIELD_RET(s, S);		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.next_pid);		SEQ_PUT_HEX_FIELD_RET(s, entry->ctx.next_prio);		SEQ_PUT_HEX_FIELD_RET(s, entry->fn.parent_ip);		SEQ_PUT_HEX_FIELD_RET(s, T);		break;	case TRACE_SPECIAL:	case TRACE_STACK:		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg1);		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg2);		SEQ_PUT_HEX_FIELD_RET(s, entry->special.arg3);		break;	}	SEQ_PUT_FIELD_RET(s, newline);	return 1;}static int print_bin_fmt(struct trace_iterator *iter){	struct trace_seq *s = &iter->seq;	struct trace_entry *entry;	entry = iter->ent;	SEQ_PUT_FIELD_RET(s, entry->pid);	SEQ_PUT_FIELD_RET(s, entry->cpu);	SEQ_PUT_FIELD_RET(s, entry->t);	switch (entry->type) {	case TRACE_FN:		SEQ_PUT_FIELD_RET(s, entry->fn.ip);		SEQ_PUT_FIELD_RET(s, entry->fn.parent_ip);		break;	case TRACE_CTX:		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_pid);		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_prio);		SEQ_PUT_FIELD_RET(s, entry->ctx.prev_state);		SEQ_PUT_FIELD_RET(s, entry->ctx.next_pid);		SEQ_PUT_FIELD_RET(s, entry->ctx.next_prio);		SEQ_PUT_FIELD_RET(s, entry->ctx.next_state);		break;	case TRACE_SPECIAL:	case TRACE_STACK:		SEQ_PUT_FIELD_RET(s, entry->special.arg1);		SEQ_PUT_FIELD_RET(s, entry->special.arg2);		SEQ_PUT_FIELD_RET(s, entry->special.arg3);		break;	}	return 1;}static int trace_empty(struct trace_iterator *iter){	struct trace_array_cpu *data;	int cpu;	for_each_tracing_cpu(cpu) {		data = iter->tr->data[cpu];		if (head_page(data) && data->trace_idx &&		    (data->trace_tail != data->trace_head ||		     data->trace_tail_idx != data->trace_head_idx))			return 0;	}	return 1;}static int print_trace_line(struct trace_iterator *iter){	if (iter->trace && iter->trace->print_line)		return iter->trace->print_line(iter);	if (trace_flags & TRACE_ITER_BIN)		return print_bin_fmt(iter);	if (trace_flags & TRACE_ITER_HEX)		return print_hex_fmt(iter);	if (trace_flags & TRACE_ITER_RAW)		return print_raw_fmt(iter);	if (iter->iter_flags & TRACE_FILE_LAT_FMT)		return print_lat_fmt(iter, iter->idx, iter->cpu);	return print_trace_fmt(iter);}static int s_show(struct seq_file *m, void *v){	struct trace_iterator *iter = v;	if (iter->ent == NULL) {		if (iter->tr) {			seq_printf(m, "# tracer: %s\n", iter->trace->name);			seq_puts(m, "#\n");		}		if (iter->iter_flags & TRACE_FILE_LAT_FMT) {			/* print nothing if the buffers are empty */			if (trace_empty(iter))				return 0;			print_trace_header(m, iter);			if (!(trace_flags & TRACE_ITER_VERBOSE))				print_lat_help_header(m);		} else {			if (!(trace_flags & TRACE_ITER_VERBOSE))				print_func_help_header(m);		}	} else {		print_trace_line(iter);		trace_print_seq(m, &iter->seq);	}	return 0;}static struct seq_operations tracer_seq_ops = {	.start		= s_start,	.next		= s_next,	.stop		= s_stop,	.show		= s_show,};static struct trace_iterator *__tracing_open(struct inode *inode, struct file *file, int *ret){	struct trace_iterator *iter;	if (tracing_disabled) {		*ret = -ENODEV;		return NULL;	}	iter = kzalloc(sizeof(*iter), GFP_KERNEL);	if (!iter) {		*ret = -ENOMEM;		goto out;	}	mutex_lock(&trace_types_lock);	if (current_trace && current_trace->print_max)		iter->tr = &max_tr;	else		iter->tr = inode->i_private;	iter->trace = current_trace;	iter->pos = -1;	/* TODO stop tracer */	*ret = seq_open(file, &tracer_seq_ops);	if (!*ret) {		struct seq_file *m = file->private_data;		m->private = iter;		/* stop the trace while dumping */		if (iter->tr->ctrl) {			tracer_enabled = 0;			ftrace_function_enabled = 0;		}		if (iter->trace && iter->trace->open)			iter->trace->open(iter);	} else {		kfree(iter);		iter = NULL;	}	mutex_unlock(&trace_types_lock); out:	return iter;}int tracing_open_generic(struct inode *inode, struct file *filp){	if (tracing_disabled)		return -ENODEV;	filp->private_data = inode->i_private;	return 0;}int tracing_release(struct inode *inode, struct file *file){	struct seq_file *m = (struct seq_file *)file->private_data;	struct trace_iterator *iter = m->private;	mutex_lock(&trace_types_lock);	if (iter->trace && iter->trace->close)		iter->trace->close(iter);	/* reenable tracing if it was previously enabled */	if (iter->tr->ctrl) {		tracer_enabled = 1;		/*		 * It is safe to enable function tracing even if it		 * isn't used		 */		ftrace_function_enabled = 1;	}	mutex_unlock(&trace_types_lock);	seq_release(inode, file);	kfree(iter);	return 0;}static int tracing_open(struct inode *inode, struct file *file){	int ret;	__tracing_open(inode, file, &ret);	return ret;}static int tracing_lt_open(struct inode *inode, struct file *file){	struct trace_iterator *iter;	int ret;	iter = __tracing_open(inode, file, &ret);	if (!ret)		iter->iter_flags |= TRACE_FILE_LAT_FMT;	return ret;}static void *t_next(struct seq_file *m, void *v, loff_t *pos){	struct tracer *t = m->private;	(*pos)++;	if (t)		t = t->next;	m->private = t;	return t;}static void *t_start(struct seq_file *m, loff_t *pos){	struct tracer *t = m->private;	loff_t l = 0;	mutex_lock(&trace_types_lock);	for (; t && l < *pos; t = t_next(m, t, &l))		;	return t;}static void t_stop(struct seq_file *m, void *p){	mutex_unlock(&trace_types_lock);}static int t_show(struct seq_file *m, void *v){	struct tracer *t = v;	if (!t)		return 0;	seq_printf(m, "%s", t->name);	if (t->next)		seq_putc(m, ' ');	else		seq_putc(m, '\n');	return 0;}static struct seq_operations show_traces_seq_ops = {	.start		= t_start,	.next		= t_next,	.stop		= t_stop,	.show		= t_show,};static int show_traces_open(struct inode *inode, struct file *file){	int ret;	if (tracing_disabled)		return -ENODEV;	ret = seq_open(file, &show_traces_seq_ops);	if (!ret) {		struct seq_file *m = file->private_data;		m->private = trace_types;	}	return ret;}static struct file_operations tracing_fops = {	.open		= tracing_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= tracing_release,};static struct file_operations tracing_lt_fops = {	.open		= tracing_lt_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= tracing_release,};static struct file_operations show_traces_fops = {	.open		= show_traces_open,	.read		= seq_read,	.release	= seq_release,};/* * Only trace on a CPU if the bitmask is set: */static cpumask_t tracing_cpumask = CPU_MASK_ALL;/* * When tracing/tracing_cpu_mask is modified then this holds * the new bitmask we are about to install: */static cpumask_t tracing_cpumask_new;/* * The tracer itself will not take this lock, but still we want * to provide a consistent cpumask to user-space: */static DEFINE_MUTEX(tracing_cpumask_update_lock);/* * Temporary storage for the character representation of the * CPU bitmask (and one more byte for the newline): */static char mask_str[NR_CPUS + 1];static ssize_ttracing_cpumask_read(struct file *filp, char __user *ubuf,		     size_t count, loff_t *ppos){	int len;	mutex_lock(&tracing_cpumask_update_lock);	len = cpumask_scnprintf(mask_str, count, tracing_cpumask);	if (count - len < 2) {		count = -EINVAL;		goto out_err;	}	len += sprintf(mask_str + len, "\n");	count = simple_read_from_buffer(ubuf, count, ppos, mask_str, NR_CPUS+1);out_err:	mutex_unlock(&tracing_cpumask_update_lock);	return count;}static ssize_ttracing_cpumask_write(struct file *filp, const char __user *ubuf,		      size_t count, loff_t *ppos){	int err, cpu;	mutex_lock(&tracing_cpumask_update_lock);	err = cpumask_parse_user(ubuf, count, tracing_cpumask_new);	if (err)		goto err_unlock;	raw_local_irq_disable();	__raw_spin_lock(&ftrace_max_lock);	for_each_tracing_cpu(cpu) {		/*		 * Increase/decrease the disabled counter if we are		 * about to flip a bit in the cpumask:		 */		if (cpu_isset(cpu, tracing_cpumask) &&				!cpu_isset(cpu, tracing_cpumask_new)) {			atomic_inc(&global_trace.data[cpu]->disabled);		}		if (!cpu_isset(cpu, tracing_cpumask) &&				cpu_isset(cpu, tracing_cpumask_new)) {			atomic_dec(&global_trace.data[cpu]->disabled);		}	}	__raw_spin_unlock(&ftrace_max_lock);	raw_local_irq_enable();	tracing_cpumask = tracing_cpumask_new;	mutex_unlock(&tracing_cpumask_update_lock);	return count;err_unlock:	mutex_unlock(&tracing_cpumask_update_lock);	return err;}static struct file_operations tracing_cpumask_fops = {	.open		= tracing_open_generic,	.read		= tracing_cpumask_read,	.write		= tracing_cpumask_write,};static ssize_ttracing_iter_ctrl_read(struct file *filp, char __user *ubuf,		       size_t cnt, loff_t *ppos){	char *buf;	int r = 0;	int len = 0;	int i;	/* calulate max size */	for (i = 0; trace_options[i]; i++) {		len += strlen(trace_options[i]);		len += 3; /* "no" and space */	}	/* +2 for \n and \0 */	buf = kmalloc(len + 2, GFP_KERNEL);	if (!buf)		return -ENOMEM;	for (i = 0; trace_options[i]; i++) {		if (trace_flags & (1 << i))			r += sprintf(buf + r, "%s ", trace_options[i]);		else			r += sprintf(buf + r, "no%s ", trace_options[i]);	}	r += sprintf(buf + r, "\n");	WARN_ON(r >= len + 2);	r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);	kfree(buf);	return r;}static ssize_ttracing_iter_ctrl_write(struct file *filp, const char __user *ubuf,			size_t cnt, loff_t *ppos){	char buf[64];	char *cmp = buf;	int neg = 0;	int i;	if (cnt >= sizeof(buf))		return -EINVAL;	if (copy_from_user(&buf, ubuf, cnt))		return -EFAULT;	buf[cnt] = 0;	if (strncmp(buf, "no", 2) == 0) {		neg = 1;		cmp += 2;	}	for (i = 0; trace_options[i]; i++) {		int len = strlen(trace_options[i]);		if (strncmp(cmp, trace_options[i], len) == 0) {			if (neg)				trace_flags &= ~(1 << i);			else				trace_flags |= (1 << i);			break;		}	}	/*	 * If no option could be set, return an error:	 */	if (!trace_options[i])		return -EINVAL;	filp->f_pos += cnt;	return cnt;}static struct file_operations tracing_iter_fops = {	.open		= tracing_open_generic,	.read		= tracing_iter_ctrl_read,	.write		= tracing_iter_ctrl_write,};static const char readme_msg[] =	"tracing mini-HOWTO:\n\n"	"# mkdir /debug\n"	"# mount -t debugfs nodev /debug\n\n"	"# cat /debug/tracing/available_tracers\n"	"wakeup preemptirqsoff preemptoff irqsoff ftrace sched_switch none\n\n"	"# cat /debug/tracing/current_tracer\n"	"none\n"	"# echo sched_switch > /debug/tracing/current_tracer\n"	"# cat /debug/tracing/current_tracer\n"	"sched_switch\n"	"# cat /debug/tracing/iter_ctrl\n"	"noprint-parent nosym-offset nosym-addr noverbose\n"	"# echo print-parent > /debug/tracing/iter_ctrl\n"	"# echo 1 > /debug/tracing/tracing_enabled\n"	"# cat /debug/tracing/trace > /tmp/trace.txt\n"	"echo 0 > /debug/tracing/tracing_enabled\n";static ssize_ttracing_readme_read(struct file *filp, char __user *ubuf,		       size_t cnt, loff_t *ppos){	return simple_read_from_buffer(ubuf, cnt, ppos,					readme_msg, strlen(readme_msg));}static struct file_operations tracing_readme_fops = {	.open		= tracing_open_generic,	.read		= tracing_readme_read,};static ssize_ttracing_ctrl_read(struct file *filp, char __user *ubuf,		  size_t cnt, loff_t *ppos){	struct trace_array *tr = filp->private_data;	char buf[64];	int r;	r = sprintf(buf, "%ld\n", tr->ctrl);	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);}static ssize_ttracing_ctrl_write(struct file *filp, const char __user *ubuf,		   size_t cnt, loff_t *ppos){	struct trace_array *tr = filp->private_data;	char buf[64];	long val;	int ret;

⌨️ 快捷键说明

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