TinyInst Binary-Only fuzzing for Windows (#854)

* step1 for tinyinst

* step2: minimal executor

* updated libafl

* Tinyinst Update (#853)

* Mac OS Autotokens (#723)

* mac_tokens

* more

* win fix

* fmt

* fmt c

* Use nightly fmt (#728)

* Fix compilation for aarch64 qemu (#731)

Typo lead to fail to compile for arm64

* Simd Fix (#729)

* simd fix

* fmt

* Fixing readme & docs (#730)

* fix

* fix

* add

* add

* fmt

* 0.8.1 (#732)

* New Pass Manager Arguments (#724)

* new pm arguments

* enable abgeana's code

* Fix tui with 1 client (#734)

* unbreak tui with 1 client

* clippy

* Add core affinity support for FreeBSD (#736)

* NYX Executor (GSoC '22) (#693)

* Add ccache

* Update codecov.yml

* Add libnyx

* Fix

* Add nyx build script

* Fix build.sh && init executor.rs

* Fix commit

* Fix code

* initialize `exector.rs`

* refine API in `nyx_bridge.rs`

* initialze `run_target`

* add `test_nyxhelper`

* initize `test_executor`

* remove `nyx_beidge.rs`

* make `test_executor` compile

* Improve test

* refine code

* update version

* fix docker

* fix docker

* Fix clippy

* Fix build

* fix build && add `set_timeout`

* Fix and refine CI

* fix CI

* Fix CI

* Add platform restrict

* cargo fmt

* add parallel mode

* add example `nyx_libxml2_parallel`

* fix fuzzer example

* fix CI

* add README

* fix CI

* fix CI

* fix CI

* remove unwrap and NyxResult

* code format fix

* add libnyx's rev

* fix format

* change Duration format && Fix CI

* caego fmt

* fix CI

* fix CI

* Add doc

* test CI

* Update test_all_fuzzers.sh

* Update test_all_fuzzers.sh

* Update test_all_fuzzers.sh

* add cache for apt and cargo-install

* Update build_and_test.yml

* Update build_and_test.yml

* tmp test CI

* fix CI

* remove debug cmd

* remove test

* code refine

* code refine

* code refine

* code refine

* add Makefile

* fix example doc for nyx

* add `NyxHelper::new_with_initial_timeout`

* fix `NyxHelper::new`

* fix curl parameter

* code refine

* add check for setup script

* use afl-clang-fast in nyx

* fix logic

* fix makefile

* fix CI

* Update build_and_test.yml

* Update build_and_test.yml

* remove debug cmd

Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>

* Fix spelling error (#745)

* OSX force_load option (#743)

* Update clang.rs

* fmt

* Add continous JSON Logging monitor (#738)

* Add simple JSON Monitor

* Add documentation

* Log global state

* Fix formatting

* Save state depending on closure outcome, have file opened all the time

* Make OnDiskJSONMonitor cloneable

* Switch to FnMut to allow stateful closures

* Use &mut M: Monitor for the closure

* Fix documentation of Rand::below (#747)

* Netopenbsd build fix (#746)

* core affinity netbsd implementation.

* openbsd build fix

* Fix autotokens doc (#751)

* fix

* remove wrong doc

* Simplification for netbsd-specific code (#750)

the cpuset api is already present in libc...

* Add test case minimising stage (tmin) (#735)

* add test case minimising stage

* general purpose minimiser impl, with fuzzer example

* reorganise, document, and other cleanup

* correct python API return value

* correct some docs

* nit: versioning in fuzzers

* ise -> ize

* Implement a corpus minimiser (cmin) (#739)

* initial try

* correct case where cull attempts to fetch non-existent corpus entries

* various on_remove, on_replace implementations

* ise -> ize (consistency), use TestcaseScore instead of rolling our own

* oops, feature gate

* documentation!

* link c++

* doc-nit: correction in opt explanation

don't write documentation at 0300

* better linking

* Skippable stage, generator wrapper for Grimoire (#748)

* Skippable stage, generator wrapper for Grimoire

* more fancy wrapper

* MapFeedback: Adding support for with_name() (#752)

* Adding support for with_name()

* Adding with_name() function description

* dragonflybsd build fix for core affinity. (#753)

supporting most of linux sched api here.

* CI for FreeBSD (#754)

* CI for FreeBSD

* rustup -y?

* fixed path, switched to clippy

* bsd don't source

* added llvm

* clippy

* more yml

* ?

* testing ci

* llvm?

* llvm??

* more llvm, more tests

* fixed testcase'

* mem limits

* more sudo

* reenable all the CI

* Fixes for new Clippy (#755)

* New Clippy fixes for QEMU (#757)

* Core affinity for FreeBSD pinning task to the wanted cpu (#756)

* Do not zero-init struct in QEMU (#758)

* New Clippy fixes for QEMU

* no need to 0-initialize mem

* clippy

* Add doc for libafl_nyx (#759)

Co-authored-by: syheliel <syheliel@gmail.com>

* Adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec (#760)

* adjust NyxExecutor trait bound to HasTargetBytes from HasBytesVec

* oops actually use HasTargetBytes instead

* libafl_frida: ASan hook adding Apple's memset_pattern* api. (#761)

* Fix cargo doc on windows (#762)

* add doc cfg

* fix nostd docs

* ignore CommandConfigurator doc test execution on non-unix platform

* add cargo doc step pipeline on windows platform

* Enable memset_patter ASan hooks for Apple on libafl_frida (#763)

* Fix forkserver options (#771)

* Stability improve (#773)

* initial

* add

* fmt & fix

* dbg remove

* clp

* clp

* more

* clippy

* del

* fix

* remove unused

* fix

* doc

* Fix doc (#780)

* Add track_stability option to CalibrationStage  (#781)

* add

* Update gramatron.rs

* Update emu.rs

* try

* clp

* Dump registers on freebsd x86_64 (#779)

* Illumos support (#775)

implementing core affinity too.

* Reduce clang warnings for version output in libafl_cc. (#778)

* Extend gramatron recursive mutator (#783)

* Dump registers on NetBSD amd64 (#786)

* Add support for ARMBE8 (#768)

* Changes to build QEMU out-of-tree so that we don't need to clone the repo for each feature combination we build

* Add be support to libafl_qemu

* More config tweaks

Co-authored-by: Your Name <you@example.com>

* [AFLplusplus/LibAFL] dump registers on OpenBSD amd64 (PR #787)

* dump registers on openbsd

* write_crash implementations

* Windows gdiplus (#789)

* Initial steps

* Harness code cleanup

* don't panic on linux in order not to break the CI

* formatting once again

* restored cfg unix to unbreak linux build

* Remove clang download from windows CI (#791)

* Attempt to remove clang 12 setup

* frida_gdiplus added to CI

* Gdiplus comments (#792)

* Attempt to remove clang 12 setup

* frida_gdiplus added to CI

* Redundancy note

* formatting again :\

* mistake of directory name

* Fix len miscalculation in grimoire string replace (#794)

* Fix len miscalculation in grimoire string replace

* ok Rust i was writing JS these days

Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>

* Fix doc typos (#796)

* Fix CI  (#798)

* bump (#799)

* Support for write_crash on netbsd (#788)

* Support for bolts::cpu::read_time_counter on arm64 (#790)

* Add ability to use virtual dispatch to StagesTuple (#801)

* Add ability to use virtual dispatch to stagesTuple

* Fix lint

* Adding CPSR register for arm qemu (#800)

* trying to add in observer

* writing test

* got up to running with instrumentation but i still need to get the map

* fixing fuzzer code

* adding tinyinst fuzzer

* adding ffi to store all the map data into vec.

* adding some new things

* adding somewhat state of how i would like it should work

* fixing some things

* alot of false positives.

* fixing before adding args

* updated to use FileInput!

* adding build script to pull tinyinst

* fixing git issue

* writing instruction to run how to run tinyinst fuzzer

Co-authored-by: Dongjia Zhang <tokazerkje@outlook.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Phan Thanh Duy <phanthanhduypr@gmail.com>
Co-authored-by: Nicholas Lang <97475577+nicklangsysdig@users.noreply.github.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: syheliel <45957390+syheliel@users.noreply.github.com>
Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Aiden Hall <AidenRHall@users.noreply.github.com>
Co-authored-by: Sönke <eknoes@users.noreply.github.com>
Co-authored-by: Sirui Mu <msrlancern@gmail.com>
Co-authored-by: Addison Crump <me@addisoncrump.info>
Co-authored-by: Patrick Gersch <gersch.patrick@gmail.com>
Co-authored-by: Teddy Heinen <teddy@heinen.dev>
Co-authored-by: Vincent <space_white@yahoo.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>
Co-authored-by: Your Name <you@example.com>
Co-authored-by: expend20 <36543551+expend20@users.noreply.github.com>
Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
Co-authored-by: Ben Davis <ben@thebendavis.net>
Co-authored-by: radl97 <radl97@users.noreply.github.com>

* fix

* fmt

* Submodule

* Submodule?

* Tinyinst Update V2 (#905)

* updated to lastest libafl

* going to replace tinyinst to more like jackalope with tinyinstrumentation

* fixing clippy

* keep working on cpp ffi. sad

* updating litecov to tinyinst. also start making our own litecov

* revert to map instead of list. not sure why its not working

* making fuzzer listobserver

* working with listobserver!:

* cleaning up

* adding cargo make run

* updating cargo for tinyinst

* updating readme

* readme, clippy

* fmt

* fmt

* fix

* fix

* docker

* fix

* fmt

Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: biazo <eric.l.biazo@gmail.com>
Co-authored-by: Phan Thanh Duy <phanthanhduypr@gmail.com>
Co-authored-by: Nicholas Lang <97475577+nicklangsysdig@users.noreply.github.com>
Co-authored-by: David CARLIER <devnexen@gmail.com>
Co-authored-by: syheliel <45957390+syheliel@users.noreply.github.com>
Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Aiden Hall <AidenRHall@users.noreply.github.com>
Co-authored-by: Sönke <eknoes@users.noreply.github.com>
Co-authored-by: Sirui Mu <msrlancern@gmail.com>
Co-authored-by: Addison Crump <me@addisoncrump.info>
Co-authored-by: Patrick Gersch <gersch.patrick@gmail.com>
Co-authored-by: Teddy Heinen <teddy@heinen.dev>
Co-authored-by: Vincent <space_white@yahoo.com>
Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
Co-authored-by: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com>
Co-authored-by: Your Name <you@example.com>
Co-authored-by: expend20 <36543551+expend20@users.noreply.github.com>
Co-authored-by: Andrea Fioraldi <andrea.fioraldi@trellix.com>
Co-authored-by: Ben Davis <ben@thebendavis.net>
Co-authored-by: radl97 <radl97@users.noreply.github.com>
Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Dongjia "toka" Zhang 2022-12-05 03:04:06 +09:00 committed by GitHub
parent 93d99beecf
commit 5d7fd8f914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 303 additions and 2 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ vendor
*.dll *.dll
*.exe *.exe
*.dSYM *.dSYM
*.obj
.cur_input .cur_input
.venv .venv

View File

@ -6,6 +6,7 @@ members = [
"libafl_targets", "libafl_targets",
"libafl_frida", "libafl_frida",
"libafl_qemu", "libafl_qemu",
"libafl_tinyinst",
"libafl_sugar", "libafl_sugar",
"libafl_nyx", "libafl_nyx",
"libafl_concolic/symcc_runtime", "libafl_concolic/symcc_runtime",

View File

@ -72,6 +72,9 @@ COPY scripts/dummy.rs libafl_concolic/symcc_libafl/src/lib.rs
COPY libafl_nyx/Cargo.toml libafl_nyx/build.rs libafl_nyx/ COPY libafl_nyx/Cargo.toml libafl_nyx/build.rs libafl_nyx/
COPY scripts/dummy.rs libafl_nyx/src/lib.rs COPY scripts/dummy.rs libafl_nyx/src/lib.rs
COPY libafl_tinyinst/Cargo.toml libafl_tinyinst/
COPY scripts/dummy.rs libafl_tinyinst/src/lib.rs
COPY utils utils COPY utils utils
RUN cargo build && cargo build --release RUN cargo build && cargo build --release

View File

@ -34,6 +34,7 @@ LibAFL offers integrations with popular instrumentation frameworks. At the momen
+ SanitizerCoverage, in [libafl_targets](./libafl_targets) + SanitizerCoverage, in [libafl_targets](./libafl_targets)
+ Frida, in [libafl_frida](./libafl_frida) + Frida, in [libafl_frida](./libafl_frida)
+ QEMU user-mode, in [libafl_qemu](./libafl_qemu) + QEMU user-mode, in [libafl_qemu](./libafl_qemu)
+ TinyInst, in [libafl_tinyinst](./libafl_tinyinst) by [elbiazo](https://github.com/elbiazo)
## Getting started ## Getting started

View File

@ -0,0 +1,13 @@
[package]
name = "tinyinst_simple"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { version = "0.8.1", path = "../../libafl", features = ["tui"] }
libafl_tinyinst = { version = "0.8.1", path = "../../libafl_tinyinst" }
[profile.release]
codegen-units = 1
opt-level = 3

View File

@ -0,0 +1,8 @@
[tasks.build_test]
command = "cl"
args = ["./test/test.c", "-o", "./test/test.exe"]
[tasks.run]
dependencies = ["build_test"]
command = "cargo"
args = ["run", "--release"]

View File

@ -0,0 +1,3 @@
# Run Instruction
1. Open up developer powershell so that you have access to cl (Windows Default Compiler)
2. Run `cargo make run` to run the fuzzer

View File

@ -0,0 +1,62 @@
use std::path::PathBuf;
use libafl::{
bolts::{
rands::{RandomSeed, StdRand},
tuples::tuple_list,
},
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
events::SimpleEventManager,
feedbacks::{CrashFeedback, ListFeedback},
inputs::BytesInput,
monitors::SimpleMonitor,
mutators::{havoc_mutations, StdScheduledMutator},
observers::ListObserver,
schedulers::RandScheduler,
stages::StdMutationalStage,
state::StdState,
Fuzzer, StdFuzzer,
};
use libafl_tinyinst::executor::TinyInstExecutor;
static mut COVERAGE: Vec<u64> = vec![];
fn main() {
// Tinyinst things
let tinyinst_args = vec!["-instrument_module".to_string(), "test.exe".to_string()];
let args = vec![".\\test\\test.exe".to_string(), "@@".to_string()];
let observer = ListObserver::new("cov", unsafe { &mut COVERAGE });
let mut feedback = ListFeedback::new_with_observer(&observer);
let input = BytesInput::new(b"bad".to_vec());
let rand = StdRand::new();
let mut corpus = CachedOnDiskCorpus::new(PathBuf::from("./corpus_discovered"), 64).unwrap();
corpus
.add(Testcase::new(input))
.expect("error in adding corpus");
let solutions = OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap();
let mut objective = CrashFeedback::new();
let mut state = StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap();
let scheduler = RandScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let monitor = SimpleMonitor::new(|x| println!("{}", x));
let mut mgr = SimpleEventManager::new(monitor);
let mut executor = unsafe {
TinyInstExecutor::new(
&mut COVERAGE,
tinyinst_args,
args,
5000,
tuple_list!(observer),
)
};
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("error in fuzzing loop");
}

View File

@ -0,0 +1 @@
bad12

View File

@ -0,0 +1 @@
ok

View File

@ -0,0 +1,36 @@
#include <stdio.h>
void pass1(char *buf, int buf_size) {
char target[0x10];
if (buf[0] == 'b') {
if (buf[1] == 'a') {
if (buf[2] == 'd') {
if (buf[3] == '1') {
if (buf[4] == '2') {
printf("You got me\n");
memcpy(target, buf, 0x1000000);
printf("GG\n");
}
}
}
}
}
}
int main(int argc, char *argv[]) {
FILE *fp;
char buf[0x1000];
if (argc == 2) {
fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("File not found\n");
printf("Received filename %s\n", argv[1]);
return 1;
}
fscanf(fp, "%s", buf);
pass1(buf, sizeof(buf));
} else {
printf("there is nothing\n");
}
}

View File

@ -963,6 +963,7 @@ where
T: Debug + Serialize + serde::de::DeserializeOwned, T: Debug + Serialize + serde::de::DeserializeOwned,
{ {
name: String, name: String,
last_addr: usize,
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
@ -1012,6 +1013,7 @@ where
pub fn new(name: &'static str) -> Self { pub fn new(name: &'static str) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
last_addr: 0,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -1021,6 +1023,7 @@ where
pub fn new_with_observer(observer: &ListObserver<T>) -> Self { pub fn new_with_observer(observer: &ListObserver<T>) -> Self {
Self { Self {
name: observer.name().to_string(), name: observer.name().to_string(),
last_addr: 0,
phantom: PhantomData, phantom: PhantomData,
} }
} }

View File

@ -9,14 +9,16 @@ echo "[*] Making sure all Nyx is checked out"
git status 1>/dev/null 2>/dev/null git status 1>/dev/null 2>/dev/null
if [ ! -d ./QEMU-Nyx ]; then if [ ! -e ./QEMU-Nyx/.git ]; then
rm -rf ./QEMU-Nyx
git clone https://github.com/nyx-fuzz/QEMU-Nyx.git || exit 1 git clone https://github.com/nyx-fuzz/QEMU-Nyx.git || exit 1
pushd QEMU-Nyx pushd QEMU-Nyx
git reset --hard 80f22f77d6aab14e62bf11c80db4e210bbca5fb5 git reset --hard 80f22f77d6aab14e62bf11c80db4e210bbca5fb5
popd popd
fi fi
if [ ! -d ./packer ]; then if [ ! -e ./packer/.git ]; then
rm -rf ./packer
git clone https://github.com/syheliel/packer.git || exit 1 git clone https://github.com/syheliel/packer.git || exit 1
pushd QEMU-Nyx pushd QEMU-Nyx
git reset --hard 86b159bafc0b2ba8feeaa8761a45b6201d34084f git reset --hard 86b159bafc0b2ba8feeaa8761a45b6201d34084f

View File

@ -0,0 +1,24 @@
[package]
name = "libafl_tinyinst"
version.workspace = true
edition = "2021"
authors = ["elbiazo <eric.l.biazo@gmail.com>", "Dongjia Zhang <tokazerkje@outlook.com>"]
repository = "https://github.com/AFLplusplus/LibAFL/"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
license = "MIT OR Apache-2.0"
keywords = ["fuzzing", "testing", "security"]
description = "TinyInst backend for libafl"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cxx = "1.0"
libafl = { path = "../libafl", version = "0.8.0", features = [
"std",
"libafl_derive",
] }
tinyinst-rs = { git = "https://github.com/elbiazo/tinyinst-rs" }
# tinyinst-rs = { path = "../../tinyinst-rs" }
[build-dependencies]
cmake = "0.1"

View File

@ -0,0 +1,3 @@
# Requirements
- you need `Visual Studio 17 2022`, though it's not tested, it should work on older versions.
- you need `cxxbridge-cmd` to generate bridge files between Rust and c++, you can install this via `cargo install cxxbridge-cmd`

View File

@ -0,0 +1,138 @@
use core::marker::PhantomData;
use libafl::{
bolts::fs::{InputFile, INPUTFILE_STD},
executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, UsesInput},
observers::{ObserversTuple, UsesObservers},
prelude::AsSlice,
state::{State, UsesState},
Error,
};
use tinyinst_rs::tinyinst::{litecov::RunResult, TinyInst};
pub struct TinyInstExecutor<'a, S, OT> {
tinyinst: TinyInst,
coverage: &'a mut Vec<u64>,
timeout: u32,
observers: OT,
phantom: PhantomData<S>,
cur_input: InputFile,
use_stdin: bool,
}
impl<'a, S, OT> std::fmt::Debug for TinyInstExecutor<'a, S, OT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TinyInstExecutor")
.field("timeout", &self.timeout)
.finish_non_exhaustive()
}
}
impl<'a, EM, S, Z, OT> Executor<EM, Z> for TinyInstExecutor<'a, S, OT>
where
EM: UsesState<State = S>,
S: UsesInput,
S::Input: HasTargetBytes,
Z: UsesState<State = S>,
{
#[inline]
fn run_target(
&mut self,
_fuzzer: &mut Z,
_state: &mut Self::State,
_mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
if !self.use_stdin {
self.cur_input.write_buf(input.target_bytes().as_slice())?;
}
#[allow(unused_assignments)]
let mut status = RunResult::OK;
unsafe {
status = self.tinyinst.run();
self.tinyinst.vec_coverage(self.coverage, false);
}
match status {
RunResult::CRASH | RunResult::HANG => Ok(ExitKind::Crash),
RunResult::OK => Ok(ExitKind::Ok),
RunResult::OTHER_ERROR => Err(Error::unknown(
"Tinyinst RunResult is other error".to_string(),
)),
_ => Err(Error::unknown("Tinyinst RunResult is unknown".to_string())),
}
}
}
impl<'a, S, OT> TinyInstExecutor<'a, S, OT>
where
OT: ObserversTuple<S>,
S: UsesInput,
{
/// # Safety
pub unsafe fn new(
coverage: &'a mut Vec<u64>,
tinyinst_args: Vec<String>,
program_args: Vec<String>,
timeout: u32,
observers: OT,
) -> Self {
let mut use_stdin = true;
let program_args = program_args
.into_iter()
.map(|arg| {
if arg == "@@" {
println!("Not using stdin");
use_stdin = false;
INPUTFILE_STD.to_string()
} else {
arg
}
})
.collect();
let cur_input = InputFile::create(INPUTFILE_STD).expect("Unable to create cur_file");
println!("post init");
let tinyinst = TinyInst::new(tinyinst_args, program_args, timeout);
Self {
tinyinst,
coverage,
timeout,
observers,
phantom: PhantomData,
cur_input,
use_stdin,
}
}
}
impl<'a, S, OT> HasObservers for TinyInstExecutor<'a, S, OT>
where
S: State,
OT: ObserversTuple<S>,
{
fn observers(&self) -> &OT {
&self.observers
}
fn observers_mut(&mut self) -> &mut OT {
&mut self.observers
}
}
impl<'a, S, OT> UsesState for TinyInstExecutor<'a, S, OT>
where
S: UsesInput,
{
type State = S;
}
impl<'a, S, OT> UsesObservers for TinyInstExecutor<'a, S, OT>
where
OT: ObserversTuple<S>,
S: UsesInput,
{
type Observers = OT;
}

View File

@ -0,0 +1 @@
pub mod executor;