我刚刚开始学习有关驱动程序和Linux内核的内容。我想了解用户write()
和read()
的工作原理。所以我开始使用ftrace来希望看到函数的路径。
但是,如下所示的单个程序的痕迹是“巨大的”。
int main() {
int w;
char buffer[] = "test string mit 512 byte";
int fd = open("/dev/sdd",O_DIRECT | O_RDWR | O_SYNC);
w = write(fd,buffer,sizeof(buffer));
}
我也不知道我可以过滤哪些功能,因为我不知道Linux内核,我不想抛弃一些重要的东西。
所以我开始研究一个function_graph跟踪。这是一个剪辑。
[...]
12) 0.468 us | .down_write();
12) 0.548 us | .do_brk();
12) 0.472 us | .up_write();
12) 0.762 us | .kfree();
12) 0.472 us | .fput();
[...]
我看到了这些.down_write()
和.up_write()
,我想,这正是我搜索的内容。所以我查了一下。 down_write() sourcecode:
/*
* lock for writing
*/
void __sched down_write(struct rw_semaphore *sem)
{
might_sleep();
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
}
但事实证明,这只是锁定和释放锁定。 然后我开始为我写一个小参考,所以我不必总是查找这些东西,因为它有超过9000的下降。然后我有了这个想法,为什么不,解析这些函数和他们的评论并将它们写在跟踪文件中的函数后面?像这样:
[...]
12) 0.468 us | .down_write(); lock for writing
12) 0.548 us | .do_brk();
12) 0.472 us | .up_write(); release a write lock
12) 0.762 us | .kfree();
12) 0.472 us | .fput();
[...]
所以我开始思考如何实现这一目标。我想用python做,因为我觉得最舒服。
1。问题
为了匹配C函数和注释,我必须定义并实现一个递归匹配语法:(
2。问题
有些函数只是包装器而没有注释。例如do_brk()
包裹__do_brk()
,评论仅在__do_brk()
所以我想,也许还有其他来源的评论。也许docs?也有可能,这个使用python的“doc generation”已经有人已经实现了。
或者我是否理解系统read()
write()
非常愚蠢?你能告诉我tipps我应该如何深入挖掘?
非常感谢你阅读,
费边
答案 0 :(得分:3)
在实践中解析评论非常困难。解析内核代码并不是特别容易。
首先,您应该理解正好 system call中的linux kernel是什么,以及应用程序如何使用它们。 Linux Assembly HowTo有很好的解释。
然后,您应该了解Linux内核的组织。我强烈建议你阅读一些好书。
使用自动工具探索内核源代码是一项大量工作(数月,而不是数天)。您可以考虑coccinelle工具(对于所谓的“语义补丁”)。您还可以考虑使用插件自定义GCC编译器,或者更好的是使用MELT扩展
(MELT是一种扩展GCC的高级域特定语言;我是它的主要设计者和实现者)。
如果与GCC合作,您将在中端获得GCC内部表示和处理的所有权力(但在此阶段,评论将丢失)。
你想要做的事情可能比你最初的想法更加雄心勃勃。另见Alexandre Lissy的作品,例如: model-checking the linux kernel以及他将在Linux Symposium 2012(2012年7月)上发表的论文
答案 1 :(得分:0)
是的,你的方法是正确的:学习内核,总是从系统调用开始。内核代码=使用比普通代码更高的权限执行的代码。英特尔有大约18个(不确定)特权指令集。
http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection/
http://en.wikipedia.org/wiki/Privilege_level
当用户代码从较低权限级别转换为较高权限以执行这些特殊指令时,它会通过标准系统调用机制。
做一个简单的" strace ls"您可以看到正在执行的许多系统调用:每个系统调用都必须转换到内核以执行某些任务。
编写一个简单的脚本,如(内核版本相关,针对您的特定内核,请参阅/ sys / kernel / debug / tracing / README):
echo function > /sys/kernel/debug/tracing/current_tracer
cat /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
ls /tmp
cat /sys/kernel/debug/tracing/trace
echo 0 > /sys/kernel/debug/tracing/tracing_on
我们将获得以下输出(删除所有非ls ftrace输出后):
现在上面的ftrace输出显示了当" ls"时执行的实际内核函数。从用户空间完成。并非所有功能都需要被理解或重要。它也不是关于学习内核API本身。但更重要的是很多概念:如何在不同的CPU,不同的进程,不同类型的同步原语等之间共享资源。
享受每一小步......一次一个。