commits
| 2026-08-26 | README.md: Directly reference the Haddock documentation | Sören Tempel |
| 2026-08-26 | README.md: Shorten bullet point in Tutorials section | Sören Tempel |
| 2026-08-26 | README.md: Fix some typos here and there | Sören Tempel |
| 2026-08-26 | README.md: Revise Tutorials section a bit | Sören Tempel |
| 2026-08-26 | README.md: Add a Tutorials section | Sören Tempel |
Clone the repository to access all 586 commits.
Qute
Qute is a work-in-progress software analysis framework built around the QBE intermediate language. Architecturally, it is composed of several modular Haskell libraries, which enable the implementation of static and dynamic software analysis techniques for QBE programs. The foundation of the framework is a formal (yet executable) description of the QBE specification, which is implemented using an abstract monad. Currently, Qute focuses primarily on dynamic software analysis through symbolic execution.
For further details, see the Qute paper.
Status
Qute is still in early stages of development, not all desired functionality has been implemented and bugs are to be expected in the existing functionality. Nonetheless, it supports all relevant features of the QBE specification and is thus compatible with existing compiler frontends for QBE. This includes the cproc and SCC (with an upstreamed patch) C compilers as well as the Hare compiler.
Architecture
The foundation of this project is a formal, yet executable, description of the QBE intermediate language.
At the time of writing, it targets v1.3 of the QBE specification.
The syntax is specified using literate Haskell and parser combinators in the qute-syntax library.
The language semantics are expressed in a modular way by distinguishing abstract and actual semantics.
Abstract semantics of the QBE language are described in terms of a Simulator monad (i.e., an abstract monad).
This monad must then be instantiated, whereby actual semantics are specified.
Presently, the following instantiations are supported:
- Concrete semantics, provided by
Language.QBE.Simulator.Default.State. - Symbolic (specifically concolic) semantics through
Language.QBE.Simulator.Concolic.State.
The former is primarily useful for simulation of programs written in the QBE intermediate language.
The latter is intended for automated software testing using symbolic execution and—as demonstrated below—can be used to automatically generate test inputs.
Central to this end is the abstract description of QBE semantics that is provided, together with a concrete instantiation, by the qute library.
Further, a symbolic instantiation is provided in a separate qute-symex library.
Additionally, executable programs are provided through qute-cli.
These programs can be used directly from a shell, without interacting with the Haskell codebase.
Presently the following executable program components are available:
qute: A simulator for QBE programs built on top of the concrete semantics.qute-symex: An automated software testing tool facilitating the symbolic semantics.
These program components operate directly on QBE input programs.
Installation
All Haskell libraries provided in this repository are available on Hackage and can hence be installed directly using Cabal, the Haskell language package manager.
As an example, qute-cli can be installed using:
$ cabal install qute-cli
However, to obtain a compatible GHC toolchain and external software (such as constraint solvers), installation using Guix is recommended.
For example, in order to install the qute-cli component and the Bitwuzla solver using Guix:
$ guix time-machine -C .guix/channels.scm -- install -L .guix/modules/ qute-cli bitwuzla
Afterwards, if Guix is configured correctly, the aforementioned program components (qute and qute-symex) should be available in your $PATH.
Note that you can also install additional packages, for example, the cproc or simple-cc QBE-based C compilers this way.
Demonstration
Qute shines when used as a library to implement custom static and dynamic analysis techniques based on QBE.
For details in this regard, refer to the Hackage documentation of the provided Haskell libraries.
Additionally, the qute-cli package provides several program components which can be used without writing your own Haskell code.
The following subsections demonstrate the utilization of this program components.
Concrete Execution
Consider the following “Hello, World!” program:
#include <stdio.h>
int main(void) {
puts("Hello, World!");
return 0;
}
In order to concretly execute this program using qute, we need to obtain an equivalent representation in QBE.
To this end, we can invoke the cproc compiler as follows:
$ cproc -emit-qbe hello.c
The resulting QBE file can then be executed with the concrete semantics using:
$ qute hello.qbe
Hello, World!
Note that qute is only able to invoke the puts(3) function because it intercepts its execution, providing a “simulated” version of it.
Presently, only a limited amount of standard library functions are intercepted in this way.
As such, interactions with the file system or more complex output functions (e.g. printf(3)) are currently not supported.
Symbolic Execution
Symbolic execution is a dynamic software analysis technique that explores reachable program paths based on a symbolic input variable (i.e., an input source). As an example, consider the following C program:
#include <stdio.h>
#include <stddef.h>
// Convert a memory region to an unconstrained symbolic value. Like calloc(3), it can
// account for memory regions which store multiple elements (nelem) of a specific size
// (elsiz). The give name is used to identify the symbolic variable and must be unique.
extern void qute_make_symbolic(void *ptr, size_t nelem, size_t elsiz, const char *name);
int main(void) {
int a;
qute_make_symbolic(&a, 1, sizeof(a), "a");
if (a == 42) {
puts("you found the answer");
} else {
puts("not the answer");
}
return 0;
}
This program can be compiled using the QBE-based cproc C11 compiler as follows:
$ cproc -emit-qbe example.c
The resulting QBE representation (example.qbe) can be symbolically executed using qute-symex:
$ qute-symex --write-tests tests/ example.qbe
This will yield the following output:
not the answer
you found the answer
---
Amount of paths: 2
This indicates that we found two execution paths through our program based on the symbolic variable a.
Due to the --write-tests option, qute-symex will create a tests/ directory that contains test inputs in the ktest format, one for each execution path.
These files can be inspected with the ktest-tool from KLEE (which is included in the Guix development environment described below).
For example:
$ ktest-tool tests/test000002.ktest
ktest file : 'tests/test000002.ktest'
args : ['example.qbe']
num objects: 1
object 0: name: 'a1'
object 0: size: 4
object 0: data: b'*\x00\x00\x00'
object 0: hex : 0x2a000000
object 0: int : 42
object 0: uint: 42
object 0: text: *...
This tells us that the second execution path, where the program prints you found the answer, was triggered with a1 := 42.
From these files, we can—for example—automatically generate high-coverage test cases.
In the future, it will be possible to replay selected .ktest files using qute-cli.
Tutorials
More practical examples wrt. utilization of Qute and symbolic execution are available separately:
- Executing Hare Programs using Qute
- Validating Hare’s Sort Module using Symbolic Execution
- An Introduction to Automated Software Testing using Symbolic Execution (uses KLEE)
Design Goals
This project is intentionally written in a simple subset of the Haskell programming language. It should be usable by anyone with a basic Haskell background (e.g., as obtained by reading Learn You a Haskell for Great Good!). Further, the project should require minimal long-term maintenance and should also support older GHC versions. Therefore, it uses the GHC2021 language standard and avoids usage of additional language extensions. Further, whenever possible, dependencies on external libraries that are not bundled by GHC must be avoided.
Development
Code should be formatted using ormolu. Git hooks performing several sanity checks, including ensuring the proper code formatting, are available. These hooks can be enabled using:
$ git config --local core.hooksPath .githooks
Further, a Guix environment for development purposes can be obtained using:
$ guix time-machine -C .guix/channels.scm -- shell -L .guix/modules/ -m .guix/manifest.scm
License
This project uses the REUSE Specification to indicated used software license.