SlideShare ist ein Scribd-Unternehmen logo
1 von 38
Downloaden Sie, um offline zu lesen
C/C++用のコードカバレッジツールを
自作してみた話
@simotin13
Who am I?
@simotin13
Hiroyuki Miyazaki
・関西で主に組込系のコード書いてます。
・組込,Ruby,低レイヤが好きです。
Abstract
C/C++のプログラム用に、カバレッジツールを書いてみま
した。
■covme
https://github.com/simotin13/covme
今のところ、完成度的にはまだまだな点はありますが、X86_64/Linuxで動く実行モ
ジュールとサンプルの実行用スクリプトなどを公開しています。
go言語で書いています。
Abstract
# カバレッジを取りたいモジュール (-gビルド必須)を指定して実行。
# モジュールが終了するとHTMLで結果を出力します。
$gcc main.c calc.c -g
$./covme a.out
Why code coverage tool?
・商用のカバレッジツールや開発環境は高い
・Linuxだとgcov使えるけど、マイコンでは使えない
■問題
組込ソフト開発でも気軽にテストを自動化したり、カバレッジ
取りたい
Inspired by PHPUnit
PHPのコードを書いていて、PHPUnitというテストフレームワー
クを使う機会がありました。
Inspired by PHPUnit
ところで、PHPUnitはどうやってカバレッジをとっている
のか?
Inspired by PHPUnit
PHPUnitを使うときには、php.iniにXDebugの設定を書く必要
がある。
そうか、デバッガを使ってカバレッジ取っているんだろう
な...
何となくPHPUnitがやっていることは察しがついた。
Inspired by PHPUnit
伝統的日本企業ではExcelにソースコードを貼り付け、
デバッガでステップ実行した結果を記録
し、ユニットテストを実施します。
Inspired by PHPUnit
PHPがXDebug使ってカバ
レッジを取れるなら、
C/C++でもデバッガを使っ
て同じことができるので
は?
linux/gdbで試してみよう。
Automate debug operation ~GDBの自動化~
4607 11.3 7.1 52927752 284968 ? Sl 12:05 1:21 /usr/share/code/code --type=renderer --disable-color-correct-rendering --field-trial-handle
4624 1.6 3.7 38053352 148960 ? Sl 12:05 0:11 /usr/share/code/code --ms-enable-electron-run-as-node --inspect-port=0 /usr/share/code/reso
4625 0.1 1.6 38035456 65348 ? Sl 12:05 0:00 /usr/share/code/code --ms-enable-electron-run-as-node /usr/share/code/resources/app/out/boo
4696 1.0 0.8 1177412 35284 ? Sl 12:05 0:07 /home/simotin13/.vscode/extensions/ms-vscode.cpptools-1.11.4/bin/cpptools
4729 0.5 2.1 37992972 86564 ? Sl 12:05 0:03 /usr/share/code/code --ms-enable-electron-run-as-node /usr/share/code/resource4696 {9A295B6
5316 6.1 1.5 3525864 61696 ? Sl 12:10 0:24 /home/simotin13/.vscode/extensions/ms-vscode.cpptools-1.11.4/debugAdapters/bin/OpenDebugAD7
5331 0.0 0.0 2616 596 pts/1 S+ 12:10 0:00 /bin/sh /tmp/Microsoft-MIEngine-Cmd-qsxfzbaz.lrg
5333 0.0 1.0 60612 43264 pts/1 S 12:10 0:00 /usr/bin/gdb --interpreter=mi --tty=/dev/pts/1
s/app/extensi
5160 0.1 0.3 4801612 13956 ? Sl 12:09 0:00 /home/simotin13/.vscode/extensions/ms-vscode.cpptools-1.11.4/bin/cpptools-srv 5338 0.0 0.0
2364 644 ? ts 12:10 0:00 /home/simotin13/tmp/main
gdbの-i=mi オプションはgdbのコマンド入出力をマシンフレンドリー
にしてくれる。EclipseやVSCodeでも使われている。
■vscodeでデバッグしているときの例
Automate debug operation ~GDBの自動化~
Breakpoint 1, main (argc=21845, argv=0x0) at main.c:7
7 {
通常起動(-i=mi なし)
~"¥n"
~"Breakpoint 1, main (argc=21845, argv=0x0) at main.c:7¥n"
~"7¥t{¥n"
*stopped,reason="breakpoint-
hit",disp="keep",bkptno="1",frame={addr="0x0000555555555189",func="main",args=[{name="argc",value="21845"},{name
="argv",value="0x0"}],file="main.c",fullname="/home/simotin13/examples/c/function_call/main.c",line="7",arch="i3
86:x86-64"},thread-id="1",stopped-threads="all",core="9"
-i=mi あり
miオプション有効時のレスポンスについて
ブレークポイントで停止したときの例
Automate debug operation ~GDBの自動化~
~"¥n"
~"Breakpoint 1, main (argc=21845, argv=0x0) at main.c:7¥n"
~"7¥t{¥n"
*stopped,reason="breakpoint-
hit",disp="keep",bkptno="1",frame={addr="0x0000555555555189",func="main",a
rgs=[{name="argc",value="21845"},{name="argv",value="0x0"}],file="main.c",
fullname="/home/simotin13/examples/c/function_call/main.c",line="7",arch="
i386:x86-64"},thread-id="1",stopped-threads="all",core="9"
レスポンスの特徴
・先頭1文字で応答の種類(同期・非同期・通知...etc)を表す
・JSONっぽいデータ構造。でも微妙に違う。
・値は全てダブルクォーテーションで囲まれている。
Automate debug operation ~GDBの自動化~
・gdbのプロセスをforkして、コマンドの送信とレスポンスの解析
ができればデバッガの操作の自動化は完了
How to measure a code coverage?
そもそもカバレッジってどう測るのか?
How to measure a code coverage?
関数のカバレッジ率 =
関数内の通過した行数
関数全体の行数
1:int func(int a, int b)
2:{
3: return a+b;
4:}
How to measure a code coverage?
~"¥n"
~"Breakpoint 1, main (argc=21845, argv=0x0) at main.c:7¥n"
~"7¥t{¥n"
*stopped,reason="breakpoint-
hit",disp="keep",bkptno="1",frame={addr="0x0000555555555189",func="main",a
rgs=[{name="argc",value="21845"},{name="argv",value="0x0"}],file="main.c",
fullname="/home/simotin13/examples/c/function_call/main.c",line="7",arch="
i386:x86-64"},thread-id="1",stopped-threads="all",core="9"
gdbのレスポンスから「通過した行やアドレス」は分かる。
関数のカバレッジ率 =
関数内の通過した行数
関数全体の行数
How to measure a code coverage?
よく考えてみたら「関数が何行あるか?」
を数えるのは簡単ではない
1:int func(int a, int b)
2:{
3:// コメントがあるよ
4:/* ここもコメントだよ */
5:/* #ifもあるよ。どっちを通るか分かるかな? */
6:#if HOGE
7: return a+b;
8:#else
9: return 0;
10:#endif
11:}
How to measure a code coverage?
1:int func(int a, int b)
2:{
3:// コメントがあるよ
4:/* ここもコメントだよ */
5:/* #ifもあるよ。どっちを通るか分かるかな? */
6:#if HOGE
7: return a+b;
8:#else
9: return 0;
10:#endif
11:}
関数のカバレッジ率 =
関数内の通過した行数
関数内の実行可能な行数
How to measure a code coverage?
「関数内の実行可能な行数」
はどうやって取得することができるのか?
もしかして、コンパイラとか書かないとだめ?
How to measure a code coverage?
DWARFというデバッグ情報に
行番号の情報が含まれている
という噂だよ
Reading DWARF sections
・DWARFってデバッグに関する情報が入っているあれでしょ(知らんけど…)
・DWARFを読みたくなったときどこから読めばいいのか?
・DWARFの仕様書には「Getting started」的な説明がない
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
........................................................................................
........................................................................................
[28] .debug_aranges PROGBITS 0000000000000000 00303a 000030 00 0 0 1
[29] .debug_info PROGBITS 0000000000000000 00306a 000339 00 0 0 1
[30] .debug_abbrev PROGBITS 0000000000000000 0033a3 0000f2 00 0 0 1
[31] .debug_line PROGBITS 0000000000000000 003495 00011b 00 0 0 1
[32] .debug_str PROGBITS 0000000000000000 0035b0 0002a0 01 MS 0 0 1
Reading DWARF sections
・デバッグ情報の歩き方 @mhiramat
https://qiita.com/mhiramat/items/8df17f5113434e93ff0c
・DWARFファイルフォーマット@koinec
https://ja.osdn.net/projects/drdeamon64/wiki/DWARF%E3%83%95%E3%82%A1%E3%
82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E
3%83%88
■日本語の有力な情報
Reading DWARF sections
■独断と偏見によるDWARFの仕様書の読み方解説
・DWARFの仕様書は読み辛い。最初から読むのは非効率。
・DWARFの各セクションの構造を理解し、プログラムで読みたいという目的であれば、
「7.5 Format of Debugging Information」から読むのがおすすめ。
※ DWARF4の場合(https://dwarfstd.org/doc/DWARF4.pdf)
.debug_infoセクションのヘッダ部の構造が書いてあるので、
.debug_infoの最初の1byteを読むコードを書き始めることができる。
Reading DWARF sections
■DWARFを読むときにやること
・eu-readelfコマンドでどんな情報が入っているか把握する。
# .debug_infoを読んでテキストで表示
$eu-readelf a.out –winfo
# .debug_lineを読んでテキストで表示
$eu-readelf a.out -wline
Reading DWARF sections
■独断と偏見によるDWARFセクションの概要説明
セクション名 難易度 内容
.debug_arranges .debug_infoで出てくるDIEのサイズに関する情報が入っている。とりあえず
は読まなくても何とかなる。
.debug_str ファイル名や関数名など、デバッグ情報で参照される文字列の情報が
0終端文字列で入っている。読むのは簡単。
.debug_abbrev TagとAttributeからなる略語表(abbreviation table)が入っている。
いわばデバッグ情報の「構造体」のテーブル。
Tag=構造体名, Attribute=メンバー変数。
※実際はTag,Attribute共にID(数値)で表現される。
.debug_line アドレスと行番号に関する情報が入っている。
例). 0x1234→ main.cの5行目
簡易的な状態機械を使って行番号やアドレスを計算するための「命令」が
入っている。計算には意味不明な式が登場する。
.debug_info .debug_abbrevで登場する「構造体」IDが入っており、その「構造体」の定義
に従って読んでいく。読むとプログラムの色んな事が分かる。
可変長のデータ構造なので読み飛ばしができない。
よく分からないDIEが出てくると詰む。
Reading DWARF sections
■独断と偏見によるDWARFの解説 .debug_lineについて
ファイルのインデックス 行番号 アドレス ブレークポイントをおけ
るか(is_stmt)
0 0 0x00000000 FALSE
インデックス ファイル名
1 main.c
2 calc.c
3 hoge.c
.debug_lineはファイル名・行番号を表現するための簡易的な状態機械に対
する命令が羅列されている。
■状態機械
■ファイル名のテーブル
Reading DWARF sections
■独断と偏見によるDWARFの解説 .debug_lineについて
ファイルの
インデックス
行番号 アドレス ブレークポイント
をおけるか(is_stmt)
0 0 0x00000000 FALSE
インデックス ファイル名
1 main.c
2 calc.c
3 hoge.c
命令に従って状態機械の各レジスタの値を更新し、行番号の情報を表現す
る
■状態機械
■ファイル名のテーブル
■命令の例
1.ファイルのインデックスに2をセット
2.行番号に1を加算
3.アドレスに0x1000をセット
4.is_stmtをTRUEにセット
5.行番号情報を確定
6.行番号に5を加算
7.アドレスに4を加算
8.行番号を確定
Reading DWARF sections
■独断と偏見によるDWARFの解説 .debug_lineについて
ファイルの
インデックス
行番号 アドレス ブレークポイント
をおけるか(is_stmt)
2 1 0x00001000 TRUE
インデックス ファイル名
1 main.c
2 calc.c
3 hoge.c
命令に従って状態機械の各レジスタの値を更新し、行番号の情報を表現す
る
■状態機械
■ファイル名のテーブル
■命令の例
1.ファイルのインデックスに2をセット
2.行番号に1を加算
3.アドレスに0x1000をセット
4.is_stmtをTRUEにセット
5.行番号情報を確定 ←いまここ
6.行番号に5を加算
7.アドレスに4を加算
8.行番号を確定
Reading DWARF sections
.debug_line を読み終わると、
・アドレスに対応するソースファイルのパス
・アドレスに対応するソースファイルの行番号
・ソースファイルの各行が実行可能(is_stmt)かどうか
が分かる
1:int func(int a, int b)
2:{
3:
4: // 足し算を行う関数
5: // aにbを加えた値を返す
6: return a+b;
7:}
filepath: calc.c
1:address 0x1000
2:not stmt
3:not stmt
4:not stmt
5:not stmt
6:address 0x1004
7:address 0x1008
Reading DWARF sections
1:int func(int a, int b)
2:{
3:
4: // 足し算を行う関数
5: // aにbを加えた値を返す
6: return a+b;
7:}
filepath: src/lib/calc.c
1:address 0x1000
2:not stmt
3:not stmt
4:not stmt
5:not stmt
6:address 0x1004
7:address 0x1008
関数のカバレッジ率 =
関数内の通過した行数
関数内の実行可能な行数
この対応表からカバレッジ率の算出に必要な「関数内の実行可能な
行数」が分かる
Demonstration
実際に動かしてみる
(デモ)
Appply to Embedded software
gdb command/response
JTAG/SWD
Remote
Serial
Protocol
gdb
server
gdb
client
covme target
board
vender
protocol
gdbを使うので組込ソフトの開発とも親和性が高い
→商用開発環境でもデバッガはgdbとDWARFが使われていることが多い。
gdbが使えるならターゲットのCPUやOSを問わずにカバレッジがとれる(はず)
JTAG/ICE
debugger
Appply to Embedded software
gdb のリモートデバッグ機能を使うことで同じ仕組み
を使ってカバレッジが取れる。
gdbクライアント:gdb-multiarch
gdbサーバ:jlinkのGDBサーバ
ARMマイコン(nucleo F446RE)のターゲットボード上
で動くプログラムのカバレッジを取れるよう修正してみた。
■ARMで試してみた
Appply to Embedded software
・プログラムによってはDWARFを読むところでバグがいっぱい出た
→想定していなかったDIEが登場する
・カバレッジを取る仕組み自体には問題なさそう
・バグを直さないと ←いまここ
■ARMで試してみた結果
Summary~まとめ~
・デバッガを自動化できると便利
・DWARFは難解。でも読めると色々面白いことができそう。
→デバッガを使役せよ
References ~参考文献~
■GDB
・Rubyist Magazine mruby 用デバッガ 「nomitory」の作り方
https://magazine.rubyist.net/articles/0050/0050-nomitory.html
・GDB/MI インターフェイスについて
https://www.asahi-net.or.jp/~wg5k-ickw/html/online/gdb-5.0/gdb-ja_20.html
■DWARF
・The DWARF Debugging Standard
https://dwarfstd.org/
・デバッグ情報の歩き方 @mhiramat
https://qiita.com/mhiramat/items/8df17f5113434e93ff0c
・DWARFファイルフォーマット@koinec
https://ja.osdn.net/projects/drdeamon64/wiki/DWARF%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83
%83%E3%83%88
ご清聴どうもありがとうございました。

Weitere ähnliche Inhalte

Was ist angesagt?

メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
Kota Mizushima
 
マルチコアとネットワークスタックの高速化技法
マルチコアとネットワークスタックの高速化技法マルチコアとネットワークスタックの高速化技法
マルチコアとネットワークスタックの高速化技法
Takuya ASADA
 
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解するそうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
shigeki_ohtsu
 

Was ist angesagt? (20)

今時のLinuxにおけるGPUエンコード事情2018
今時のLinuxにおけるGPUエンコード事情2018今時のLinuxにおけるGPUエンコード事情2018
今時のLinuxにおけるGPUエンコード事情2018
 
プログラマ目線から見たRDMAのメリットと その応用例について
プログラマ目線から見たRDMAのメリットとその応用例についてプログラマ目線から見たRDMAのメリットとその応用例について
プログラマ目線から見たRDMAのメリットと その応用例について
 
C/C++プログラマのための開発ツール
C/C++プログラマのための開発ツールC/C++プログラマのための開発ツール
C/C++プログラマのための開発ツール
 
トランザクションの設計と進化
トランザクションの設計と進化トランザクションの設計と進化
トランザクションの設計と進化
 
高位合成でDeep learning
高位合成でDeep learning高位合成でDeep learning
高位合成でDeep learning
 
