~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/translations/zh_CN/dev-tools/kcov.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /Documentation/translations/zh_CN/dev-tools/kcov.rst (Version linux-6.12-rc7) and /Documentation/translations/zh_CN/dev-tools/kcov.rst (Version linux-6.11.7)


  1 .. SPDX-License-Identifier: GPL-2.0                 1 .. SPDX-License-Identifier: GPL-2.0
  2                                                     2 
  3 .. include:: ../disclaimer-zh_CN.rst                3 .. include:: ../disclaimer-zh_CN.rst
  4                                                     4 
  5 :Original: Documentation/dev-tools/kcov.rst         5 :Original: Documentation/dev-tools/kcov.rst
  6 :Translator: 刘浩阳 Haoyang Liu <tttturtleru      6 :Translator: 刘浩阳 Haoyang Liu <tttturtleruss@hust.edu.cn>
  7                                                     7 
  8 KCOV: 用于模糊测试的代码覆盖率          8 KCOV: 用于模糊测试的代码覆盖率
  9 ==============================                      9 ==============================
 10                                                    10 
 11 KCOV 以一种适用于覆盖率引导的模     11 KCOV 以一种适用于覆盖率引导的模糊测试的形式收集和暴露内核代码覆盖率信息。
 12 一个正在运行的内核的覆盖率数据     12 一个正在运行的内核的覆盖率数据可以通过 ``kcov`` 调试文件导出。覆盖率的收集是基
 13 于任务启用的,因此 KCOV 可以精确     13 于任务启用的,因此 KCOV 可以精确捕获单个系统调用的覆盖率。
 14                                                    14 
 15 要注意的是 KCOV 不是为了收集尽可     15 要注意的是 KCOV 不是为了收集尽可能多的覆盖率数据。而是为了收集相对稳定的覆盖率
 16 ,这是系统调用输入的函数。为了     16 ,这是系统调用输入的函数。为了完成这个目标,它不收集软硬中断的覆盖率(除非移除
 17 覆盖率收集被启用,见下文)以及     17 覆盖率收集被启用,见下文)以及内核中固有的不确定部分的覆盖率(如调度器,锁定)
 18                                                    18 
 19 除了收集代码覆盖率,KCOV 还收集     19 除了收集代码覆盖率,KCOV 还收集操作数比较的覆盖率。见 "操作数比较收集" 一节
 20 查看详细信息。                              20 查看详细信息。
 21                                                    21 
 22 除了从系统调用处理器收集覆盖率     22 除了从系统调用处理器收集覆盖率数据,KCOV 还从后台内核或软中断任务中执行的内核
 23 被标注的部分收集覆盖率。见 "远     23 被标注的部分收集覆盖率。见 "远程覆盖率收集" 一节查看详细信息。
 24                                                    24 
 25 先决条件                                       25 先决条件
 26 --------                                           26 --------
 27                                                    27 
 28 KCOV 依赖编译器插桩,要求 GCC 6.1.0      28 KCOV 依赖编译器插桩,要求 GCC 6.1.0 及更高版本或者内核支持的任意版本的 Clang。
 29                                                    29 
 30 收集操作数比较的覆盖率需要 GCC 8+     30 收集操作数比较的覆盖率需要 GCC 8+ 或者 Clang。
 31                                                    31 
 32 为了启用 KCOV,需要使用如下参数     32 为了启用 KCOV,需要使用如下参数配置内核::
 33                                                    33 
 34         CONFIG_KCOV=y                              34         CONFIG_KCOV=y
 35                                                    35 
 36 为了启用操作数比较覆盖率的收集     36 为了启用操作数比较覆盖率的收集,使用如下参数::
 37                                                    37 
 38     CONFIG_KCOV_ENABLE_COMPARISONS=y               38     CONFIG_KCOV_ENABLE_COMPARISONS=y
 39                                                    39 
 40 覆盖率数据只会在调试文件系统被     40 覆盖率数据只会在调试文件系统被挂载后才可以获取::
 41                                                    41 
 42         mount -t debugfs none /sys/kernel/debu     42         mount -t debugfs none /sys/kernel/debug
 43                                                    43 
 44 覆盖率收集                                    44 覆盖率收集
 45 ----------                                         45 ----------
 46                                                    46 
 47 下面的程序演示了如何使用 KCOV 在     47 下面的程序演示了如何使用 KCOV 在一个测试程序中收集单个系统调用的覆盖率:
 48                                                    48 
 49 .. code-block:: c                                  49 .. code-block:: c
 50                                                    50 
 51     #include <stdio.h>                             51     #include <stdio.h>
 52     #include <stddef.h>                            52     #include <stddef.h>
 53     #include <stdint.h>                            53     #include <stdint.h>
 54     #include <stdlib.h>                            54     #include <stdlib.h>
 55     #include <sys/types.h>                         55     #include <sys/types.h>
 56     #include <sys/stat.h>                          56     #include <sys/stat.h>
 57     #include <sys/ioctl.h>                         57     #include <sys/ioctl.h>
 58     #include <sys/mman.h>                          58     #include <sys/mman.h>
 59     #include <unistd.h>                            59     #include <unistd.h>
 60     #include <fcntl.h>                             60     #include <fcntl.h>
 61     #include <linux/types.h>                       61     #include <linux/types.h>
 62                                                    62 
 63     #define KCOV_INIT_TRACE                        63     #define KCOV_INIT_TRACE                     _IOR('c', 1, unsigned long)
 64     #define KCOV_ENABLE                 _IO('c     64     #define KCOV_ENABLE                 _IO('c', 100)
 65     #define KCOV_DISABLE                           65     #define KCOV_DISABLE                        _IO('c', 101)
 66     #define COVER_SIZE                  (64<<1     66     #define COVER_SIZE                  (64<<10)
 67                                                    67 
 68     #define KCOV_TRACE_PC  0                       68     #define KCOV_TRACE_PC  0
 69     #define KCOV_TRACE_CMP 1                       69     #define KCOV_TRACE_CMP 1
 70                                                    70 
 71     int main(int argc, char **argv)                71     int main(int argc, char **argv)
 72     {                                              72     {
 73         int fd;                                    73         int fd;
 74         unsigned long *cover, n, i;                74         unsigned long *cover, n, i;
 75                                                    75 
 76         /* 单个文件描述符允许             76         /* 单个文件描述符允许
 77          * 在单线程上收集覆盖率。       77          * 在单线程上收集覆盖率。
 78          */                                        78          */
 79         fd = open("/sys/kernel/debug/kcov", O_     79         fd = open("/sys/kernel/debug/kcov", O_RDWR);
 80         if (fd == -1)                              80         if (fd == -1)
 81                 perror("open"), exit(1);           81                 perror("open"), exit(1);
 82         /* 设置跟踪模式和跟踪大小     82         /* 设置跟踪模式和跟踪大小。 */
 83         if (ioctl(fd, KCOV_INIT_TRACE, COVER_S     83         if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
 84                 perror("ioctl"), exit(1);          84                 perror("ioctl"), exit(1);
 85         /* 映射内核空间和用户空间     85         /* 映射内核空间和用户空间共享的缓冲区。 */
 86         cover = (unsigned long*)mmap(NULL, COV     86         cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
 87                                      PROT_READ     87                                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 88         if ((void*)cover == MAP_FAILED)            88         if ((void*)cover == MAP_FAILED)
 89                 perror("mmap"), exit(1);           89                 perror("mmap"), exit(1);
 90         /* 在当前线程中启用覆盖率     90         /* 在当前线程中启用覆盖率收集。 */
 91         if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_     91         if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC))
 92                 perror("ioctl"), exit(1);          92                 perror("ioctl"), exit(1);
 93         /* 在调用 ioctl() 之后重置覆     93         /* 在调用 ioctl() 之后重置覆盖率。 */
 94         __atomic_store_n(&cover[0], 0, __ATOMI     94         __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
 95         /* 调用目标系统调用。 */          95         /* 调用目标系统调用。 */
 96         read(-1, NULL, 0);                         96         read(-1, NULL, 0);
 97         /* 读取收集到的 PC 的数目。      97         /* 读取收集到的 PC 的数目。 */
 98         n = __atomic_load_n(&cover[0], __ATOMI     98         n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
 99         for (i = 0; i < n; i++)                    99         for (i = 0; i < n; i++)
100                 printf("0x%lx\n", cover[i + 1]    100                 printf("0x%lx\n", cover[i + 1]);
101         /* 在当前线程上禁用覆盖率    101         /* 在当前线程上禁用覆盖率收集。在这之后
102          * 可以在其他线程上收集覆    102          * 可以在其他线程上收集覆盖率
103          */                                       103          */
104         if (ioctl(fd, KCOV_DISABLE, 0))           104         if (ioctl(fd, KCOV_DISABLE, 0))
105                 perror("ioctl"), exit(1);         105                 perror("ioctl"), exit(1);
106         /* 释放资源 */                        106         /* 释放资源 */
107         if (munmap(cover, COVER_SIZE * sizeof(    107         if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
108                 perror("munmap"), exit(1);        108                 perror("munmap"), exit(1);
109         if (close(fd))                            109         if (close(fd))
110                 perror("close"), exit(1);         110                 perror("close"), exit(1);
111         return 0;                                 111         return 0;
112     }                                             112     }
113                                                   113 
114 在使用 ``addr2line`` 传输后,程序输    114 在使用 ``addr2line`` 传输后,程序输出应该如下所示::
115                                                   115 
116     SyS_read                                      116     SyS_read
117     fs/read_write.c:562                           117     fs/read_write.c:562
118     __fdget_pos                                   118     __fdget_pos
119     fs/file.c:774                                 119     fs/file.c:774
120     __fget_light                                  120     __fget_light
121     fs/file.c:746                                 121     fs/file.c:746
122     __fget_light                                  122     __fget_light
123     fs/file.c:750                                 123     fs/file.c:750
124     __fget_light                                  124     __fget_light
125     fs/file.c:760                                 125     fs/file.c:760
126     __fdget_pos                                   126     __fdget_pos
127     fs/file.c:784                                 127     fs/file.c:784
128     SyS_read                                      128     SyS_read
129     fs/read_write.c:562                           129     fs/read_write.c:562
130                                                   130 
131 如果一个程序需要从多个线程收集    131 如果一个程序需要从多个线程收集覆盖率(独立地)。那么每个线程都需要单独打开
132 ``/sys/kernel/debug/kcov``。                     132 ``/sys/kernel/debug/kcov``。
133                                                   133 
134 接口的细粒度允许高效的创建测试    134 接口的细粒度允许高效的创建测试进程。即,一个父进程打开了
135 ``/sys/kernel/debug/kcov``,启用了追踪    135 ``/sys/kernel/debug/kcov``,启用了追踪模式,映射了覆盖率缓冲区,然后在一个循
136 环中创建了子进程。这个子进程只    136 环中创建了子进程。这个子进程只需要启用覆盖率收集即可(当一个线程退出时将自动禁
137 用覆盖率收集)。                          137 用覆盖率收集)。
138                                                   138 
139 操作数比较收集                             139 操作数比较收集
140 --------------                                    140 --------------
141                                                   141 
142 操作数比较收集和覆盖率收集类似    142 操作数比较收集和覆盖率收集类似:
143                                                   143 
144 .. code-block:: c                                 144 .. code-block:: c
145                                                   145 
146     /* 包含和上文一样的头文件和宏    146     /* 包含和上文一样的头文件和宏定义。 */
147                                                   147 
148     /* 每次记录的 64 位字的数量。 *    148     /* 每次记录的 64 位字的数量。 */
149     #define KCOV_WORDS_PER_CMP 4                  149     #define KCOV_WORDS_PER_CMP 4
150                                                   150 
151     /*                                            151     /*
152      * 收集的比较种类的格式。          152      * 收集的比较种类的格式。
153      *                                            153      *
154      * 0 比特表示是否是一个编译时    154      * 0 比特表示是否是一个编译时常量。
155      * 1 & 2 比特包含参数大小的 log2     155      * 1 & 2 比特包含参数大小的 log2 值,最大 8 字节。
156      */                                           156      */
157                                                   157 
158     #define KCOV_CMP_CONST          (1 << 0)      158     #define KCOV_CMP_CONST          (1 << 0)
159     #define KCOV_CMP_SIZE(n)        ((n) << 1)    159     #define KCOV_CMP_SIZE(n)        ((n) << 1)
160     #define KCOV_CMP_MASK           KCOV_CMP_S    160     #define KCOV_CMP_MASK           KCOV_CMP_SIZE(3)
161                                                   161 
162     int main(int argc, char **argv)               162     int main(int argc, char **argv)
163     {                                             163     {
164         int fd;                                   164         int fd;
165         uint64_t *cover, type, arg1, arg2, is_    165         uint64_t *cover, type, arg1, arg2, is_const, size;
166         unsigned long n, i;                       166         unsigned long n, i;
167                                                   167 
168         fd = open("/sys/kernel/debug/kcov", O_    168         fd = open("/sys/kernel/debug/kcov", O_RDWR);
169         if (fd == -1)                             169         if (fd == -1)
170                 perror("open"), exit(1);          170                 perror("open"), exit(1);
171         if (ioctl(fd, KCOV_INIT_TRACE, COVER_S    171         if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
172                 perror("ioctl"), exit(1);         172                 perror("ioctl"), exit(1);
173         /*                                        173         /*
174         * 注意缓冲区指针的类型是 ui    174         * 注意缓冲区指针的类型是 uint64_t*,因为所有的
175         * 比较操作数都被提升为 uint6    175         * 比较操作数都被提升为 uint64_t 类型。
176         */                                        176         */
177         cover = (uint64_t *)mmap(NULL, COVER_S    177         cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
178                                      PROT_READ    178                                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
179         if ((void*)cover == MAP_FAILED)           179         if ((void*)cover == MAP_FAILED)
180                 perror("mmap"), exit(1);          180                 perror("mmap"), exit(1);
181         /* 注意这里是 KCOV_TRACE_CMP 而    181         /* 注意这里是 KCOV_TRACE_CMP 而不是 KCOV_TRACE_PC。 */
182         if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_    182         if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP))
183                 perror("ioctl"), exit(1);         183                 perror("ioctl"), exit(1);
184         __atomic_store_n(&cover[0], 0, __ATOMI    184         __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
185         read(-1, NULL, 0);                        185         read(-1, NULL, 0);
186         /* 读取收集到的比较操作数    186         /* 读取收集到的比较操作数的数量。 */
187         n = __atomic_load_n(&cover[0], __ATOMI    187         n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
188         for (i = 0; i < n; i++) {                 188         for (i = 0; i < n; i++) {
189                 uint64_t ip;                      189                 uint64_t ip;
190                                                   190 
191                 type = cover[i * KCOV_WORDS_PE    191                 type = cover[i * KCOV_WORDS_PER_CMP + 1];
192                 /* arg1 和 arg2 - 比较的    192                 /* arg1 和 arg2 - 比较的两个操作数。 */
193                 arg1 = cover[i * KCOV_WORDS_PE    193                 arg1 = cover[i * KCOV_WORDS_PER_CMP + 2];
194                 arg2 = cover[i * KCOV_WORDS_PE    194                 arg2 = cover[i * KCOV_WORDS_PER_CMP + 3];
195                 /* ip - 调用者的地址。     195                 /* ip - 调用者的地址。 */
196                 ip = cover[i * KCOV_WORDS_PER_    196                 ip = cover[i * KCOV_WORDS_PER_CMP + 4];
197                 /* 操作数的大小。 */       197                 /* 操作数的大小。 */
198                 size = 1 << ((type & KCOV_CMP_    198                 size = 1 << ((type & KCOV_CMP_MASK) >> 1);
199                 /* is_const - 当操作数是    199                 /* is_const - 当操作数是一个编译时常量时为真。*/
200                 is_const = type & KCOV_CMP_CON    200                 is_const = type & KCOV_CMP_CONST;
201                 printf("ip: 0x%lx type: 0x%lx,    201                 printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, "
202                         "size: %lu, %s\n",        202                         "size: %lu, %s\n",
203                         ip, type, arg1, arg2,     203                         ip, type, arg1, arg2, size,
204                 is_const ? "const" : "non-cons    204                 is_const ? "const" : "non-const");
205         }                                         205         }
206         if (ioctl(fd, KCOV_DISABLE, 0))           206         if (ioctl(fd, KCOV_DISABLE, 0))
207                 perror("ioctl"), exit(1);         207                 perror("ioctl"), exit(1);
208         /* 释放资源。 */                     208         /* 释放资源。 */
209         if (munmap(cover, COVER_SIZE * sizeof(    209         if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
210                 perror("munmap"), exit(1);        210                 perror("munmap"), exit(1);
211         if (close(fd))                            211         if (close(fd))
212                 perror("close"), exit(1);         212                 perror("close"), exit(1);
213         return 0;                                 213         return 0;
214     }                                             214     }
215                                                   215 
216 注意 KCOV 的模式(代码覆盖率收集    216 注意 KCOV 的模式(代码覆盖率收集或操作数比较收集)是互斥的。
217                                                   217 
218 远程覆盖率收集                             218 远程覆盖率收集
219 --------------                                    219 --------------
220                                                   220 
221 除了从用户空间进程发布的系统调    221 除了从用户空间进程发布的系统调用句柄收集覆盖率数据以外,KCOV 也可以从部分在其
222 他上下文中执行的内核中收集覆盖    222 他上下文中执行的内核中收集覆盖率 - 称为“远程”覆盖率。
223                                                   223 
224 使用 KCOV 收集远程覆盖率要求:        224 使用 KCOV 收集远程覆盖率要求:
225                                                   225 
226 1. 修改内核源码并使用 ``kcov_remote_s    226 1. 修改内核源码并使用 ``kcov_remote_start`` 和 ``kcov_remote_stop`` 来标注要收集
227    覆盖率的代码片段。                    227    覆盖率的代码片段。
228                                                   228 
229 2. 在用户空间的收集覆盖率的进程    229 2. 在用户空间的收集覆盖率的进程应使用 ``KCOV_REMOTE_ENABLE`` 而不是 ``KCOV_ENABLE``。
230                                                   230 
231 ``kcov_remote_start`` 和 ``kcov_remote_stop``    231 ``kcov_remote_start`` 和 ``kcov_remote_stop`` 的标注以及 ``KCOV_REMOTE_ENABLE``
232 ioctl 都接受可以识别特定覆盖率收    232 ioctl 都接受可以识别特定覆盖率收集片段的句柄。句柄的使用方式取决于匹配代码片段执
233 行的上下文。                                233 行的上下文。
234                                                   234 
235 KCOV 支持在如下上下文中收集远程    235 KCOV 支持在如下上下文中收集远程覆盖率:
236                                                   236 
237 1. 全局内核后台任务。这些任务是    237 1. 全局内核后台任务。这些任务是内核启动时创建的数量有限的实例(如,每一个
238    USB HCD 产生一个 USB ``hub_event`` 工    238    USB HCD 产生一个 USB ``hub_event`` 工作器)。
239                                                   239 
240 2. 局部内核后台任务。这些任务通    240 2. 局部内核后台任务。这些任务通常是由于用户空间进程与某些内核接口进行交互时产
241    生的,并且通常在进程退出时会    241    生的,并且通常在进程退出时会被停止(如,vhost 工作器)。
242                                                   242 
243 3. 软中断。                                   243 3. 软中断。
244                                                   244 
245 对于 #1 和 #3,必须选择一个独特的    245 对于 #1 和 #3,必须选择一个独特的全局句柄并将其传递给对应的
246 ``kcov_remote_start`` 调用。一个用户空    246 ``kcov_remote_start`` 调用。一个用户空间进程必须将该句柄存储在
247 ``kcov_remote_arg`` 结构体的 ``handle``     247 ``kcov_remote_arg`` 结构体的 ``handle`` 数组字段中并将其传递给
248 ``KCOV_REMOTE_ENABLE``。这会将使用的 KC    248 ``KCOV_REMOTE_ENABLE``。这会将使用的 KCOV 设备附加到由此句柄引用的代码片段。多个全局
249 句柄标识的不同代码片段可以一次    249 句柄标识的不同代码片段可以一次性传递。
250                                                   250 
251 对于 #2,用户空间进程必须通过 ``k    251 对于 #2,用户空间进程必须通过 ``kcov_remote_arg`` 结构体的 ``common_handle`` 字段
252 传递一个非零句柄。这个通用句柄    252 传递一个非零句柄。这个通用句柄将会被保存在当前 ``task_struct`` 结构体的
253 ``kcov_handle`` 字段中并且需要通过自    253 ``kcov_handle`` 字段中并且需要通过自定义内核代码的修改来传递给新创建的本地任务
254 。这些任务需要在 ``kcov_remote_start``    254 。这些任务需要在 ``kcov_remote_start`` 和 ``kcov_remote_stop`` 标注中依次使用传递过来的
255 句柄。                                         255 句柄。
256                                                   256 
257 KCOV 对全局句柄和通用句柄均遵循    257 KCOV 对全局句柄和通用句柄均遵循一个预定义的格式。每一个句柄都是一个 ``u64`` 整形
258 。当前,只有最高位和低四位字节    258 。当前,只有最高位和低四位字节被使用。第 4-7 字节是保留位并且值必须为 0。
259                                                   259 
260 对于全局句柄,最高位的字节表示    260 对于全局句柄,最高位的字节表示该句柄属于的子系统的标识。比如,KCOV 使用 ``1``
261 表示 USB 子系统类型。全局句柄的    261 表示 USB 子系统类型。全局句柄的低 4 字节表示子系统中任务实例的标识。比如,每一
262 个 ``hub_event`` 工作器使用 USB 总线    262 个 ``hub_event`` 工作器使用 USB 总线号作为任务实例的标识。
263                                                   263 
264 对于通用句柄,使用一个保留值 ``0    264 对于通用句柄,使用一个保留值 ``0`` 作为子系统标识,因为这些句柄不属于一个特定
265 的子系统。通用句柄的低 4 字节用    265 的子系统。通用句柄的低 4 字节用于识别有用户进程生成的所有本地句柄的集合实例,
266 该进程将通用句柄传递给 ``KCOV_REMOT    266 该进程将通用句柄传递给 ``KCOV_REMOTE_ENABLE``。
267                                                   267 
268 实际上,如果只从系统中的单个用    268 实际上,如果只从系统中的单个用户空间进程收集覆盖率,那么可以使用任意值作为通用
269 句柄的实例标识。然而,如果通用    269 句柄的实例标识。然而,如果通用句柄被多个用户空间进程使用,每个进程必须使用唯一
270 的实例标识。一个选择是使用进程    270 的实例标识。一个选择是使用进程标识作为通用句柄实例的标识。
271                                                   271 
272 下面的程序演示了如何使用 KCOV 从    272 下面的程序演示了如何使用 KCOV 从一个由进程产生的本地任务和处理 USB 总线的全局
273 任务 #1 收集覆盖率:                      273 任务 #1 收集覆盖率:
274                                                   274 
275 .. code-block:: c                                 275 .. code-block:: c
276                                                   276 
277     /* 包含和上文一样的头文件和宏    277     /* 包含和上文一样的头文件和宏定义。 */
278                                                   278 
279     struct kcov_remote_arg {                      279     struct kcov_remote_arg {
280         __u32           trace_mode;               280         __u32           trace_mode;
281         __u32           area_size;                281         __u32           area_size;
282         __u32           num_handles;              282         __u32           num_handles;
283         __aligned_u64   common_handle;            283         __aligned_u64   common_handle;
284         __aligned_u64   handles[0];               284         __aligned_u64   handles[0];
285     };                                            285     };
286                                                   286 
287     #define KCOV_INIT_TRACE                       287     #define KCOV_INIT_TRACE                     _IOR('c', 1, unsigned long)
288     #define KCOV_DISABLE                          288     #define KCOV_DISABLE                        _IO('c', 101)
289     #define KCOV_REMOTE_ENABLE          _IOW('    289     #define KCOV_REMOTE_ENABLE          _IOW('c', 102, struct kcov_remote_arg)
290                                                   290 
291     #define COVER_SIZE  (64 << 10)                291     #define COVER_SIZE  (64 << 10)
292                                                   292 
293     #define KCOV_TRACE_PC       0                 293     #define KCOV_TRACE_PC       0
294                                                   294 
295     #define KCOV_SUBSYSTEM_COMMON       (0x00u    295     #define KCOV_SUBSYSTEM_COMMON       (0x00ull << 56)
296     #define KCOV_SUBSYSTEM_USB  (0x01ull << 56    296     #define KCOV_SUBSYSTEM_USB  (0x01ull << 56)
297                                                   297 
298     #define KCOV_SUBSYSTEM_MASK (0xffull << 56    298     #define KCOV_SUBSYSTEM_MASK (0xffull << 56)
299     #define KCOV_INSTANCE_MASK  (0xffffffffull    299     #define KCOV_INSTANCE_MASK  (0xffffffffull)
300                                                   300 
301     static inline __u64 kcov_remote_handle(__u    301     static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst)
302     {                                             302     {
303         if (subsys & ~KCOV_SUBSYSTEM_MASK || i    303         if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK)
304                 return 0;                         304                 return 0;
305         return subsys | inst;                     305         return subsys | inst;
306     }                                             306     }
307                                                   307 
308     #define KCOV_COMMON_ID      0x42              308     #define KCOV_COMMON_ID      0x42
309     #define KCOV_USB_BUS_NUM    1                 309     #define KCOV_USB_BUS_NUM    1
310                                                   310 
311     int main(int argc, char **argv)               311     int main(int argc, char **argv)
312     {                                             312     {
313         int fd;                                   313         int fd;
314         unsigned long *cover, n, i;               314         unsigned long *cover, n, i;
315         struct kcov_remote_arg *arg;              315         struct kcov_remote_arg *arg;
316                                                   316 
317         fd = open("/sys/kernel/debug/kcov", O_    317         fd = open("/sys/kernel/debug/kcov", O_RDWR);
318         if (fd == -1)                             318         if (fd == -1)
319                 perror("open"), exit(1);          319                 perror("open"), exit(1);
320         if (ioctl(fd, KCOV_INIT_TRACE, COVER_S    320         if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE))
321                 perror("ioctl"), exit(1);         321                 perror("ioctl"), exit(1);
322         cover = (unsigned long*)mmap(NULL, COV    322         cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long),
323                                      PROT_READ    323                                      PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
324         if ((void*)cover == MAP_FAILED)           324         if ((void*)cover == MAP_FAILED)
325                 perror("mmap"), exit(1);          325                 perror("mmap"), exit(1);
326                                                   326 
327         /* 通过通用句柄和 USB 总线 #1    327         /* 通过通用句柄和 USB 总线 #1 启用代码覆盖率收集。 */
328         arg = calloc(1, sizeof(*arg) + sizeof(    328         arg = calloc(1, sizeof(*arg) + sizeof(uint64_t));
329         if (!arg)                                 329         if (!arg)
330                 perror("calloc"), exit(1);        330                 perror("calloc"), exit(1);
331         arg->trace_mode = KCOV_TRACE_PC;          331         arg->trace_mode = KCOV_TRACE_PC;
332         arg->area_size = COVER_SIZE;              332         arg->area_size = COVER_SIZE;
333         arg->num_handles = 1;                     333         arg->num_handles = 1;
334         arg->common_handle = kcov_remote_handl    334         arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON,
335                                                   335                                                         KCOV_COMMON_ID);
336         arg->handles[0] = kcov_remote_handle(K    336         arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB,
337                                                   337                                                 KCOV_USB_BUS_NUM);
338         if (ioctl(fd, KCOV_REMOTE_ENABLE, arg)    338         if (ioctl(fd, KCOV_REMOTE_ENABLE, arg))
339                 perror("ioctl"), free(arg), ex    339                 perror("ioctl"), free(arg), exit(1);
340         free(arg);                                340         free(arg);
341                                                   341 
342         /*                                        342         /*
343          * 在这里用户需要触发执行    343          * 在这里用户需要触发执行一个内核代码段
344          * 该代码段要么使用通用句    344          * 该代码段要么使用通用句柄标识
345          * 要么触发了一些 USB 总线 #1    345          * 要么触发了一些 USB 总线 #1 上的一些活动。
346          */                                       346          */
347         sleep(2);                                 347         sleep(2);
348                                                   348 
349         n = __atomic_load_n(&cover[0], __ATOMI    349         n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
350         for (i = 0; i < n; i++)                   350         for (i = 0; i < n; i++)
351                 printf("0x%lx\n", cover[i + 1]    351                 printf("0x%lx\n", cover[i + 1]);
352         if (ioctl(fd, KCOV_DISABLE, 0))           352         if (ioctl(fd, KCOV_DISABLE, 0))
353                 perror("ioctl"), exit(1);         353                 perror("ioctl"), exit(1);
354         if (munmap(cover, COVER_SIZE * sizeof(    354         if (munmap(cover, COVER_SIZE * sizeof(unsigned long)))
355                 perror("munmap"), exit(1);        355                 perror("munmap"), exit(1);
356         if (close(fd))                            356         if (close(fd))
357                 perror("close"), exit(1);         357                 perror("close"), exit(1);
358         return 0;                                 358         return 0;
359     }                                             359     }
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php