| // SPDX-License-Identifier: GPL-2.0 | |
| #include <linux/init.h> | |
| #include <linux/errno.h> | |
| #include <linux/kernel.h> | |
| #include <linux/proc_fs.h> | |
| #include <linux/slab.h> | |
| #include <linux/types.h> | |
| #include <asm/ptrace.h> | |
| #include <linux/uaccess.h> | |
| #define SAMPLE_BUFFER_SIZE 8192 | |
| static char *sample_buffer; | |
| static char *sample_buffer_pos; | |
| static int prof_running = 0; | |
| void cris_profile_sample(struct pt_regs *regs) | |
| { | |
| if (!prof_running) | |
| return; | |
| if (user_mode(regs)) | |
| *(unsigned int*)sample_buffer_pos = current->pid; | |
| else | |
| *(unsigned int*)sample_buffer_pos = 0; | |
| *(unsigned int *)(sample_buffer_pos + 4) = instruction_pointer(regs); | |
| sample_buffer_pos += 8; | |
| if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE) | |
| sample_buffer_pos = sample_buffer; | |
| } | |
| static ssize_t | |
| read_cris_profile(struct file *file, char __user *buf, | |
| size_t count, loff_t *ppos) | |
| { | |
| unsigned long p = *ppos; | |
| ssize_t ret; | |
| ret = simple_read_from_buffer(buf, count, ppos, sample_buffer, | |
| SAMPLE_BUFFER_SIZE); | |
| if (ret < 0) | |
| return ret; | |
| memset(sample_buffer + p, 0, ret); | |
| return ret; | |
| } | |
| static ssize_t | |
| write_cris_profile(struct file *file, const char __user *buf, | |
| size_t count, loff_t *ppos) | |
| { | |
| sample_buffer_pos = sample_buffer; | |
| memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE); | |
| return count < SAMPLE_BUFFER_SIZE ? count : SAMPLE_BUFFER_SIZE; | |
| } | |
| static const struct file_operations cris_proc_profile_operations = { | |
| .read = read_cris_profile, | |
| .write = write_cris_profile, | |
| .llseek = default_llseek, | |
| }; | |
| static int __init init_cris_profile(void) | |
| { | |
| struct proc_dir_entry *entry; | |
| sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL); | |
| if (!sample_buffer) { | |
| return -ENOMEM; | |
| } | |
| sample_buffer_pos = sample_buffer; | |
| entry = proc_create("system_profile", S_IWUSR | S_IRUGO, NULL, | |
| &cris_proc_profile_operations); | |
| if (entry) { | |
| proc_set_size(entry, SAMPLE_BUFFER_SIZE); | |
| } | |
| prof_running = 1; | |
| return 0; | |
| } | |
| __initcall(init_cris_profile); | |