【问题标题】:Extract function names and their comments from C code with python (to understand the Linux kernel)使用 python 从 C 代码中提取函数名称及其注释(以了解 Linux 内核)
【发布时间】:2012-06-16 09:18:27
【问题描述】:

背景信息

我刚刚开始学习有关驱动程序和 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 个。然后我有了想法,为什么不解析这些函数和它们的 cmets并将它们写在跟踪文件中的函数后面?像这样:

 [...]
 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 函数和 cmets,我必须定义并实现递归匹配语法:(

2。问题
有些函数只是包装器,没有 cmets。例如do_brk() 包裹__do_brk() 并且评论仅在__do_brk() 上方

所以我想,cmets 可能还有其他来源。也许是文档?也有可能,这个使用 python 的“文档生成”已经有人实现了。

或者我理解系统read()write()的方式很不智能?你能给我提示我应该如何深入挖掘吗?

非常感谢您的阅读,
费边

【问题讨论】:

  • 感谢您的反对,没有评论我可以在我的问题中改进什么。感谢您的反馈...:/
  • 你签出LXR了吗?

标签: python c linux kernel ftrace


【解决方案1】:

在实践中解析 cmets 是相当困难的。解析内核代码并不是特别容易。

首先,您应该准确地了解system call 中的linux kernel 是什么,以及应用程序如何使用它们。 Linux Assembly HowTo 有很好的解释。

然后,您应该了解 Linux 内核的组织结构。我强烈建议阅读一些关于这方面的好书。

使用自动工具探索内核源代码需要大量工作(几个月,而不是几天)。您可以考虑使用coccinelle 工具(用于所谓的“语义补丁”)。您还可以考虑使用插件自定义 GCC 编译器,或者更好的是使用 MELT 扩展

(MELT 是一种用于扩展 GCC 的高级领域特定语言;我是它的主要设计者和实现者)。

如果使用 GCC,您将在中端获得 GCC 内部表示和处理的所有功能(但在此阶段 cmets 会丢失)。

您尝试做的事情可能比您最初想的要雄心勃勃。另见 Alexandre Lissy 的作品,例如model-checking the linux kernel 和他将在Linux Symposium 2012 上发表的论文(2012 年 7 月)

【讨论】:

    【解决方案2】:

    是的,你的方法是对的:学习内核,总是从系统调用开始。内核代码 = 以比普通代码更高的权限执行的代码。英特尔有大约 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 输出后):

    http://pastebin.com/vEk2NrDQ

    现在上面的 ftrace 输出显示了从用户空间执行“ls”时实际执行的内核函数。并非每个功能都需要理解或很重要。也不是关于学习内核 API 本身。但更重要的是很多概念:如何在不同的 CPU、不同的进程、不同类型的同步原语等之间共享资源。

    享受每一个小小的步骤......一次一个。

    【讨论】:

      猜你喜欢
      • 2011-12-24
      • 2015-06-30
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-20
      相关资源
      最近更新 更多