Skip to content

Commit 9681603

Browse files
Support --mmio-region in cbmc
Add --mmio-region to cbmc so that per-region MMIO instrumentation is available without requiring goto-instrument as a separate step. The option is handled in process_goto_program, which is shared by cbmc, goto-analyzer, goto-diff, and the C++ API. Per-region instrumentation runs before the callback model so that declared regions get precise array-backed modeling while callbacks can still handle remaining dereferences. Extract parse_mmio_regions() into mm_io.h/mm_io.cpp to eliminate duplicated region-parsing and overlap-checking logic. Add cmdline.desc tests for all existing tests that use __CPROVER_allocated_memory (memory_allocation1/2, Pointer28, union12, pointer-overflow2, cbmc-incr-smt2/pointer_from_int) with #ifndef CMDLINE guards so the same source works with both mechanisms. Includes cbmc man page entry and updated CProver manual and goto-instrument man page with cross-references. Co-authored-by: Kiro (autonomous agent) <[email protected]>
1 parent a822ebb commit 9681603

23 files changed

Lines changed: 247 additions & 80 deletions

File tree

doc/cprover-manual/modeling-mmio.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ functions, there are two approaches available.
7575

7676
#### Per-region object model (recommended)
7777

78-
Use `--mmio-region <address>:<size>` (with `goto-instrument` or `cbmc`) to
79-
declare each contiguous MMIO region as an individual object. Each region becomes
80-
a byte array in the symbol table, named `__CPROVER_mmio_region_0x<address>`.
81-
Reads and writes to addresses within a declared region are redirected to the
82-
corresponding array element.
78+
Use `--mmio-region <address>:<size>` to declare each
79+
contiguous MMIO region as an individual object. Each region becomes a byte array
80+
in the symbol table, named `__CPROVER_mmio_region_0x<address>`. Reads and writes
81+
to addresses within a declared region are redirected to the corresponding array
82+
element.
83+
84+
This option is supported by both `cbmc` and `goto-instrument`.
8385

8486
This approach avoids the scalability problems of the single-array callback model:
8587
each write only updates the targeted region object rather than the entire memory
@@ -89,6 +91,12 @@ For example, given firmware that accesses a UART at `0x40000000` (256 bytes) and
8991
a GPIO controller at `0x40001000` (64 bytes):
9092

