📄 trace.c
字号:
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 + -