Reputation: 483
I am reading this answer to generate a well-look call graph with clang++-13 and 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
Here is an example code:
#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();
}
Here is the command I am using:
clang++-13 -S -emit-llvm main1.cpp -o - |
opt-13 -analyze -std-link-opts -dot-callgraph -enable-new-pm=0
Here comes a message but I don't understand it:
Writing '<stdin>.callgraph.dot'...
Printing analysis 'Print call graph to 'dot' file':
Pass::print not implemented for pass: 'Print call graph to 'dot' file'!
Since the dot file is still generated, I ran the following command:
cat \<stdin\>.callgraph.dot |
c++filt |
sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' |
gawk '/external node/{id=$1} $1 != id' |
dot -Tpng -ocallgraph.png
And this is the result:
This is far way out what I expected:
I don't see any difference between the answer and mine, however the output is different. I understand what shown in my output are decorated function names, yet read and understand them is tormenting.
I wonder if there are ways to improve my output, or read and understand the output more efficiently?
I have outlined the progress in my answer below. However, the question is not fully answered:
Upvotes: 2
Views: 495
Reputation: 483
The function name demangling problem is with LLVM's c++filt
. Here is a small demonstration:
You can generate a dot file with clang
and opt
either on MacOS or Linux. The specific instructions may vary due to the version of your clang
and opt
, but generally they are the same. I used clang++-13
and opt-13
in my original question, and here I use clang++-14
and opt-14
clang++-14 -S -emit-llvm main1.cpp -o - |
opt-14 -analyze -dot-callgraph -enable-new-pm=0
The decorated function names are like:
_ZNSt3__14pairINS_16reverse_iteratorIP1AEES4_EC2B6v15006IS4_S4_LPv0EEEOT_OT0_
If we use LLVM's c++filt
, it can not parse it:
❯ 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_
However, if we use GNU's 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*>&&)
Things just work fine
Upvotes: 0