xref: /llvm-project/clang/docs/SanitizerCoverage.rst (revision 7800d59f5bd03e38db0bbe94db5f8a3e0ec1a9a6)
1=================
2SanitizerCoverage
3=================
4
5.. contents::
6   :local:
7
8Introduction
9============
10
11LLVM has a simple code coverage instrumentation built in (SanitizerCoverage).
12It inserts calls to user-defined functions on function-, basic-block-, and edge- levels.
13Default implementations of those callbacks are provided and implement
14simple coverage reporting and visualization,
15however if you need *just* coverage visualization you may want to use
16:doc:`SourceBasedCodeCoverage <SourceBasedCodeCoverage>` instead.
17
18Tracing PCs with guards
19=======================
20
21With ``-fsanitize-coverage=trace-pc-guard`` the compiler will insert the following code
22on every edge:
23
24.. code-block:: none
25
26   __sanitizer_cov_trace_pc_guard(&guard_variable)
27
28Every edge will have its own `guard_variable` (uint32_t).
29
30The compiler will also insert calls to a module constructor:
31
32.. code-block:: c++
33
34   // The guards are [start, stop).
35   // This function will be called at least once per DSO and may be called
36   // more than once with the same values of start/stop.
37   __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
38
39With an additional ``...=trace-pc,indirect-calls`` flag
40``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
41
42The functions `__sanitizer_cov_trace_pc_*` should be defined by the user.
43
44Example:
45
46.. code-block:: c++
47
48  // trace-pc-guard-cb.cc
49  #include <stdint.h>
50  #include <stdio.h>
51  #include <sanitizer/coverage_interface.h>
52
53  // This callback is inserted by the compiler as a module constructor
54  // into every DSO. 'start' and 'stop' correspond to the
55  // beginning and end of the section with the guards for the entire
56  // binary (executable or DSO). The callback will be called at least
57  // once per DSO and may be called multiple times with the same parameters.
58  extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
59                                                      uint32_t *stop) {
60    static uint64_t N;  // Counter for the guards.
61    if (start == stop || *start) return;  // Initialize only once.
62    printf("INIT: %p %p\n", start, stop);
63    for (uint32_t *x = start; x < stop; x++)
64      *x = ++N;  // Guards should start from 1.
65  }
66
67  // This callback is inserted by the compiler on every edge in the
68  // control flow (some optimizations apply).
69  // Typically, the compiler will emit the code like this:
70  //    if(*guard)
71  //      __sanitizer_cov_trace_pc_guard(guard);
72  // But for large functions it will emit a simple call:
73  //    __sanitizer_cov_trace_pc_guard(guard);
74  extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
75    if (!*guard) return;  // Duplicate the guard check.
76    // If you set *guard to 0 this code will not be called again for this edge.
77    // Now you can get the PC and do whatever you want:
78    //   store it somewhere or symbolize it and print right away.
79    // The values of `*guard` are as you set them in
80    // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive
81    // and use them to dereference an array or a bit vector.
82    void *PC = __builtin_return_address(0);
83    char PcDescr[1024];
84    // This function is a part of the sanitizer run-time.
85    // To use it, link with AddressSanitizer or other sanitizer.
86    __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
87    printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);
88  }
89
90.. code-block:: c++
91
92  // trace-pc-guard-example.cc
93  void foo() { }
94  int main(int argc, char **argv) {
95    if (argc > 1) foo();
96  }
97
98.. code-block:: console
99
100  clang++ -g  -fsanitize-coverage=trace-pc-guard trace-pc-guard-example.cc -c
101  clang++ trace-pc-guard-cb.cc trace-pc-guard-example.o -fsanitize=address
102  ASAN_OPTIONS=strip_path_prefix=`pwd`/ ./a.out
103
104.. code-block:: console
105
106  INIT: 0x71bcd0 0x71bce0
107  guard: 0x71bcd4 2 PC 0x4ecd5b in main trace-pc-guard-example.cc:2
108  guard: 0x71bcd8 3 PC 0x4ecd9e in main trace-pc-guard-example.cc:3:7
109
110.. code-block:: console
111
112  ASAN_OPTIONS=strip_path_prefix=`pwd`/ ./a.out with-foo
113
114
115.. code-block:: console
116
117  INIT: 0x71bcd0 0x71bce0
118  guard: 0x71bcd4 2 PC 0x4ecd5b in main trace-pc-guard-example.cc:3
119  guard: 0x71bcdc 4 PC 0x4ecdc7 in main trace-pc-guard-example.cc:4:17
120  guard: 0x71bcd0 1 PC 0x4ecd20 in foo() trace-pc-guard-example.cc:2:14
121
122Inline 8bit-counters
123====================
124
125**Experimental, may change or disappear in future**
126
127With ``-fsanitize-coverage=inline-8bit-counters`` the compiler will insert
128inline counter increments on every edge.
129This is similar to ``-fsanitize-coverage=trace-pc-guard`` but instead of a
130callback the instrumentation simply increments a counter.
131
132Users need to implement a single function to capture the counters at startup.
133
134.. code-block:: c++
135
136  extern "C"
137  void __sanitizer_cov_8bit_counters_init(char *start, char *end) {
138    // [start,end) is the array of 8-bit counters created for the current DSO.
139    // Capture this array in order to read/modify the counters.
140  }
141
142
143Inline bool-flag
144================
145
146**Experimental, may change or disappear in future**
147
148With ``-fsanitize-coverage=inline-bool-flag`` the compiler will insert
149setting an inline boolean to true on every edge.
150This is similar to ``-fsanitize-coverage=inline-8bit-counter`` but instead of
151an increment of a counter, it just sets a boolean to true.
152
153Users need to implement a single function to capture the flags at startup.
154
155.. code-block:: c++
156
157  extern "C"
158  void __sanitizer_cov_bool_flag_init(bool *start, bool *end) {
159    // [start,end) is the array of boolean flags created for the current DSO.
160    // Capture this array in order to read/modify the flags.
161  }
162
163
164PC-Table
165========
166
167**Experimental, may change or disappear in future**
168
169**Note:** this instrumentation might be incompatible with dead code stripping
170(``-Wl,-gc-sections``) for linkers other than LLD, thus resulting in a
171significant binary size overhead. For more information, see
172`Bug 34636 <https://bugs.llvm.org/show_bug.cgi?id=34636>`_.
173
174With ``-fsanitize-coverage=pc-table`` the compiler will create a table of
175instrumented PCs. Requires either ``-fsanitize-coverage=inline-8bit-counters``,
176or ``-fsanitize-coverage=inline-bool-flag``, or ``-fsanitize-coverage=trace-pc-guard``.
177
178Users need to implement a single function to capture the PC table at startup:
179
180.. code-block:: c++
181
182  extern "C"
183  void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg,
184                                const uintptr_t *pcs_end) {
185    // [pcs_beg,pcs_end) is the array of ptr-sized integers representing
186    // pairs [PC,PCFlags] for every instrumented block in the current DSO.
187    // Capture this array in order to read the PCs and their Flags.
188    // The number of PCs and PCFlags for a given DSO is the same as the number
189    // of 8-bit counters (-fsanitize-coverage=inline-8bit-counters), or
190    // boolean flags (-fsanitize-coverage=inline=bool-flags), or trace_pc_guard
191    // callbacks (-fsanitize-coverage=trace-pc-guard).
192    // A PCFlags describes the basic block:
193    //  * bit0: 1 if the block is the function entry block, 0 otherwise.
194  }
195
196
197Tracing PCs
198===========
199
200With ``-fsanitize-coverage=trace-pc`` the compiler will insert
201``__sanitizer_cov_trace_pc()`` on every edge.
202With an additional ``...=trace-pc,indirect-calls`` flag
203``__sanitizer_cov_trace_pc_indirect(void *callee)`` will be inserted on every indirect call.
204These callbacks are not implemented in the Sanitizer run-time and should be defined
205by the user.
206This mechanism is used for fuzzing the Linux kernel
207(https://github.com/google/syzkaller).
208
209Instrumentation points
210======================
211Sanitizer Coverage offers different levels of instrumentation.
212
213* ``edge`` (default): edges are instrumented (see below).
214* ``bb``: basic blocks are instrumented.
215* ``func``: only the entry block of every function will be instrumented.
216
217Use these flags together with ``trace-pc-guard`` or ``trace-pc``,
218like this: ``-fsanitize-coverage=func,trace-pc-guard``.
219
220When ``edge`` or ``bb`` is used, some of the edges/blocks may still be left
221uninstrumented (pruned) if such instrumentation is considered redundant.
222Use ``no-prune`` (e.g. ``-fsanitize-coverage=bb,no-prune,trace-pc-guard``)
223to disable pruning. This could be useful for better coverage visualization.
224
225
226Edge coverage
227-------------
228
229Consider this code:
230
231.. code-block:: c++
232
233    void foo(int *a) {
234      if (a)
235        *a = 0;
236    }
237
238It contains 3 basic blocks, let's name them A, B, C:
239
240.. code-block:: none
241
242    A
243    |\
244    | \
245    |  B
246    | /
247    |/
248    C
249
250If blocks A, B, and C are all covered we know for certain that the edges A=>B
251and B=>C were executed, but we still don't know if the edge A=>C was executed.
252Such edges of control flow graph are called
253`critical <https://en.wikipedia.org/wiki/Control_flow_graph#Special_edges>`_.
254The edge-level coverage simply splits all critical edges by introducing new
255dummy blocks and then instruments those blocks:
256
257.. code-block:: none
258
259    A
260    |\
261    | \
262    D  B
263    | /
264    |/
265    C
266
267Tracing data flow
268=================
269
270Support for data-flow-guided fuzzing.
271With ``-fsanitize-coverage=trace-cmp`` the compiler will insert extra instrumentation
272around comparison instructions and switch statements.
273Similarly, with ``-fsanitize-coverage=trace-div`` the compiler will instrument
274integer division instructions (to capture the right argument of division)
275and with  ``-fsanitize-coverage=trace-gep`` --
276the `LLVM GEP instructions <https://llvm.org/docs/GetElementPtr.html>`_
277(to capture array indices).
278Similarly, with ``-fsanitize-coverage=trace-loads`` and ``-fsanitize-coverage=trace-stores``
279the compiler will instrument loads and stores, respectively.
280
281Currently, these flags do not work by themselves - they require one
282of ``-fsanitize-coverage={trace-pc,inline-8bit-counters,inline-bool}``
283flags to work.
284
285Unless ``no-prune`` option is provided, some of the comparison instructions
286will not be instrumented.
287
288.. code-block:: c++
289
290  // Called before a comparison instruction.
291  // Arg1 and Arg2 are arguments of the comparison.
292  void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2);
293  void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2);
294  void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2);
295  void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2);
296
297  // Called before a comparison instruction if exactly one of the arguments is constant.
298  // Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant.
299  // These callbacks are emitted by -fsanitize-coverage=trace-cmp since 2017-08-11
300  void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2);
301  void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2);
302  void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2);
303  void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2);
304
305  // Called before a switch statement.
306  // Val is the switch operand.
307  // Cases[0] is the number of case constants.
308  // Cases[1] is the size of Val in bits.
309  // Cases[2:] are the case constants.
310  void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases);
311
312  // Called before a division statement.
313  // Val is the second argument of division.
314  void __sanitizer_cov_trace_div4(uint32_t Val);
315  void __sanitizer_cov_trace_div8(uint64_t Val);
316
317  // Called before a GetElemementPtr (GEP) instruction
318  // for every non-constant array index.
319  void __sanitizer_cov_trace_gep(uintptr_t Idx);
320
321  // Called before a load of appropriate size. Addr is the address of the load.
322  void __sanitizer_cov_load1(uint8_t *addr);
323  void __sanitizer_cov_load2(uint16_t *addr);
324  void __sanitizer_cov_load4(uint32_t *addr);
325  void __sanitizer_cov_load8(uint64_t *addr);
326  void __sanitizer_cov_load16(__int128 *addr);
327  // Called before a store of appropriate size. Addr is the address of the store.
328  void __sanitizer_cov_store1(uint8_t *addr);
329  void __sanitizer_cov_store2(uint16_t *addr);
330  void __sanitizer_cov_store4(uint32_t *addr);
331  void __sanitizer_cov_store8(uint64_t *addr);
332  void __sanitizer_cov_store16(__int128 *addr);
333
334
335Tracing control flow
336====================
337
338With ``-fsanitize-coverage=control-flow`` the compiler will create a table to collect
339control flow for each function. More specifically, for each basic block in the function,
340two lists are populated. One list for successors of the basic block and another list for
341non-intrinsic called functions.
342
343**TODO:** in the current implementation, indirect calls are not tracked
344and are only marked with special value (-1) in the list.
345
346Each table row consists of the basic block address
347followed by ``null``-ended lists of successors and callees.
348The table is encoded in a special section named ``sancov_cfs``
349
350Example:
351
352.. code-block:: c++
353
354  int foo (int x) {
355    if (x > 0)
356      bar(x);
357    else
358      x = 0;
359    return x;
360  }
361
362The code above contains 4 basic blocks, let's name them A, B, C, D:
363
364.. code-block:: none
365
366    A
367    |\
368    | \
369    B  C
370    | /
371    |/
372    D
373
374The collected control flow table is as follows:
375``A, B, C, null, null, B, D, null, @bar, null, C, D, null, null, D, null, null.``
376
377Users need to implement a single function to capture the CF table at startup:
378
379.. code-block:: c++
380
381  extern "C"
382  void __sanitizer_cov_cfs_init(const uintptr_t *cfs_beg,
383                                const uintptr_t *cfs_end) {
384    // [cfs_beg,cfs_end) is the array of ptr-sized integers representing
385    // the collected control flow.
386  }
387
388Gated Trace Callbacks
389=====================
390
391Gate the invocation of the tracing callbacks with
392``-sanitizer-coverage-gated-trace-callbacks``.
393
394When this option is enabled, the instrumentation will not call into the
395runtime-provided callbacks for tracing, thus only incurring in a trivial
396branch without going through a function call.
397
398It is up to the runtime to toggle the value of the global variable in order to
399enable tracing.
400
401This option is only supported for trace-pc-guard and trace-cmp.
402
403Disabling instrumentation with ``__attribute__((no_sanitize("coverage")))``
404===========================================================================
405
406It is possible to disable coverage instrumentation for select functions via the
407function attribute ``__attribute__((no_sanitize("coverage")))``. Because this
408attribute may not be supported by other compilers, it is recommended to use it
409together with ``__has_feature(coverage_sanitizer)``.
410
411Disabling instrumentation without source modification
412=====================================================
413
414It is sometimes useful to tell SanitizerCoverage to instrument only a subset of the
415functions in your target without modifying source files.
416With ``-fsanitize-coverage-allowlist=allowlist.txt``
417and ``-fsanitize-coverage-ignorelist=blocklist.txt``,
418you can specify such a subset through the combination of an allowlist and a blocklist.
419
420SanitizerCoverage will only instrument functions that satisfy two conditions.
421First, the function should belong to a source file with a path that is both allowlisted
422and not blocklisted.
423Second, the function should have a mangled name that is both allowlisted and not blocklisted.
424
425The allowlist and blocklist format is similar to that of the sanitizer blocklist format.
426The default allowlist will match every source file and every function.
427The default blocklist will match no source file and no function.
428
429A common use case is to have the allowlist list folders or source files for which you want
430instrumentation and allow all function names, while the blocklist will opt out some specific
431files or functions that the allowlist loosely allowed.
432
433Here is an example allowlist:
434
435.. code-block:: none
436
437  # Enable instrumentation for a whole folder
438  src:bar/*
439  # Enable instrumentation for a specific source file
440  src:foo/a.cpp
441  # Enable instrumentation for all functions in those files
442  fun:*
443
444And an example blocklist:
445
446.. code-block:: none
447
448  # Disable instrumentation for a specific source file that the allowlist allowed
449  src:bar/b.cpp
450  # Disable instrumentation for a specific function that the allowlist allowed
451  fun:*myFunc*
452
453The use of ``*`` wildcards above is required because function names are matched after mangling.
454Without the wildcards, one would have to write the whole mangled name.
455
456Be careful that the paths of source files are matched exactly as they are provided on the clang
457command line.
458For example, the allowlist above would include file ``bar/b.cpp`` if the path was provided
459exactly like this, but would it would fail to include it with other ways to refer to the same
460file such as ``./bar/b.cpp``, or ``bar\b.cpp`` on Windows.
461So, please make sure to always double check that your lists are correctly applied.
462
463Default implementation
464======================
465
466The sanitizer run-time (AddressSanitizer, MemorySanitizer, etc) provide a
467default implementations of some of the coverage callbacks.
468You may use this implementation to dump the coverage on disk at the process
469exit.
470
471Example:
472
473.. code-block:: console
474
475    % cat -n cov.cc
476         1  #include <stdio.h>
477         2  __attribute__((noinline))
478         3  void foo() { printf("foo\n"); }
479         4
480         5  int main(int argc, char **argv) {
481         6    if (argc == 2)
482         7      foo();
483         8    printf("main\n");
484         9  }
485    % clang++ -g cov.cc -fsanitize=address -fsanitize-coverage=trace-pc-guard
486    % ASAN_OPTIONS=coverage=1 ./a.out; wc -c *.sancov
487    main
488    SanitizerCoverage: ./a.out.7312.sancov 2 PCs written
489    24 a.out.7312.sancov
490    % ASAN_OPTIONS=coverage=1 ./a.out foo ; wc -c *.sancov
491    foo
492    main
493    SanitizerCoverage: ./a.out.7316.sancov 3 PCs written
494    24 a.out.7312.sancov
495    32 a.out.7316.sancov
496
497Every time you run an executable instrumented with SanitizerCoverage
498one ``*.sancov`` file is created during the process shutdown.
499If the executable is dynamically linked against instrumented DSOs,
500one ``*.sancov`` file will be also created for every DSO.
501
502Sancov data format
503------------------
504
505The format of ``*.sancov`` files is very simple: the first 8 bytes is the magic,
506one of ``0xC0BFFFFFFFFFFF64`` and ``0xC0BFFFFFFFFFFF32``. The last byte of the
507magic defines the size of the following offsets. The rest of the data is the
508offsets in the corresponding binary/DSO that were executed during the run.
509
510Sancov Tool
511-----------
512
513A simple ``sancov`` tool is provided to process coverage files.
514The tool is part of LLVM project and is currently supported only on Linux.
515It can handle symbolization tasks autonomously without any extra support
516from the environment. You need to pass .sancov files (named
517``<module_name>.<pid>.sancov`` and paths to all corresponding binary elf files.
518Sancov matches these files using module names and binaries file names.
519
520.. code-block:: console
521
522    USAGE: sancov [options] <action> (<binary file>|<.sancov file>)...
523
524    Action (required)
525      -print                    - Print coverage addresses
526      -covered-functions        - Print all covered functions.
527      -not-covered-functions    - Print all not covered functions.
528      -symbolize                - Symbolizes the report.
529
530    Options
531      -blocklist=<string>         - Blocklist file (sanitizer blocklist format).
532      -demangle                   - Print demangled function name.
533      -strip_path_prefix=<string> - Strip this prefix from file paths in reports
534
535
536Coverage Reports
537----------------
538
539**Experimental**
540
541``.sancov`` files do not contain enough information to generate a source-level
542coverage report. The missing information is contained
543in debug info of the binary. Thus the ``.sancov`` has to be symbolized
544to produce a ``.symcov`` file first:
545
546.. code-block:: console
547
548    sancov -symbolize my_program.123.sancov my_program > my_program.123.symcov
549
550The ``.symcov`` file can be browsed overlaid over the source code by
551running ``tools/sancov/coverage-report-server.py`` script that will start
552an HTTP server.
553
554Output directory
555----------------
556
557By default, .sancov files are created in the current working directory.
558This can be changed with ``ASAN_OPTIONS=coverage_dir=/path``:
559
560.. code-block:: console
561
562    % ASAN_OPTIONS="coverage=1:coverage_dir=/tmp/cov" ./a.out foo
563    % ls -l /tmp/cov/*sancov
564    -rw-r----- 1 kcc eng 4 Nov 27 12:21 a.out.22673.sancov
565    -rw-r----- 1 kcc eng 8 Nov 27 12:21 a.out.22679.sancov
566