Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 99793e3d authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branches 'tracing/kmemtrace2' and 'tracing/ftrace' into tracing/urgent

parents 3e806802 a103e2ab
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ obj-$(CONFIG_FUNCTION_TRACER) += libftrace.o
obj-$(CONFIG_RING_BUFFER) += ring_buffer.o

obj-$(CONFIG_TRACING) += trace.o
obj-$(CONFIG_TRACING) += trace_output.o
obj-$(CONFIG_TRACING) += trace_stat.o
obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
obj-$(CONFIG_SYSPROF_TRACER) += trace_sysprof.o
obj-$(CONFIG_FUNCTION_TRACER) += trace_functions.o
+41 −700
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/irqflags.h>

#include "trace.h"
#include "trace_output.h"

#define TRACE_BUFFER_FLAGS	(RB_FL_OVERWRITE)

@@ -329,132 +330,6 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
	tracing_record_cmdline(current);
}

/**
 * trace_seq_printf - sequence printing of trace information
 * @s: trace sequence descriptor
 * @fmt: printf format string
 *
 * The tracer may use either sequence operations or its own
 * copy to user routines. To simplify formating of a trace
 * trace_seq_printf is used to store strings into a special
 * buffer (@s). Then the output may be either used by
 * the sequencer or pulled into another buffer.
 */
int
trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
{
	int len = (PAGE_SIZE - 1) - s->len;
	va_list ap;
	int ret;

	if (!len)
		return 0;

	va_start(ap, fmt);
	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
	va_end(ap);

	/* If we can't write it all, don't bother writing anything */
	if (ret >= len)
		return 0;

	s->len += ret;

	return len;
}

/**
 * trace_seq_puts - trace sequence printing of simple string
 * @s: trace sequence descriptor
 * @str: simple string to record
 *
 * The tracer may use either the sequence operations or its own
 * copy to user routines. This function records a simple string
 * into a special buffer (@s) for later retrieval by a sequencer
 * or other mechanism.
 */
static int
trace_seq_puts(struct trace_seq *s, const char *str)
{
	int len = strlen(str);

	if (len > ((PAGE_SIZE - 1) - s->len))
		return 0;

	memcpy(s->buffer + s->len, str, len);
	s->len += len;

	return len;
}

static int
trace_seq_putc(struct trace_seq *s, unsigned char c)
{
	if (s->len >= (PAGE_SIZE - 1))
		return 0;

	s->buffer[s->len++] = c;

	return 1;
}

static int
trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
{
	if (len > ((PAGE_SIZE - 1) - s->len))
		return 0;

	memcpy(s->buffer + s->len, mem, len);
	s->len += len;

	return len;
}

#define MAX_MEMHEX_BYTES	8
#define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)

static int
trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
{
	unsigned char hex[HEX_CHARS];
	unsigned char *data = mem;
	int i, j;

#ifdef __BIG_ENDIAN
	for (i = 0, j = 0; i < len; i++) {
#else
	for (i = len-1, j = 0; i >= 0; i--) {
#endif
		hex[j++] = hex_asc_hi(data[i]);
		hex[j++] = hex_asc_lo(data[i]);
	}
	hex[j++] = ' ';

	return trace_seq_putmem(s, hex, j);
}

static int
trace_seq_path(struct trace_seq *s, struct path *path)
{
	unsigned char *p;

	if (s->len >= (PAGE_SIZE - 1))
		return 0;
	p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
	if (!IS_ERR(p)) {
		p = mangle_path(s->buffer + s->len, p, "\n");
		if (p) {
			s->len = p - s->buffer;
			return 1;
		}
	} else {
		s->buffer[s->len++] = '?';
		return 1;
	}

	return 0;
}

static void
trace_seq_reset(struct trace_seq *s)
{
@@ -1472,154 +1347,6 @@ static void s_stop(struct seq_file *m, void *p)
	mutex_unlock(&trace_types_lock);
}

#ifdef CONFIG_KRETPROBES
static inline const char *kretprobed(const char *name)
{
	static const char tramp_name[] = "kretprobe_trampoline";
	int size = sizeof(tramp_name);

	if (strncmp(tramp_name, name, size) == 0)
		return "[unknown/kretprobe'd]";
	return name;
}
#else
static inline const char *kretprobed(const char *name)
{
	return name;
}
#endif /* CONFIG_KRETPROBES */

static int
seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
	char str[KSYM_SYMBOL_LEN];
	const char *name;

	kallsyms_lookup(address, NULL, NULL, NULL, str);

	name = kretprobed(str);

	return trace_seq_printf(s, fmt, name);
#endif
	return 1;
}

