SCIENCE PARK

  1. ホーム
  2. デバイスドライバー開発
  3. デバドラ講座
  4. デバイスドライバ講座(中級)

デバドラ講座

【デバドラ講座4(中級):NotMyFaultを使ってみよう②】

前回に引き続き、NotMyFaultを使ったデバッグを行っていきたいと思います。

1. メモリーリークを選択して仮想マシンのメモリをリークさせてみる。

NotMyFaultのLeakタブを選択し、秒単位でリークさせたいメモリ量、PagedかNonPagedのどちらかのメモリを指定してリークさせることができます。

今回は10000(KB)leak/sec.でNonpagedをリークしてみます。(図1)

(図1:NotMyFault_Leakタブ)

ちなみにタスクマネージャのパフォーマンスを開いてみるとメモリが解放されないため、どんどん領域が少なくなっていることがわかります(図2)
メモリ使用量が最大になるとフリーズ、再起動がおこります。

(図2:タスクマネージャ)

3-1 「!poolused」コマンドを使ってみる。

このコマンドでNonpagedとPagedのメモリ割り当て量(Allcos)と使用量(Used)をみることができます。
Tag:Leakに着目してみると、Nopaged/Allcos:9・Used:9216000と、割り当て量に対してかなり大きなメモリが使われいていることがわかります。

0: kd> !poolused

 Sorting by Tag

               NonPaged                  Paged
 Tag     Allocs         Used     Allocs         Used
…
 LSnn         1          368          0            0	SMB2 netname , Binary: srv2.sys
 LSwi         1        16520          0            0	SMB1 initial work context , Binary: srv.sys
 LSwq         2         1824          0            0	SMB1 BlockTypeWorkQueue , Binary: srv.sys
 LeGe        10         8512          0            0	Legacy Registry Mapping Module Buffers , Binary: tcpip.sys
 Leak         9      9216000          0            0	UNKNOWN pooltag 'Leak', please update pooltag.txt
 Lfs          0            0         11         5328	Lfs allocations 
 LfsI         1           24          0            0	Lfs allocations 
 LfsS         1          112          3       131528	UNKNOWN pooltag 'LfsS', please update pooltag.txt
 Lfsr         1        69632          0            0	UNKNOWN pooltag 'Lfsr', please update pooltag.txt
 LqWi       128         7168          0            0	UNKNOWN pooltag 'LqWi', please update pooltag.txt
…

メモリリークの場合、クラッシュ等が発生するわけではなく表面化しにくいため、先の2例と比べると解析が難しくなります。
メモリ関連で問題が発生していると分かった時の便利な手として、OSにプリインストールされている「DriverVerfier」というツールがあります。
このツールを使うことでメモリの確保状況の様子をダンプ解析することができます。

3-2 「DriverVerfier」を使ってデバッグしてみる。

このツールはpoolリークの検出などpool関連のデバッグに有効なツールです。
DriverVerifier を使用するには、Verifier.exe を実行してコンピュータを再起動します。

詳しい設定の仕方、デバッグ方法は下記Microsoftのブログに書いてあります(2018/12/6現在)

https://blogs.msdn.microsoft.com/jpwdkblog/2015/02/26/driver-verifier/

Verifierでmyfaultに対し標準設定を行った状態で16回/秒、10000KBリークさせてみます。

使うコマンドは「!verfier 3」です。この「3」は全てのドライバのメモリ関連のVerifier情報を表示します。きっかり16回10000KB_ずつリークされていることがわかります。

0: kd> !verifier 3

 Pool Allocations:

      Address     Length      Tag   Caller    
      ----------  ----------  ----  ----------
      0xb1000000  0x009c5000  Leak  *** ERROR: Module load completed but symbols could not be loaded for myfault.sys
0xa11f58a5  myfault+0x18a5
      0xb0600000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xafc00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xaf200000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xae800000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xade00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xad400000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xaca00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xac000000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xab600000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xaac00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xaa200000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xa9800000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xa8e00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xa8400000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5
      0xa7a00000  0x009c5000  Leak  0xa11f58a5  myfault+0x18a5

確保されたそれぞれのNonpagedpoolのコールスタックを見ることもできます。16個確保されたうちの最後のアドレス0xb1000000のコールスタックを見てみましょう。

使うコマンドは「!verifier 80 0xb1000000」です。この「80」で対象アドレス(0xb1000000)のNonpagedpoolのコールスタックを下から順に見ていくことができます。

0: kd> !verifier 80 0xb1000000  

Log of recent kernel pool Allocate and Free operations:

There are up to 0x10000 entries in the log.

Parsing 0x00010000 log entries, searching for address 0xb1000000.
======================================================================
Pool block b1000000, Size 009c4000, Thread 86ef16c0
816d5247 nt!XdvExAllocatePoolInternal+0x17
816cc19e nt!VerifierExAllocatePoolWithTag+0x24
a11f58a5 myfault+0x18a5
a11f5a4a myfault+0x1a4a
816ca903 nt!IovCallDriver+0x82
812a9772 nt!IofCallDriver+0x62
814b765e nt!IopSynchronousServiceTail+0x16e
814bb518 nt!IopXxxControlFile+0x3e8
814ba516 nt!NtDeviceIoControlFile+0x2a
8132de17 nt!KiSystemServicePostCall+0
Parsed entry 00010000/00010000...
Finished parsing all pool tracking information.

このようにしてメモリーリークの場合はOSにプリインストールされている「verifier」をつかうことで、メモリーリークされている瞬間を確認することが有効です。

コマンド一覧

ここでこれまで使ったコマンドをまとめておきます。

基本的に「Ctrl+Break」でOSをストップさせてから適当なコマンドを打って操作し、「コマンド+Enter」でコマンドが実行されます。

「F1」キーを押すとWindbgのヘルプが表示されます。各コマンドにはオプションがついており、それも「F1」から検索が可能です。

・g        OSをスタートさせます。F5キーも同じです。

・!analyze -v   自動解析の結果を表示します。

・!memusage    フレーム事のメモリ量を表示します。

・!poolused    NonpagedとPagedのメモリ割り当て量と使用量を表示します。

  

・!process     実行中のプロセスの一覧を表示します。

・!stackusage   モジュール毎に使われたメモリ量と回数を表示します。

・!vm       仮想メモリの情報を表示します。

・!verfier    メモリリークされたメモリ量や回数などの情報を表示します。

・kf       フレーム毎によって使われたスタックメモリーサイズを表示します。

・kv       スタックトレースを表示します。

・lm       実行中のモジュールを表示します。

page up