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状态发生变化,就可以打印出对应的调用栈了。

 

posted @ 2021-03-29 20:55  smilingsusu  阅读(186)  评论(0编辑  收藏  举报