看起来应该存在这样的东西,但我没有使用过类似的东西。不过,我可以告诉你我将如何一起编写脚本。可能有更快和/或更性感的方式来做到这一点。
首先一些你可能已经知道的东西:
addr2line 命令接收一个地址,并可以告诉您机器代码在哪里实现的源代码。可执行文件需要使用调试符号构建,并且您可能不想对其进行太多优化(-O0、-O1 或 -Os 可能与您最初想要的一样高)。 addr2line 有几个标志,您需要阅读它的手册页,但如果您想查看输出中有意义的 C++ 函数名称,您肯定需要使用 -C 或 --demangle。
objdump 命令可以打印出关于许多类型的目标文件中的东西的各种有趣的东西。它可以做的事情之一是打印出一个表,该表表示对象文件(包括可执行文件)中或引用的符号。
现在,你想用它做什么:
您需要让 objdump 告诉您 .text 部分的地址和大小。这是实际的可执行机器代码所在的位置。有几种方法可以做到这一点,但最简单的(无论如何)可能是你做的:
objdump -h my_exe | grep text
这应该是这样的:
12 .text 0000049 000000f000 0000000f000 00000400 2**4
如果你没有 grep 它会给你一个像这样的标题:
Idx Name Size VMA LMA File off Algn
我认为对于可执行文件,VMA 和 LMA 应该是相同的,所以使用哪个并不重要,但我认为 LMA 是最好的。您还需要尺寸。
使用 LMA 和大小,您可以反复调用 addr2line 询问机器代码的源代码来源。如果你传递一个指令中的地址,我不确定这将如何工作,但我认为它应该可以工作。
addr2line -e my_exe <address>
它的输出将是一个路径/文件名、一个冒号和一个行号。
如果您要计算每个唯一路径/文件:num 的出现次数,您应该能够查看计数最高的那些。
Perl 使用 path/file:num 作为键和计数器作为值的散列将是实现这一点的简单方法,但如果您发现运行速度太慢,还有更快的方法。
您还可以过滤掉您可以确定不需要及早包含的内容。
为了显示您的输出,您可能希望从同一个函数中过滤掉不同的行,但您可能会注意到一个函数中的不同行具有不同的计数,这可能很有趣。无论如何,这可以通过让 addr2line 告诉您函数名称或在第一步中使用 objdump -t 并一次处理一个函数来完成。
如果您发现某些模板代码或其他代码行在可执行文件中出现的频率超出了您的预期,那么您可以轻松找到它们并仔细查看。宏和内联函数的最终表现可能与您的预期不同。
如果您不知道,objdump 和 addr2line 来自 GNU binutils 包,其中包括其他几个有用的工具。