static int
seq_print_sym_offset(struct trace_seq *s, const char *fmt,
		     unsigned long address)
{
#ifdef CONFIG_KALLSYMS
	char str[KSYM_SYMBOL_LEN];
	const char *name;

	sprint_symbol(str, address);
	name = kretprobed(str);

	return trace_seq_printf(s, fmt, name);
#endif
	return 1;
}

#ifndef CONFIG_64BIT
# define IP_FMT "%08lx"
#else
# define IP_FMT "%016lx"
#endif

int
seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
{
	int ret;

	if (!ip)
		return trace_seq_printf(s, "0");

	if (sym_flags & TRACE_ITER_SYM_OFFSET)
		ret = seq_print_sym_offset(s, "%s", ip);
	else
		ret = seq_print_sym_short(s, "%s", ip);

	if (!ret)
		return 0;

	if (sym_flags & TRACE_ITER_SYM_ADDR)
		ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
	return ret;
}

static inline int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
				    unsigned long ip, unsigned long sym_flags)
{
	struct file *file = NULL;
	unsigned long vmstart = 0;
	int ret = 1;

	if (mm) {
		const struct vm_area_struct *vma;

		down_read(&mm->mmap_sem);
		vma = find_vma(mm, ip);
		if (vma) {
			file = vma->vm_file;
			vmstart = vma->vm_start;
		}
		if (file) {
			ret = trace_seq_path(s, &file->f_path);
			if (ret)
				ret = trace_seq_printf(s, "[+0x%lx]", ip - vmstart);
		}
		up_read(&mm->mmap_sem);
	}
	if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
		ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
	return ret;
}

static int
seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
		      unsigned long sym_flags)
{
	struct mm_struct *mm = NULL;
	int ret = 1;
	unsigned int i;

	if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
		struct task_struct *task;
		/*
		 * we do the lookup on the thread group leader,
		 * since individual threads might have already quit!
		 */
		rcu_read_lock();
		task = find_task_by_vpid(entry->ent.tgid);
		if (task)
			mm = get_task_mm(task);
		rcu_read_unlock();
	}

	for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
		unsigned long ip = entry->caller[i];

		if (ip == ULONG_MAX || !ret)
			break;
		if (i && ret)
			ret = trace_seq_puts(s, " <- ");
		if (!ip) {
			if (ret)
				ret = trace_seq_puts(s, "??");
			continue;
		}
		if (!ret)
			break;
		if (ret)
			ret = seq_print_user_ip(s, mm, ip, sym_flags);
	}

	if (mm)
		mmput(mm);
	return ret;
}

static void print_lat_help_header(struct seq_file *m)
{
	seq_puts(m, "#                  _------=> CPU#            \n");
@@ -1755,52 +1482,6 @@ lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
		trace_seq_puts(s, " : ");
}

static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;

static int task_state_char(unsigned long state)
{
	int bit = state ? __ffs(state) + 1 : 0;

	return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
}

/*
 * The message is supposed to contain an ending newline.
 * If the printing stops prematurely, try to add a newline of our own.
 */
void trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
{
	struct trace_entry *ent;
	struct trace_field_cont *cont;
	bool ok = true;

	ent = peek_next_entry(iter, iter->cpu, NULL);
	if (!ent || ent->type != TRACE_CONT) {
		trace_seq_putc(s, '\n');
		return;
	}

	do {
		cont = (struct trace_field_cont *)ent;
		if (ok)
			ok = (trace_seq_printf(s, "%s", cont->buf) > 0);

		ftrace_disable_cpu();

		if (iter->buffer_iter[iter->cpu])
			ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
		else
			ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL);

		ftrace_enable_cpu();

		ent = peek_next_entry(iter, iter->cpu, NULL);
	} while (ent && ent->type == TRACE_CONT);

	if (!ok)
		trace_seq_putc(s, '\n');
}

static void test_cpu_buff_start(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
@@ -1824,17 +1505,14 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
	struct trace_seq *s = &iter->seq;
	unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
	struct trace_entry *next_entry;
	struct trace_event *event;
	unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
	struct trace_entry *entry = iter->ent;
	unsigned long abs_usecs;
	unsigned long rel_usecs;
	u64 next_ts;
	char *comm;
	int S, T;
	int i;

	if (entry->type == TRACE_CONT)
		return TRACE_TYPE_HANDLED;
	int ret;

	test_cpu_buff_start(iter);

@@ -1859,96 +1537,16 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
		lat_print_generic(s, entry, cpu);
		lat_print_timestamp(s, abs_usecs, rel_usecs);
	}
	switch (entry->type) {
	case TRACE_FN: {
		struct ftrace_entry *field;

		trace_assign_type(field, entry);

		seq_print_ip_sym(s, field->ip, sym_flags);
		trace_seq_puts(s, " (");
		seq_print_ip_sym(s, field->parent_ip, sym_flags);
		trace_seq_puts(s, ")\n");
		break;
	}
	case TRACE_CTX:
	case TRACE_WAKE: {
		struct ctx_switch_entry *field;

		trace_assign_type(field, entry);

		T = task_state_char(field->next_state);
		S = task_state_char(field->prev_state);
		comm = trace_find_cmdline(field->next_pid);
		trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
				 field->prev_pid,
				 field->prev_prio,
				 S, entry->type == TRACE_CTX ? "==>" : "  +",
				 field->next_cpu,
				 field->next_pid,
				 field->next_prio,
				 T, comm);
		break;
	}
	case TRACE_SPECIAL: {
		struct special_entry *field;

		trace_assign_type(field, entry);

		trace_seq_printf(s, "# %ld %ld %ld\n",
				 field->arg1,
				 field->arg2,
				 field->arg3);
		break;
	}
	case TRACE_STACK: {
		struct stack_entry *field;

		trace_assign_type(field, entry);

		for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
			if (i)
				trace_seq_puts(s, " <= ");
			seq_print_ip_sym(s, field->caller[i], sym_flags);
		}
		trace_seq_puts(s, "\n");
		break;
	}
	case TRACE_PRINT: {
		struct print_entry *field;

		trace_assign_type(field, entry);

		seq_print_ip_sym(s, field->ip, sym_flags);
		trace_seq_printf(s, ": %s", field->buf);
		if (entry->flags & TRACE_FLAG_CONT)
			trace_seq_print_cont(s, iter);
		break;
	}
	case TRACE_BRANCH: {
		struct trace_branch *field;

		trace_assign_type(field, entry);

		trace_seq_printf(s, "[%s] %s:%s:%d\n",
				 field->correct ? "  ok  " : " MISS ",
				 field->func,
				 field->file,
				 field->line);
		break;
	event = ftrace_find_event(entry->type);
	if (event && event->latency_trace) {
		ret = event->latency_trace(s, entry, sym_flags);
		if (ret)
			return ret;
		return TRACE_TYPE_HANDLED;
	}
	case TRACE_USER_STACK: {
		struct userstack_entry *field;

		trace_assign_type(field, entry);

		seq_print_userip_objs(field, s, sym_flags);
		trace_seq_putc(s, '\n');
		break;
	}
	default:
	trace_seq_printf(s, "Unknown type %d\n", entry->type);
	}
	return TRACE_TYPE_HANDLED;
}

@@ -1957,19 +1555,15 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
	struct trace_seq *s = &iter->seq;
	unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
	struct trace_entry *entry;
	struct trace_event *event;
	unsigned long usec_rem;
	unsigned long long t;
	unsigned long secs;
	char *comm;
	int ret;
	int S, T;
	int i;

	entry = iter->ent;

	if (entry->type == TRACE_CONT)
		return TRACE_TYPE_HANDLED;

	test_cpu_buff_start(iter);

	comm = trace_find_cmdline(iter->ent->pid);
