gcc-vcg-pluginを試してみる

GNU Wikiに公開されているpluginの一覧がある。gcc-vcg-pluginはGCC内部構 造を見るのに使うことができるらしい。内部構造を知るきっかけになればと思い、使用してみる。

 

1. コードの入手

プロジェクトのページは以下。

https://code.google.com/p/gcc-vcg-plugin/

svnでコードを取得。

$ svn co http://gcc-vcg-plugin.googlecode.com/svn/trunk \
gcc-vcg-plugin-read-only

2. ビルド

configureが用意されているのでそれを利用。gcc-4.7環境だとgccでpluginを ビルドするとpluginロード時にundefined symbolでエラーになる為、g++でビ ルドする。gcc-vcg-pluginをg++でビルドしようとするとbasename関数定義の 重複と不適切なキャストでエラーになるので、CFLAGSに-DHAVE_DECL_BASENAME と-fpermissiveを与える。

$ mkdir gcc-vcg-plugin-read-only.build
$ cd gcc-vcg-plugin-read-only.build
$ CC=g++ CFLAGS="-DHAVE_DECL_BASENAME -fpermissive" \
../gcc-vcg-plugin-read-only/configure
$ make
$ sudo make install

3. 実行

対象コードは以下。

#include <stdio.h>
 
struct hello_struct {
  char *buffer_field;
};
 
typedef struct hello_struct hello_typedef;
 
static void echo1(struct hello_struct hello_struct_echo1)
{
  char *echo1_nouse = NULL;
  printf("%s\n", hello_struct_echo1.buffer_field);
}
 
static char echo2(struct hello_struct *hello_struct_echo2)
{
  return (char)printf("%s\n", hello_struct_echo2->buffer_field);
}
 
int main(void)
{
  static char buffer [] = "hello, world\n";
  struct hello_struct hello_struct_obj = { .buffer_field = buffer, };
  printf("%s\n", buffer);
  echo1(hello_struct_obj);
  echo2(&hello_struct_obj);
  return 0;
}

pluginでcgraphというものを出力する。<SOURCE CODE>.cgraph.vcgというファ イルが生成される。

$ g++ -fplugin=/usr/local/lib/gcc-vcg-plugin/vcg_plugin.so \
-fplugin-arg-vcg_plugin-cgraph hello.c 
$ cat hello.c.cgraph.vcg 
// Generated by GCC VCG Plugin 1.8
// Report bugs to <mingjie.xing@gmail.com>
// Home page: http://code.google.com/p/gcc-vcg-plugin
// GCC: (GNU) 4.7 20130421 ()
graph: {
colorentry 100: 70 130 180
node_alignment: top
orientation: left_to_right
title: "top graph"
node.borderwidth: 1
node.color: 100
node.textcolor: white
edge.color: 100
edge.thickness: 1
node: {
label: "int printf(const char*, ...)"
title: "int printf(const char*, ...)"
}
node: {
label: "int __builtin_puts(const char*)"
title: "int __builtin_puts(const char*)"
}
node: {
label: "int main()"
title: "int main()"
}
node: {
label: "char echo2(hello_struct*)"
title: "char echo2(hello_struct*)"
}
node: {
label: "void echo1(hello_struct)"
title: "void echo1(hello_struct)"
}
edge: {
sourcename: "int main()"
targetname: "char echo2(hello_struct*)"
}
edge: {
sourcename: "int main()"
targetname: "void echo1(hello_struct)"
}
edge: {
sourcename: "int main()"
targetname: "int __builtin_puts(const char*)"
}
edge: {
sourcename: "char echo2(hello_struct*)"
targetname: "int printf(const char*, ...)"
}
edge: {
sourcename: "void echo1(hello_struct)"
targetname: "int __builtin_puts(const char*)"
}
}

4. xvcgの導入

上記の出力ファイルはvcg形式なので、vcg viewerを導入する必要がある。 xvcgというvcg viewerがあるので、debianのパッチとアーカイブを取得。パッ チがないとセグメンテーションフォルト。

https://launchpad.net/ubuntu/+source/vcg/1.30debian-6
$ wget https://launchpad.net/ubuntu/+archive/primary/+files/vcg_1.30debian.orig.tar.gz
$ wget https://launchpad.net/ubuntu/+archive/primary/+files/vcg_1.30debian-6.diff.gz
$ tar zxvf vcg_1.30debian.orig.tar.gz 
$ cd vcg-1.30debian/
$ zcat ../vcg_1.30debian-6.diff.gz | patch -p1
$ make

src/xvcgが作成される。

$ xvcg hello.c.cgraph.vcg

viewer=nameオプションは機能しない模様。内部で子プロセスを実行するみた いだが、オプションを指定しても呼ばれることがない(改造は可能)。

  viewer=name          set the vcg viewer, default is vcgview.

5. 出力

cgraphでコールグラフが出力された。GCC内部のcgraph_nodeを読み込んでいる。

pass-listsでPLUGIN_PASS_MANAGER_SETUPのコールバック群が出力された。gcc_pass_listsというGCC内部の変数を読み込んでいる。

$ cat dump-pass-lists.vcg 
// Generated by GCC VCG Plugin 1.8
// Report bugs to <mingjie.xing@gmail.com>
// Home page: http://code.google.com/p/gcc-vcg-plugin
// GCC: (GNU) 4.7 20130421 ()
graph: {
colorentry 100: 70 130 180
node_alignment: top
title: "top graph"
yspace: 15
node.borderwidth: 1
node.color: 100
node.textcolor: white
edge.color: 100
edge.thickness: 1
graph: {
folding: 1
label: "all_lowering_passes"
shape: ellipse
title: "all_lowering_passes"
node: {
label: "*warn_unused_result"
title: "1. *warn_unused_result [<none>]"
}
<snip>

tree-hierarchy-4.7でtreeの対応関係(変数宣言用treeとか関数宣言用treeとか)が出力される。でもこれってpluginのソースコードにハードコーディングされているような・・・。pluginで出力する意味があるんだろうか?

6. 感想

内部構造を知ることができたかといえば、できていない(関数本体をトラバースする方法が知りたかった)。どうもGNU Wikiに記載されているpluginは機能が充実しているものという訳ではないらしい。