Quick/Dirty Function Coverage using Windbg

To find code coverage at line and block granularity you need a full-fledged code coverage tool. However, sometimes you can use a quick and dirty trick in WinDbg to see which functions are being called. This works well when you need to do this for a small set of functions, which is what I recently needed to do. Lets say it was for all the functions of a class called Graph.

First I got the application under the debugger, wherein it automatically broke into the debugger at the application start. Then I added breakpoints to all these functions using the following

 0:000> bm test!Graph*::* 10000
  2: 003584a0          @!"test!Graph::Vertex::`scalar deleting destructor'"
  3: 00356f80          @!"test!Graph::Vertex::~Vertex"
  4: 00358910          @!"test!Graph::AddVertex"
  5: 00356b70          @!"test!Graph::~Graph"
  6: 003589d0          @!"test!Graph::RangeCheck"
  7: 003589b0          @!"test!Graph::Count"
  8: 00357ce0          @!"test!Graph::operator[]"
  9: 003561a0          @!"test!Graph::Vertex::Vertex"
 10: 00356170          @!"test!Graph::Vertex::Vertex"
 11: 00358130          @!"test!Graph::`scalar deleting destructor'"
 12: 003588a0          @!"test!Graph::AddEdge"
 13: 003551e0          @!"test!Graph::Graph"

Here I am telling windbg to add breakpoints on all methods in the Graph class with a very large hit count of 0x10000. Then I just let the application proceed and play with the various controls. Finally I closed the application, when it again broke under the debugger. At this point I just list the breakpoints.

 0:000> bl
 1 e 00352c70     0001 (0001)  0:**** test!main
 2 e 003584a0     fd8f (10000)  0:**** test!Graph::Vertex::`scalar deleting destructor'
 3 e 00356f80     fcc7 (10000)  0:**** test!Graph::Vertex::~Vertex
 4 e 00358910     ff38 (10000)  0:**** test!Graph::AddVertex
 5 e 00356b70     ffff (10000)  0:**** test!Graph::~Graph
 6 e 003589d0     d653 (10000)  0:**** test!Graph::RangeCheck
 7 e 003589b0     c1de (10000)  0:**** test!Graph::Count
 8 e 00357ce0     fda7 (10000)  0:**** test!Graph::operator[]
 9 e 003561a0     fd8f (10000)  0:**** test!Graph::Vertex::Vertex
10 e 00356170     ff38 (10000)  0:**** test!Graph::Vertex::Vertex
11 e 00358130     ffff (10000)  0:**** test!Graph::`scalar deleting destructor'
12 e 003588a0     ec56 (10000)  0:**** test!Graph::AddEdge
13 e 003551e0     ffff (10000)  0:**** test!Graph::Graph

The key fields are marked below

13 e 003551e0 ffff (10000) 0:**** test!Graph::Graph

10000 indicates that after 0x10000 times the breakpoint is hit should the debugger actually break on this. FFFF indicates how many times it is left for this break to happen. So a simple subtraction (0x10000 – 0xFFFF) tells us that this function has been called once. It’s easy to see that one Graph object was created and destroyed (1 call to ctor and 1 to dtor) and that the Graph<T>::Count has been called 15906 times (0x10000 – 0xC1DE). So I didn’t really miss any of the functions in that test. If I did it would say 10000 (10000) for the function that I missed.