GCOV Cross Profiling: __gcov_flush() does not flush coverage data for shared libraries

7.2k views Asked by At

I am trying to get code coverage for an arm based embedded system. Using x86 for cross compilation.So basically, I have a cross profiling question.

For the application I want to generate code coverage data, I have defined a signal handler inside which I call __gcov_flush() to flush code coverage data to .gcda files. I am sending SIGUSR1 to the application. The application uses multiple .so files where bulk of the code and logic is implemented.

When I send the signal to the process, the .gcda files for just the application get created/updated. The .gcda files for the .so's are not created/updated at all.

Is there a way to make __gcov_flush() flush all the coverage data for the .so's that the application is using?

I dont want to force the application to exit() because that would defeat the purpose of what I am trying to do. I need to be able to dump coverage data for the application and the .so it uses at runtime. Please help!!

Using ARM GCC v4.5.1.

This is what I have done so far to generate code coverage data:

I have defined the following options for GCC in the Master makefile: CFLAGS += -fprofile-arcs -ftest-coverage LDFLAGS += -fprofile-arcs -ftest-coverage

I am also exporting GCOV_PREFIX and GCOV_PREFIX_STRIP as global environment variables on the target system to force the .gcda files to be created in a specific path. This is working.

My only problem is the .gcda files for the .so's not getting created/update when __gcov_flush() is called from the application.

1

There are 1 answers

0
Valentyn On

This question got answered on GCC mailing list. TLDR: One needs to add a handler inside every shared library used, that will dump the coverage data. Then these handlers need to be called.

Detailed answer from the mailing list follows.

Question from the mailing list

On Fri, 19 Jun 2015, Utpal Patel wrote:

I am trying to get code coverage for an arm based embedded system. Using x86 for cross compilation.So basically, I have a cross profiling question.

For the application I want to generate code coverage data, I have defined a signal handler inside which I call __gcov_flush() to flush code coverage data to .gcda files. I am sending SIGUSR1 to the application. The application uses multiple .so files where bulk of the code and logic is implemented.

When I send the signal to the process, the .gcda files for just the application get created/updated. The .gcda files for the .so's are not created/updated at all.

Is there a way to make __gcov_flush() flush all the coverage data for the .so's that the application is using?

I dont want to force the application to exit() because that would defeat the purpose of what I am trying to do. I need to be able to dump coverage data for the application and the .so it uses at runtime. Please help!!

Answer from the mailing list

When you compiled your application with -fprofile-arcs -ftest-coverage only the application was instrumented (conceptually a 64bit counters in each basic block of the apps minimum spaning tree) and those counters are what __gcov_flush() is dumping.

So if you want profiling infos from libraries you need to compile the library for profiling as gcov is a static instrumentation and there is no way to get infos from a .so without that it was compiled for profiling just like your application. If the application is compiled for profiling then its data will be dumped when you call __gcov_flush() but since you can not send signals to a library to call some handler you would need to install some other mechanism in the library e.g. brute force put a

int libdump(void) {
        __gcov_flush();                                                         
}

into the library and call that from your application signal handler just like you called __gcov_flush(); now.

This is from a trivial library that just provides an open call that is a wrapper to libc open and the libdump function

    2:   77:int libdump(void) {
    2:   78:        __gcov_flush();
    1:   79:        return 0;
    -:   80:}
    -:   81:/* we now can get code coverage of the library */
  145:   82:int open(const char *pathname, int flags, mode_t mode) {
  145:   83:        return __open(pathname, flags, mode);
    -:   84:}

the library is compiled with

gcc -fPIC -Wall -g -O2 -fprofile-arcs -ftest-coverage -shared -o libgctest.so.0 libgc.c 

the application has the libdump() in the signal handler

int libdump(void);

void gc_handler(int signum)
{
        printf("received signal\n");
        __gcov_flush(); /* dump coverage data on receiving SIGUSR1 */
        libdump();      /* and dump library converage data */
}

and is compiled with

gcc -O2 -fprofile-arcs -ftest-coverage hello.c -o hello -lgctest
 `kill -10 <PIDOF application>` will now dump the gcda of both application and library.

HTH hofrat

ps: I have no clue why the count of the return 0 line in the libhandler does not have a count of 2 as well....