I am using Bullseye for code coverage test with some C code. I successfully instrumented my c code with Bullseye. Then I tried to disassemble it to see what's in there.
I was expecting that there should be some probe function inserted at every control transfer location
. Such as for
, if
, while
, etc. But to my surprise, I only see a single probe at the the beginning of each of my functions
. Such as this one:
So how could this single probe trace all the control transfers?
And when I view the collected coverage data, all my control-transfers are recorded as not covered. Only the function entry point is rocorded as covered.
Did I mis-configure the Bullseye so the above screenshot is only coarse function coverage
? If so, how can I configure Bullseye for fine-grained control-transfer-based coverage?
OK, I figured it out.
The instrumented code looks like this:
#pragma bss_seg(push,".covbss")
static struct cov_V_d934b203 cov_v_d934b203;
#pragma bss_seg(pop)
#pragma const_seg(push,".covconst")
static const struct cov_O_d934b203 cov_o_d934b203 = {
0x5a6b7c8d, 0x6b54972d, &cov_v_d934b203, 0x254972d, cov_V_d934b203_n, "CpuPeimTest.obj 21Apr18 22:20"
};
...
if(!cov_v_d934b203.data[0])cov_probe_v11(&cov_o_d934b203,0);{ // this is right after the function entry.
do { if (DebugPrintEnabled ()) { do { if (DebugPrintLevelEnabled (0x80000000)) { DebugPrint (0x80000000,"Ming: Code coverage test start.\n"); } } while (((BOOLEAN)(0==1))); } } while (((BOOLEAN)(0==1)));
So essentially, it stored some coverage data collector objects, cov_c_xxx
and cov_v_xxx
, in the .covconst
and .covbss
segments respectively. And at runtime, the instrumented code log data points to cov_v_xxx
object.
The cov_probe_v11
invoking at the function entry just link the cov_c_xxx
and cov_v_xxx
into the final result link list. The cov_probe_v11
is part of the Bullseye runtime lib. You can modify it to adapt to your code under test.
Once linked, all the other data collection can happen without the need to invoke the cov_probe_v11
.