Understanding branches in gcov files

I am trying to understand the output of the gcov tool. Running it without parameters makes sense, but I want to try to understand the options for covering branches. Unfortunately, it is difficult to understand what the branches do and why they are not accepted. Below is the result for the method (compile using the latest LLVM / Clang build).

function -[TestCoverageAppDelegate loopThroughArray:] called 5 returned 100% blocks executed 88% 5: 30:- (NSInteger)loopThroughArray:(NSArray *)array { 5: 31: NSInteger i = 0; 22: 32: for (NSString *string in array) { branch 0 taken 0 branch 1 taken 7 -: 33: 22: 34: } branch 0 taken 4 branch 1 taken 3 branch 2 taken 0 branch 3 taken 3 5: 35: return i; -: 36:} 

I missed 5 tests through this, passing nil, an empty array, an array with 1 object and an array with 2 objects and an array with 4 objects. I can guess that in the first case, branch 1 means β€œgo to loop”, but I don’t know what branch 0 is. In the second case, branch 0 seems to go through the loop again, branch 1 seems to end the loop, and branch 3 continues / exits the loop, but I have no idea what branch 2 is or why / when it will be executed.

If someone knows how to decrypt information about the branch, or knows any detailed documentation about what all this means, I would appreciate help.

+7
source share
1 answer

Gcov works with the toolkit (when compiling) of each basic block of machine instructions (you can think of assembler). The main block means a linear section of code in which there are no branches inside and no inside it. So, if and only if you run the base block, you will reach the end of the base block. The main blocks are organized in CFG (control flow graph, think of it as an oriented graph), which shows the relationships between the base blocks (the edge from V1 to V2 are V1 calls V2 and V2 are V1). Thus, the profile-arcs mode of the compiler and gcov wants to get a run count for each line and do this by counting the execution of the base blocks. Some of the edges in CFG are instrumental, and some are not, because there are algebraic relations between the main blocks in the graph.

The ObjC (for..in) construct is omitted (converted at the beginning of compilation) into several base blocks. So, gcov sees 4 branches, because it sees only lower BBs. He does not know anything about this downgrade, but he knows which line corresponds to each assembler instruction (this is debugging information). So, branches are the edges of CFG.

If you want to see the basic blocks, you must dump the compiler of the compiled program or disassemble the CFG from the compiler. You can do this for both profile-arcs and non- profile-arcs modes and compare them.

profile-arcs mode will have many calls and increments of something like "__llvm_gcov_ctr" or "__llvm_gcda_edge" - this is the actual tool for the base blocks.

+3
source

All Articles