Linux kcov工具

阅读数:74 评论数:0

跳转到新版页面

分类

Linux

正文

代码覆盖率(Code Coverage)是反映测试用例对被测软件覆盖程序的重要指标,kcov是用于随机测试中合适表达代码覆盖率的一种工具。

前置需求

内核需要配置

CONFIG_KCOV=y

CONFIG_KCOV需要231296以上版本的gcc,如果需要收集比较操作

CONFIG_KCOV_ENABLE_COMPARISONS=y

只有挂载了debugfs,才可以访问配置数据。

使用方法

 

  1.  
    #include <stdio.h>
  2.  
    #include <stddef.h>
  3.  
    #include <stdint.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <sys/types.h>
  6.  
    #include <sys/stat.h>
  7.  
    #include <sys/ioctl.h>
  8.  
    #include <sys/mman.h>
  9.  
    #include <unistd.h>
  10.  
    #include <fcntl.h>
  11.  
     
  12.  
    #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long)
  13.  
    #define KCOV_ENABLE _IO('c', 100)
  14.  
    #define KCOV_DISABLE _IO('c', 101)
  15.  
    #define COVER_SIZE (64<<10)
  16.  
     
  17.  
    #define KCOV_TRACE_PC 0
  18.  
    #define KCOV_TRACE_CMP 1
  19.  
     
  20.  
    int main(int argc, char **argv)
  21.  
    {
  22.  
    int fd;
  23.  
    unsigned long *cover, n, i;
  24.  
     
  25.  
    /* A single fd descriptor allows coverage collection on a single
  26.  
    * thread.
  27.  
    */
  28.  
    fd = open("/sys/kernel/debug/kcov", O_RDWR);
  29.  
    if (fd == -1)
  30.  
    perror("open"), exit(1);
  31.  
    /* Setup trace mode and trace size. */
  32.  
    if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
  33.  
    perror("ioctl"), exit(1);
  34.  
    /* Mmap buffer shared between kernel- and user-space. */
  35.  
    cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
  36.  
    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  37.  
    if ((void*)cover == MAP_FAILED)
  38.  
    perror("mmap"), exit(1);
  39.  
    /* Enable coverage collection on the current thread. */
  40.  
    if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC))
  41.  
    perror("ioctl"), exit(1);
  42.  
    /* Reset coverage from the tail of the ioctl() call. */
  43.  
    __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
  44.  
    /* That's the target syscal call. */
  45.  
    read(-1, NULL, 0);
  46.  
    /* Read number of PCs collected. */
  47.  
    n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
  48.  
    for (i = 0; i < n; i++)
  49.  
    printf("0x%lx\n", cover[i + 1]);
  50.  
    /* Disable coverage collection for the current thread. After this call
  51.  
    * coverage can be enabled for a different thread.
  52.  
    */
  53.  
    if (ioctl(fd, KCOV_DISABLE, 0))
  54.  
    perror("ioctl"), exit(1);
  55.  
    /* Free resources. */
  56.  
    if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
  57.  
    perror("munmap"), exit(1);
  58.  
    if (close(fd))
  59.  
    perror("close"), exit(1);
  60.  
    return 0;
  61.  
    }

输出信息

  1.  
    SyS_read
  2.  
    fs/read_write.c:562
  3.  
    __fdget_pos
  4.  
    fs/file.c:774
  5.  
    __fget_light
  6.  
    fs/file.c:746
  7.  
    __fget_light
  8.  
    fs/file.c:750
  9.  
    __fget_light
  10.  
    fs/file.c:760
  11.  
    __fdget_pos
  12.  
    fs/file.c:784
  13.  
    SyS_read
  14.  
    fs/read_write.c:562

 

  1.  
    /* Same includes and defines as above. */
  2.  
     
  3.  
    /* Number of 64-bit words per record. */
  4.  
    #define KCOV_WORDS_PER_CMP 4
  5.  
     
  6.  
    /*
  7.  
    * The format for the types of collected comparisons.
  8.  
    *
  9.  
    * Bit 0 shows whether one of the arguments is a compile-time constant.
  10.  
    * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes.
  11.  
    */
  12.  
     
  13.  
    #define KCOV_CMP_CONST (1 << 0)
  14.  
    #define KCOV_CMP_SIZE(n) ((n) << 1)
  15.  
    #define KCOV_CMP_MASK KCOV_CMP_SIZE(3)
  16.  
     
  17.  
    int main(int argc, char **argv)
  18.  
    {
  19.  
    int fd;
  20.  
    uint64_t *cover, type, arg1, arg2, is_const, size;
  21.  
    unsigned long n, i;
  22.  
     
  23.  
    fd = open("/sys/kernel/debug/kcov", O_RDWR);
  24.  
    if (fd == -1)
  25.  
    perror("open"), exit(1);
  26.  
    if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
  27.  
    perror("ioctl"), exit(1);
  28.  
    /*
  29.  
    * Note that the buffer pointer is of type uint64_t*, because all
  30.  
    * the comparison operands are promoted to uint64_t.
  31.  
    */
  32.  
    cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
  33.  
    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  34.  
    if ((void*)cover == MAP_FAILED)
  35.  
    perror("mmap"), exit(1);
  36.  
    /* Note KCOV_TRACE_CMP instead of KCOV_TRACE_PC. */
  37.  
    if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP))
  38.  
    perror("ioctl"), exit(1);
  39.  
    __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
  40.  
    read(-1, NULL, 0);
  41.  
    /* Read number of comparisons collected. */
  42.  
    n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
  43.  
    for (i = 0; i < n; i++) {
  44.  
    type = cover[i * KCOV_WORDS_PER_CMP + 1];
  45.  
    /* arg1 and arg2 - operands of the comparison. */
  46.  
    arg1 = cover[i * KCOV_WORDS_PER_CMP + 2];
  47.  
    arg2 = cover[i * KCOV_WORDS_PER_CMP + 3];
  48.  
    /* ip - caller address. */
  49.  
    ip = cover[i * KCOV_WORDS_PER_CMP + 4];
  50.  
    /* size of the operands. */
  51.  
    size = 1 << ((type & KCOV_CMP_MASK) >> 1);
  52.  
    /* is_const - true if either operand is a compile-time constant.*/
  53.  
    is_const = type & KCOV_CMP_CONST;
  54.  
    printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, "
  55.  
    "size: %lu, %s\n",
  56.  
    ip, type, arg1, arg2, size,
  57.  
    is_const ? "const" : "non-const");
  58.  
    }
  59.  
    if (ioctl(fd, KCOV_DISABLE, 0))
  60.  
    perror("ioctl"), exit(1);
  61.  
    /* Free resources. */
  62.  
    if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
  63.  
    perror("munmap"), exit(1);
  64.  
    if (close(fd))
  65.  
    perror("close"), exit(1);
  66.  
    return 0;
  67.  
    }