gcov_lcov

一、报错lcov和gcov的使用错误

编译使用的gcc版本和gcov的版本对不上的话,使用lcov和gcov的时候会报错

lcov的错误:
[xx@localhost XXX]$ lcov --capture --directory cov --output-file xxx.info --test-name xxx
Capturing coverage data from cov
Found gcov version: 4.8.5
Scanning cov for .gcda files ...
Found 35 data files in cov
Processing XXX.gcda
geninfo: ERROR: XXX.gcno: reached unexpected end of file

gcov的错误:
[xxx@localhost xxx]$ gcov -o cov ./xxx.c
cov/xxx.gcno:版本‘405 ’,首选‘408R’

gcov: out of memory allocating 16030351984 bytes after a total of 135168 bytes

确保gcc和gcov版本一样即可

按照上面说的方法实践,果然搞定

查看了一下:
  gcc -v : 4.4.7
  g++ -v  : 4.4.7
   gcov -v :4.4.7
    lcov -v :1.10

然后将lcov 版本升级到 1.12,问题搞定

通用代码的覆盖率问题

1、问题描述

公共代码在项目A中被覆盖 30,在项目 B 中覆盖另外 70,怎样才能统计出 100% 的覆盖效果?

2、实验代码

[zhoujinhua@ecs-b0b7 tmp]$ cat common.c
#include <stdio.h>

int myAdd(int a, int b)
{
    return a+b;
}
int mySub(int a, int b)
{
    return a - b;
}

[zhoujinhua@ecs-b0b7 tmp]$ cat good.c
    #include <stdio.h>
    #include <execinfo.h>
    #include <stdlib.h>

    extern int myAdd(int a, int b);
    void print_call_stack()
    {
        int    i          = 0;
        int    size       =32;
        void  *array[32];
        int    stack_num  = backtrace(array, size);
        char **stacktrace = (char**)backtrace_symbols(array, stack_num);
        for (i=0; i<stack_num; i++)
        {
            printf("func_%d addr:%s\n", i, stacktrace[i]);
        }
        free(stacktrace);
        return;
    }
    void func_1(){print_call_stack();}
    void func_2(){func_1();}
    void func_3(){func_2();}
    void func_4(){func_3();}
    void func_5(){func_4();}
    void func_6(){func_5();}
    int main(int argc, char **argv)
    {
        myAdd(3,4);
        printf("argc = %d\n", argc);
        if (argc < 2)
        {
            printf("please use at least one parameter!\n");
            return 1;
        }
        func_6();
        return 0;
    }
[zhoujinhua@ecs-b0b7 tmp]$ cat better.c
#include <stdio.h>
extern int mySub(int a,int b);
int main()
{
    return mySub(9, 2);
}
[zhoujinhua@ecs-b0b7 tmp]$

3、实验操作步骤

1、编译第一个项目
gcc -g3 -fprofile-arcs -ftest-coverage good.c common.c -o dir1/good
2、运行第一个项目,产生覆盖率数据
  ./dir1/good
3、将中间文件放入第一个目录
  mv *.gcda ./dir1/
  mv *.gcna ./dir1/
  mv *.gcov ./dir1/
4、编译第二个项目,同样的操作步骤
  gcc -g3 -fprofile-arcs -ftest-coverage better.c common.c -o dir2/better
5、当前目录下的所有覆盖文件进行统计
  lcov -d ./ -c -o ./prj_dir/my_prj.info -t 'prj_title' -b ./
  说明:-d ./ 表示当前目录下的所有
6、最终生成漂亮的覆盖率网页
  genhtml -o prj_dir/ prj_dir/my_prj.info
7、网页查看,不用浏览器,直接在 linux 命令行就能查看,TAB切换、跳转
   yum -y install w3m w3m-image
   w3m ./prj_dir/index.html

在某些大型项目中,无法随意修改编译、链接参数,怎样实现stacktrace

当编译、链接参数无法正确✔️配置时,尽管如下函数可以运行,但是结果缺不是预想那样
void print_call_stack()
{
    int    i          = 0;
    int    size       =32;
    void  *array[32];
    int    stack_num  = backtrace(array, size);
    char **stacktrace = (char**)backtrace_symbols(array, stack_num);
    for (i=0; i<stack_num; i++)
    {
        printf("func_%d addr:%s\n", i, stacktrace[i]);
    }
    free(stacktrace);
    return;
}

stacktrace[i] 并没有被转换成函数名,仍然是栈中十六进制数的样子。

此时只能自己实现转换。
通过观察发现,array[1],就是上一层函数中的某个地址,一般是函数名离开偏移地址。
如果上层函数是func,责array[1]的值是 func + offset.
可以通过简单的条件判断:
if ((array[1]>func) && ((array[1]-func)<1024)) //限定偏移范围,可以调整
{
    return true;
}

但是实际编译是,编译器会报错,提示void*类型不能和函数类型进行减法操作。
需要做一次转换,将两个值都转化为word32:

typedef word32 unsinged int
typedef void (*entryFuncType)()
typedef struct
{
    eFuncIdx      idx;
    entryFuncType func;
}funcMapType;
funcMapType map[]=
{
    {eIdx_1,  func_1},
    {eIdx_2,  func_2},
};
BOOL isInFunction(void *stackPos, entryFuncType func)
{
    bool ret = false;
    int  offset=0;
    char buf_1[32] = {0};
    char buf_2[32] = {0};
    word32 stackPosVal=0;
    word32 funcVal=0;
    sprintf(buf_1, "0x%x",stackPos);
    sprintf(buf_2, "0x%x",func);
    sscanf(buf_1, "%x", &stackPosVal);
    sscanf(buf_2, "%x", &funcVal);
    offset=stackPosVal - funcVal;
    if ((0<offset) && (offset<1024))
    {
        ret = true;
    }
    return ret;
}

void print_call_stack()
{
    int    i          = 0;
    int    size       =32;
    void  *array[32];
    int    stack_num  = backtrace(array, size);
    char **stacktrace = (char**)backtrace_symbols(array, stack_num);

    //这个简单的判断,可以替换成一个循环
    if(isInFunction(array[1], myFunction))
    {
        //do something....
    }


    free(stacktrace);
    return;
}

《“gcov_lcov”》 有 1 条评论

  1. The following time I learn a blog, I hope that it doesnt disappoint me as a lot as this one. I imply, I know it was my choice to learn, however I really thought youd have something attention-grabbing to say. All I hear is a bunch of whining about something that you may fix if you happen to werent too busy in search of attention. Billie Hoffstatter

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注