#include "monitor_kernel.h" #include // for cdev #include #include #include #include #include #include // for kmalloc #define DEVICE_NAME "variable_monitor" #include enum { MY_SOFTIRQ = 11, // 这个值是示例,确保它没有被其他软中断使用 }; static void my_softirq_handler(struct softirq_action *action) { // 这是软中断处理函数,它不能睡眠,必须快速执行 // 在这里调用 get_raw_stack diag_task_all(); } // for character device static dev_t dev_num; static struct cdev *watch_cdev; static struct class *watch_class; struct my_device_data { pid_t pid; }; static int device_open(struct inode *inode, struct file *file) { struct my_device_data *data; printk(KERN_INFO "variable_monitor open device with pid %d\n", current->pid); // save pid data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->pid = current->pid; file->private_data = data; return 0; } static int device_release(struct inode *inode, struct file *file) { // load pid struct my_device_data *data = file->private_data; printk(KERN_INFO "variable_monitor release device with pid %d\n", data->pid); // clear watch with pid clear_watch(data->pid); kfree(data); // free data memory return 0; } typedef struct { int id; } ioctl_id; // dump log from buffer static int dump_log(ioctl_dump_param *dump_param, unsigned long ioctl_param, struct diag_variant_buffer *buffer) { int ret = 0; ret = copy_from_user(dump_param, (ioctl_dump_param *)ioctl_param, sizeof(ioctl_dump_param)); printk(KERN_INFO "dump_param: %p %lx %p\n", dump_param->user_ptr_len, dump_param->user_buf_len, dump_param->user_buf); if (!ret) { ret = copy_to_user_variant_buffer(buffer, dump_param->user_ptr_len, dump_param->user_buf, dump_param->user_buf_len); printk(KERN_INFO "ret %d, %lx\n", ret, dump_param->user_buf_len); } return ret; } static long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { int ret = 0; watch_arg warg; ioctl_dump_param dump_param; ioctl_id wid; printk(KERN_INFO "variable_monitor fun: %s with ioctl_num %d\n", __FUNCTION__, ioctl_num); switch (ioctl_num) { case IOCTL_WATCH_VARIABLE: // copy watch_arg if (copy_from_user(&warg, (watch_arg *)ioctl_param, sizeof(warg))) { return -EACCES; } printk(KERN_INFO "Watch_arg: task_id=%d, name=%s, ptr=%p, length_byte=%d, " "time_ns=%ld, threshold=%lld\n", warg.task_id, warg.name, warg.ptr, warg.length_byte, warg.time_ns, warg.threshold); warg.time_ns = warg.time_ns == 0 ? def_interval_ns : warg.time_ns; // default 10us // start watch variable ret = start_watch_variable(warg); if (ret) { printk(KERN_INFO "start_watch_variable failed\n"); } break; case IOCTL_DUMP_LOG: printk(KERN_INFO "variable_monitor IOCTL_DUMP_LOG\n"); ret = dump_log(&dump_param, ioctl_param, &load_monitor_variant_buffer); if (ret) { printk(KERN_INFO "dump_log failed\n"); } break; case IOCTL_PID: printk(KERN_INFO "variable_monitor PID\n"); ret = copy_from_user(&wid, (ioctl_id *)ioctl_param, sizeof(ioctl_id)); if (ret) { printk(KERN_INFO "copy_from_user failed\n"); } ret = diag_pid(wid.id); if (ret) { printk(KERN_INFO "diag_pid failed\n"); } break; case IOCTL_TGID: printk(KERN_INFO "variable_monitor TGID\n"); ret = copy_from_user(&wid, (ioctl_id *)ioctl_param, sizeof(ioctl_id)); diag_tgid(wid.id); break; case IOCTL_DUMP_LOG_SA: printk(KERN_INFO "variable_monitor IOCTL_DUMP_LOG_SA\n"); ret = dump_log(&dump_param, ioctl_param, &stand_alone_buffer); if (ret) { printk(KERN_INFO "dump_log failed\n"); } break; default: break; } return 0; } static struct file_operations fops = { .open = device_open, .release = device_release, .unlocked_ioctl = device_ioctl, }; int init_module(void) { printk(KERN_INFO "variable_monitor fun: %s\n", __FUNCTION__); if (alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME) < 0) { printk(KERN_ALERT "Failed to register device number\n"); return -1; } if ((watch_class = class_create(THIS_MODULE, DEVICE_NAME)) == NULL) { printk(KERN_ALERT "Failed to create class\n"); cdev_del(watch_cdev); unregister_chrdev_region(dev_num, 1); return -1; } if (device_create(watch_class, NULL, dev_num, NULL, DEVICE_NAME) == NULL) { printk(KERN_ALERT "Failed to create device\n"); class_destroy(watch_class); cdev_del(watch_cdev); unregister_chrdev_region(dev_num, 1); return -1; } if ((watch_cdev = cdev_alloc()) == NULL) { printk(KERN_ALERT "Failed to allocate cdev structure\n"); unregister_chrdev_region(dev_num, 1); return -1; } cdev_init(watch_cdev, &fops); if (cdev_add(watch_cdev, dev_num, 1) == -1) { printk(KERN_ALERT "Failed to add cdev structure\n"); device_destroy(watch_class, dev_num); class_destroy(watch_class); unregister_chrdev_region(dev_num, 1); return -1; } printk(KERN_INFO "dev number: %d\n", dev_num); printk(KERN_INFO "path: /dev/%s %d\n", DEVICE_NAME, dev_num); // proc monitor_proc_init(); // orig_X | buffer monitor_init(); orig_open_softirq(MY_SOFTIRQ, my_softirq_handler); return 0; } void cleanup_module(void) { printk(KERN_INFO "variable_monitor fun: %s\n", __FUNCTION__); // clear all watch | free buffer monitor_exit(); // proc monitor_proc_exit(); // unmount device_destroy(watch_class, dev_num); class_destroy(watch_class); cdev_del(watch_cdev); unregister_chrdev_region(dev_num, 1); cleanup_perf_event(); // just for perf test } MODULE_LICENSE("GPL");