simotin13's message

simotin13といいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

C/C++ 用のコードカバレッジツールを作ってみた

タイトルの通り C/C++言語で使えるコードカバレッジツールを作ってみました。
x86_64 GNU/Linux 向けのバイナリと動作確認のサンプル用シェルスクリプトGithubで公開しています。

github.com

このコードカバレッジツールは covme という名称のシングルバイナリのプログラムです。機能的にはまだまだ充実していなくて、現時点では実用性は低いのですが、簡単なプログラムであればC0レベルのカバレッジを取ることができ、結果をHTMLファイルとして出力します。

covme動作イメージ
covme demo

使い方について

詳しくはレポジトリのREADME(日本語)に書きましたが、ダウンロードして


$ ./covme 計測したいプログラム名

のように実行して頂くと引数で指定したプログラムのカバレッジ計測ができます。

いくつか動作確認用のスクリプトを同梱しており、 00_build_examples.sh から 04_try_simple_cpp_example.sh まで順番に実行して頂けると雰囲気を理解して頂けるのではないかと思います。

計測の精度・機能性についてですが、I/Oを伴うプログラムだとうまく動作しない可能性があります。(ターゲットプログラムによってはフリーズしてしまうかもしれません...ごめんなさい)
今後も継続して機能を追加・改善していきたいので、バグレポートや要望など頂けると嬉しいです。

どうやってカバレッジを計測しているのか?

GDBの利用

covme ではカバレッジを計測したいプログラムをターゲットプログラム(デバッギ)として gdb を起動しています。

covmeのプロセス構成
covmeのプロセス構成

gdb によりターゲットプログラムをステップ実行することでどのコードが実行されたかを記録しています。

要するに

IDE でデバッガを起動し、ステップ実行のボタンを押してはどの行に止まったかをメモする」

をひたすら繰り返すことによりカバレッジ計測を行っています。

伝統的な日本企業のソフトウェア開発では、Excel シートにソースコードを張り付けて、プログラムを1行1行ステップ実行し、Exccel シートの実行できた行に印をつけるという、地下帝国の労働のようなことが現実に行われていることがあります。この手の作業を自動化してくれるようなツールと思って頂ければよいかと思います。

ちなみにこのような話を口裂け女のような都市伝説と思っている方がいらっしゃるかもしれませんが、実際に私自身も何度かそのような仕事をしたことがあります。(当時ギャンブルで破産していた私は、メモリ 4GB の Intel Celeron のパソコンで作業させられ給料はペリカで支払われていました。)

DWARFの利用

gdb を使ってデバッガを1行1行ステップ実行させるだけではコードカバレッジを取ることはできなくて、コードカバレッジを取るためには、例えば

  1. ソースコードのうち、ある関数は何行目から何行目までなのか?
  2. ブレークポイントで止まったアドレスはソースコードの何行目なのか?

といった情報が必要になります。

1に関しては「構文解析ツールを自作する」「llvm を利用する」というアプローチも考えてみましたが、よくよく考えるとビルド時のコンパイラの解析結果と一致しないとうまく機能しない可能性があります。

2に関しても、ファイル名と行番号の情報はGDBのレスポンスに含まれているのですが、ソースコードのパスは含まれていませんので、同じファイル名のファイルが複数あるとどのファイルの関数なのかが特定できないという欠点があります。

ということで、 ビルド時にデバッグ情報をつけるという制約を設ける(具体的には -g オプションをつけてビルドしてもらう)ことにしてバイナリに含まれるDWARF形式のデバッグ情報を解析することで、カバレッジに必要な情報を得ることにしました。
セクションとしては .debug_aranges, .debug_info, .debug_abbrev, .debug_line といったセクションの情報を解析しています。お陰でDWARFを読むことができるようになりましたので、機会があればDWARFの読み方についてブログの記事やどこか勉強会の場などで発表させて頂きたいなぁと思います。

動機

C/C++ 言語用のコードカバレッジツールがあまりない

そもそも、なんでこんなものをつくったかというと、シンプルに C/C++ のフリーのコードカバレッジツールが欲しいからでした。
C/C++ 言語用のコードカバレッジツールは世の中にあるにはありますが、有償かつ高額だったりするので気軽に手が出せないというのが現状かと思います。