KVM環境におけるネットワーク速度ベンチマーク
KVM環境におけるネットワーク速度ベンチマークKVM環境におけるネットワーク速度ベンチマーク
KVM環境におけるネットワーク速度ベンチマーク
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
CRDT in 15 minutes
CRDT in 15 minutesCRDT in 15 minutes
CRDT in 15 minutes
 
CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説
CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説
CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説
 
10GbE時代のネットワークI/O高速化
10GbE時代のネットワークI/O高速化10GbE時代のネットワークI/O高速化
10GbE時代のネットワークI/O高速化
 
Magnum IO GPUDirect Storage 最新情報
Magnum IO GPUDirect Storage 最新情報Magnum IO GPUDirect Storage 最新情報
Magnum IO GPUDirect Storage 最新情報
 
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
 
メタプログラミングって何だろう
メタプログラミングって何だろうメタプログラミングって何だろう
メタプログラミングって何だろう
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
Tensor flow usergroup 2016 (公開版)
Tensor flow usergroup 2016 (公開版)Tensor flow usergroup 2016 (公開版)
Tensor flow usergroup 2016 (公開版)
 
マルチコアとネットワークスタックの高速化技法
マルチコアとネットワークスタックの高速化技法マルチコアとネットワークスタックの高速化技法
マルチコアとネットワークスタックの高速化技法
 
