📄 ftrace.c
字号:
type = MATCH_END_ONLY; search_len = len - (i + 1); } else { if (type == MATCH_END_ONLY) { type = MATCH_MIDDLE_ONLY; } else { match = i; type = MATCH_FRONT_ONLY; } buff[i] = 0; break; } } } /* keep kstop machine from running */ preempt_disable(); if (enable) ftrace_filtered = 1; pg = ftrace_pages_start; while (pg) { for (i = 0; i < pg->index; i++) { int matched = 0; char *ptr; rec = &pg->records[i]; if (rec->flags & FTRACE_FL_FAILED) continue; kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); switch (type) { case MATCH_FULL: if (strcmp(str, buff) == 0) matched = 1; break; case MATCH_FRONT_ONLY: if (memcmp(str, buff, match) == 0) matched = 1; break; case MATCH_MIDDLE_ONLY: if (strstr(str, search)) matched = 1; break; case MATCH_END_ONLY: ptr = strstr(str, search); if (ptr && (ptr[search_len] == 0)) matched = 1; break; } if (matched) rec->flags |= flag; } pg = pg->next; } preempt_enable();}static ssize_tftrace_regex_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos, int enable){ struct ftrace_iterator *iter; char ch; size_t read = 0; ssize_t ret; if (!cnt || cnt < 0) return 0; mutex_lock(&ftrace_regex_lock); if (file->f_mode & FMODE_READ) { struct seq_file *m = file->private_data; iter = m->private; } else iter = file->private_data; if (!*ppos) { iter->flags &= ~FTRACE_ITER_CONT; iter->buffer_idx = 0; } ret = get_user(ch, ubuf++); if (ret) goto out; read++; cnt--; if (!(iter->flags & ~FTRACE_ITER_CONT)) { /* skip white space */ while (cnt && isspace(ch)) { ret = get_user(ch, ubuf++); if (ret) goto out; read++; cnt--; } if (isspace(ch)) { file->f_pos += read; ret = read; goto out; } iter->buffer_idx = 0; } while (cnt && !isspace(ch)) { if (iter->buffer_idx < FTRACE_BUFF_MAX) iter->buffer[iter->buffer_idx++] = ch; else { ret = -EINVAL; goto out; } ret = get_user(ch, ubuf++); if (ret) goto out; read++; cnt--; } if (isspace(ch)) { iter->filtered++; iter->buffer[iter->buffer_idx] = 0; ftrace_match(iter->buffer, iter->buffer_idx, enable); iter->buffer_idx = 0; } else iter->flags |= FTRACE_ITER_CONT; file->f_pos += read; ret = read; out: mutex_unlock(&ftrace_regex_lock); return ret;}static ssize_tftrace_filter_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos){ return ftrace_regex_write(file, ubuf, cnt, ppos, 1);}static ssize_tftrace_notrace_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos){ return ftrace_regex_write(file, ubuf, cnt, ppos, 0);}static voidftrace_set_regex(unsigned char *buf, int len, int reset, int enable){ if (unlikely(ftrace_disabled)) return; mutex_lock(&ftrace_regex_lock); if (reset) ftrace_filter_reset(enable); if (buf) ftrace_match(buf, len, enable); mutex_unlock(&ftrace_regex_lock);}/** * ftrace_set_filter - set a function to filter on in ftrace * @buf - the string that holds the function filter text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. * * Filters denote which functions should be enabled when tracing is enabled. * If @buf is NULL and reset is set, all functions will be enabled for tracing. */void ftrace_set_filter(unsigned char *buf, int len, int reset){ ftrace_set_regex(buf, len, reset, 1);}/** * ftrace_set_notrace - set a function to not trace in ftrace * @buf - the string that holds the function notrace text. * @len - the length of the string. * @reset - non zero to reset all filters before applying this filter. * * Notrace Filters denote which functions should not be enabled when tracing * is enabled. If @buf is NULL and reset is set, all functions will be enabled * for tracing. */void ftrace_set_notrace(unsigned char *buf, int len, int reset){ ftrace_set_regex(buf, len, reset, 0);}static intftrace_regex_release(struct inode *inode, struct file *file, int enable){ struct seq_file *m = (struct seq_file *)file->private_data; struct ftrace_iterator *iter; mutex_lock(&ftrace_regex_lock); if (file->f_mode & FMODE_READ) { iter = m->private; seq_release(inode, file); } else iter = file->private_data; if (iter->buffer_idx) { iter->filtered++; iter->buffer[iter->buffer_idx] = 0; ftrace_match(iter->buffer, iter->buffer_idx, enable); } mutex_lock(&ftrace_sysctl_lock); mutex_lock(&ftraced_lock); if (iter->filtered && ftraced_suspend && ftrace_enabled) ftrace_run_update_code(FTRACE_ENABLE_CALLS); mutex_unlock(&ftraced_lock); mutex_unlock(&ftrace_sysctl_lock); kfree(iter); mutex_unlock(&ftrace_regex_lock); return 0;}static intftrace_filter_release(struct inode *inode, struct file *file){ return ftrace_regex_release(inode, file, 1);}static intftrace_notrace_release(struct inode *inode, struct file *file){ return ftrace_regex_release(inode, file, 0);}static ssize_tftraced_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos){ /* don't worry about races */ char *buf = ftraced_stop ? "disabled\n" : "enabled\n"; int r = strlen(buf); return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);}static ssize_tftraced_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos){ char buf[64]; long val; int ret; if (cnt >= sizeof(buf)) return -EINVAL; if (copy_from_user(&buf, ubuf, cnt)) return -EFAULT; if (strncmp(buf, "enable", 6) == 0) val = 1; else if (strncmp(buf, "disable", 7) == 0) val = 0; else { buf[cnt] = 0; ret = strict_strtoul(buf, 10, &val); if (ret < 0) return ret; val = !!val; } if (val) ftrace_enable_daemon(); else ftrace_disable_daemon(); filp->f_pos += cnt; return cnt;}static struct file_operations ftrace_avail_fops = { .open = ftrace_avail_open, .read = seq_read, .llseek = seq_lseek, .release = ftrace_avail_release,};static struct file_operations ftrace_failures_fops = { .open = ftrace_failures_open, .read = seq_read, .llseek = seq_lseek, .release = ftrace_avail_release,};static struct file_operations ftrace_filter_fops = { .open = ftrace_filter_open, .read = ftrace_regex_read, .write = ftrace_filter_write, .llseek = ftrace_regex_lseek, .release = ftrace_filter_release,};static struct file_operations ftrace_notrace_fops = { .open = ftrace_notrace_open, .read = ftrace_regex_read, .write = ftrace_notrace_write, .llseek = ftrace_regex_lseek, .release = ftrace_notrace_release,};static struct file_operations ftraced_fops = { .open = tracing_open_generic, .read = ftraced_read, .write = ftraced_write,};/** * ftrace_force_update - force an update to all recording ftrace functions */int ftrace_force_update(void){ int ret = 0; if (unlikely(ftrace_disabled)) return -ENODEV; mutex_lock(&ftrace_sysctl_lock); mutex_lock(&ftraced_lock); /* * If ftraced_trigger is not set, then there is nothing * to update. */ if (ftraced_trigger && !ftrace_update_code()) ret = -EBUSY; mutex_unlock(&ftraced_lock); mutex_unlock(&ftrace_sysctl_lock); return ret;}static void ftrace_force_shutdown(void){ struct task_struct *task; int command = FTRACE_DISABLE_CALLS | FTRACE_UPDATE_TRACE_FUNC; mutex_lock(&ftraced_lock); task = ftraced_task; ftraced_task = NULL; ftraced_suspend = -1; ftrace_run_update_code(command); mutex_unlock(&ftraced_lock); if (task) kthread_stop(task);}static __init int ftrace_init_debugfs(void){ struct dentry *d_tracer; struct dentry *entry; d_tracer = tracing_init_dentry(); entry = debugfs_create_file("available_filter_functions", 0444, d_tracer, NULL, &ftrace_avail_fops); if (!entry) pr_warning("Could not create debugfs " "'available_filter_functions' entry\n"); entry = debugfs_create_file("failures", 0444, d_tracer, NULL, &ftrace_failures_fops); if (!entry) pr_warning("Could not create debugfs 'failures' entry\n"); entry = debugfs_create_file("set_ftrace_filter", 0644, d_tracer, NULL, &ftrace_filter_fops); if (!entry) pr_warning("Could not create debugfs " "'set_ftrace_filter' entry\n"); entry = debugfs_create_file("set_ftrace_notrace", 0644, d_tracer, NULL, &ftrace_notrace_fops); if (!entry) pr_warning("Could not create debugfs " "'set_ftrace_notrace' entry\n"); entry = debugfs_create_file("ftraced_enabled", 0644, d_tracer, NULL, &ftraced_fops); if (!entry) pr_warning("Could not create debugfs " "'ftraced_enabled' entry\n"); return 0;}fs_initcall(ftrace_init_debugfs);static int __init ftrace_dynamic_init(void){ struct task_struct *p; unsigned long addr; int ret; addr = (unsigned long)ftrace_record_ip; stop_machine(ftrace_dyn_arch_init, &addr, NULL); /* ftrace_dyn_arch_init places the return code in addr */ if (addr) { ret = (int)addr; goto failed; } ret = ftrace_dyn_table_alloc(); if (ret) goto failed; p = kthread_run(ftraced, NULL, "ftraced"); if (IS_ERR(p)) { ret = -1; goto failed; } last_ftrace_enabled = ftrace_enabled = 1; ftraced_task = p; return 0; failed: ftrace_disabled = 1; return ret;}core_initcall(ftrace_dynamic_init);#else# define ftrace_startup() do { } while (0)# define ftrace_shutdown() do { } while (0)# define ftrace_startup_sysctl() do { } while (0)# define ftrace_shutdown_sysctl() do { } while (0)# define ftrace_force_shutdown() do { } while (0)#endif /* CONFIG_DYNAMIC_FTRACE *//** * ftrace_kill_atomic - kill ftrace from critical sections * * This function should be used by panic code. It stops ftrace * but in a not so nice way. If you need to simply kill ftrace * from a non-atomic section, use ftrace_kill. */void ftrace_kill_atomic(void){ ftrace_disabled = 1; ftrace_enabled = 0;#ifdef CONFIG_DYNAMIC_FTRACE ftraced_suspend = -1;#endif clear_ftrace_function();}/** * ftrace_kill - totally shutdown ftrace * * This is a safety measure. If something was detected that seems * wrong, calling this function will keep ftrace from doing * any more modifications, and updates. * used when something went wrong. */void ftrace_kill(void){ mutex_lock(&ftrace_sysctl_lock); ftrace_disabled = 1; ftrace_enabled = 0; clear_ftrace_function(); mutex_unlock(&ftrace_sysctl_lock); /* Try to totally disable ftrace */ ftrace_force_shutdown();}/** * register_ftrace_function - register a function for profiling * @ops - ops structure that holds the function for profiling. * * Register a function to be called by all functions in the * kernel. * * Note: @ops->func and all the functions it calls must be labeled * with "notrace", otherwise it will go into a * recursive loop. */int register_ftrace_function(struct ftrace_ops *ops){ int ret; if (unlikely(ftrace_disabled)) return -1; mutex_lock(&ftrace_sysctl_lock); ret = __register_ftrace_function(ops); ftrace_startup(); mutex_unlock(&ftrace_sysctl_lock); return ret;}/** * unregister_ftrace_function - unresgister a function for profiling. * @ops - ops structure that holds the function to unregister * * Unregister a function that was added to be called by ftrace profiling. */int unregister_ftrace_function(struct ftrace_ops *ops){ int ret; mutex_lock(&ftrace_sysctl_lock); ret = __unregister_ftrace_function(ops); ftrace_shutdown(); mutex_unlock(&ftrace_sysctl_lock); return ret;}intftrace_enable_sysctl(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *lenp, loff_t *ppos){ int ret; if (unlikely(ftrace_disabled)) return -ENODEV; mutex_lock(&ftrace_sysctl_lock); ret = proc_dointvec(table, write, file, buffer, lenp, ppos); if (ret || !write || (last_ftrace_enabled == ftrace_enabled)) goto out; last_ftrace_enabled = ftrace_enabled; if (ftrace_enabled) { ftrace_startup_sysctl(); /* we are starting ftrace again */ if (ftrace_list != &ftrace_list_end) { if (ftrace_list->next == &ftrace_list_end) ftrace_trace_function = ftrace_list->func; else ftrace_trace_function = ftrace_list_func; } } else { /* stopping ftrace calls (just send to ftrace_stub) */ ftrace_trace_function = ftrace_stub; ftrace_shutdown_sysctl(); } out: mutex_unlock(&ftrace_sysctl_lock); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -