Search

Wednesday, October 02, 2013

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.