フリーのC/C++言語のアプリケーションのコードカバレッジ用ソフトとしては gcov が挙げられます。gcov は便利なのですがいくつかデメリットがあります。

  • gccでないと使えない
  • gcc と gcov のバージョンで互換性がないバージョンがある
  • Unix/Linux 環境以外で使えない
  • C2カバレッジが取れない

というデメリットがあります。

組み込みソフトウェアの開発で CI/CD したい

長期的な目標としてはこちらの理由が大きな理由です。

長年自分がやりたいと思っていることの一つに組み込みソフトウェアでのテストの自動化があります。
ソフトウェアのテストとその自動化は、近年のアプリケーションの開発では当たり前のように行われつつあるといってよいかと思います。
かつてはテストが難しいとされていたフロントエンドの領域ですら Selenium や puppeteer といったブラウザを制御するためのソフトを使ってテストが行われるようになってきており、今後もこの傾向は強くなると考えられます。

しかしながら、組み込みソフトウェアのテストとその自動化は他のソフトウェア開発の分野と比べてあまり進歩していません。

これにはいくつか克服が難しい理由がありますが、コスト的な理由として

  1. ターゲットボード上で動作するプログラムをトレースをするためのハード・ソフトが非常に高価
  2. C/C++言語のアプリケーションの品質測定(静的解析・動的解析・カバレッジ計測...etc)のためのソフトウェアは少なく、高価であることが多い

の2つがあるかと思います。自作のツールでこの2つの要因を解決したいと思い コードカバレッジツールを書き始めました。

covme で実現したいこと

gcov は上記のようにUnix/Linux系OS以外の環境での利用ができません。

組込ソフトウェア開発でもLinuxが利用されることが多くなってきましたが、全ての機器がそのようなリッチなCPU/OSを使って開発されているわけではありません。IoT機器のようにインターネットに接続するような機器であってもOSレスやRTOSなどを使って開発されていることが多いです。

そしてIoT機器のようにネットワークに接続する機器にとって品質を担保する重要性は、サイバー攻撃の脅威に対応する」という観点からも高くなっていると言ってよいかと思いますが、にもかかわらずそういった組み込みソフトウェアの品質を担保するための敷居は高く、人命にかかわるようなクリティカルな製品の開発を除いては、実際の品質担保が置いてけぼりになっているのが組み込みソフトウェア開発の現状と言えます。

covme はそういった組み込みソフトウェア開発における品質担保に使えるレベルにしたいと思います。

どうやってやるのさ?

組み込みソフト開発でのホスト環境とターゲットボードの関係は以下のような構成になっています。

組み込みソフトウェア開発の構成
組み込みソフト開発の構成

この構成のうち、JTAG・デバッガに関してはある程度低価格で入手できるようになってきていますが、動的解析やコードカバレッジの計測を行おうとすると「開発環境(IDE)」「JTAG・デバッガ」の部分のソフト・ハードにそれ相当の機能を持った製品を導入する必要があり、これにはそれなりのコストをかける必要があります。

ところで、このJTAG・デバッガ」との通信ですが、最終的にはGDBプロトコルで扱われることが多いようです。具体的には GDB Server がホスト環境上に存在しており、この GDB Server と 適切な通信をすることで ターゲットボード上で動作するプログラムのコードカバレッジを取ることが実現できると考えています。

そして、組み込み開発で使われる商用コンパイラにおいてもデバッグ情報はDWARF形式で出力されていることが多いという点も covme でのアプローチにはメリットになります。ちなみに、DWARF 以外のデバッグ情報の形式としてマイクロソフトPDB がありますが、PDB 形式に関する情報も多少は世に出ているようですので必要があればサポートしたいと考えています。

ソースコードについて

covme は go言語で書いてみましたが、私は go初心者ということもあり現状ではソースが雑な状態なので今のところバイナリを公開しています。
あと、コードカバレッジツールはビジネスの世界にも関わる面もあるので、コードは少し寝かしておいてもよいのではという気持ちもちょっとあります。

まとめ・今後について

現在公開している covme は x86_64 GNU/Linux 専用になっています。始めたばかりのプロジェクトなので性能的な改善や機能の追加は十分にあり、x86_64 向けの機能も充実させていきたいですが、並行して ARMv7-M あたりをターゲットとしたバージョンも作っていければと思います。

追記

こちらのコードカバレッジツールについてKernel/VM探検隊online part5 で発表させて頂きました。
5:45あたりからが私の発表になります。

www.youtube.com