【发布时间】:2010-11-01 23:56:38
【问题描述】:
有没有人知道一些工具可以为将在微控制器 (Cortex-M3) 上运行的 C 应用程序创建调用树?它可以从源代码(不理想)、目标代码(首选解决方案)或运行时(可接受)生成。我查看了 gprof,但仍然缺少很多东西要让它在嵌入式系统上工作。
另一个好处是该工具还提供最大堆栈深度。
更新:解决方案最好是免费的。
【问题讨论】:
标签: c embedded stack microcontroller
有没有人知道一些工具可以为将在微控制器 (Cortex-M3) 上运行的 C 应用程序创建调用树?它可以从源代码(不理想)、目标代码(首选解决方案)或运行时(可接受)生成。我查看了 gprof,但仍然缺少很多东西要让它在嵌入式系统上工作。
另一个好处是该工具还提供最大堆栈深度。
更新:解决方案最好是免费的。
【问题讨论】:
标签: c embedded stack microcontroller
来自源代码的调用图没有问题,如上所述,您的编译器或 doxygen 可以从源代码生成此信息。大多数现代编译器都可以在编译过程中生成调用图。
在以前的嵌入式项目中,我用一种模式填充了该堆栈并运行了一项任务。检查堆栈破坏了我的模式到哪一点。使用模式重新加载堆栈并运行下一个任务。这使您的代码非常 ssslloowww .... 但是是免费的。它并不完全准确,因为所有数据一直都在超时,并且代码在错误处理程序中花费了大量时间。
在某些处理器上,您可以获得一个跟踪 pod,以便您可以监控代码覆盖率,如果您的处理器需要全速运行以进行测试,并且您也不能使用检测代码,那该怎么办。不幸的是,这些类型的工具非常昂贵。有钱就看Green Hills Time machine。这使得所有类型的调试都变得更加容易。
【讨论】:
我知道这是在回答一个非常古老的问题,但有人可能会偶然发现这个问题......
我最近尝试了一个 Python 脚本,该脚本分析应用程序的汇编版本,提取堆栈使用情况和调用树,并报告最大堆栈使用情况。然后在我的构建系统中,我使用它来创建一个完全相同大小的堆栈。
我只将它用于小型应用程序,但它似乎适用于 AVR8、MSP430 和 Cortex-M3。显然,有严格的限制:没有间接调用(没有函数指针,没有虚函数),没有递归,并且使用的堆栈使用汇编程序指令模式仅限于我在 GCC 的输出中找到的内容。如果不满足这些限制,脚本会报错。
Python 源代码为 24k,免费(增强许可),速度不是很快,仍在开发中。有兴趣可以联系我。
【讨论】:
【讨论】:
我的调用树图生成器,用 bash 实现,使用 cscope 和 dot。
可以生成上游调用者、下游调用者以及函数之间的调用关联的图表。您可以将其设置为以多种方式查看图形,包括 xfig、.png 查看器和动态点可视化工具“zgrviewer”。
http://toolchainguru.blogspot.com/2011/03/c-calltrees-in-bash-revisited.html
【讨论】:
一个非常轻便的工具:Egypt
【讨论】:
我已经在another discussion 关于嵌入式开发中提出了这种方法,但如果你真的需要一个调用图,以及堆栈使用信息,而且所有这些都是免费的,我个人会考虑使用开源模拟器来模拟整个事情,同时通过向模拟器本身添加一些挂钩来检测目标代码以获取这些数据。
我不熟悉这个特定的目标,但是有很多可用的开源 ARM 仿真器(freshmeat、sourceforge、google),您可能最感兴趣的是与 call/ret 和 push/pop 相关的操作码? 例如查看skyeye。
因此,即使您发现扩展编译器或仿真器来提供这些信息并不简单,仍然应该可以创建一个简单的脚本来查找入口点和所有调用/返回作为与堆栈使用相关的操作码。
当然,关于堆栈使用的唯一可靠信息将来自运行时检测,最好是使用所有重要的代码路径。
【讨论】:
带有 CDT 的 Eclipse 具有 C/C++ 索引,并会显示调用图。据我所知,您不需要能够在 Eclipse 中构建以使索引器工作,只需确保您的所有源文件都在项目中。
效果很好。
Visual Studio 也会做类似的事情(但它不是免费的)。我使用 Visual Studio 处理嵌入式项目;使用 makefile 项目,我可以完成除了在 VS IDE 中调试之外的所有工作。
【讨论】:
我没用过,但你知道吗:
由于他们分析源代码,他们不计算堆栈深度。
注意,Doxygen 可以做“调用图”和“调用者图”,但我相信这些是每个函数的,并且只显示每个函数的特定数量的“跃点”树。
编译器工具可能支持堆栈深度和/或调用树生成。例如,对于 Renesas micros,有一个名为 Call Walker 的实用程序。
【讨论】:
实现此目的的一个好方法是使用 ARM 链接器 (armlink) 的 --callgraph 选项,它是 RVCT 的一部分(不是免费的)。
更多详情-callgraph documentation。
我从其中一个 cmets 中了解到,您正在寻找基于 gcc 的解决方案,但事实并非如此。但它可能仍然有用。
【讨论】:
从源代码中,您可以使用Doxygen 和GraphViz,即使您还没有使用 Doxygen 来记录您的代码。可以对其进行配置,使其包含所有函数和方法,无论它们是否具有文档 cmets。安装 AT&T Graphviz 后,Doxygen 将包含大多数函数和方法的调用图和调用者图。
对于目标代码,我没有现成的答案。我想这将是高度依赖于目标的,因为即使存在调试信息,它也必须解析目标代码以查找调用和其他堆栈用户。在最坏的情况下,这种方法似乎需要有效地模拟目标。
在目标硬件上运行时,您的选择将部分取决于存在哪种嵌入式操作系统,以及它如何管理每个线程的堆栈。
一种常见的方法是将每个堆栈初始化为一个已知值,似乎不太可能通常存储在自动变量中。然后,中断处理程序或线程可以检查堆栈并测量近似的高水位线。
即使没有预先填充堆栈并稍后遍历堆栈以查找足迹,中断也可以仅采样堆栈指针的当前值(对于每个线程)并记录其最大观察范围。这将需要存储每个线程 SP 的副本,并且中断处理程序不需要做太多工作来维护信息。当然,它必须访问所有活动线程的已保存状态。
我不知道有什么工具可以明确地做到这一点。
如果您碰巧使用来自Micrium 的 µC/OS-II 作为您的操作系统,您可以看看他们的 µC/Probe 产品。我自己没有使用过它,但它声称允许连接的 PC 近乎实时地观察程序和操作系统状态信息。如果需要它可以适应另一个 RTOS,我不会感到惊讶。
【讨论】:
只是一个想法。是否可以在虚拟机(如 Valgrind)中运行并获取堆栈样本?
【讨论】:
【讨论】: