我正在阅读这个答案,以使用 clang++-13 和 opt-13 生成一个美观的调用图
❯ clang++-13 --version
Homebrew clang version 13.0.1
Target: x86_64-apple-darwin22.5.0
Thread model: posix
InstalledDir: /usr/local/bin
❯ opt-13 --version
Homebrew LLVM version 13.0.1
Optimized build.
Default target: x86_64-apple-darwin22.5.0
Host CPU: westmere
这是示例代码:
#include <vector>
struct A {
A(int);
void f(); // not defined, prevents inlining it!
};
int main() {
std::vector<A> v;
v.push_back(42);
v[0].f();
}
这是我正在使用的命令:
clang++-13 -S -emit-llvm main1.cpp -o - |
opt-13 -analyze -std-link-opts -dot-callgraph -enable-new-pm=0
这里有一条消息,但我不明白:
Writing '<stdin>.callgraph.dot'...
Printing analysis 'Print call graph to 'dot' file':
Pass::print not implemented for pass: 'Print call graph to 'dot' file'!
由于仍然生成点文件,因此我运行了以下命令:
cat \<stdin\>.callgraph.dot |
c++filt |
sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' |
gawk '/external node/{id=$1} $1 != id' |
dot -Tpng -ocallgraph.png
这就是结果:
这与我的预期相去甚远:
我看不出答案和我的有什么区别,但输出不同。我明白我的输出中显示的是装饰函数名称,但阅读和理解它们是令人痛苦的。
我想知道是否有方法可以改进我的输出,或者更有效地阅读和理解输出?
我在下面的回答中概述了进展。然而,这个问题还没有完全得到解答:
函数名称重组问题是 LLVM 的
c++filt
。这是一个小演示:
您可以在 MacOS 或 Linux 上使用
clang
和 opt
生成点文件。具体说明可能会因您的 clang
和 opt
的版本而有所不同,但通常是相同的。我在原来的问题中使用了 clang++-13
和 opt-13
,这里我使用 clang++-14
和 opt-14
clang++-14 -S -emit-llvm main1.cpp -o - |
opt-14 -analyze -dot-callgraph -enable-new-pm=0
修饰后的函数名称如下:
_ZNSt3__14pairINS_16reverse_iteratorIP1AEES4_EC2B6v15006IS4_S4_LPv0EEEOT_OT0_
如果我们使用LLVM的
c++filt
,它无法解析它:
❯ c++filt --version
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++filt
Apple LLVM version 14.0.3 (clang-1403.0.22.14.1)
Optimized build.
Default target: arm64-apple-darwin22.5.0
Host CPU: apple-m1
❯ c++filt _ZNSt3__14pairINS_16reverse_iteratorIP1AEES4_EC2B6v15006IS4_S4_LPv0EEEOT_OT0_
_ZNSt3__14pairINS_16reverse_iteratorIP1AEES4_EC2B6v15006IS4_S4_LPv0EEEOT_OT0_
但是,如果我们使用 GNU 的
c++filt
:
➜ ~ c++filt --version
GNU c++filt (GNU Binutils for Ubuntu) 2.38
Copyright (C) 2022 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.
➜ ~ c++filt _ZNSt3__14pairINS_16reverse_iteratorIP1AEES4_EC2B6v15006IS4_S4_LPv0EEEOT_OT0_
std::__1::reverse_iterator<A*>&& std::__1::pair<std::__1::reverse_iterator<A*>, std::__1::reverse_iterator<A*> >::pair[abi:v15006]<std::__1::reverse_iterator<A*>, std::__1::reverse_iterator<A*>, (void*)0>(std::__1::reverse_iterator<A*>&&)
一切正常