Linux内核中是否存在宏可判断内存地址的分配来源?
Linux内核地址类型判断的方法与宏
Linux内核中没有直接提供ADDR_IS_STACK_ADDR这类统一命名的宏,但可以通过内核原生接口或自定义宏实现地址类型的判断,以下是针对各类地址的具体方案:
1. 判断地址是否来自栈
内核每个进程的栈有固定范围,可通过当前进程的task_struct获取栈起始地址,结合THREAD_SIZE(栈大小)判断:
#include <linux/sched.h> #define ADDR_IS_STACK_ADDR(ptr) \ ((unsigned long)(ptr) >= (unsigned long)current->stack && \ (unsigned long)(ptr) < (unsigned long)current->stack + THREAD_SIZE)
- 注意:该宏仅适用于当前进程的栈地址判断,若需检查其他进程的栈地址,需替换
current为对应进程的task_struct指针。
2. 判断地址是否来自kmalloc
kmalloc分配的内存属于内核线性映射区(直接映射物理内存),不在vmalloc范围内,可通过以下逻辑判断:
#include <linux/vmalloc.h> #define ADDR_IS_KMALLOC_ADDR(ptr) \ (is_kernel_addr((unsigned long)(ptr)) && \ !is_vmalloc_addr((unsigned long)(ptr)))
- 若需更精准判断,可结合slab分配器接口
kmem_cache_find,但上述宏已满足大部分场景需求。
3. 判断地址是否来自vmalloc
内核直接提供is_vmalloc_addr()宏(定义于<linux/vmalloc.h>),可直接用于判断:
#include <linux/vmalloc.h> if (is_vmalloc_addr(v)) { pr_debug("%p is allocated via vmalloc\n", v); }
4. 判断地址是否来自.text段(函数指针)
内核代码段的起始和结束由_text、_etext符号标记,可通过对比地址区间判断:
extern char _text[], _etext[]; #define ADDR_IS_TEXT_ADDR(ptr) \ ((unsigned long)(ptr) >= (unsigned long)_text && \ (unsigned long)(ptr) < (unsigned long)_etext)
- 若需判断内核模块的代码段地址,需使用
is_module_addr()宏(定义于<linux/module.h>)。
5. 其他地址分类判断
- 内核模块地址:使用
is_module_addr()宏直接判断地址是否属于已加载的内核模块。 - 用户空间地址:可通过
access_ok()接口,或检查地址是否小于PAGE_OFFSET(不同架构略有差异,如x86_64使用TASK_SIZE_MAX)。 - 物理直接映射区(如
__get_free_pages分配):同kmalloc地址逻辑,属于内核线性映射区,virt_to_phys()可直接转换为物理地址。
示例代码(修改为实际可用版本)
#include <linux/sched.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/printk.h> #include <linux/module.h> extern char _text[], _etext[]; #define ADDR_IS_STACK_ADDR(ptr) \ ((unsigned long)(ptr) >= (unsigned long)current->stack && \ (unsigned long)(ptr) < (unsigned long)current->stack + THREAD_SIZE) #define ADDR_IS_KMALLOC_ADDR(ptr) \ (is_kernel_addr((unsigned long)(ptr)) && \ !is_vmalloc_addr((unsigned long)(ptr))) #define ADDR_IS_TEXT_ADDR(ptr) \ ((unsigned long)(ptr) >= (unsigned long)_text && \ (unsigned long)(ptr) < (unsigned long)_etext) void foo() { int bar; void *v = vmalloc(123); void *k = kmalloc(123, GFP_KERNEL); if (ADDR_IS_STACK_ADDR(&bar)) pr_debug("%p is on the stack\n", &bar); if (k && ADDR_IS_KMALLOC_ADDR(k)) pr_debug("%p is from kmalloc\n", k); if (v && is_vmalloc_addr(v)) pr_debug("%p is from vmalloc, physical addr: %p\n", v, virt_to_phys(v)); if (ADDR_IS_TEXT_ADDR(foo)) pr_debug("%p is in .text section\n", foo); kfree(k); vfree(v); }
内容的提问来源于stack exchange,提问作者KJ7LNW
相关产品推荐
相关产品推荐

