执行摘要:我想使用GDB提取存储在嵌入式目标内存中的coverage执行计数,并使用它们创建.gcda
个文件(用于提供给的gcov / LCOV )。
设置:
tar extended-remote localhost:...
连接到正在运行的QEMU GDB服务器,并完全控制我的二进制文件的执行。) 覆盖范围:
现在,为了执行“目标”覆盖分析,我用交叉编译
-fprofile-arcs -ftest-coverage
。然后,GCC发出64位计数器以跟踪特定代码块的执行计数。
在正常(即基于主机,而不是交叉编译)执行时,当应用程序完成__gcov_exit
被调用时 - 并将所有这些执行计数收集到.gcda
文件中(然后gcov用于报告)报道细节)。
然而,在我的嵌入式目标中,没有文件系统可供使用 - 而libgcov基本上包含所有__gcov_...
函数的空存根。
通过QEMU / GDB解决方法:为了解决这个问题,并以GCC版本无关的方式进行解决,我可以通过MYPLATFORM-readelf
在我的二进制文件中列出与覆盖相关的符号,和grep
- 相关的(例如__gcov0.Task1_EntryPoint
,__gcov0.worker
等):
$ MYPLATFORM-readelf -s binary | grep __gcov
...
46: 40021498 48 OBJECT LOCAL DEFAULT 4 __gcov0.Task1_EntryPoint
...
然后我可以使用报告的偏移量/大小来自动创建GDB脚本 - 一个通过简单内存转储(来自偏移,转储长度到本地文件的字节)。
我不知道(并且未能找到任何相关信息/工具),是如何将生成的(内存偏移量,内存数据)对转换为.gcda
个文件。如果存在这样的工具/脚本,我将使用便携式(平台无关)的方式在任何支持QEMU的平台上进行覆盖。
是否有这样的工具/脚本?
任何建议/指示都将非常受欢迎。
更新:我自己解决了这个问题,你可以在下面阅读 - 然后写了blog post about it。
答案 0 :(得分:1)
原来有一种(更好的)方法可以做我想做的事。
Linux内核includes portable GCOV related functionality,通过提供此端点抽象出GCC特定于版本的详细信息:
size_t convert_to_gcda(char *buffer, struct gcov_info *info)
基本上,我能够通过以下步骤进行目标覆盖:
第1步
我在我的项目中添加了三个稍微修改过的linux gcov文件版本:base.c,gcc_4_7.c和gcov.h。我不得不更换其中的一些linux-isms - 比如vmalloc
,kfree
等 - 以使代码可移植(因此,可在我的嵌入式平台上编译,这与Linux无关)。
第2步
然后我提供了自己的__gcov_init
...
typedef struct tagGcovInfo {
struct gcov_info *info;
struct tagGcovInfo *next;
} GcovInfo;
GcovInfo *headGcov = NULL;
void __gcov_init(struct gcov_info *info)
{
printf(
"__gcov_init called for %s!\n",
gcov_info_filename(info));
fflush(stdout);
GcovInfo *newHead = malloc(sizeof(GcovInfo));
if (!newHead) {
puts("Out of memory!");
exit(1);
}
newHead->info = info;
newHead->next = headGcov;
headGcov = newHead;
}
...和__gcov_exit
:
void __gcov_exit()
{
GcovInfo *tmp = headGcov;
while(tmp) {
char *buffer;
int bytesNeeded = convert_to_gcda(NULL, tmp->info);
buffer = malloc(bytesNeeded);
if (!buffer) {
puts("Out of memory!");
exit(1);
}
convert_to_gcda(buffer, tmp->info);
printf("Emitting %6d bytes for %s\n", bytesNeeded, gcov_info_filename(tmp->info));
free(buffer);
tmp = tmp->next;
}
}
第3步
最后,我通过以下方式编写了我的GDB(远程驱动QEMU)脚本:
$ cat coverage.gdb
tar extended-remote :9976
file bin.debug/fputest
b base.c:88 <================= This breaks on the "Emitting" printf in __gcov_exit
commands 1
silent
set $filename = tmp->info->filename
set $dataBegin = buffer
set $dataEnd = buffer + bytesNeeded
eval "dump binary memory %s 0x%lx 0x%lx", $filename, $dataBegin, $dataEnd
c
end
c
quit
最后,执行了QEMU和GDB - 就像这样:
$ # In terminal 1:
qemu-system-MYPLATFORM ... -kernel bin.debug/fputest -gdb tcp::9976 -S
$ # In terminal 2:
MYPLATFORM-gdb -x coverage.gdb
......那就是它 - 我能够在我的本地文件系统中生成.gcda文件,然后在gcov
和lcov
上查看覆盖率结果。