9193
```sh
94+
# Directly with cbmc:
95+
cbmc --mmio-region 0x40000000:256 \
96+
--mmio-region 0x40001000:64 \
97+
--no-pointer-check --no-bounds-check firmware.c
98+
99+
# Or via goto-instrument:
92100
goto-cc -o firmware.gb firmware.c
93101
goto-instrument --mmio-region 0x40000000:256 \
94102
--mmio-region 0x40001000:64 \

doc/man/cbmc.1

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,29 @@ print test suite for coverage criterion (requires \fB\-\-cover\fR)
322322
\fB\-\-mm\fR MM
323323
memory consistency model for concurrent programs (default: sc)
324324
.TP
325+
\fB\-\-mmio\-region\fR \fIaddress\fR:\fIsize\fR
326+
Define a contiguous memory\-mapped I/O region starting at \fIaddress\fR with the
327+
given \fIsize\fR in bytes. The \fIaddress\fR may use a \fB0x\fR prefix for
328+
hexadecimal notation. This option may be repeated to define multiple regions.
329+
Regions must not overlap.
330+
.IP
331+
Each region is modeled as an individual byte\-array object in the symbol table.
332+
Reads from and writes to constant addresses that fall within a declared region
333+
are mapped directly to the corresponding array element. Symbolic addresses are
334+
handled via a conditional dispatch over all declared regions.
335+
.IP
336+
Use \fB\-\-no\-pointer\-check\fR and \fB\-\-no\-bounds\-check\fR when verifying
337+
programs with MMIO regions, since integer addresses used for memory\-mapped I/O
338+
are not valid pointers from CBMC's perspective.
339+
.IP
340+
Example:
341+
.EX
342+
.in +4n
343+
cbmc \-\-mmio\-region 0x40000000:256 \-\-mmio\-region 0x40001000:64 \\
344+
\-\-no\-pointer\-check \-\-no\-bounds\-check firmware.c
345+
.in
346+
.EE
347+
.TP
325348
\fB\-\-malloc\-may\-fail\fR
326349
allow malloc calls to return a null pointer
327350
.TP

doc/man/goto-instrument.1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ This per\-region model avoids the scalability problems of the single unbounded
407407
write only updates the targeted region object rather than the entire memory
408408
array. Both options can be combined.
409409
.IP
410+
This option is also supported directly by \fBcbmc\fR(1).
411+
.IP
410412
Example:
411413
.EX
412414
.in +4n

regression/cbmc-incr-smt2/pointers-conversions/pointer_from_int.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
int main()
22
{
33
int *p = (int *)4;
4+
#ifndef CMDLINE
45
__CPROVER_allocated_memory(4, sizeof(int));
6+
#endif
57

68
__CPROVER_assert(p == 4, "p == 4: expected success");
79
__CPROVER_assert(p != 0, "p != 0: expected success");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
pointer_from_int.c
3+
-DCMDLINE --mmio-region 0x4:4 --trace --no-pointer-check --no-bounds-check
4+
\[main\.assertion\.1\] line \d+ p == 4: expected success: SUCCESS
5+
\[main\.assertion\.2\] line \d+ p != 0: expected success: SUCCESS
6+
\[main\.assertion\.3\] line \d+ p == 0x1020304: expected success: SUCCESS
7+
\[main\.assertion\.4\] line \d+ p != 0: expected success: SUCCESS
8+
\[main\.assertion\.5\] line \d+ p != 0: expected failure: FAILURE
9+
^VERIFICATION FAILED$
10+
^EXIT=10$
11+
^SIGNAL=0$
12+
--
13+
--
14+
Same as pointer_from_int.desc but uses --mmio-region instead of
15+
__CPROVER_allocated_memory.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
KNOWNBUG no-new-smt
2+
main.c
3+
-DCMDLINE --mmio-region 0x4:4 --mmio-region 0x8:8 --little-endian --no-pointer-check --no-bounds-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
The per-region byte-array model does not support storing and loading
11+
pointer values through MMIO regions, so the **q test case fails.

regression/cbmc/Pointer28/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
int main()
22
{
33
int *p = (int *)4;
4+
#ifndef CMDLINE
45
__CPROVER_allocated_memory(4, sizeof(int));
6+
#endif
57
int i;
68
int **q;
79
char *pp;
@@ -21,7 +23,9 @@ int main()
2123
__CPROVER_assert(p == 0, "i==0 => p==NULL");
2224

2325
q = (int **)8;
26+
#ifndef CMDLINE
2427
__CPROVER_allocated_memory(8, sizeof(int *));
28+
#endif
2529
*q = &i;
2630
**q = 0x01020304;
2731
__CPROVER_assert(i == 0x01020304, "**q");
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE broken-smt-backend paths-lifo-expected-failure
2+
main.c
3+
-DCMDLINE --mmio-region 0x10:4 --no-pointer-check --no-bounds-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1\] .* assertion \*p==42: SUCCESS$
7+
^\[main\.assertion\.2\] .* assertion \*\(p\+1\)==42: FAILURE$
8+
^VERIFICATION FAILED$
9+
--
10+
^warning: ignoring

regression/cbmc/memory_allocation1/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ int main()
44
{
55
int *p=0x10;
66

7+
#ifndef CMDLINE
78
__CPROVER_allocated_memory(0x10, sizeof(int));
9+
#endif
810
*p=42;
911
assert(*p==42);
1012
*(p+1)=42;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
KNOWNBUG
2+
main.c
3+
-DCMDLINE --mmio-region 0x1000:400 --mmio-region 0x11000:400 --mmio-region 0x21000:400 --mmio-region 0x31000:400 --no-pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main\.array_bounds\.[1-2]\] .*: SUCCESS$
7+
^\[main\.array_bounds\.3\] .* upper bound in buffers\[.*0\]->buffer\[.*100\]: FAILURE$
8+
^VERIFICATION FAILED$
9+
--
10+
^warning: ignoring
11+
--
12+
The per-region MMIO model uses byte arrays, so structured access via
13+
buffers[0]->buffer[N] does not preserve the original array bounds.
14+
All three bounds checks fail instead of only the out-of-bounds one.

0 commit comments

Comments
 (0)