Linux内核模块新手求助:获取init_task信息时出现段错误
问题排查与解决方案
核心问题原因
find_vpid()和find_task_by_vpid()仅用于查找用户空间可见的进程PID,而PID为0的init_task(idle进程)是内核专属进程,并不存在于用户空间PID命名空间中,因此这两个函数会返回NULL。直接访问NULL指针的state成员必然触发段错误。- 代码中用
%s打印task->state属于格式错误:task->state是整数类型的进程状态位,并非字符串,直接打印会导致内存访问异常或输出乱码。
正确实现方式
方法1:直接引用init_task
init_task是内核导出的全局变量,可直接访问:
#include <linux/sched.h> #include <linux/init.h> #include <linux/module.h> static void init_task_info(void) { struct task_struct *task = &init_task; const char *state_str; // 将进程状态值转换为可读字符串 switch (task->state) { case TASK_RUNNING: state_str = "TASK_RUNNING"; break; case TASK_INTERRUPTIBLE: state_str = "TASK_INTERRUPTIBLE"; break; case TASK_UNINTERRUPTIBLE: state_str = "TASK_UNINTERRUPTIBLE"; break; case __TASK_STOPPED: state_str = "__TASK_STOPPED"; break; case __TASK_TRACED: state_str = "__TASK_TRACED"; break; default: state_str = "UNKNOWN"; break; } printk(KERN_INFO "init_task PID: %d, state: %s\n", task->pid, state_str); } static int __init mymodule_init(void) { init_task_info(); return 0; } static void __exit mymodule_exit(void) { printk(KERN_INFO "Module exited\n"); } module_init(mymodule_init); module_exit(mymodule_exit); MODULE_LICENSE("GPL");
方法2:遍历进程列表查找PID0
如果需要通过PID匹配的方式查找,可使用for_each_process宏遍历所有内核进程:
#include <linux/sched.h> #include <linux/init.h> #include <linux/module.h> static void init_task_info(void) { struct task_struct *task; const char *state_str; // 遍历所有内核进程 for_each_process(task) { if (task->pid == 0) { switch (task->state) { case TASK_RUNNING: state_str = "TASK_RUNNING"; break; case TASK_INTERRUPTIBLE: state_str = "TASK_INTERRUPTIBLE"; break; case TASK_UNINTERRUPTIBLE: state_str = "TASK_UNINTERRUPTIBLE"; break; case __TASK_STOPPED: state_str = "__TASK_STOPPED"; break; case __TASK_TRACED: state_str = "__TASK_TRACED"; break; default: state_str = "UNKNOWN"; break; } printk(KERN_INFO "init_task PID: %d, state: %s\n", task->pid, state_str); break; } } } // 模块入口、出口函数同方法1 module_init(mymodule_init); module_exit(mymodule_exit); MODULE_LICENSE("GPL");
注意事项
- 访问
task_struct时需注意进程上下文,禁止在原子上下文(如中断处理函数)中遍历进程列表。 - 不同内核版本的进程状态宏定义可能略有差异,建议参考对应版本的
linux/sched.h头文件。 - 模块必须声明
MODULE_LICENSE("GPL"),否则可能无法访问init_task等GPL-only的内核导出符号。
内容的提问来源于stack exchange,提问作者Acheese
相关产品推荐
相关产品推荐