FPGA+SoC+Linux実践勉強会資料
FPGA+SoC+Linux実践勉強会資料FPGA+SoC+Linux実践勉強会資料
FPGA+SoC+Linux実践勉強会資料
 
コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料)
コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料)コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料)
コレクションフレームワーク関連セッション(JavaOne & Devoxx報告会 2022 発表資料)
 
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解するそうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
そうだったのか! よくわかる process.nextTick() node.jsのイベントループを理解する
 
何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門何となく勉強した気分になれるパーサ入門
何となく勉強した気分になれるパーサ入門
 

Ähnlich wie C・C++用のコードカバレッジツールを自作してみた話

ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
Hiroh Satoh
 
スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
Kiwamu Okabe
 

Ähnlich wie C・C++用のコードカバレッジツールを自作してみた話 (20)

mruby を C# に 組み込んでみる
mruby を C# に 組み込んでみるmruby を C# に 組み込んでみる
mruby を C# に 組み込んでみる
 
トランザクションスクリプトのすすめ
トランザクションスクリプトのすすめトランザクションスクリプトのすすめ
トランザクションスクリプトのすすめ
 
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく - YAPC Asia 2011
 
Code Reading at Security and Programming camp 2011
Code Reading at Security and Programming camp 2011 Code Reading at Security and Programming camp 2011
Code Reading at Security and Programming camp 2011
 
