LiuYuan
LiuYuan

Reputation: 483

How to demangle a function name generated by opt with LLVM's c++filt and how to omit some intermediate nodes?

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:

The output of my platform

This is far way out what I expected:

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?


Update

I have outlined the progress in my answer below. However, the question is not fully answered:

  1. Is there a way to parse decorated function names on MacOS?
  2. The generated graph is still huge, but we can wish it gets smaller, by omitting some too-detailed nodes. But, how?

Upvotes: 2

Views: 495

Answers (1)

LiuYuan
LiuYuan

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

Related Questions