Ftrace hook的使用方法,利用Ftrace写一个memory debug程序
1. 背景
Ftrace利用汇编时,在每个函数的入口处放一个mcont函数来monitor代码行为,利用这一个特性,可以写一个程序来监控每个函数执行后,系统的memory状态的功能。
2.代码
这里主要是检查0x90000000 ~ 90200000中间2M内存的每个page的0x520处memory的值。
#include <linux/stacktrace.h> #include <linux/ftrace.h> #include <linux/module.h> #include <linux/sysctl.h> #include <linux/init.h> #include <asm/setup.h> #include <linux/memblock.h> #include <linux/pfn.h> #include <linux/err.h> #include <linux/io.h> #include <asm/memory.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/kexec.h> #include <linux/smp.h> #include <linux/utsname.h> #include <linux/slab.h> #include <linux/sched/task_stack.h> #include <linux/stacktrace.h> #define MAX_STACK_TRACE_DEPTH 64 static unsigned long memory_monitor_addr = 0; static unsigned long memory_monitor_size = 0; static int _kprint_stack(struct task_struct *task, int saved) { struct stack_trace trace; unsigned long *entries; int err; entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); if (!entries) return –ENOMEM; trace.nr_entries = 0; trace.max_entries = MAX_STACK_TRACE_DEPTH; trace.entries = entries; trace.skip = 0; if (!err) { unsigned int i; save_stack_trace_tsk(task,&trace); for (i = 0; i < trace.nr_entries; i ++) { pr_cont(“[<%px>] %pS\n”, (void*)entries[i], (void*)entries[i]); if (saved) backup_stacktrace[checked_cnt][i] = entries[i]; } } kfree(entries); return err; } static unsigned long end_pfn = 0; static unsigned long start_pfn = 0; static void funcpoint_trace_call(unsigned long ip, unsigned long parent_ip, struct ftrace_pos *op, struct pt_regs *pt_regs) { void *va_pos; unsigned long cur_pfn; unsigned long mem_data; if (strncmp(current->comm, “PCM_OfflineDete”, sizeof(“PCM_OfflineDete”))) return; if (start_pfn == 0 || end_pfn == 0) return; for (cur_pfn = start_pfn; cur_pfn < end_pfn; cur_pfn ++) { va_pos = __va(PFN_PHYS(cur_pfn) + 0x520); mem_data = *(uint64_t*)va_pos >> 40; if (mem_data==0xb0ffff || mem_data==0xb0cccc || mem_data==0xb00000){ pr_emerg(“address[%px]=%lx, CPU=%d\n”, __pa(va_pos),*(uint64_t*)va_pos, smp_processor_id()); pr_emerg(“----current process stack----\n”); _kprint_stack(current,0); dump_stack(); } } return; } static struct ftrace_ops funcpoint_trace_ops __read_mostly = { .func = funcpoint_trace_call, .flags = FTRACE_OPS_FL_RECURSION_SAFE, } static int __init get_funcpoint_monitor_range(char *str) { unsigned long addr, size; pr_info(“%s(%s)\n”, __func__, str); if (!str) return 0; size = memparse(str, &str); if (*str != ‘@’) return 0; addr = memparse(str + 1, &str); if (addr == 0 || size == 0){ pr_info (“memory monitor is disable, addr=%#x, size=%#x\n”, addr, size); return 0; } pr_info (“memory monitor is enable, addr=%#x, size=%#x\n”, addr, size); memory_monitor_addr = addr; memory_monitor_size = size; return 0; } early_param(“funcpoint_memory_range”, get_funcpoint_monitor_range); static int __init func_tracepoint_init(void) { if (memory_monitor_addr == 0 || memory_monitor_size == 0) return 0; start_pfn = PHYS_PFN(memory_monitor_addr); end_pfn = PHYS_PFN(memory_monitor_addr + memory_monitor_size); pr_info(“funcpoint_memory_range: start_pfn=%#x, end_pfn=%#x.\n”,start_pfn,end_pfn); register_ftrace_function(&funcpoint_trace_ops); return 0; } device_initcall(func_tracepoint_init);
3.运行结果
使用后,如果这里的memory状态发生变化,就可以打印出对应的调用栈了。