Cプログラマのためのカッコつけないプログラミングの勧め
Cプログラマのためのカッコつけないプログラミングの勧めCプログラマのためのカッコつけないプログラミングの勧め
Cプログラマのためのカッコつけないプログラミングの勧め
 
Programming camp code reading
Programming camp code readingProgramming camp code reading
Programming camp code reading
 
第1回勉強会スライド
第1回勉強会スライド第1回勉強会スライド
第1回勉強会スライド
 
Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011 Debug Hacks at Security and Programming camp 2011
Debug Hacks at Security and Programming camp 2011
 
つぶLT20121215
つぶLT20121215つぶLT20121215
つぶLT20121215
 
Web技術勉強会 第33回
Web技術勉強会 第33回Web技術勉強会 第33回
Web技術勉強会 第33回
 
Programming camp 2008, Codereading
Programming camp 2008, CodereadingProgramming camp 2008, Codereading
Programming camp 2008, Codereading
 
Programming camp 2010 debug hacks
Programming camp 2010 debug hacksProgramming camp 2010 debug hacks
Programming camp 2010 debug hacks
 
オープンソースで作るスマホ文字認識アプリ
オープンソースで作るスマホ文字認識アプリオープンソースで作るスマホ文字認識アプリ
オープンソースで作るスマホ文字認識アプリ
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
Inside frogc in Dart
Inside frogc in DartInside frogc in Dart
Inside frogc in Dart
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺
 
Groovy Bootcamp 2015 by JGGUG
Groovy Bootcamp 2015 by JGGUGGroovy Bootcamp 2015 by JGGUG
Groovy Bootcamp 2015 by JGGUG
 
C#や.NET Frameworkがやっていること
C#や.NET FrameworkがやっていることC#や.NET Frameworkがやっていること
C#や.NET Frameworkがやっていること
 
スタート低レイヤー #0
スタート低レイヤー #0スタート低レイヤー #0
スタート低レイヤー #0
 
Flutterを体験してみませんか
Flutterを体験してみませんかFlutterを体験してみませんか
Flutterを体験してみませんか
 

C・C++用のコードカバレッジツールを自作してみた話