#include "monitor_kernel.h" #include // for cdev #include #include #include #include #include #include // for kmalloc #define DEVICE_NAME "variable_monitor" // 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; 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 = copy_from_user(&dump_param, (ioctl_dump_param *)ioctl_param, sizeof(ioctl_dump_param)); printk(KERN_INFO "dump_param: %p %d %p\n", dump_param.user_ptr_len, dump_param.user_buf_len, dump_param.user_buf); if (!ret) { ret = copy_to_user_variant_buffer( &load_monitor_variant_buffer, dump_param.user_ptr_len, dump_param.user_buf, dump_param.user_buf_len); printk(KERN_INFO "ret %d, %d\n", ret, dump_param.user_buf_len); } // printk(KERN_INFO "copy_to_user_variant_buffer \n"); break; case IOCTL_PID: printk(KERN_INFO "variable_monitor PID\n"); ret = copy_from_user(&wid, (ioctl_id *)ioctl_param, sizeof(ioctl_id)); diag_pid(wid.id); 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; 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(); 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); } MODULE_LICENSE("GPL");