GCC GCOV / Coverage Shared Library Tracing

GCC GCOV / Coverage Shared Library Tracing

This post explains how to flush gcov[1] trace data dynamically from all linked shared libraries.

Technique

Typically tracing data is written when the application terminates. Tracing date from all shared libraries with activated gcov are written to the specified location. However, when tracing date is needed during runtime, a signal handler is needed to call __gcov_flush. But this only flushes the tracing date from the application itself and not for the shared libraries. To solve this issue you need to call the flush function from inside each shared library. The following approach includes an exported function to each self-maintained library which is later called dynamically during a custom signal handler call.


#define _GNU_SOURCE
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <signal.h>
#include <string.h>

/* DL ITERATION CALLBACK */
static int
gcov_flush_callback(struct dl_phdr_info *info, size_t size, void *data)
{
    void (*func)();
    if (strlen(info->dlpi_name) == 0) return 0;

    void *handle = dlopen(info->dlpi_name,  RTLD_NOW | RTLD_GLOBAL);
    func = dlsym(handle, "exported_gcov_flush");

    if (func) {
        printf("LIBRARY GCOV_FLUSH - %s\n", info->dlpi_name);
        func();
    }
    return 0;
}

/* CUSTOM SIGNAL HANDLER */
void __gcov_flush(void);
void sig_handler(int signum)
{
    dl_iterate_phdr(gcov_flush_callback, NULL);
}

Conclusion

This technique allows to add self-maintained libraries which gcov tracing data which are called dynamically during runtime.

[1] https://gcc.gnu.org/onlinedocs/gcc/Gcov.html