gpt4 book ai didi

embedded - 通过 QEMU/GDB 生成 .gcda 覆盖文件

转载 作者:行者123 更新时间:2023-12-04 00:56:43 25 4
gpt4 key购买 nike

执行摘要:我想使用 GDB 来提取存储在我的嵌入式目标内存中的覆盖执行计数,并使用它们来创建 .gcda文件(用于输入 gcov/lcov)。

设置 :

  • 我可以成功地交叉编译我的二进制文件,以我的特定嵌入式目标为目标——然后在 QEMU 下执行它。
  • 我还可以使用 QEMU 的 GDB 支持来调试二进制文件(即使用 tar extended-remote localhost:... 附加到正在运行的 QEMU GDB 服务器,并完全控制我的二进制文件的执行)。

  • 覆盖范围:
    现在,为了执行“目标”覆盖率分析,我使用交叉编译 -fprofile-arcs -ftest-coverage .然后 GCC 发出 64 位计数器来跟踪特定代码块的执行计数。

    在正常(即基于主机,未交叉编译)执行下,当应用程序完成时 __gcov_exit被调用 - 并将所有这些执行计数收集到 .gcda文件(然后 gcov 用来报告覆盖率详细信息)。

    然而,在我的嵌入式目标中,没有文件系统可言——而且 libgcov 基本上包含所有 __gcov_... 的空 stub 。职能。

    通过 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 .

    最佳答案

    原来有一种(很多)更好的方法来做我想做的事。

    Linux 内核 includes portable GCOV related functionality ,通过提供此端点抽象出特定于 GCC 版本的详细信息:

    size_t convert_to_gcda(char *buffer, struct gcov_info *info)

    所以基本上,我可以通过以下步骤进行目标覆盖:

    第一步

    我在我的项目中添加了三个稍微修改过的 linux gcov 文件版本: base.c , gcc_4_7.cgcov.h .我不得不替换其中的一些 linux-isms - 比如 vmalloc , kfree等 - 使代码可移植(因此,可以在我的嵌入式平台上编译,这与 Linux 无关)。

    第二步

    然后我提供了我自己的 __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;
    }
    }

    第三步

    最后,我通过以下脚本编写了我的 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 .

    更新 : 我写了 blog post showing the process in detail .

    关于embedded - 通过 QEMU/GDB 生成 .gcda 覆盖文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36839354/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com