c - Linux内核模块内存检查器

标签 c linux kernel-module

我正在开发一个内核内存检查器来查找内核空间中的内存泄漏。

  1. 我有两个函数 profile_vmalloc 和 profile_vfree,profile_vmalloc 使用 vmalloc 分配内存并将内存分配信息添加到列表中,profile_vfree 释放分配的内存并从列表中删除该信息。如何替换 vmalloc 和 vfree,以便当我编译和运行我的模块时,任何分配和释放内存的内核模块都将使用我的函数?

  2. 如何使用 sysfs 创建只读文件以允许用户查看内存泄漏摘要?

这就是我的代码到目前为止的样子

// Linux Kernel headers
#include    <linux/module.h>
#include    <linux/kernel.h>
#include    <linux/init.h>
#include    <linux/config.h>
#include    <linux/vmalloc.h>

#define  FILE_NAME_LENGTH          256
#define  vmalloc(size)              profile_malloc (block_size, __FILE__, __LINE__)
#define  vfree(mem_ref)                 profile_free(mem_ref)

struct _MEM_INFO
{
    const void          *address;
    size_t              size;
    char                file_name[FILE_NAME_LENGTH];
    size_t              length;
};
typedef struct _MEM_INFO MEM_INFO;

struct _MEM_LEAK {
    MEM_INFO mem_info;
    struct _MEM_LEAK * next;
};
typedef struct _MEM_LEAK MEM_LEAK;



#undef      vmalloc
#undef      vfree


static MEM_PROFILER_LIST * ptr_start = NULL;
static MEM_PROFILER_LIST * ptr_next =  NULL;

/*
 * adds allocated memory info. into the list
 *
 */
void add(MEM_INFO alloc_info)
{

    MEM_PROFILER_LIST * mem_leak_info = NULL;
    mem_leak_info = (MEM_PROFILER_LIST *) malloc (sizeof(MEM_PROFILER_LIST));
    mem_leak_info->mem_info.address = alloc_info.address;
    mem_leak_info->mem_info.size = alloc_info.size;
    strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name); 
    mem_leak_info->mem_info.line = alloc_info.line;
    mem_leak_info->next = NULL;

    if (ptr_start == NULL)  
    {
        ptr_start = mem_leak_info;
        ptr_next = ptr_start;
    }
    else {
        ptr_next->next = mem_leak_info;
        ptr_next = ptr_next->next;              
    }

}

/*
 * remove memory info. from the list
 *
 */
void erase(unsigned pos)
{

    unsigned int i = 0;
    MEM_PROFILER_LIST * alloc_info, * temp;

    if(pos == 0)
    {
        MEM_PROFILER_LIST * temp = ptr_start;
        ptr_start = ptr_start->next;
        free(temp);
    }
    else 
    {
        for(i = 0, alloc_info = ptr_start; i < pos; 
            alloc_info = alloc_info->next, ++i)
        {
            if(pos == i + 1)
            {
                temp = alloc_info->next;
                alloc_info->next =  temp->next;
                free(temp);
                break;
            }
        }
    }
}

/*
 * deletes all the elements from the list
 */
void clear()
{
    MEM_PROFILER_LIST * temp = ptr_start;
    MEM_PROFILER_LIST * alloc_info = ptr_start;

    while(alloc_info != NULL) 
    {
        alloc_info = alloc_info->next;
        free(temp);
        temp = alloc_info;
    }
}

/*
 * profile of vmalloc
 */
void * profile_vmalloc (unsigned int size, const char * file, unsigned int line)
{
    void * ptr = vmalloc (size);
    if (ptr != NULL) 
    {
        add_mem_info(ptr, size, file, line);
    }
    return ptr;
}


/*
 * profile of free
 */
void profile_free(void * mem_ref)
{
    remove_mem_info(mem_ref);
    free(mem_ref);
}

/*
 * gets the allocated memory info and adds it to a list
 *
 */
void add_mem_info (void * mem_ref, unsigned int size,  const char * file, unsigned int line)
{
    MEM_INFO mem_alloc_info;

    /* fill up the structure with all info */
    memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) );
    mem_alloc_info.address  = mem_ref;
    mem_alloc_info.size = size;
    strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
    mem_alloc_info.line = line;

    /* add the above info to a list */
    add(mem_alloc_info);
}

/*
 * if the allocated memory info is part of the list, removes it
 *
 */
void remove_mem_info (void * mem_ref)
{
    unsigned int i;
    MEM_PROFILER_LIST  * leak_info = ptr_start;

    /* check if allocate memory is in our list */
    for(i = 0; leak_info != NULL; ++i, leak_info = leak_info->next)
    {
        if ( leak_info->mem_info.address == mem_ref )
        {
            erase ( i );
            break;
        }
    }
}

/*
 * writes a memory leak summary to a file
 */
void mem_leak_summary(void)
{
    unsigned int i;
    MEM_PROFILER_LIST * mem_output;

    FILE * fp_write = fopen (SUMMARY_FILE, "wt");
    char info[1024];

    if(fp_write != NULL)
    {

        fwrite(info, (strlen(info) + 1) , 1, fp_write);
        sprintf(info, "%s\n", "-----------------------------------");   
        fwrite(info, (strlen(info) + 1) , 1, fp_write);

        for(mem_output= ptr_start; mem_output!= NULL; mem_output= mem_output->next)
        {
            sprintf(info, "address : %d\n", leak_info->mem_output.address);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "size    : %d bytes\n", leak_info->mem_output.size);          
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "line    : %d\n", leak_info->mem_output.line);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "%s\n", "-----------------------------------");   
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
        }
    }   
    clear();
}

static int __init profiler_init(void)
{
    return 0;
}

static void __exit profiler_cleanup(void)
{
    printk("profiler module uninstalled\n");
}

module_init(profiler_init);
module_exit(profiler_cleanup);
MODULE_LICENSE("GPL");

最佳答案

How to replace vmalloc and vfree so that when I compile and run my module any kernel module allocating and freeing memory will use my functions ?

步骤 1. 在调用 vmallocvfree 的文件中,定义宏:

 #define vmalloc(x) profile_vmalloc(x)
 #define vfree(x) profile_vfree(x)

这将确保您的函数被调用。

第 2 步:profile_* 函数的定义中,计算并调用实际的 vmalloc/vfree 函数。

您已经执行了第 2 步,因此您只需执行第 1 步即可。

关于c - Linux内核模块内存检查器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23123718/

相关文章:

c++ - 能否仅对 recv() 函数使套接字成为非阻塞的?

c - tcpclient - 用于获取 c 中内容的 Web 客户端

r - 转置和分组数据 - Linux/R

linux - 如何知道哪个是当前内核模块?

c - 前缀和的并行化 (Openmp)

c - 如何使用 C 在 Ubuntu 上获取 WIFI 参数(带宽、延迟)

linux - foreach 循环 : files. 列表中的 TCSH 错误:找不到命令

windows - 从 Windows Server 2008 在 Linux 上执行管理任务

linux - 如何从当前模块获取kobject

linux - 从内核空间中给定的结构套接字获取结构文件