diff --git a/source/module/monitor_kallsyms.c b/source/module/monitor_kallsyms.c new file mode 100644 index 0000000..81dec2e --- /dev/null +++ b/source/module/monitor_kallsyms.c @@ -0,0 +1,29 @@ +#include "monitor_kallsyms.h" + +/// @brief init kallsyms_lookup_name +/// @param +/// @return 0 is success +static int fn_kallsyms_lookup_name_init(void) { + register_kprobe(&kprobe_kallsyms_lookup_name); + diag_kallsyms_lookup_name = (void *)kprobe_kallsyms_lookup_name.addr; + unregister_kprobe(&kprobe_kallsyms_lookup_name); + + printk("xby-debug, diag_kallsyms_lookup_name is %p\n", + diag_kallsyms_lookup_name); + + if (!diag_kallsyms_lookup_name) { + return -EINVAL; + } + return 0; +} + +int init_orig_fun(void) { + fn_kallsyms_lookup_name_init(); // init kallsyms_lookup_name + LOOKUP_SYMS(stack_trace_save_tsk); // stack_trace_save_tsk + LOOKUP_SYMS(show_stack); // show_stack + LOOKUP_SYMS(idle_sched_class); // idle_sched_class + LOOKUP_SYMS(access_remote_vm); // access_remote_vm + + LOOKUP_SYMS_NORET(get_task_type); // get_task_type + LOOKUP_SYMS_NORET(kernfs_name); // kernfs_name +} diff --git a/source/module/monitor_kallsyms.h b/source/module/monitor_kallsyms.h new file mode 100644 index 0000000..92cbc24 --- /dev/null +++ b/source/module/monitor_kallsyms.h @@ -0,0 +1,44 @@ +#include + +// for diag_kallsyms_lookup_name +unsigned long (*diag_kallsyms_lookup_name)(const char *name); +struct kprobe kprobe_kallsyms_lookup_name = {.symbol_name = + "kallsyms_lookup_name"}; + +// int fn_kallsyms_lookup_name_init(void); // init kallsyms_lookup_name + +// form +// https://github.com/alibaba/diagnose-tools/blob/8cd905a1c17f2201e460a2d607413a1303757a32/SOURCE/module/internal.h#L65 +// look for current function address, all the function with prefix "orig_" are +#define LOOKUP_SYMS(name) \ + do { \ + orig_##name = (void *)diag_kallsyms_lookup_name(#name); \ + if (!orig_##name) { \ + printk(KERN_ERR "kallsyms_lookup_name: %s\n", #name); \ + return -EINVAL; \ + } \ + } while (0) + +#define LOOKUP_SYMS_NORET(name) \ + do { \ + orig_##name = (void *)diag_kallsyms_lookup_name(#name); \ + if (!orig_##name) \ + pr_err("kallsyms_lookup_name: %s\n", #name); \ + } while (0) + +int init_orig_fun(void); + +// All the function with prefix "orig_X" are +// LOOKUP_SYMS(X); +unsigned int (*orig_stack_trace_save_tsk)(struct task_struct *task, + unsigned long *store, + unsigned int size, + unsigned int skipnr); +void (*orig_show_stack)(struct task_struct *task, unsigned long *sp, + const char *loglvl); + +struct sched_class *orig_idle_sched_class; +int (*orig_get_task_type)(struct sched_entity *se); +int (*orig_kernfs_name)(struct kernfs_node *kn, char *buf, size_t buflen); +int (*orig_access_remote_vm)(struct mm_struct *mm, unsigned long addr, + void *buf, int len, unsigned int gup_flags); \ No newline at end of file diff --git a/source/module/monitor_kernel.c b/source/module/monitor_kernel.c index f0cea23..b79d131 100644 --- a/source/module/monitor_kernel.c +++ b/source/module/monitor_kernel.c @@ -1,11 +1,12 @@ +#include // for cdev #include #include #include #include #include +#include // for kmalloc -#include "monitor_kernel_lib.c" -#include "monitor_kernel_task.c" +#include "monitor_kernel.h" #define DEVICE_NAME "variable_monitor" @@ -43,45 +44,16 @@ static int device_release(struct inode *inode, struct file *file) { static long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { watch_arg warg; - void *kptr; - kernel_watch_timer *timer = NULL; - kernel_watch_arg k_watch_arg; // 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); - // user space address to kernel space address - kptr = convert_user_space_ptr(warg.task_id, (unsigned long)warg.ptr); - if (kptr == NULL) { - printk(KERN_ERR "Cannot access user space\n"); - return -EACCES; - } - // check length - if (warg.length_byte != 1 && warg.length_byte != 2 && warg.length_byte != 4 && - warg.length_byte != 8) { - printk(KERN_ERR "Invalid length %d\n", warg.length_byte); - return -EINVAL; - } - // k_watch_arg init - w_arg2k_w_arg(kptr, warg, &k_watch_arg); - timer = get_timer(warg.time_ns); // get a valuable timer - - printk(KERN_INFO "ptr transform kptr: %p\n", kptr); - printk(KERN_INFO "timer: %p\n", timer); - printk(KERN_INFO "timer->sentinel: %d, timer->time_ns: %lld\n", - timer->sentinel, timer->time_ns); - printk(KERN_INFO "timer->hr_timer: %p\n", &timer->hr_timer); - - TIMER_CANCEL(timer); // just in case - timer_add_watch(timer, k_watch_arg); - TIMER_START(timer); - - printk(KERN_INFO "Start watching var: %s\n", warg.name); + // start watch variable + start_watch_variable(warg); return 0; } @@ -131,6 +103,7 @@ int init_module(void) { printk(KERN_INFO "dev number: %d\n", dev_num); printk(KERN_INFO "path: /dev/%s %d\n", DEVICE_NAME, dev_num); + // orig_X | buffer monitor_init(); return 0; @@ -138,8 +111,9 @@ int init_module(void) { void cleanup_module(void) { printk(KERN_INFO "%s\n", __FUNCTION__); - // clear all timer and page list - clear_all_watch(); + // clear all watch | free buffer + monitor_exit(); + // unmount device_destroy(watch_class, dev_num); class_destroy(watch_class); @@ -148,15 +122,3 @@ void cleanup_module(void) { } MODULE_LICENSE("GPL"); - -// one more thing -int monitor_init(void){ - fn_kallsyms_lookup_name_init(); // init kallsyms_lookup_name - LOOKUP_SYMS(stack_trace_save_tsk); // stack_trace_save_tsk - LOOKUP_SYMS(show_stack); // show_stack - LOOKUP_SYMS(idle_sched_class); // idle_sched_class - LOOKUP_SYMS(access_remote_vm); // access_remote_vm - - LOOKUP_SYMS_NORET(get_task_type); // get_task_type - LOOKUP_SYMS_NORET(kernfs_name); // kernfs_name -} \ No newline at end of file diff --git a/source/module/monitor_kernel.h b/source/module/monitor_kernel.h index f44efef..dda9108 100644 --- a/source/module/monitor_kernel.h +++ b/source/module/monitor_kernel.h @@ -1,182 +1,13 @@ -#include -#include -#include -#include -#include /* for kmalloc */ -#include +#include "monitor_kallsyms.h" +#include "monitor_mem.h" +#include "monitor_timer.h" +#include "monitor_trace.h" -#include -#include -#include -#include -#include /* for avenrun, LOAD_* */ -#include -#include -#include /* for stack_trace_print */ +extern mm_tree mm_tree_struct; +extern struct diag_variant_buffer load_monitor_variant_buffer; -#define MAX_TIMER_NUM (128) // max timer number -#define TIMER_MAX_WATCH_NUM (32) // A timer max watch number at once time -#define MAX_NAME_LEN (15) // max name length -typedef struct { - pid_t task_id; // current process id - char name[MAX_NAME_LEN + 1]; // name - void *ptr; // virtual address - int length_byte; // byte - long long threshold; // threshold value - unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) - unsigned char greater_flag; // reverse flag (true: >, false: <) - unsigned long time_ns; // timer interval (ns) -} watch_arg; - -typedef struct { - pid_t task_id; // current process id - char name[MAX_NAME_LEN + 2]; // name, last char automatically add '\0' - void *kptr; // kernel address + offset - int length_byte; // byte - long long threshold; // threshold value - unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) - unsigned char greater_flag; // reverse flag (true: >, false: <) -} kernel_watch_arg; - -typedef struct { - unsigned long long time_ns; // hrTimer time interval (ns) - struct hrtimer hr_timer; // hrTimer - ktime_t kt; // hrTimer time - unsigned sentinel; // sentinel - kernel_watch_arg - k_watch_args[TIMER_MAX_WATCH_NUM]; // all watched kernel_watch_arg -} kernel_watch_timer; - -#define TIMER_FILLED(timer) ((timer)->sentinel >= TIMER_MAX_WATCH_NUM) -#define TIMER_EMPTY(timer) (!((timer)->time_ns | (timer)->sentinel)) -#define TIMER_NO_KWARG(timer) ((timer)->sentinel == 0) - -#define TIMER_START(timer) \ - (hrtimer_start(&timer->hr_timer, timer->kt, HRTIMER_MODE_REL)) -#define TIMER_CANCEL(timer) (hrtimer_cancel(&timer->hr_timer)) - -kernel_watch_timer kernel_wtimer_list[MAX_TIMER_NUM] = { - 0}; // all kernel_watch_timer -int kernel_wtimer_num = 0; // current kernel_watch_timer number - -EXPORT_SYMBOL(kernel_wtimer_list); // export kernel_watch_timer_list -EXPORT_SYMBOL(kernel_wtimer_num); // export kernel_watch_timer_num - -// Helper function -unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, - kernel_watch_arg *k_watch_arg); - -// for timer -kernel_watch_timer *get_timer(unsigned long long time_ns); -unsigned char timer_add_watch(kernel_watch_timer *timer, - kernel_watch_arg k_watch_arg); -unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid); - -// for memory access -typedef struct { - pid_t task_id; // current process id - struct page *page; - void *kaddr; - struct list_head entry; -} watch_local_memory; - -static LIST_HEAD(watch_local_memory_list); - -void free_page_list(pid_t task_id); -void free_all_page_list(void); - -// static struct page *page = NULL; -// static void *kaddr = NULL; - -void *convert_user_space_ptr(pid_t pid, unsigned long kaddr); - -// for timer -// #define US2NS (1000) // Interval in microseconds -// static struct hrtimer hr_timer; -// static ktime_t kt; - -// hrTimer -enum hrtimer_restart check_variable_cb(struct hrtimer *timer); -void start_all_hrTimer(void); -void cancel_all_hrTimer(void); - -unsigned char read_and_compare(kernel_watch_arg *k_arg); - -// for diag_kallsyms_lookup_name -unsigned long (*diag_kallsyms_lookup_name)(const char *name); -static struct kprobe kprobe_kallsyms_lookup_name = {.symbol_name = - "kallsyms_lookup_name"}; - -int fn_kallsyms_lookup_name_init(void); // init kallsyms_lookup_name - -// form -// https://github.com/alibaba/diagnose-tools/blob/8cd905a1c17f2201e460a2d607413a1303757a32/SOURCE/module/internal.h#L65 -// look for current function address, all the function with prefix "orig_" are -#define LOOKUP_SYMS(name) \ - do { \ - orig_##name = (void *)diag_kallsyms_lookup_name(#name); \ - if (!orig_##name) { \ - printk(KERN_ERR "kallsyms_lookup_name: %s\n", #name); \ - return -EINVAL; \ - } \ - } while (0) - -#define LOOKUP_SYMS_NORET(name) \ - do { \ - orig_##name = (void *)diag_kallsyms_lookup_name(#name); \ - if (!orig_##name) \ - pr_err("kallsyms_lookup_name: %s\n", #name); \ - } while (0) - -#define BACKTRACE_DEPTH 20 // max stack depth - -// LOOKUP_SYMS(stack_trace_save_tsk); -unsigned int (*orig_stack_trace_save_tsk)(struct task_struct *task, - unsigned long *store, - unsigned int size, - unsigned int skipnr); -// LOOKUP_SYMS(show_stack); -void (*orig_show_stack)(struct task_struct *task, unsigned long *sp, - const char *loglvl); - -// https://www.spinics.net/lists/kernel/msg3582022.html -// remove from 5.8.rc3,but it still work -// whether the task contributes to the load -#define __task_contributes_to_load(task) \ - ((READ_ONCE(task->__state) & TASK_UNINTERRUPTIBLE) != 0 && \ - (task->flags & PF_FROZEN) == 0 && \ - (READ_ONCE(task->__state) & TASK_NOLOAD) == 0) - -/// @brief print all task stack -/// @param -static void print_task_stack(void) { - struct task_struct *g, *p; // g: task group; p: task - unsigned long backtrace[BACKTRACE_DEPTH]; // save stack - unsigned int nr_bt; // stack depth - unsigned long long current_time; // last time - current_time = ktime_get_real(); - printk("Timestamp (ns): %lld\n", current_time); - printk("Recent Load: %lu.%02lu, %lu.%02lu, %lu.%02lu\n", // recent load - LOAD_INT(avenrun[0]), LOAD_FRAC(avenrun[0]), LOAD_INT(avenrun[1]), - LOAD_FRAC(avenrun[1]), LOAD_INT(avenrun[2]), LOAD_FRAC(avenrun[2])); - rcu_read_lock(); // lock run queue - // printk("Running task\n"); - do_each_thread(g, p) { - if (p->__state == TASK_RUNNING || __task_contributes_to_load(p) || - p->__state == TASK_IDLE) { - printk("task: %s, pid %d, state %d\n", p->comm, p->pid, - p->__state); //! todo - nr_bt = orig_stack_trace_save_tsk(p, backtrace, BACKTRACE_DEPTH, 0); - stack_trace_print(backtrace, nr_bt, 0); // print - } - } - while_each_thread(g, p); - rcu_read_unlock(); // unlock run queue -} - -unsigned char del_all_kwarg_by_pid(pid_t pid); -void clear_watch(pid_t pid); -void clear_all_watch(void); - -// one more thing int monitor_init(void); +void monitor_exit(void); + +int start_watch_variable(watch_arg warg); +void clear_watch(pid_t pid); diff --git a/source/module/monitor_kernel_lib.c b/source/module/monitor_kernel_lib.c index 3dea0cd..38fdfd4 100644 --- a/source/module/monitor_kernel_lib.c +++ b/source/module/monitor_kernel_lib.c @@ -1,7 +1,15 @@ #include "monitor_kernel.h" -unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, - kernel_watch_arg *k_watch_arg) { +/** + * @brief watch_arg to kernel_watch_arg + * + * @param ptr: kernel space address + * @param warg: watch_arg + * @param k_watch_arg: kernel_watch_arg + * @return unsigned char + */ +static unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, + kernel_watch_arg *k_watch_arg) { // k_watch_arg init k_watch_arg->task_id = warg.task_id; strncpy(k_watch_arg->name, warg.name, MAX_NAME_LEN + 1); // name @@ -14,408 +22,22 @@ unsigned char w_arg2k_w_arg(void *ptr, watch_arg warg, return 0; } -/// @brief get a valuable timer -/// @param time_ns -/// @return kernel_watch_timer *, NULL means fail -kernel_watch_timer *get_timer(unsigned long long time_ns) { - int i = 0; - kernel_watch_timer *timer = NULL; - // chose a timer - for (i = 0; i < kernel_wtimer_num; i++) { - timer = &kernel_wtimer_list[i]; - - if (TIMER_EMPTY(timer)) { - break; - } - if ((timer->time_ns == time_ns) && (!TIMER_FILLED(timer))) { - break; - } - } - // if all timer is full - if (i >= MAX_TIMER_NUM) { - printk(KERN_ERR "No timer available\n"); - return NULL; - } - // if a new timer, init it - if (i > kernel_wtimer_num - 1) { - printk(KERN_INFO "New timer\n"); - - kernel_wtimer_list[i].time_ns = time_ns; - kernel_wtimer_list[i].sentinel = 0; - - kernel_wtimer_list[i].kt = ktime_set(0, (unsigned long)time_ns); // ns - // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time - hrtimer_init(&(kernel_wtimer_list[i].hr_timer), CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - kernel_wtimer_list[i].hr_timer.function = - check_variable_cb; // callback function - - kernel_wtimer_num = i + 1; - } - printk(KERN_INFO "now, we have %d timers\n", kernel_wtimer_num); - return &kernel_wtimer_list[i]; +static void init_mm_tree(mm_tree *mm_tree) { + INIT_RADIX_TREE(&mm_tree->mm_tree, GFP_ATOMIC); + spin_lock_init(&mm_tree->mm_tree_lock); } -/// @brief hrTimer add watch -/// @param timer -/// @param k_watch_arg -/// @return 0 is success -unsigned char timer_add_watch(kernel_watch_timer *timer, - kernel_watch_arg k_watch_arg) { - if (TIMER_FILLED(timer)) { - printk(KERN_ERR "Timer is full\n"); - return -1; - } - memcpy(&timer->k_watch_args[timer->sentinel], &k_watch_arg, - sizeof(k_watch_arg)); - // timer->k_watch_args[timer->sentinel] = k_watch_arg; - timer->sentinel++; - return 0; -} - -unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid) { - int i = 0; - for (i = 0; i < timer->sentinel; i++) { - // if pid match, delete it and move the last one to this position, check - // again - if (timer->k_watch_args[i].task_id == pid) { - if (i != timer->sentinel - 1) { - memcpy(&timer->k_watch_args[i], - &timer->k_watch_args[timer->sentinel - 1], - sizeof(kernel_watch_arg)); - } - timer->sentinel--; - i--; - } - } - return 0; -} - -/// @brief transfer user space address to kernel space address -/// change static global "kaddr" and "page" value -/// @param pid: process id -/// @param kaddr: user space address -/// @return kernel space address + offset -void *convert_user_space_ptr(pid_t pid, unsigned long addr) { - struct task_struct *task; - struct mm_struct *mm; - int ret; - - // unsigned long aligned_addr = 0; - // unsigned long offset = 0; - - watch_local_memory *node; - - // if (addr < TASK_SIZE || addr > -PAGE_SIZE) - // { - // printk(KERN_ERR "Invalid address\n"); - // return NULL; - // } - - // for get_user_pages_remote - unsigned long aligned_addr = addr & PAGE_MASK; - unsigned long offset = addr & ~PAGE_MASK; - - printk(KERN_INFO "%s\n", __FUNCTION__); - - node = kmalloc(sizeof(watch_local_memory), GFP_KERNEL); - node->task_id = pid; - - // Find the task with pid - rcu_read_lock(); - task = pid_task(find_vpid(pid), PIDTYPE_PID); - rcu_read_unlock(); - - if (!task) { - printk(KERN_ERR "Cannot find task for PID %d\n", pid); - kfree(node); // careful there is kfree - return NULL; - } - // Get memory descriptor - mm = get_task_mm(task); - if (!mm) { - printk(KERN_ERR "Cannot get memory descriptor\n"); - kfree(node); // careful there is kfree - return NULL; - } - down_read(&task->mm->mmap_lock); - ret = get_user_pages_remote(task->mm, aligned_addr, 1, FOLL_FORCE, - &(node->page), NULL, NULL); - up_read(&task->mm->mmap_lock); - - if (ret != 1) { - printk(KERN_ERR "Cannot get user page\n"); - kfree(node); // careful there is kfree - return NULL; - } - // Map the page to kernel space - node->kaddr = kmap(node->page); - list_add_tail(&node->entry, &watch_local_memory_list); // add to list - // printk(KERN_INFO "node->kaddr: %p, aligned_addr: %ld, offset: %ld\n", - // node->kaddr, aligned_addr, offset); - return (void *)((unsigned long)(node->kaddr) + offset); -} - -/// @brief free page in watch_local_memory_list with task_id -/// @param task_id -void free_page_list(pid_t task_id) { - watch_local_memory *node, *next; - list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { - if (node == NULL) - break; - if (node->task_id == task_id) { - // unmap and release the page - if (node->kaddr) - kunmap(node->kaddr); - if (node->page) - put_page(node->page); - list_del(&node->entry); - kfree(node); // careful there is kfree - } - } -} - -/// @brief free all page in watch_local_memory_list -/// @param -void free_all_page_list(void) { - watch_local_memory *node, *next; - list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { - if (node == NULL) - break; - // unmap and release the page - if (node->kaddr) - kunmap(node->kaddr); - if (node->page) - put_page(node->page); - list_del(&node->entry); - kfree(node); // careful there is kfree - } -} - -/// @brief hrTimer handler -enum hrtimer_restart check_variable_cb(struct hrtimer *timer) { - kernel_watch_timer *k_watch_timer = - container_of(timer, kernel_watch_timer, hr_timer); - int i = 0, j = 0; - int buffer[TIMER_MAX_WATCH_NUM]; // Buffer to store the messages - - // check all watched kernel_watch_arg - for (i = 0; i < k_watch_timer->sentinel; i++) { - if (read_and_compare(&k_watch_timer->k_watch_args[i])) { - // snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " - // name: %s, threshold: %lld, pid: %d\n", - // k_watch_timer->k_watch_args[i].name, - // k_watch_timer->k_watch_args[i].threshold, - // k_watch_timer->k_watch_args[i].task_id); - buffer[j] = i; - j++; - - // printk(KERN_INFO "j: name %s, threshold: %lld\n", - // k_watch_timer->k_watch_args[i].name, - // k_watch_timer->k_watch_args[i].threshold); - // printk(KERN_INFO "j: %d\n", j); - } - } - if (j > 0) // if any threshold reached - { - printk("-------------------------------------\n"); - printk("-------------watch monitor-----------\n"); - printk("Threshold reached:\n"); - - for (i = 0; i < j; i++) { - printk(" name: %s, threshold: %lld, pid: %d\n", - k_watch_timer->k_watch_args[buffer[i]].name, //! todo - k_watch_timer->k_watch_args[buffer[i]].threshold, - k_watch_timer->k_watch_args[buffer[i]].task_id); - } - print_task_stack(); - // restart timer after 1s - hrtimer_forward(timer, timer->base->get_time(), ktime_set(1, 0)); //! todo - printk("-------------------------------------\n"); - } else { - // keep frequency - hrtimer_forward(timer, timer->base->get_time(), k_watch_timer->kt); - } - return HRTIMER_RESTART; // restart timer -} - -/// @brief start hrTimer -/// @param timeout: timeout in us -/// @return 0 is success -// int start_hrTimer(unsigned long timeout) -// { -// printk("HrTimer Start\n"); - -// kt = ktime_set(0, (unsigned long)timeout); // us -> ns -// // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time -// hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -// hr_timer.function = check_variable_cb; -// // mode the same as hrtimer_init -// hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL); -// return 0; -// } - -/// @brief start all hrTimer -/// @param -void start_all_hrTimer(void) { - int i = 0; - kernel_watch_timer *timer = NULL; - for (i = 0; i < kernel_wtimer_num; i++) { - timer = &(kernel_wtimer_list[i]); - TIMER_START(timer); - } - printk("HrTimer start,module keep %d hrtimer for now\n", kernel_wtimer_num); -} - -/// @brief cancel hrTimer -/// @param -void cancel_all_hrTimer(void) { - int i = 0; - kernel_watch_timer *timer = NULL; - for (i = 0; i < kernel_wtimer_num; i++) { - timer = &(kernel_wtimer_list[i]); - TIMER_CANCEL(timer); - } - - printk("HrTimer cancel,module keep %d hrtimer for now\n", kernel_wtimer_num); -} - -// for read_and_compare -typedef unsigned char (*compare_func)(void *, long long); - -unsigned char compare_1_byte_signed(void *ptr, long long threshold) { - // printk("compare_1_byte_signed: value %d, biss: %lld\n", *(char *)ptr, - // threshold); - return *(char *)ptr > threshold; -} -unsigned char compare_1_byte_unsigned(void *ptr, long long threshold) { - // printk("compare_1_byte_unsigned: value %d, biss: %lld\n", *(unsigned char - // *)ptr, threshold); - return *(unsigned char *)ptr > threshold; -} -unsigned char compare_2_byte_signed(void *ptr, long long threshold) { - // printk("compare_2_byte_signed: value %d, biss: %lld\n", *(short int *)ptr, - // threshold); - return *(short int *)ptr > threshold; -} -unsigned char compare_2_byte_unsigned(void *ptr, long long threshold) { - // printk("compare_2_byte_unsigned: value %d, biss: %lld\n", *(unsigned short - // int *)ptr, threshold); - return *(unsigned short int *)ptr > threshold; -} -unsigned char compare_4_byte_signed(void *ptr, long long threshold) { - // printk("compare_4_byte_signed: value %d, biss: %lld\n", *(int *)ptr, - // threshold); - return *(int *)ptr > threshold; -} -unsigned char compare_4_byte_unsigned(void *ptr, long long threshold) { - // printk("compare_4_byte_unsigned: value %d, biss: %lld\n", *(unsigned int - // *)ptr, threshold); - return *(unsigned int *)ptr > threshold; -} -unsigned char compare_8_byte_signed(void *ptr, long long threshold) { - // printk("compare_8_byte_signed: value %lld, biss: %lld\n", *(long long - // *)ptr, threshold); - return *(long long *)ptr > threshold; -} -unsigned char compare_8_byte_unsigned(void *ptr, long long threshold) { - // printk("compare_8_byte_unsigned: value %lld, biss: %lld\n", *(unsigned long - // long *)ptr, threshold); - return *(unsigned long long *)ptr > threshold; -} -// list of compare functions -static compare_func compare_funcs[8] = { - compare_1_byte_signed, compare_2_byte_signed, compare_4_byte_signed, - compare_8_byte_signed, compare_1_byte_unsigned, compare_2_byte_unsigned, - compare_4_byte_unsigned, compare_8_byte_unsigned}; - -static int func_indices[2][9] = {{0, 0, 1, 0, 2, 0, 0, 0, 3}, - {0, 4, 5, 0, 6, 0, 0, 0, 7}}; - -/// @brief read k_arg->kptr and compare with threshold -/// @param k_arg -/// @return result of compare -unsigned char read_and_compare(kernel_watch_arg *k_arg) { - void *ptr = k_arg->kptr; - int len = k_arg->length_byte; - unsigned char is_unsigned = k_arg->unsigned_flag; - long long threshold = k_arg->threshold; - - unsigned char result = 0; - - // if (len != 1 && len != 2 && len != 4 && len != 8) - // { - // printk(KERN_ERR "Invalid length\n"); - // return 0; - // } - - result = compare_funcs[func_indices[is_unsigned][len]](ptr, threshold); - - // printk(KERN_INFO "read_and_compare: name %s, value %d, biss: %lld, result: - // %d \n", k_arg->name, *(int *)ptr, - // threshold, result); - - if (k_arg->greater_flag) - return result; - else - return !result; -} - -/// @brief init kallsyms_lookup_name -/// @param -/// @return 0 is success -int fn_kallsyms_lookup_name_init(void) { - register_kprobe(&kprobe_kallsyms_lookup_name); - diag_kallsyms_lookup_name = (void *)kprobe_kallsyms_lookup_name.addr; - unregister_kprobe(&kprobe_kallsyms_lookup_name); - - printk("xby-debug, diag_kallsyms_lookup_name is %p\n", - diag_kallsyms_lookup_name); - - if (!diag_kallsyms_lookup_name) { - return -EINVAL; - } - return 0; -} - -unsigned char del_all_kwarg_by_pid(pid_t pid) { - int i = 0; - kernel_watch_timer *timer = NULL; - - printk(KERN_INFO "del kwarg..."); - - for (i = 0; i < kernel_wtimer_num; i++) { - timer = &(kernel_wtimer_list[i]); - timer_del_watch_by_pid(timer, pid); - } - for (i = 0; i < kernel_wtimer_num; i++) { - timer = &(kernel_wtimer_list[i]); - if (TIMER_NO_KWARG(timer)) // no available kwarg - { - if (i != kernel_wtimer_num - 1) { - memcpy(timer, &kernel_wtimer_list[kernel_wtimer_num - 1], - sizeof(kernel_watch_timer)); - } - kernel_wtimer_num--; - i--; - } - } - return 0; -} - -/// @brief clear watch with pid -/// @param pid -void clear_watch(pid_t pid) { - printk(KERN_INFO "clear pid %d 's watch variable\n", pid); - cancel_all_hrTimer(); // just in case - del_all_kwarg_by_pid(pid); // delete all kwarg with pid - free_page_list(pid); // free page with pid - start_all_hrTimer(); // restart timer +static int init_buffer(unsigned int buf_size) { + init_mm_tree(&mm_tree_struct); // init mm_tree + init_diag_variant_buffer(&load_monitor_variant_buffer, buf_size); + int ret = 0; + ret = alloc_diag_variant_buffer(&load_monitor_variant_buffer); + return ret; } /// @brief clear all watch and reset kernel_wtimer_list/kernel_wtimer_num /// @param -void clear_all_watch(void) { +static void clear_all_watch(void) { printk(KERN_INFO "clear all watch variable\n"); // unmap and release the page free_all_page_list(); @@ -424,4 +46,84 @@ void clear_all_watch(void) { // clear timer kernel_wtimer_num = 0; memset(kernel_wtimer_list, 0, sizeof(kernel_wtimer_list)); +} + +/** + * @brief all module function init. orig_X | buffer + * + * @return int + */ +int monitor_init(void) { + int ret = 0; + + init_orig_fun(); // init orig_X + ret = init_buffer(50 * 1024 * 1024); // 50M + if (ret) + return 0; + return 0; +} + +/** + * @brief monitor exit: clear all watch and free buffer + * + */ +void monitor_exit() { + // clear all watch + clear_all_watch(); + // free buffer + destroy_diag_variant_buffer(&load_monitor_variant_buffer); +} +/** + * @brief start watch variable + * + * @param warg: uapi watch_arg + * @return int 0 is success + * !todo: adjust printk + */ +int start_watch_variable(watch_arg warg) { + void *kptr; + kernel_watch_timer *timer = NULL; + kernel_watch_arg k_watch_arg; + + // user space address to kernel space address + kptr = convert_user_space_ptr(warg.task_id, (unsigned long)warg.ptr); + if (kptr == NULL) { + printk(KERN_ERR "Cannot access user space\n"); + return -EACCES; + } + // check length + if (warg.length_byte != 1 && warg.length_byte != 2 && warg.length_byte != 4 && + warg.length_byte != 8) { + printk(KERN_ERR "Invalid length %d\n", warg.length_byte); + return -EINVAL; + } + // k_watch_arg init + w_arg2k_w_arg(kptr, warg, &k_watch_arg); + timer = get_timer(warg.time_ns); // get a valuable timer + + printk(KERN_INFO "ptr transform kptr: %p\n", kptr); + printk(KERN_INFO "timer: %p\n", timer); + printk(KERN_INFO "timer->sentinel: %d, timer->time_ns: %lld\n", + timer->sentinel, timer->time_ns); + printk(KERN_INFO "timer->hr_timer: %p\n", &timer->hr_timer); + + TIMER_CANCEL(timer); // just in case + timer_add_watch(timer, k_watch_arg); + TIMER_START(timer); + + printk(KERN_INFO "Start watching var: %s\n", warg.name); + return 0; +} + +/** + * @brief clear watch with pid + * + * @param pid + */ +void clear_watch(pid_t pid) { + printk(KERN_INFO "clear pid %d 's watch variable\n", pid); + cancel_all_hrTimer(); // just in case + del_all_kwarg_by_pid(pid); // delete all kwarg with pid + free_page_list(pid); // free page with pid + start_all_hrTimer(); // restart timer } \ No newline at end of file diff --git a/source/module/monitor_mem.c b/source/module/monitor_mem.c new file mode 100644 index 0000000..f6d59eb --- /dev/null +++ b/source/module/monitor_mem.c @@ -0,0 +1,184 @@ +#include "monitor_mem.h" + +#include // for FOLL_FORCE +#include // pid pid_task +#include /* for kmalloc */ +#include // get_task_mm + +/// @brief transfer user space address to kernel space address +/// change static global "kaddr" and "page" value +/// @param pid: process id +/// @param kaddr: user space address +/// @return kernel space address + offset +void *convert_user_space_ptr(pid_t pid, unsigned long addr) { + struct task_struct *task; + struct mm_struct *mm; + int ret; + + // unsigned long aligned_addr = 0; + // unsigned long offset = 0; + + watch_local_memory *node; + + // if (addr < TASK_SIZE || addr > -PAGE_SIZE) + // { + // printk(KERN_ERR "Invalid address\n"); + // return NULL; + // } + + // for get_user_pages_remote + unsigned long aligned_addr = addr & PAGE_MASK; + unsigned long offset = addr & ~PAGE_MASK; + + printk(KERN_INFO "%s\n", __FUNCTION__); + + node = kmalloc(sizeof(watch_local_memory), GFP_KERNEL); + node->task_id = pid; + + // Find the task with pid + rcu_read_lock(); + task = pid_task(find_vpid(pid), PIDTYPE_PID); + rcu_read_unlock(); + + if (!task) { + printk(KERN_ERR "Cannot find task for PID %d\n", pid); + kfree(node); // careful there is kfree + return NULL; + } + // Get memory descriptor + mm = get_task_mm(task); + if (!mm) { + printk(KERN_ERR "Cannot get memory descriptor\n"); + kfree(node); // careful there is kfree + return NULL; + } + down_read(&task->mm->mmap_lock); + ret = get_user_pages_remote(task->mm, aligned_addr, 1, FOLL_FORCE, + &(node->page), NULL, NULL); + up_read(&task->mm->mmap_lock); + + if (ret != 1) { + printk(KERN_ERR "Cannot get user page\n"); + kfree(node); // careful there is kfree + return NULL; + } + // Map the page to kernel space + node->kaddr = kmap(node->page); + list_add_tail(&node->entry, &watch_local_memory_list); // add to list + // printk(KERN_INFO "node->kaddr: %p, aligned_addr: %ld, offset: %ld\n", + // node->kaddr, aligned_addr, offset); + return (void *)((unsigned long)(node->kaddr) + offset); +} + +/// @brief free page in watch_local_memory_list with task_id +/// @param task_id +void free_page_list(pid_t task_id) { + watch_local_memory *node, *next; + list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { + if (node == NULL) + break; + if (node->task_id == task_id) { + // unmap and release the page + if (node->kaddr) + kunmap(node->kaddr); + if (node->page) + put_page(node->page); + list_del(&node->entry); + kfree(node); // careful there is kfree + } + } +} + +/// @brief free all page in watch_local_memory_list +/// @param +void free_all_page_list(void) { + watch_local_memory *node, *next; + list_for_each_entry_safe(node, next, &watch_local_memory_list, entry) { + if (node == NULL) + break; + // unmap and release the page + if (node->kaddr) + kunmap(node->kaddr); + if (node->page) + put_page(node->page); + list_del(&node->entry); + kfree(node); // careful there is kfree + } +} + +// for read_and_compare +typedef unsigned char (*compare_func)(void *, long long); + +unsigned char compare_1_byte_signed(void *ptr, long long threshold) { + // printk("compare_1_byte_signed: value %d, biss: %lld\n", *(char *)ptr, + // threshold); + return *(char *)ptr > threshold; +} +unsigned char compare_1_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_1_byte_unsigned: value %d, biss: %lld\n", *(unsigned char + // *)ptr, threshold); + return *(unsigned char *)ptr > threshold; +} +unsigned char compare_2_byte_signed(void *ptr, long long threshold) { + // printk("compare_2_byte_signed: value %d, biss: %lld\n", *(short int *)ptr, + // threshold); + return *(short int *)ptr > threshold; +} +unsigned char compare_2_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_2_byte_unsigned: value %d, biss: %lld\n", *(unsigned short + // int *)ptr, threshold); + return *(unsigned short int *)ptr > threshold; +} +unsigned char compare_4_byte_signed(void *ptr, long long threshold) { + // printk("compare_4_byte_signed: value %d, biss: %lld\n", *(int *)ptr, + // threshold); + return *(int *)ptr > threshold; +} +unsigned char compare_4_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_4_byte_unsigned: value %d, biss: %lld\n", *(unsigned int + // *)ptr, threshold); + return *(unsigned int *)ptr > threshold; +} +unsigned char compare_8_byte_signed(void *ptr, long long threshold) { + // printk("compare_8_byte_signed: value %lld, biss: %lld\n", *(long long + // *)ptr, threshold); + return *(long long *)ptr > threshold; +} +unsigned char compare_8_byte_unsigned(void *ptr, long long threshold) { + // printk("compare_8_byte_unsigned: value %lld, biss: %lld\n", *(unsigned long + // long *)ptr, threshold); + return *(unsigned long long *)ptr > threshold; +} +// list of compare functions +static compare_func compare_funcs[8] = { + compare_1_byte_signed, compare_2_byte_signed, compare_4_byte_signed, + compare_8_byte_signed, compare_1_byte_unsigned, compare_2_byte_unsigned, + compare_4_byte_unsigned, compare_8_byte_unsigned}; + +static int func_indices[2][9] = {{0, 0, 1, 0, 2, 0, 0, 0, 3}, + {0, 4, 5, 0, 6, 0, 0, 0, 7}}; + +/// @brief read k_arg->kptr and compare with threshold +/// @param k_arg +/// @return result of compare +unsigned char read_and_compare(void *ptr, int len, unsigned char greater_flag, + unsigned char is_unsigned, long long threshold) { + unsigned char result = 0; + + // if (len != 1 && len != 2 && len != 4 && len != 8) + // { + // printk(KERN_ERR "Invalid length\n"); + // return 0; + // } + + result = compare_funcs[func_indices[is_unsigned][len]](ptr, threshold); + + // printk(KERN_INFO "read_and_compare: name %s, value %d, biss: %lld, result: + // %d \n", k_arg->name, *(int *)ptr, + // threshold, result); + + if (greater_flag) + return result; + else + return !result; +} \ No newline at end of file diff --git a/source/module/monitor_mem.h b/source/module/monitor_mem.h new file mode 100644 index 0000000..44bd189 --- /dev/null +++ b/source/module/monitor_mem.h @@ -0,0 +1,21 @@ +#include + +// for memory access +// #include + +typedef struct { + pid_t task_id; // current process id + struct page *page; + void *kaddr; + struct list_head entry; +} watch_local_memory; + +// Global variable +static LIST_HEAD(watch_local_memory_list); + +void *convert_user_space_ptr(pid_t pid, unsigned long kaddr); +void free_page_list(pid_t task_id); +void free_all_page_list(void); + +unsigned char read_and_compare(void *ptr, int len, unsigned char greater_flag, + unsigned char is_unsigned, long long threshold); diff --git a/source/module/monitor_timer.c b/source/module/monitor_timer.c new file mode 100644 index 0000000..ef40d94 --- /dev/null +++ b/source/module/monitor_timer.c @@ -0,0 +1,195 @@ +#include "monitor_timer.h" + +#define TIMER_FILLED(timer) ((timer)->sentinel >= TIMER_MAX_WATCH_NUM) +#define TIMER_EMPTY(timer) (!((timer)->time_ns | (timer)->sentinel)) +#define TIMER_NO_KWARG(timer) ((timer)->sentinel == 0) + +unsigned char del_all_kwarg_by_pid(pid_t pid) { + int i = 0; + kernel_watch_timer *timer = NULL; + + printk(KERN_INFO "del kwarg..."); + + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + timer_del_watch_by_pid(timer, pid); + } + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + if (TIMER_NO_KWARG(timer)) // no available kwarg + { + if (i != kernel_wtimer_num - 1) { + memcpy(timer, &kernel_wtimer_list[kernel_wtimer_num - 1], + sizeof(kernel_watch_timer)); + } + kernel_wtimer_num--; + i--; + } + } + return 0; +} + +/// @brief get a valuable timer +/// @param time_ns +/// @return kernel_watch_timer *, NULL means fail +kernel_watch_timer *get_timer(unsigned long long time_ns) { + int i = 0; + kernel_watch_timer *timer = NULL; + // chose a timer + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &kernel_wtimer_list[i]; + + if (TIMER_EMPTY(timer)) { + break; + } + if ((timer->time_ns == time_ns) && (!TIMER_FILLED(timer))) { + break; + } + } + // if all timer is full + if (i >= MAX_TIMER_NUM) { + printk(KERN_ERR "No timer available\n"); + return NULL; + } + // if a new timer, init it + if (i > kernel_wtimer_num - 1) { + printk(KERN_INFO "New timer\n"); + + kernel_wtimer_list[i].time_ns = time_ns; + kernel_wtimer_list[i].sentinel = 0; + + kernel_wtimer_list[i].kt = ktime_set(0, (unsigned long)time_ns); // ns + // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time + hrtimer_init(&(kernel_wtimer_list[i].hr_timer), CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + kernel_wtimer_list[i].hr_timer.function = + check_variable_cb; // callback function + + kernel_wtimer_num = i + 1; + } + printk(KERN_INFO "now, we have %d timers\n", kernel_wtimer_num); + return &kernel_wtimer_list[i]; +} + +/// @brief hrTimer add watch +/// @param timer +/// @param k_watch_arg +/// @return 0 is success +unsigned char timer_add_watch(kernel_watch_timer *timer, + kernel_watch_arg k_watch_arg) { + if (TIMER_FILLED(timer)) { + printk(KERN_ERR "Timer is full\n"); + return -1; + } + memcpy(&timer->k_watch_args[timer->sentinel], &k_watch_arg, + sizeof(k_watch_arg)); + // timer->k_watch_args[timer->sentinel] = k_watch_arg; + timer->sentinel++; + return 0; +} + +unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid) { + int i = 0; + for (i = 0; i < timer->sentinel; i++) { + // if pid match, delete it and move the last one to this position, check + // again + if (timer->k_watch_args[i].task_id == pid) { + if (i != timer->sentinel - 1) { + memcpy(&timer->k_watch_args[i], + &timer->k_watch_args[timer->sentinel - 1], + sizeof(kernel_watch_arg)); + } + timer->sentinel--; + i--; + } + } + return 0; +} + +/// @brief hrTimer handler +enum hrtimer_restart check_variable_cb(struct hrtimer *timer) { + kernel_watch_timer *k_watch_timer = + container_of(timer, kernel_watch_timer, hr_timer); + int i = 0, j = 0; + int buffer[TIMER_MAX_WATCH_NUM]; // Buffer to store the messages + + // check all watched kernel_watch_arg + for (i = 0; i < k_watch_timer->sentinel; i++) { + if (read_and_compare(&k_watch_timer->k_watch_args[i])) { + // snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), " + // name: %s, threshold: %lld, pid: %d\n", + // k_watch_timer->k_watch_args[i].name, + // k_watch_timer->k_watch_args[i].threshold, + // k_watch_timer->k_watch_args[i].task_id); + buffer[j] = i; + j++; + + // printk(KERN_INFO "j: name %s, threshold: %lld\n", + // k_watch_timer->k_watch_args[i].name, + // k_watch_timer->k_watch_args[i].threshold); + // printk(KERN_INFO "j: %d\n", j); + } + } + if (j > 0) // if any threshold reached + { + printk("-------------------------------------\n"); + printk("-------------watch monitor-----------\n"); + printk("Threshold reached:\n"); + + for (i = 0; i < j; i++) { + printk(" name: %s, threshold: %lld, pid: %d\n", + k_watch_timer->k_watch_args[buffer[i]].name, //! todo + k_watch_timer->k_watch_args[buffer[i]].threshold, + k_watch_timer->k_watch_args[buffer[i]].task_id); + } + print_task_stack(); + // restart timer after 1s + hrtimer_forward(timer, timer->base->get_time(), ktime_set(1, 0)); //! todo + printk("-------------------------------------\n"); + } else { + // keep frequency + hrtimer_forward(timer, timer->base->get_time(), k_watch_timer->kt); + } + return HRTIMER_RESTART; // restart timer +} + +/// @brief start hrTimer +/// @param timeout: timeout in us +/// @return 0 is success +// int start_hrTimer(unsigned long timeout) +// { +// printk("HrTimer Start\n"); + +// kt = ktime_set(0, (unsigned long)timeout); // us -> ns +// // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time +// hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +// hr_timer.function = check_variable_cb; +// // mode the same as hrtimer_init +// hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL); +// return 0; +// } + +/// @brief start all hrTimer +/// @param +void start_all_hrTimer(void) { + int i = 0; + kernel_watch_timer *timer = NULL; + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + TIMER_START(timer); + } + printk("HrTimer start,module keep %d hrtimer for now\n", kernel_wtimer_num); +} + +/// @brief cancel hrTimer +/// @param +void cancel_all_hrTimer(void) { + int i = 0; + kernel_watch_timer *timer = NULL; + for (i = 0; i < kernel_wtimer_num; i++) { + timer = &(kernel_wtimer_list[i]); + TIMER_CANCEL(timer); + } + + printk("HrTimer cancel,module keep %d hrtimer for now\n", kernel_wtimer_num); +} \ No newline at end of file diff --git a/source/module/monitor_timer.h b/source/module/monitor_timer.h new file mode 100644 index 0000000..e5b4fa2 --- /dev/null +++ b/source/module/monitor_timer.h @@ -0,0 +1,73 @@ +#include +// #include +// #include +// #include +// // #include /* for kmalloc */ +// #include + +// #include +// #include +// #include +// #include +// #include /* for avenrun, LOAD_* */ +// #include +// #include +// #include /* for stack_trace_print */ + +#define MAX_TIMER_NUM (128) // max timer number +#define TIMER_MAX_WATCH_NUM (32) // A timer max watch number at once time +#define MAX_NAME_LEN (15) // max name length + +typedef struct { + pid_t task_id; // current process id + char name[MAX_NAME_LEN + 1]; // name + void *ptr; // virtual address + int length_byte; // byte + long long threshold; // threshold value + unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) + unsigned char greater_flag; // reverse flag (true: >, false: <) + unsigned long time_ns; // timer interval (ns) +} watch_arg; + +typedef struct { + pid_t task_id; // current process id + char name[MAX_NAME_LEN + 2]; // name, last char automatically add '\0' + void *kptr; // kernel address + offset + int length_byte; // byte + long long threshold; // threshold value + unsigned char unsigned_flag; // unsigned flag (true: unsigned, false: signed) + unsigned char greater_flag; // reverse flag (true: >, false: <) +} kernel_watch_arg; + +typedef struct { + unsigned long long time_ns; // hrTimer time interval (ns) + struct hrtimer hr_timer; // hrTimer + ktime_t kt; // hrTimer time + unsigned sentinel; // sentinel + kernel_watch_arg + k_watch_args[TIMER_MAX_WATCH_NUM]; // all watched kernel_watch_arg +} kernel_watch_timer; + +// Global variable +kernel_watch_timer kernel_wtimer_list[MAX_TIMER_NUM] = { + 0}; // all kernel_watch_timer +int kernel_wtimer_num = 0; // current kernel_watch_timer number + +EXPORT_SYMBOL(kernel_wtimer_list); // export kernel_watch_timer_list +EXPORT_SYMBOL(kernel_wtimer_num); // export kernel_watch_timer_num + +unsigned char del_all_kwarg_by_pid(pid_t pid); + +#define TIMER_START(timer) \ + (hrtimer_start(&timer->hr_timer, timer->kt, HRTIMER_MODE_REL)) +#define TIMER_CANCEL(timer) (hrtimer_cancel(&timer->hr_timer)) + +// for timer +kernel_watch_timer *get_timer(unsigned long long time_ns); +unsigned char timer_add_watch(kernel_watch_timer *timer, + kernel_watch_arg k_watch_arg); +unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid); + +enum hrtimer_restart check_variable_cb(struct hrtimer *timer); // callback +void start_all_hrTimer(void); +void cancel_all_hrTimer(void); \ No newline at end of file diff --git a/source/module/monitor_kernel_task.c b/source/module/monitor_trace.c similarity index 86% rename from source/module/monitor_kernel_task.c rename to source/module/monitor_trace.c index 48b193b..153cefe 100644 --- a/source/module/monitor_kernel_task.c +++ b/source/module/monitor_trace.c @@ -1,4 +1,4 @@ -#include "monitor_kernel_task.h" +#include "monitor_trace.h" #include #include #include // for syscall_get_nr @@ -191,8 +191,8 @@ static void diagnose_save_stack_trace_user(unsigned long *backtrace) { struct stack_trace trace; memset(&trace, 0, sizeof(trace)); - memset(backtrace, 0, BACKTRACE_DEPTH2 * sizeof(unsigned long)); - trace.max_entries = BACKTRACE_DEPTH2; + memset(backtrace, 0, BACKTRACE_DEPTH * sizeof(unsigned long)); + trace.max_entries = BACKTRACE_DEPTH; trace.entries = backtrace; perfect_save_stack_trace_user(&trace); } @@ -202,8 +202,8 @@ static void diagnose_save_stack_trace_user_remote(struct task_struct *tsk, struct stack_trace trace; memset(&trace, 0, sizeof(trace)); - memset(backtrace, 0, BACKTRACE_DEPTH2 * sizeof(unsigned long)); - trace.max_entries = BACKTRACE_DEPTH2; + memset(backtrace, 0, BACKTRACE_DEPTH * sizeof(unsigned long)); + trace.max_entries = BACKTRACE_DEPTH; trace.entries = backtrace; /* @@ -332,7 +332,7 @@ void diag_task_user_stack(struct task_struct *tsk, user_stack_detail *detail) { } void diag_task_kern_stack(struct task_struct *tsk, kern_stack_detail *detail) { - orig_stack_trace_save_tsk(tsk, detail->stack, BACKTRACE_DEPTH2, 0); + orig_stack_trace_save_tsk(tsk, detail->stack, BACKTRACE_DEPTH, 0); } void dump_proc_chains_argv(int style, struct task_struct *tsk, mm_tree *mm_tree, @@ -382,4 +382,31 @@ void dump_proc_chains_argv(int style, struct task_struct *tsk, mm_tree *mm_tree, break; } rcu_read_unlock(); -} \ No newline at end of file +} + +/// @brief print all task stack +/// @param +// static void print_task_stack(void) { +// struct task_struct *g, *p; // g: task group; p: task +// unsigned long backtrace[BACKTRACE_DEPTH]; // save stack +// unsigned int nr_bt; // stack depth +// unsigned long long current_time; // last time +// current_time = ktime_get_real(); +// printk("Timestamp (ns): %lld\n", current_time); +// printk("Recent Load: %lu.%02lu, %lu.%02lu, %lu.%02lu\n", // recent load +// LOAD_INT(avenrun[0]), LOAD_FRAC(avenrun[0]), LOAD_INT(avenrun[1]), +// LOAD_FRAC(avenrun[1]), LOAD_INT(avenrun[2]), LOAD_FRAC(avenrun[2])); +// rcu_read_lock(); // lock run queue +// // printk("Running task\n"); +// do_each_thread(g, p) { +// if (p->__state == TASK_RUNNING || __task_contributes_to_load(p) || +// p->__state == TASK_IDLE) { +// printk("task: %s, pid %d, state %d\n", p->comm, p->pid, +// p->__state); //! todo +// nr_bt = orig_stack_trace_save_tsk(p, backtrace, BACKTRACE_DEPTH, 0); +// stack_trace_print(backtrace, nr_bt, 0); // print +// } +// } +// while_each_thread(g, p); +// rcu_read_unlock(); // unlock run queue +// } \ No newline at end of file diff --git a/source/module/monitor_kernel_task.h b/source/module/monitor_trace.h similarity index 82% rename from source/module/monitor_kernel_task.h rename to source/module/monitor_trace.h index 0983a32..bfcd117 100644 --- a/source/module/monitor_kernel_task.h +++ b/source/module/monitor_trace.h @@ -1,10 +1,11 @@ #include #include +#include "../buffer/variant_buffer.h" #define CGROUP_NAME_LEN 32 // max length of cgroup name #define TASK_COMM_LEN 16 // max length of task name -#define BACKTRACE_DEPTH2 30 // max depth of backtrace +#define BACKTRACE_DEPTH 30 // max depth of backtrace #define PROCESS_CHAINS_COUNT 10 // max count of process chains #define PROCESS_ARGV_LEN 128 // max length of process argv @@ -34,7 +35,7 @@ typedef struct { } task_detail; typedef struct { - unsigned long stack[BACKTRACE_DEPTH2]; + unsigned long stack[BACKTRACE_DEPTH]; } kern_stack_detail; typedef struct { @@ -42,7 +43,7 @@ typedef struct { unsigned long ip; unsigned long bp; unsigned long sp; - unsigned long stack[BACKTRACE_DEPTH2]; + unsigned long stack[BACKTRACE_DEPTH]; } user_stack_detail; typedef struct { @@ -67,6 +68,9 @@ typedef struct { spinlock_t mm_tree_lock; } mm_tree; +mm_tree mm_tree_struct; +struct diag_variant_buffer load_monitor_variant_buffer; // Global buffer + void diag_task_brief(struct task_struct *tsk, task_detail *detail); // get task brief void diag_task_user_stack(struct task_struct *tsk, @@ -78,13 +82,12 @@ void dump_proc_chains_argv( proc_chains_detail *detail); // get process chains argv // orig_X -struct sched_class *orig_idle_sched_class; -int (*orig_get_task_type)(struct sched_entity *se); -int (*orig_kernfs_name)(struct kernfs_node *kn, char *buf, size_t buflen); -int (*orig_access_remote_vm)(struct mm_struct *mm, unsigned long addr, +extern struct sched_class *orig_idle_sched_class; +extern int (*orig_get_task_type)(struct sched_entity *se); +extern int (*orig_kernfs_name)(struct kernfs_node *kn, char *buf, size_t buflen); +extern int (*orig_access_remote_vm)(struct mm_struct *mm, unsigned long addr, void *buf, int len, unsigned int gup_flags); extern unsigned int (*orig_stack_trace_save_tsk)(struct task_struct *task, unsigned long *store, unsigned int size, unsigned int skipnr); -