STM32F439ZI无OS无文件系统环境下GCOV代码覆盖率数据UART输出改造问题求助
STM32F439ZI无OS无文件系统环境下GCOV代码覆盖率数据UART输出改造问题求助
嘿,我刚好在裸机STM32项目里踩过GCOV覆盖率输出的坑,给你分享一下我是怎么把.gcda数据通过UART发出去的,亲测在F4系列上有效!
首先得搞明白:GCOV默认是依赖标准C库的文件IO来写.gcda文件的,咱们裸机没文件系统,核心就是劫持这些文件操作函数,把数据转去UART发送,具体步骤如下:
一、重定向标准C库的文件操作函数
GCOV在输出覆盖率数据时会调用fopen、fwrite、fclose这些函数,我们自己实现这些函数,让它们绕开文件系统直接用UART:
1. 重写fopen
让它返回一个非空的虚拟文件指针,骗GCOV认为文件打开成功:
#include "stm32f4xx_hal.h" #include <stdio.h> // 虚拟文件结构体,只要非空就行 static FILE dummy_gcov_file; FILE *fopen(const char *path, const char *mode) { // 这里可以忽略path和mode参数,因为咱们不需要真的打开文件 return &dummy_gcov_file; }
2. 重写fwrite
把原本要写入文件的字节直接通过UART发送:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { // 用HAL_UART_Transmit发送数据,这里假设你已经初始化了huart1 HAL_UART_Transmit(&huart1, (uint8_t*)ptr, size * nmemb, HAL_MAX_DELAY); // 返回实际发送的成员数,让GCOV认为写入成功 return nmemb; }
3. 重写fclose
可以在这里加个结束标记,方便上位机识别.gcda数据的结尾:
int fclose(FILE *stream) { // 发送4个0xFF作为数据结束标记,上位机接收时可以用这个来截断数据 uint8_t eof_marker[] = {0xFF, 0xFF, 0xFF, 0xFF}; HAL_UART_Transmit(&huart1, eof_marker, sizeof(eof_marker), HAL_MAX_DELAY); return 0; // 返回0表示关闭成功 }
二、重写GCOV的刷新函数
GCOV有个__gcov_flush()函数,默认会触发数据写入文件,我们可以自定义它,主动触发覆盖率数据的输出:
// 要包含GCOV的头文件 #include <gcov.h> void __gcov_flush(void) { // 调用GCOV内部的__gcov_dump(),它会把覆盖率数据写入我们"打开"的虚拟文件 __gcov_dump(); // 如果需要,也可以在这里额外发送一些标识信息 }
三、编译与运行注意事项
- 编译时必须加上GCOV相关参数:
-fprofile-arcs -ftest-coverage,链接时也要带上,同时建议用-O0优化等级,避免编译器把我们重写的函数优化掉 - 确保UART初始化要早于GCOV的任何操作,比如在
main()函数开头先调用MX_USART1_UART_Init() - 触发覆盖率输出:你可以在程序的某个节点调用
__gcov_flush(),比如按键按下时、定时中断里,或者程序结束前 - 上位机处理:用串口助手把接收到的二进制数据(要去掉我们加的结束标记)保存成
.gcda文件,比如和你的main.gcno文件放在一起,然后运行gcov main.c就能生成覆盖率报告了
踩过的坑提醒
- 不要用非阻塞UART发送,调试阶段用阻塞的
HAL_UART_Transmit更稳妥,避免数据丢失 - 重写的函数要确保被编译器链接到,必要时可以给函数加
__attribute__((used))属性,防止被优化掉 - 如果GCOV还是没反应,检查编译参数是否正确,有没有把
-fprofile-arcs -ftest-coverage加到所有需要统计覆盖率的源文件上
内容来源于stack exchange
相关产品推荐
相关产品推荐

