OpenCppCoverageは如何にしてカバレッジ計測しているか


# OpenCppCoverageとは？
- カバレッジを算出してくれるオープンソース（[GitHub](https://github.com/OpenCppCoverage/OpenCppCoverage)）
- visual studioのプラグインもある（2019まで）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/4ab151fd-45a5-ceab-19ad-474370315b87.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/15059b11-2112-fe21-26ae-ce428a622f66.png)


# OpenCppCoverageの全体
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/0f7bece6-5ea8-cae6-b948-9e86a5316395.png)
処理の流れとしては上図のようになっており5Stepからなる。
1. 分析対象のexeファイルから、exe作成に使用された.hファイル.cpp/.cファイル情報（ファイル名/行数/行数の仮想アドレス）の取得
2. [仮想アドレス](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/gettingstarted/virtual-address-spaces)を物理アドレスに変換し、各ポイントにブレイクポイントをはる
3. 分析対象のexeの処理を実行開始
4. ブレイクポイントのイベントを補足し、ブレイクポイントをはった行数を通過したという情報を蓄積していく
5. 行数と通過した/通過していないの情報をまとめて、カバレッジ情報を作成する

# 使用されている技術
- DIA(Debug Interface Access)というAPI
    - exeやpdbファイルから様々な情報を取得できる
    - [DIA SDK](https://docs.microsoft.com/ja-jp/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk?view=vs-2022)

# ①.exeからファイル情報の抽出
- 情報の抽出対象としたexeファイル
以下のようなfunction.cppファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/cbfbc5cc-ab33-094e-303e-da3639fb0f5a.png)

- 抽出できる情報
[DIA SDK](https://docs.microsoft.com/ja-jp/visualstudio/debugger/debug-interface-access/getting-started-debug-interface-access-sdk?view=vs-2022)のサンプルプロジェクトをビルドして作成したDia2dump.exeで抽出可能な情報を表示してみた。OpenCppCoverageでも同じAPIを使用して情報を抽出している。
様々な情報が抽出できていることが分かる。
OpenCppCoverageで使用している情報はLINESの情報。
どのファイルのどの行数が仮想アドレスに格納されているかの情報が得られている模様。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/74ba7671-eb57-c3c1-4946-8903890d1102.png)

一般的に[PE形式に含まれる情報は以下のようになっている
](https://docs.microsoft.com/ja-jp/windows/win32/debug/pe-format?redirectedfrom=MSDN)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/aacd6fd4-af2f-1482-cb44-9a3fe7c49c3b.png)　

- OpenCppCoverageのコード
④の関数がメインなのでそこを深堀していく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/bedb070f-34af-54cc-d1f7-807316fd0775.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/d88292b0-74c5-cb82-086c-b0c1aaa1d3e1.png)

    - EnumetrateCollection
EnumetrateCollectionの引数は*sourceFilesとラムダ式。
sourceFilesから１ファイルが取りだされて、ラムダ式が実行されていく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/aacc8c52-5bc0-8c2b-e86b-e1ea17410af9.png)


      
        - EnumLines()：ラムダ式の中で実行されている関数
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/7f074197-fc89-757d-026c-53527f8ce999.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/862d0617-7bae-0cf1-3776-b0ddc07004b0.png)

            - OnNewLines
            lines_に行数と、仮想アドレス、シンボルIndexが追加されていく。
ファイル情報の抽出は完了。

            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/89cbd72b-abfc-8c7d-cab5-10587cb736df.png)
            ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/fefba8fe-7f3c-c5b1-f6ac-eb8cfef9072f.png)

　　　　　　　得られた行数と、仮想アドレス、シンボルIndexの例
　　　　　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/b68ad82e-2ed7-77da-e1e2-e6c905a4e87a.png)

- OnSorceFile
        
    ブレイクポイントをSetすることが役割
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/a2ff8e22-6ec2-62ea-04a1-5196c305092b.png)

仮想アドレスとモジュールのbaseOfImageの値からアドレスの値を求め、アドレスの値とライン行数の対応vectorを作成
# ②ブレイクポイントのSet
   - SetBreakPoint:OnNewLines()の中でcallされている
   ここまでに求めた行数に対応するアドレスに対してブレイクポイントをSetしていく
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/4c4f2b93-7dd1-5a91-d528-b7516b566078.png)
	        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/cd6bc435-ae9f-25bb-63fe-f99d41d707de.png)

# ③.exeの実処理実行
実行が始まる
       
# ④ブレイクポイントイベントの補足と通過情報の蓄積
デバッグ時のイベント補足には[WaitForDebugEvent()を使う](https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-waitfordebugevent)

EXCEPTION_DEBUG_EVENT（1）の[EXCEPTION_BREAKPOINTを使う](https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-waitfordebugevent)
ことでブレイクポイントイベントを補足できる。
OnBreakPoint()の中でブレイクポイントが止まった（通過した）行に通過した情報を残す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/8688262e-007d-1911-8d22-e19f50df2ead.png)

# ⑤カバレッジ情報の作成
④で通過した行には通過した情報が残っており、通過していない行は通過していないの状態のままなので、この情報を使って、カバレッジ情報を作成する


# OpenCppCoverageのデバッグ環境構築
[GitHub](https://github.com/OpenCppCoverage/OpenCppCoverage)をcloneしてビルドすると以下のエラーが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680528/09a42f5a-ba2a-8c73-9743-d26fb4d3ad1d.png)

[thirdParty1.4.0.nupkg](https://github.com/OpenCppCoverage/OpenCppCoverageThirdParty/releases/tag/1.4.0)をダウンロードして、エラーで指摘されているパスに置き、パッケージの復元をNuGetパッケージの管理から行うとデバッグ実行可能な状態になる。


- 環境 visual studio 2019