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は機能が充実しているものという訳ではないらしい。