@@ -1988,129 +1582,17 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	switch (entry->type) {
	case TRACE_FN: {
		struct ftrace_entry *field;

		trace_assign_type(field, entry);

		ret = seq_print_ip_sym(s, field->ip, sym_flags);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		if ((sym_flags & TRACE_ITER_PRINT_PARENT) &&
						field->parent_ip) {
			ret = trace_seq_printf(s, " <-");
			if (!ret)
				return TRACE_TYPE_PARTIAL_LINE;
			ret = seq_print_ip_sym(s,
					       field->parent_ip,
					       sym_flags);
			if (!ret)
				return TRACE_TYPE_PARTIAL_LINE;
		}
		ret = trace_seq_printf(s, "\n");
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_CTX:
	case TRACE_WAKE: {
		struct ctx_switch_entry *field;

		trace_assign_type(field, entry);

		T = task_state_char(field->next_state);
		S = task_state_char(field->prev_state);
		ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n",
				       field->prev_pid,
				       field->prev_prio,
				       S,
				       entry->type == TRACE_CTX ? "==>" : "  +",
				       field->next_cpu,
				       field->next_pid,
				       field->next_prio,
				       T);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_SPECIAL: {
		struct special_entry *field;

		trace_assign_type(field, entry);

		ret = trace_seq_printf(s, "# %ld %ld %ld\n",
				 field->arg1,
				 field->arg2,
				 field->arg3);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_STACK: {
		struct stack_entry *field;

		trace_assign_type(field, entry);

		for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
			if (i) {
				ret = trace_seq_puts(s, " <= ");
				if (!ret)
					return TRACE_TYPE_PARTIAL_LINE;
			}
			ret = seq_print_ip_sym(s, field->caller[i],
					       sym_flags);
			if (!ret)
				return TRACE_TYPE_PARTIAL_LINE;
	event = ftrace_find_event(entry->type);
	if (event && event->trace) {
		ret = event->trace(s, entry, sym_flags);
		if (ret)
			return ret;
		return TRACE_TYPE_HANDLED;
	}
		ret = trace_seq_puts(s, "\n");
	ret = trace_seq_printf(s, "Unknown type %d\n", entry->type);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_PRINT: {
		struct print_entry *field;

		trace_assign_type(field, entry);

		seq_print_ip_sym(s, field->ip, sym_flags);
		trace_seq_printf(s, ": %s", field->buf);
		if (entry->flags & TRACE_FLAG_CONT)
			trace_seq_print_cont(s, iter);
		break;
	}
	case TRACE_GRAPH_RET: {
		return print_graph_function(iter);
	}
	case TRACE_GRAPH_ENT: {
		return print_graph_function(iter);
	}
	case TRACE_BRANCH: {
		struct trace_branch *field;

		trace_assign_type(field, entry);

		trace_seq_printf(s, "[%s] %s:%s:%d\n",
				 field->correct ? "  ok  " : " MISS ",
				 field->func,
				 field->file,
				 field->line);
		break;
	}
	case TRACE_USER_STACK: {
		struct userstack_entry *field;

		trace_assign_type(field, entry);

		ret = seq_print_userip_objs(field, s, sym_flags);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		ret = trace_seq_putc(s, '\n');
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	}
	return TRACE_TYPE_HANDLED;
}

@@ -2118,152 +1600,47 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry;
	struct trace_event *event;
	int ret;
	int S, T;

	entry = iter->ent;

	if (entry->type == TRACE_CONT)
		return TRACE_TYPE_HANDLED;

	ret = trace_seq_printf(s, "%d %d %llu ",
		entry->pid, iter->cpu, iter->ts);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	switch (entry->type) {
	case TRACE_FN: {
		struct ftrace_entry *field;

		trace_assign_type(field, entry);

		ret = trace_seq_printf(s, "%x %x\n",
					field->ip,
					field->parent_ip);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_CTX:
	case TRACE_WAKE: {
		struct ctx_switch_entry *field;

		trace_assign_type(field, entry);

		T = task_state_char(field->next_state);
		S = entry->type == TRACE_WAKE ? '+' :
			task_state_char(field->prev_state);
		ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
				       field->prev_pid,
				       field->prev_prio,
				       S,
				       field->next_cpu,
				       field->next_pid,
				       field->next_prio,
				       T);
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
		break;
	event = ftrace_find_event(entry->type);
	if (event && event->raw) {
		ret = event->raw(s, entry, 0);
		if (ret)
			return ret;
		return TRACE_TYPE_HANDLED;
	}
	case TRACE_SPECIAL:
	case TRACE_USER_STACK:
	case TRACE_STACK: {
		struct special_entry *field;

		trace_assign_type(field, entry);

		ret = trace_seq_printf(s, "# %ld %ld %ld\n",
				 field->arg1,
				 field->arg2,
				 field->arg3);
	ret = trace_seq_printf(s, "%d ?\n", entry->type);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;
		break;
	}
	case TRACE_PRINT: {
		struct print_entry *field;

		trace_assign_type(field, entry);

		trace_seq_printf(s, "# %lx %s", field->ip, field->buf);
		if (entry->flags & TRACE_FLAG_CONT)
			trace_seq_print_cont(s, iter);
		break;
	}
	}
	return TRACE_TYPE_HANDLED;
}

#define SEQ_PUT_FIELD_RET(s, x)				\
do {							\
	if (!trace_seq_putmem(s, &(x), sizeof(x)))	\
		return 0;				\
} while (0)

#define SEQ_PUT_HEX_FIELD_RET(s, x)			\
do {							\
	BUILD_BUG_ON(sizeof(x) > MAX_MEMHEX_BYTES);	\
	if (!trace_seq_putmem_hex(s, &(x), sizeof(x)))	\
		return 0;				\
} while (0)

static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	unsigned char newline = '\n';
	struct trace_entry *entry;
	int S, T;
	struct trace_event *event;

	entry = iter->ent;

	if (entry->type == TRACE_CONT)
		return TRACE_TYPE_HANDLED;

	SEQ_PUT_HEX_FIELD_RET(s, entry->pid);
	SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);
	SEQ_PUT_HEX_FIELD_RET(s, iter->ts);

	switch (entry->type) {
	case TRACE_FN: {
		struct ftrace_entry *field;
	event = ftrace_find_event(entry->type);
	if (event && event->hex)
		event->hex(s, entry, 0);

		trace_assign_type(field, entry);

		SEQ_PUT_HEX_FIELD_RET(s, field->ip);
		SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
		break;
	}
	case TRACE_CTX:
	case TRACE_WAKE: {
		struct ctx_switch_entry *field;

		trace_assign_type(field, entry);

		T = task_state_char(field->next_state);
		S = entry->type == TRACE_WAKE ? '+' :
			task_state_char(field->prev_state);
		SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
		SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
		SEQ_PUT_HEX_FIELD_RET(s, S);
		SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
		SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
		SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
		SEQ_PUT_HEX_FIELD_RET(s, T);
		break;
	}
	case TRACE_SPECIAL:
	case TRACE_USER_STACK:
	case TRACE_STACK: {
		struct special_entry *field;

		trace_assign_type(field, entry);

		SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
		SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
		SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
		break;
	}
	}
	SEQ_PUT_FIELD_RET(s, newline);

	return TRACE_TYPE_HANDLED;
@@ -2282,9 +1659,6 @@ static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	if (entry->flags & TRACE_FLAG_CONT)
		trace_seq_print_cont(s, iter);

	return TRACE_TYPE_HANDLED;
}

@@ -2292,53 +1666,19 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
{
	struct trace_seq *s = &iter->seq;
	struct trace_entry *entry;
	struct trace_event *event;

	entry = iter->ent;

	if (entry->type == TRACE_CONT)
		return TRACE_TYPE_HANDLED;

	SEQ_PUT_FIELD_RET(s, entry->pid);
	SEQ_PUT_FIELD_RET(s, entry->cpu);
	SEQ_PUT_FIELD_RET(s, iter->ts);

	switch (entry->type) {
	case TRACE_FN: {
		struct ftrace_entry *field;

		trace_assign_type(field, entry);

		SEQ_PUT_FIELD_RET(s, field->ip);
		SEQ_PUT_FIELD_RET(s, field->parent_ip);
		break;
	}
	case TRACE_CTX: {
		struct ctx_switch_entry *field;

		trace_assign_type(field, entry);

		SEQ_PUT_FIELD_RET(s, field->prev_pid);
		SEQ_PUT_FIELD_RET(s, field->prev_prio);
		SEQ_PUT_FIELD_RET(s, field->prev_state);
		SEQ_PUT_FIELD_RET(s, field->next_pid);
		SEQ_PUT_FIELD_RET(s, field->next_prio);
		SEQ_PUT_FIELD_RET(s, field->next_state);
		break;
	}
	case TRACE_SPECIAL:
	case TRACE_USER_STACK:
	case TRACE_STACK: {
		struct special_entry *field;
	event = ftrace_find_event(entry->type);
	if (event && event->binary)
		event->binary(s, entry, 0);

		trace_assign_type(field, entry);

		SEQ_PUT_FIELD_RET(s, field->arg1);
		SEQ_PUT_FIELD_RET(s, field->arg2);
		SEQ_PUT_FIELD_RET(s, field->arg3);
		break;
	}
	}
	return 1;
	return TRACE_TYPE_HANDLED;
}

static int trace_empty(struct trace_iterator *iter)
@@ -3013,6 +2353,7 @@ static int tracing_set_tracer(char *buf)
		if (ret)
			goto out;
	}
	init_tracer_stat(t);

	trace_branch_enable(tr);
 out:
@@ -3877,7 +3218,7 @@ __init static int tracer_alloc_buffers(void)
#else
	current_trace = &nop_trace;
#endif

	init_tracer_stat(current_trace);
	/* All seems OK, enable tracing */
	tracing_disabled = 0;

+20 −16
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ enum trace_type {
	TRACE_FN,
	TRACE_CTX,
	TRACE_WAKE,
	TRACE_CONT,
	TRACE_STACK,
	TRACE_PRINT,
	TRACE_SPECIAL,
@@ -34,7 +33,7 @@ enum trace_type {
	TRACE_KMEM_FREE,
	TRACE_POWER,

	__TRACE_LAST_TYPE
	__TRACE_LAST_TYPE,
};

/*
@@ -199,7 +198,6 @@ struct kmemtrace_free_entry {
 *  NEED_RESCED		- reschedule is requested
 *  HARDIRQ		- inside an interrupt handler
 *  SOFTIRQ		- inside a softirq handler
 *  CONT		- multiple entries hold the trace item
 */
enum trace_flag_type {
	TRACE_FLAG_IRQS_OFF		= 0x01,
@@ -207,7 +205,6 @@ enum trace_flag_type {
	TRACE_FLAG_NEED_RESCHED		= 0x04,
	TRACE_FLAG_HARDIRQ		= 0x08,
	TRACE_FLAG_SOFTIRQ		= 0x10,
	TRACE_FLAG_CONT			= 0x20,
};

#define TRACE_BUF_SIZE		1024
@@ -283,7 +280,6 @@ extern void __ftrace_bad_type(void);
	do {								\
		IF_ASSIGN(var, ent, struct ftrace_entry, TRACE_FN);	\
		IF_ASSIGN(var, ent, struct ctx_switch_entry, 0);	\
		IF_ASSIGN(var, ent, struct trace_field_cont, TRACE_CONT); \
		IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);	\
		IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
		IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);	\
@@ -365,6 +361,21 @@ struct tracer {
	struct tracer		*next;
	int			print_max;
	struct tracer_flags 	*flags;

	/*
	 * If you change one of the following on tracing runtime, recall
	 * init_tracer_stat()
	 */

	/* Iteration over statistic entries */
	void			*(*stat_start)(void);
	void			*(*stat_next)(void *prev, int idx);
	/* Compare two entries for sorting (optional) for stats */
	int			(*stat_cmp)(void *p1, void *p2);
	/* Print a stat entry */
	int			(*stat_show)(struct seq_file *s, void *p);
	/* Print the headers of your stat entries */
	int			(*stat_headers)(struct seq_file *s);
};

struct trace_seq {
@@ -450,6 +461,8 @@ void tracing_start_sched_switch_record(void);
int register_tracer(struct tracer *type);
void unregister_tracer(struct tracer *type);

void init_tracer_stat(struct tracer *trace);

extern unsigned long nsecs_to_usecs(unsigned long nsecs);

extern unsigned long tracing_max_latency;
@@ -481,10 +494,10 @@ struct tracer_switch_ops {
	void				*private;
	struct tracer_switch_ops	*next;
};

char *trace_find_cmdline(int pid);
#endif /* CONFIG_CONTEXT_SWITCH_TRACER */

extern char *trace_find_cmdline(int pid);

#ifdef CONFIG_DYNAMIC_FTRACE
extern unsigned long ftrace_update_tot_cnt;
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
@@ -513,15 +526,6 @@ extern int trace_selftest_startup_branch(struct tracer *trace,
#endif /* CONFIG_FTRACE_STARTUP_TEST */

extern void *head_page(struct trace_array_cpu *data);
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
extern void trace_seq_print_cont(struct trace_seq *s,
				 struct trace_iterator *iter);

extern int
seq_print_ip_sym(struct trace_seq *s, unsigned long ip,
		unsigned long sym_flags);
extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
				 size_t cnt);
extern long ns2usecs(cycle_t nsec);
extern int
trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args);
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/kallsyms.h>

#include "trace.h"
#include "trace_output.h"

static struct trace_array *boot_trace;
static bool pre_initcalls_finished;
Loading