aristo-cli 0.6.0

Aristo CLI binary (the `aristo` command).
Documentation
/*
 * aristo.h - Aristo C instrumentation runtime.
 *
 * Vendored by `aristo instrument vendor-c` (aristo {{SDK_VERSION}}).
 * Do not edit by hand; re-vendor to update. Standard C11, no compiler
 * extensions.
 *
 * Everything instrumentation-related is gated by ARISTO_INSTRUMENT (set via
 * -DARISTO_INSTRUMENT). With the flag absent the macros expand to nothing /
 * Continue / static, and at -O1 or higher the compiled .text/.data/.rodata
 * are byte-identical to un-annotated source.
 */
#ifndef ARISTO_H
#define ARISTO_H

#include <stdint.h>

/*
 * ABI version of the runtime + generated-code contract. Bump on ANY layout
 * change to aristo_decision, the hook typedefs, or the macro signatures.
 */
#define ARISTO_ABI {{ARISTO_ABI}}

/*
 * aristo_decision is defined in BOTH build modes so a fault-point call site
 * (`aristo_decision d = ARISTO_FAULT_POINT(...)`) compiles either way.
 */
typedef struct {
    uint8_t  inject; /* 0 => Continue; non-zero => inject a fault          */
    uint64_t code;   /* opaque selector, meaningful only to the SUT        */
} aristo_decision;

/*
 * Continue value. ARISTO_CONTINUE is a compound literal (automatic storage
 * only). Use ARISTO_CONTINUE_INIT for a static/global initializer.
 */
#define ARISTO_CONTINUE       ((aristo_decision){ 0, 0 })
#define ARISTO_CONTINUE_INIT  { 0, 0 }

static inline int aristo_is_inject(aristo_decision d) { return d.inject != 0; }

#ifdef ARISTO_INSTRUMENT

_Static_assert(ARISTO_ABI == {{ARISTO_ABI}},
    "aristo.h ABI does not match the code generated against it; "
    "re-vendor aristo.h/aristo.c from the same aristo CLI version");

static inline aristo_decision aristo_inject(uint64_t code) {
    aristo_decision d;
    d.inject = 1;
    d.code = code;
    return d;
}

typedef void            (*aristo_yield_fn)(const char *label, void *state);
typedef aristo_decision (*aristo_fault_fn)(const char *label, void *state);

/*
 * Install (or clear, with fn == NULL) the calling thread's hook. Hooks are
 * thread-local; a fresh set replaces the prior hook with no chaining. The
 * setter returns void - save/restore is the harness's job.
 */
void aristo_set_hook(aristo_yield_fn fn, void *state);
void aristo_set_fault_hook(aristo_fault_fn fn, void *state);

/* Dispatch targets - call only via the macros below. */
void            aristo_yield_point(const char *label);
aristo_decision aristo_fault_point(const char *label);

#define ARISTO_YIELD_POINT(label) aristo_yield_point((label))
#define ARISTO_FAULT_POINT(label) aristo_fault_point((label))
#define ARISTO_TU_LOCAL           /* external linkage: linkable by a harness */

#else /* !ARISTO_INSTRUMENT */

#define ARISTO_YIELD_POINT(label) ((void)0)
#define ARISTO_FAULT_POINT(label) ARISTO_CONTINUE
#define ARISTO_TU_LOCAL           static /* production: translation-unit-local */

#endif /* ARISTO_INSTRUMENT */

#endif /* ARISTO_H */