Search code examples
gcov

why gcc embedded gcov library by JPL NASA is not creating full gcda data on STM32F429 target memory?


I am using embedded gcov library from JPL/NASA to get code coverage on my stme32f429 target using Embitz IDE and gcc compiler v5.4. The link is shared below:

https://github.com/nasa-jpl/embedded-gcov

However, it seems that gcov_conver-togcda() functions is not producing full gcda coverage data because It is not entering a for loop. I am only getting fixed 12 bytes of gcda data that should be more than that, including coverage counters information. My debugging efforts showed that number of instrumented functions variable of gcc handled gcov_ info structure is always 0. Can anyone tell me what is going wrong here? Please feel free to see the attachments.enter image description hereenter image description here

I wanted to see the instrumented code generated by gcc gcov to ensure that it is instrumenting my source code with coverage counters. I am able to compile code with -ftest-coverage and -fprofile-arcs compiler options.


Solution

  • I had the same problem and was able to fix it.

    For compiling my code I use GNU toolchain 6.3.1 from Microchip Studio: https://www.microchip.com/en-us/tools-resources/develop/microchip-studio/gcc-compilers

    Find below more details about my toolchain version.

    $ arm-none-eabi-gcc --version
    arm-none-eabi-gcc.exe (Atmel build: 508) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]
    Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    $ arm-none-eabi-gcc -dM -E - < /dev/null | grep __GNUC__
    #define __GNUC__ 6
    

    Firstly, like you, I was only getting 12 bytes from my device corresponding to .gcda headers. After taking a look with the debugger, I found out that all gcov_info structs given to the __gcov_init function have the field n_functions = 0. I thought it was odd because this value is defined at compile time and represents the number of functions for a given C file.

    So I decided to take a closer look at the memory for each field of the structure:

    struct gcov_info {
        gcov_unsigned_t version;
        struct gcov_info *next;
        gcov_unsigned_t stamp;
        const char *filename;
        gcov_merge_fn merge[GCOV_COUNTERS];
        unsigned n_functions;
        struct gcov_fn_info **functions;
    };
    

    Here we can see the only field that will modify the size of the array, with a macro which is defined depending on the GCC version used. The comment in the code warns us that it has only been tested with two versions "/* This has been used with GCC 7.5.0 and GCC 11.1.0 */" (so it doesn't include either yours or mine):

    #if (__GNUC__ >= 10)
    #define GCOV_COUNTERS           8
    #elif (__GNUC__ >= 5) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
    #define GCOV_COUNTERS           9
    #else
    #define GCOV_COUNTERS           8
    #endif
    

    Now that I had identified the problem, I checked the memory of my program to see if I could spot the n_functions field value. I noticed that the array field merge had only one non-null element, the first one. Since only the first member of my array was non-null, I tried to set its size to 0. Then I observed n_functions having the same non-null value for all (i.e., taking the value of the first member of my array).

    I concluded that the value of GCOV_COUNTERS was incorrect for my GCC version. I looked at the first non-null value after the values of the merge field, which was the eleventh. So the array size should be 10.

    #define GCOV_COUNTERS           10
    

    And it's finally working !