Skip to content

Commit 30ee2aa

Browse files
Merge pull request #232 from microsoft/main
Fork Sync: Update from parent repository
2 parents 9e57857 + f12319b commit 30ee2aa

File tree

2 files changed

+142
-126
lines changed

2 files changed

+142
-126
lines changed

docs/how-to/coverage-filtering.md

Lines changed: 0 additions & 126 deletions
This file was deleted.

src/agent/coverage/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# `coverage`
2+
3+
## Summary
4+
5+
The `coverage` crate is a library that provides components for recording binary code
6+
coverage for userspace targets. The binary modules under test do not require static
7+
instrumentation of any kind, but coverage will only be recorded for executable modules
8+
that have debuginfo.
9+
10+
## Usage
11+
12+
### Example Tool
13+
14+
The `record` example demonstrates comprehensive usage of binary coverage recording and
15+
conversion to source. It can be built from the `coverage` crate root via the command
16+
`cargo build --examples --release.`
17+
18+
As an example, suppose you had a target name `app.exe`, with a directory of PNG test cases in `corpus`.
19+
20+
Binary coverage for a single specific input `example.png` could be recorded with the command:
21+
22+
```
23+
record.exe -- ./app.exe corpus/example.png
24+
```
25+
26+
The combined coverage for all inputs in the corpus can be recorded using the `--input-dir`/`-d` option:
27+
```
28+
record.exe -d corpus -- ./app.exe '@@'
29+
```
30+
31+
In this case, the command after `--` is invoked multiple times. For each invocation, the
32+
special `@@` input marker is replaced with the path to an input in `corpus`. The example
33+
binary then merges the per-input coverage to produce the aggregated result.
34+
35+
To emit source + line coverage, just specify the `--output`/`-o` option:
36+
37+
```
38+
record.exe -o source -d corpus -- ./app.exe '@@'
39+
```
40+
41+
For Cobertura XML:
42+
43+
```
44+
record.exe -o cobertura -d corpus -- ./app.exe '@@'
45+
```
46+
47+
See `record.exe -h` for more options.
48+
49+
### Recording
50+
51+
The core type used for recording is `record::CoverageRecorder`. This accepts a Rust
52+
standard library `Command`, and invokes it as a debuggee. Targets must exit before the
53+
timeout, or no coverage will be returned. The output of recording is the `Recorded`
54+
struct. This contains both an `output` field (target exit status and captured stdio
55+
streams) and a `coverage` field. The `coverage` field contains the binary code coverage
56+
organized by module and module-relative image offset.
57+
58+
### Allowlists
59+
60+
By default, coverage is recorded for all runtime-observed modules with debuginfo, and any
61+
source file referred to by that debuginfo. Two allowlists can be used to control which
62+
modules and source files have their coverage recorded.
63+
64+
Each allowlist is a flat text file with a simple syntax for path-matching rules.
65+
66+
- `/` or `\`-separated literal paths include an item (module or source file) exactly.
67+
- `*` glob characters can be included anywhere, including within path components.
68+
- Path patterns can be _excluded_ via the syntax `! <rule>`.
69+
- Comments are supported using the `#` character.
70+
71+
If no allowlist is provided, the default allowlist contains only the rule `*`, which
72+
includes all paths. If an allowlist is provided, then the default allow-all rule is
73+
omitted. Files are then included only if they match an include rule but don't _also_ match
74+
an (overriding) exclude rule.
75+
76+
An example source allowlist:
77+
78+
```
79+
# 1. Record coverage for source files application root.
80+
app/*
81+
82+
# 2. Also include library code, factored out of the application proper.
83+
lib/*
84+
85+
# 3. But do _not_ record coverage for vendored library code.
86+
! lib/vendor/*
87+
```
88+
89+
With the above rules, we would have the following inclusion behavior:
90+
- Include `src/main.c` (matches (1))
91+
- Include `lib/utility.c` (matches (2))
92+
- Exclude `lib/vendor/json.c` (matches (3), an exclude rule)
93+
- Exclude `other/stuff.c` (does not match any allow rule)
94+
95+
### Source Coverage
96+
97+
#### Source File and Line
98+
99+
Source coverage is derived from binary coverage using debuginfo. The
100+
`source::binary_to_source_coverage()` function converts a `BinaryCoverage` value to a
101+
`SourceCoverage`, which describes the input binary coverage in terms of source files and
102+
lines.
103+
104+
#### Cobertura XML
105+
106+
To obtain source and line coverage in the Cobertura XML format, you can directly convert a
107+
`SourceCoverage` value to a `CoberturaCoverage` value using the `From` trait. The result
108+
is serializable via the `CoberturaCoverage::to_string()` method. The conversion defined in
109+
the `cobertura` module emits Cobertura designed to produce sensible HTML reports when
110+
consumed by the ReportGenerator project.
111+
112+
## FAQ
113+
114+
1 _My Linux target uses dynamic linking or loading and has zero coverage info for shared libraries._
115+
116+
Make sure that your target shared libraries were compiled with debuginfo. If not, no
117+
coverage will be measured for them at all. If coverage locations are defined, but never
118+
reached, the shared libraries may not be found by the dynamic linker/loader at runtime.
119+
This is an issue with your command invocation. You can debug this with the `record` tool's
120+
`--dump-stdio` option. A typical fix is to include the directories of non-system shared
121+
libraries in the `LD_LIBRARY_PATH` environment variable.
122+
123+
2 _Coverage is being recorded generally, but the branches of `switch` statements don't seem reachable._
124+
125+
Please report your case to the OneFuzz team. Large `switch` statements are frequently
126+
compiled to indirect jumps via tables, and we are working to improve coverage in these
127+
cases.
128+
129+
3 _I have a source line with multiple statements. How do I know which ones are being hit or missed?_
130+
131+
Binary coverage is both ground truth and the most granular coverage format. The source
132+
coverage representations do not currently include column info. If any module offset that
133+
maps to a source line is missed, then the entire line is considered missed. In the future,
134+
we intend to support partial line coverage.
135+
136+
4 _The source coverage reported for my target looks strange or incomplete._
137+
138+
Report your case to the OneFuzz team. Source coverage for optimized builds can be lossy,
139+
and we are constrained by what info we get from the debuginfo. If possible, try recording
140+
coverage for an unoptimized build of your target, and see if the same issue occurs. Either
141+
way, we are always looking for edge cases we could use to drive improvements or
142+
workarounds.

0 commit comments

Comments
 (0)