Linux mod_sysfs_setup模块sysfs符号表暴露
mod_sysfs_setup()是Linux内核模块加载过程中负责在sysfs中创建模块相关目录和文件的关键函数。它在load_module()完成ELF重定位和符号解析之后被调用,向用户空间暴露模块的元数据、参数信息和导出的符号表。
mod_sysfs_setup()位于kernel/module/sysfs.c,其调用链为load_module() -> mod_sysfs_setup() -> add_module_usage()等辅助函数:
static int mod_sysfs_setup(struct module *mod,
const struct load_info *info,
struct kernel_param *kparam,
unsigned int num_params)
{
int err;
/* 第一步:创建模块在/sys/module/下的kobject */
mod->mkobj.kobj.kset = module_kset;
err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype,
NULL, "%s", mod->name);
if (err)
goto out;
/* 第二步:创建version info文件 */
err = mod_sysfs_setup_vermagic(mod, info);
if (err)
goto out_unreg;
/* 第三步:创建模块参数sysfs条目 */
err = module_param_sysfs_setup(mod, kparam, num_params);
if (err)
goto out_unreg;
/* 第四步:创建模块符号表的sysfs文件 */
err = module_sysfs_setup_holders(mod, info);
if (err)
goto out_unreg;
/* 第五步:创建notes section文件 */
err = module_notes_init(mod, info);
if (err)
goto out_unreg;
/* 第六步:创建模块依赖关系符号链接 */
add_module_usage(mod, info);
/* 第七步:暴露导出的内核符号到/sys/module//sections/ */
add_sect_attrs(mod, info);
add_notes_attrs(mod, info);
return 0;
out_unreg:
kobject_put(&mod->mkobj.kobj);
mod->mkobj.kobj.parent = NULL;
out:
return err;
}
module_kset是模块subsystem的全局kset,其父kobject为module_kobj(即/sys/module)。所有模块的kobject都在此之下形成/sys/module/目录。
符号表暴露的核心在add_sect_attrs()函数中,该函数遍历ELF节区(section),对其中包含符号的节创建sysfs属性文件:
static void add_sect_attrs(struct module *mod, const struct load_info *info)
{
struct module_sect_attrs *sattrs;
struct module_sect_attr *sattr;
unsigned int nsect;
int i;
/* 计算需要暴露的节区数量 */
nsect = 0;
for (i = 0; i < info->hdr->e_shnum; i++)
if (info->secstrings[info->sechdrs[i].sh_name][0] != '.')
nsect++;
sattrs = kzalloc(struct_size(sattrs, attrs, nsect), GFP_KERNEL);
sattr = &sattrs->attrs[0];
/* 为每个节区创建属性 */
for (i = 0; i < info->hdr->e_shnum; i++) {
if (info->secstrings[info->sechdrs[i].sh_name][0] == '.')
continue;
sattr->name = info->secstrings + info->sechdrs[i].sh_name;
sattr->address = info->sechdrs[i].sh_addr;
sysfs_attr_init(&sattr->attr);
sattr->attr.name = sattr->name;
sattr->attr.mode = 0400;
sattr->attr.show = module_sect_show;
sattr++;
}
/* 创建sysfs目录/sys/module//sections/ */
sattrs->kobj.kset = &mod->mkobj.kobj;
err = kobject_init_and_add(&sattrs->kobj, &module_sect_ktype, &mod->mkobj.kobj, "sections");
/* 为每个节区创建属性文件 */
for (i = 0; i < nsect; i++)
sysfs_create_file(&sattrs->kobj, &sattrs->attrs[i].attr);
}
module_sect_show()是属性文件的read回调,它返回对应节区的基地址:
static ssize_t module_sect_show(struct module_attribute *mattr,
struct module_kobject *mk, char *buf)
{
struct module_sect_attr *sattr = container_of(mattr, struct module_sect_attr, mattr);
return sprintf(buf, "0x%px\n", (void *)sattr->address);
}
通过/sys/module//sections/.text,用户空间可以读取模块代码段的加载地址,这对于调试和崩溃分析至关重要。
module_param_sysfs_setup()创建/sys/module//parameters/目录,并在其中为每个module_param()定义的参数创建属性文件。属性的读写回调指向param_ops中对应的get/set函数,使得用户空间可以通过写sysfs文件在运行时修改模块参数:
static int module_param_sysfs_setup(struct module *mod,
struct kernel_param *kparam,
unsigned int num_params)
{
int i;
for (i = 0; i < num_params; i++) {
struct param_attribute *param_attr = kzalloc(sizeof(*param_attr), GFP_KERNEL);
sysfs_attr_init(¶m_attr->mattr.attr);
param_attr->mattr.attr.name = kparam[i].name;
param_attr->mattr.attr.mode = kparam[i].perm;
param_attr->mattr.show = param_attr_show;
param_attr->mattr.store = param_attr_store;
param_attr->mattr.attr.owner = mod;
param_attr->param = &kparam[i];
sysfs_create_file(&mod->mkobj.kobj, ¶m_attr->mattr.attr);
}
return 0;
}
add_module_usage()分析模块的符号依赖关系,在/sys/module//holders/目录下创建指向被依赖模块的符号链接。当模块B使用了模块A导出的符号时,/sys/module/A/holders/B符号链接出现,反映了模块间的依赖关系。
mod_sysfs_teardown()是逆操作,在模块卸载时被调用,依次移除所有sysfs节点并释放相关内存。如果某个模块的sysfs节点在用户空间仍有打开的文件描述符,kobject的引用计数机制会延迟实际的内存释放直到所有引用关闭。
通过mod_sysfs_setup()暴露的sysfs接口为系统管理员和调试工具提供了无需专用工具的模块信息查看能力。用户可以通过cat /sys/module//version、cat /sys/module//sections/.text等命令获取模块的加载信息。
Linux mod_sysfs_setup模块sysfs符号表暴露
张小明
前端开发工程师
DMA控制器编程:从原理到实战的深度解析
1. DMA控制器编程:从原理到实战的深度解析在嵌入式系统开发,尤其是涉及高速数据流处理的场景里,CPU的时间是极其宝贵的资源。想象一下,你的处理器核心正在处理一个复杂的音频解码算法,此时网络接口卡(NIC&a…
FTUtils 性能优化技巧:提升 iOS 动画流畅度的 7 个终极方法 [特殊字符]
FTUtils 性能优化技巧:提升 iOS 动画流畅度的 7 个终极方法 🚀 【免费下载链接】ftutils iPhone utilities mostly for Core Animation 项目地址: https://gitcode.com/gh_mirrors/ft/ftutils FTUtils 是一个专注于 iOS Core Animation 优化的实用…
零绿幕AI背景移除:OBS背景移除插件终极使用指南
零绿幕AI背景移除:OBS背景移除插件终极使用指南 【免费下载链接】obs-backgroundremoval An OBS plugin for removing background in portrait images (video), making it easy to replace the background when recording or streaming. 项目地址: https://gitcod…
别再乱改VM参数了!手把手教你用IntelliJ IDEA自带的Activity Monitor精准定位卡顿元凶
别再盲目调优!用IntelliJ IDEA Activity Monitor实现精准性能诊断当IDE响应迟缓时,大多数开发者的第一反应往往是粗暴地增加JVM堆内存参数。这种条件反射式的"解决方案"不仅治标不治本,还可能掩盖真正的性能瓶颈。作为JetBrains生态…
终极免费方案:OBS多平台同步直播插件完整指南
终极免费方案:OBS多平台同步直播插件完整指南 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 如果你是一位内容创作者、游戏主播或在线教育讲师,肯定经历过这样的…
TC-Bot最佳实践:参数调优与模型训练的7个关键技巧
TC-Bot最佳实践:参数调优与模型训练的7个关键技巧 【免费下载链接】TC-Bot User Simulation for Task-Completion Dialogues 项目地址: https://gitcode.com/gh_mirrors/tcb/TC-Bot TC-Bot作为任务完成对话的用户模拟工具,其核心性能取决于智能体…