Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using gcov on STM32

I'm trying to use GCOV for code coverage on my stm32F439ZI.

I just have a quick LED example set up, no OS, no filesystem. My goal, i think, is to edit the write function that gcov use to write the data, to instead forward it to my HAL_UART_Transmit() function. In theory it's simple but i can't figure out what to edit exactly.

I have found few repositories on github that provide an alternative to that method but i can't make it work either.

I'm referring to the coverage data that is normally written into .gcda files. The .gcno files are correctly generated since it's happening at compilation time.

Does anyone have an idea ?

like image 280
Léo Fresnay Avatar asked Dec 06 '25 03:12

Léo Fresnay


1 Answers

Alright, thanks to @G.M. i could come up with an answer, if anyone is interested i will share it.
It resumes the steps from the document he shared on GNU GCC freestanding environnements:

main.c:

#include "app.h"
#include <gcov.h>
#include <stdio.h>
#include <stdlib.h>

extern const struct gcov_info *const __gcov_info_start[];
extern const struct gcov_info *const __gcov_info_end[];

static void dump(const void *d, unsigned n, void *arg) {
    (void)arg;
    fwrite(d, 1, n, stderr);
}

static void filename(const char *f, void *arg) {
    __gcov_filename_to_gcfn(f, dump, arg);
}

static void *allocate(unsigned length, void *arg) {
    (void)arg;
    return malloc(length);
}

static void dump_gcov_info(void) {
    const struct gcov_info *const *info = __gcov_info_start;
    const struct gcov_info *const *end = __gcov_info_end;

    __asm__ ("" : "+r" (info));

    while (info != end) {
        void *arg = NULL;
        __gcov_info_to_gcda(*info, filename, dump, allocate, arg);
        ++info;
    }
}

int main(void) {
    application();
    dump_gcov_info();
    return 0;
}

app.c:


#include "app.h"
#include <stdio.h>

void application(void) {
    int x = 1;

    if (x == 1) {
        printf("Works\n");
    }

    if (x == 2) {
        printf("Doesn't work\n");
    }
}

The app.h file is empty, just the application() function prototype.

  • Once you've written your code, compile it as object files with --coverage -fprofile-info-section:
gcc --coverage -fprofile-info-section -c app.c
gcc --coverage -fprofile-info-section -c main.c
  • Once you've compile to object files, get the linker cmds file:
ld --verbose | sed '1,/^===/d' | sed '/^===/d' > linkcmds
  • Open it and find where .rodata is referenced (you may also have a .rodata1 referenced or more) and add the following below it. This will indicate to the linker that tere is a special place in memory reserved for .gcov_info:
  .gcov_info      :
  {
    PROVIDE (__gcov_info_start = .);
    KEEP (*(.gcov_info))
    PROVIDE (__gcov_info_end = .);
  }
  • Now link it with:
gcc --coverage main.o app.o -T linkcmds # This will output an executable file "a.out"
  • You may execute it as you wish, in this example, the app file is pretty simple so just
./a.out 2>gcda.txt
  • It's important to redirect the stderr to a file because that's where all the gcov info is dumped
static void dump(const void *d, unsigned n, void *arg) {
    (void)arg;
    fwrite(d, 1, n, stderr);
}
  • Then use the stream to create a gcda file:
gcov-tool merge-stream gcda.txt
  • And now use gcov to get your report on execution:
gcov -bc app.c

-> File 'app.c'
Lines executed:85.71% of 7
Branches executed:100.00% of 4
Taken at least once:50.00% of 4
Calls executed:50.00% of 2
Creating 'app.c.gcov'

Lines executed:85.71% of 7
like image 87
Léo Fresnay Avatar answered Dec 08 '25 18:12

Léo Fresnay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!