LoginSignup
3
1

More than 5 years have passed since last update.

Windows環境でclang(LLVM)でC++ソースコードからいい感じのコールグラフを作成するまでのメモ

Posted at

Windows環境でclang(LLVM)でC++ソースコードからいい感じのコールグラフを作成するまでのメモ

普段はMSVCを使っていて、コールグラフを作る場合はdoxygenなどを利用しているが、どうしても精度は低くなってしまう。

clang(LLVM)でも作れるらしいとのことで、試行錯誤してみた。

前提

下記をインスールして、PATHを通しているものとする。

  • LLVM 6.0.1 Pre-build
  • Graphviz 2.38

基本的なやり方

こちら(https://yutopp.hateblo.jp/entry/2014/05/03/004049) などを参考にすると、以下のようなコマンドでコールグラフを作成することができるようだ。

clang++ -S -emit-llvm main.cpp -o - | opt -analyze -dot-callgraph
dot -Tpng callgraph.dot > callgraph.f.png

clangでコンパイルする

MSVCでコンパイルしているソースコード(プロジェクト)だと、まずclangでコンパイルできるようにする必要がある。
方法としては

  • Visual Studio で調べたコマンドラインを、clang-cl ...で実行さる
  • Visual Studio で調べたコマンドラインを、clang-cl -v ...で実行させて、 clang のコマンドラインに変換する

あるC++ソースでコールグラフを作成した結果

callgraph1.png

イマイチなコールグラフを調整する。

作成されたコールグラフはいろいろと問題がある。

  1. 作成されたコールグラフの関数名はマングリングされている
  2. 仮想的なノード("external code" / "Node????????")が邪魔
  3. 組み込み関数("llvm*"/ "__*")が邪魔

デマングルする

デマングリングしないととても見れたものではない。 .dotファイルをUndname.exe などでデマングリングさせる。

しかし、.dotファイル内のラベルでは<>は特殊文字らしいので、エスケープさせる必要がある。

sedを使えばいいが、Windowsらしくpowershellでエスケープ処理をする。

面倒なことに、opt では既にエスケープされている場合がある(ラムダとか)ので、デマングル前に一旦エスケープを外す。

REM {$_  -replace "\<","<" -replace "\>",">" }
powershell.exe -Command "Get-Content callgraph.dot | %% { $_ -replace \"\\^<\",\"^<\" -replace \"\\^>\",\"^>\" } " > callgraph1.dot 
REM { $_ -replace "<","\<" -replace ">","\>"  -replace "-\\>","->" } 
Undname.exe callgraph1.dot | powershell.exe -Command "$input | %% { $_ -replace \"\\^<\",\"^<\" -replace \"\\^>\",\"^>\" -replace \"^<\",\"\^<\" -replace \"^>\",\"\^>\" -replace \"-\\^>\",\"-^>\" } " > callgraph_demangled.dot

邪魔なノードを消す

DOT言語で特定のノードを消す(非表示にする)には、[style=invis]を指定すると消すことができるようだが、optの引数や後処理などでうまいこと消すことができなかった。

結局、LLVMのソースコードに手を入れた。

--- CallPrinter.cpp.bak 2017-06-06 20:49:48.000000000 +0900
+++ CallPrinter.cpp     2018-09-09 23:18:40.844019700 +0900
@@ -33,6 +33,15 @@

     return "external node";
   }
+
+  /// isNodeHidden - If the function returns true, the given node is not
+  /// displayed in the graph.
+  static bool isNodeHidden(CallGraphNode *Node){
+    if (Function *Func = Node->getFunction())
+      return Func->isIntrinsic() || Func->getName().startswith("__");
+    else
+         return true;
+  }
 };

 struct AnalysisCallGraphWrapperPassTraits {

改善した結果

callgraph.png

最終的なコマンド(バッチファイル)

@setlocal
@set LLVM=D:\tmp\llvm-6.0.1.build\RelWithDebInfo
@set PATH=%LLVM%\bin;%PATH%
@set DOT=C:\usr\graphviz\bin\dot
@set CXXFILT="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.15.26726\bin\HostX64\x64\undname.exe"
@set PS=powershell.exe

@clang -cc1 -S -emit-llvm -D_DEBUG -D_MT -D_DLL -fcxx-exceptions -fexceptions -fms-volatile -v -D WIN32 -D _DEBUG -D _CONSOLE -D LLVM=C:/usr/LLVM -D _UNICODE -D UNICODE -internal-isystem "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.15.26726\\include" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17134.0\\ucrt" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\shared" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\um" -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\winrt" -O0 -Wno-error -fms-extensions -fms-compatibility -fms-compatibility-version=19.15.26726 -std=c++2a -fdelayed-template-parsing -fdiagnostics-show-option -fcolor-diagnostics -isystemC:/usr/llvm/include -o - -x c++ main.cpp | opt -dot-callgraph

@REM デマングル前に、エスケープされている"\<"を"<"に置換する
@%PS% -Command "Get-Content callgraph.dot | %% { $_ -replace \"\\^<\",\"^<\" -replace \"\\^>\",\"^>\" } " > callgraph1.dot 
@REM { $_ -replace "<","\<" -replace ">","\>"  -replace "-\\>","->" } 
%CXXFILT% callgraph1.dot | %PS% -Command "$input | %% { $_ -replace \"\\^<\",\"^<\" -replace \"\\^>\",\"^>\" -replace \"^<\",\"\^<\" -replace \"^>\",\"\^>\" -replace \"-\\^>\",\"-^>\" } " > callgraph_demangled.dot

@%DOT% -x -Tsvg -ocallgraph.svg callgraph_demangled.dot
@endlocal

残課題

  1. デマングルをLLVMの中で出来るようにする。(UnDecorateSymbolName 関数を呼びだけでいいと思うけど。)
  2. ラムダ関数がデマングルできていない。
  3. STL内の関数を省けるようにしたい。
  4. powershellの使い方が下手。
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1