Expand description
Detcore is a Reverie tool that determinizes the execution of a process.
§Backend-abstraction commandment
Detcore is a tool written against Reverie’s abstract instrumentation
interface (the reverie crate). It depends only on those traits and types
and is deliberately ignorant of how a guest is actually traced.
Detcore MUST NEVER depend on or import a concrete Reverie backend or support
crate – any reverie-* crate other than the abstract reverie-core
interface. Choosing and instantiating a backend, and running a detcore tool
against it, is the sole responsibility of the hermit-cli package. There
are no backend-specific hacks in detcore: any tracing-mechanism-specific
behavior belongs behind the Reverie abstraction, not here.
Why: Hermit follows Reverie’s abstract model. A backend dependency in detcore would couple the determinism engine to one tracing mechanism and break the clean abstraction boundary that lets the same tool run over any backend.
The one allowed exception is test-only: detcore’s own integration tests
(under detcore/tests/, wired via the reverie-ptrace dev-dependency)
drive a real tracer to exercise the tool. That coupling never reaches the
shipped library. This invariant is enforced in CI by
scripts/check-detcore-backend-abstraction.sh.
Re-exports§
pub use util::punch_out_print;
Modules§
- access_
trace - Detcore’s side of the access trace (
--record-access-trace-to); the record types aredetcore_model::access_trace. - detlog
- Module contains macroses that help tracing DETLOG entires for the purpose of verifiying determinism [‘detlog’] can be used to write a deterministic log entry at INFO level [’detlog_debug] can be use to write a deterministic log entry at DEBUG level
- edit_
distance - Schedule-alignment and edit-distance algorithms shared by Hermit tools.
- exec_
record - The image a process executes, which its
/proc/<pid>/exelink names. - exit_
dependencies - Descriptors that would make a guest the server another guest’s exit waits for, refused while process exits complete asynchronously.
- guest_
log - Detcore’s warnings from inside the guest, printed by the coordinator.
- host_
timed_ producers - Signal producers whose signal Linux sends at a moment host timing decides, which an in-guest run refuses (A5 step 3c slice 0b; design sections 16.30, D25, D28 and D28a of https://github.com/rrnewton/hermit/issues/4485).
- in_
guest_ launch - What Hermit tells the in-guest LiteInst runtime at launch, carried in the
sealed preload bootstrap’s tool data (
reverie_inguest::bootstrap) rather than in the guest’s environment. - in_
guest_ site_ patching - The check that an in-guest Tool image runs with syscall site patching off,
and collects the statistics it reports at exit, when the host asked for it
(
Config::in_guest_site_patching_off, set forhermit --backend=in-guest-trap). - logdiff
- Everything to do with post-processing hermit/detcore logs.
- machine
- The machine a guest runs on, as Hermit describes it: one description that every guest-visible source of machine facts reads, so that they tell the same story on every backend and every host (https://github.com/rrnewton/hermit/issues/4266).
- native_
exec - Inactive, backend-neutral validation of a prepared single-thread exec cut.
- native_
exec_ control - Coordinator-owned native exec transactions. No Tool is decoded or run here.
- netlink_
route - Determinize the statistics counters carried by
NETLINK_ROUTElink dumps. - nonwaiting_
write - Diagnostic writes that never wait for the reader of a descriptor.
- preemptions
- A datatype to abstract a record of thread preemptions, as generated during chaos mode execution.
- race_
probe - Race probes: env-gated perturbation points on Hermit’s own host-timed edges, for reproducing rare races in Hermit itself (docs/RACE_PROBES.md).
- random
- Shared guest random-state and memory operations, independent of a backend. These synchronous operations preserve draws even when a later write fails.
- refused_
signal_ controls - Guest signal controls an in-guest runtime refused before Detcore saw the call, reported once per run.
- signal_
restart - What a syscall interrupted for a caught signal gives the guest, by Linux’s x86 table (A5 design 16.6 and D40, D43).
- slice_
boundary - Slice-boundary observation/reset API. Authenticated startup activates it for a typed recording or replay. Actual callback observations stay separate from expectations; reset adds no scheduler request.
- types
- Widely-shared type definitions.
- util
- Widely useful small utilities.
Macros§
- detlog
- Macro used to encapsulate tracing should-be-deterministic information. This is currently at the INFO log level.
- detlog_
debug - Macro used to encapsulate tracing should-be-deterministic information. This variant is at a higher log level and requires that logging verbosity is set to DEBUG.
- detlog_
observed - Whether a
detlog!record emitted at this point would reach anything. - ordered_
info - The ordinary tracing arm retains the original tokens, callsite target, fields and subscriber context. Only explicit InitialImage opt-in selects the counted message-only arm; this does not capture arbitrary INFO events.
Structs§
- Backend
Failure Cleanup - Separate terminal cleanup outcomes; neither replaces the backend failure.
- Chosen
Binary Input Refusal - Binary streams do not carry the reserved-input provenance required by Chosen execution. This is an admission refusal, never a guest errno or a replay desync; the typed inner Tool is authoritative even when Config’s mode booleans are false.
- Chunked
Open File Channel - A
SharedOpenFileChannelthat moves models in chunks over anOpenFileControlTransport. - Config
- Configuration options for detcore.
- Detcore
- The detcore tool and its per-process state.
- Digest
- A SHA-256 content digest.
- Fatal
Core Capture - Where and how much
Config::fatal_core_capturemay write. - File
Metadata - The metadata associated with the file system view of a particular process.
- Finalization
Failure - An earlier error plus a later finalization failure. Only the primary is in the cause chain: a secondary policy refusal must not reclassify an I/O or backend failure. Both full diagnostics remain available through Display.
- Global
State - Global state associated with the detcore tool.
- Launch
Image - What a launch tells Detcore about the guest’s first image
(
Config::launch_image). - Namespace
- A namespace that may be unshared with
Command::unshare. - Open
File Lease - The canonical model of one shared open file description, taken by one
process for the length of one synchronous
DetFdmethod call. - Open
File Model - The canonical model of an open file description that several guest
processes share. Detcore’s global state stores it, and a
SharedOpenFileChannelcarries it to and from the process that holds the lease. Its contents are private to Detcore. - Priority
History Refusal - Priority-history replay of a callback-annotated record ended with recorded
checkpoints unconsumed (
Config::annotated_priority_replay). Constructed only by the scheduler’s terminal summary, after the record it re-records is flushed; the run ends as a policy refusal. - Replay
Departure Error - Accepted faithful replay findings or a refused finding publication. These remain distinct: a refused payload contributes no accepted finding or marker. Constructed only after recording and summary finalization are attempted.
- Shared
Open File Error - A failure to take or publish a shared open file description.
- Terminal
Outcome Unwind Guard - Installs a run’s
TerminalOutcomeUnwindon the calling thread while it lives. Without one a terminal outcome exits the process withTerminalOutcome::exit_status, which the parent recognises the same way. Whether, and with which outcome, the run ended is thenGlobalState::terminal_outcome. - Terminal
Replay Refusal - A typed replay cursor refused its terminal state. This marker is constructed only at terminal cursor validation, not for recording I/O or summary errors.
- Thread
State - The Detcore per-thread state.
- Thread
Stats - Various measurements of one guest thread’s execution. This is useful for printing context in logs as we go and printing a final summary.
- Unsupported
Syscall Error - Identifies an unsupported syscall that a backend must terminate without unwinding.
Enums§
- Blocking
Mode - How should we handle syscalls which may block, but are internal to the hermit container? These syscalls are determinizable, but there are multiple methods of doing so. These choices do not apply to blocking syscalls that wait for external conditions outside the container, such as network responses.
- Guest
Ids - How the guest’s process and thread IDs are numbered
(
Config::guest_ids). - Inherited
Seccomp - The seccomp state of the thread that starts the guest, which the guest
inherits: every filter that thread has applies to the guest’s system calls,
and to the calls Detcore injects into it. Detcore refuses the guest’s own
seccomp(2)andprctl(PR_SET_SECCOMP), so these and the backend’s own filter are the only filters a guest has. - Open
File Control - One control request about a shared open file description.
- Open
File Control Reply - The answer to an
OpenFileControlrequest. - Runs
Post Fork - Which side of an ordinary fork/clone receives the first post-registration turn.
- Sched
Heuristic - Apply a specialized scheduling heuristic which may help exercise certain bugs.
- Syscall
Observation Gap - Why the accounting point did not see every syscall the guest made.
- Terminal
Outcome - How Detcore’s scheduler ended a run itself, with a status and a stderr class
line of its own: NEITHER KIND IS A GUEST RESULT. A deadlock is a verdict of
Hermit’s model (see
HERMIT_GUEST_DEADLOCK_EXIT) and a virtual timeout is a bound Hermit imposed, so--verify(under the default--verify-allow=success), chaos-stress andanalyzedo not take either as the guest’s outcome. Neither is a Hermit failure (125) either.
Constants§
- CONFIG_
FINGERPRINT_ ENV - N.B. we don’t want to specify two different notions of “default”, so we use the
Clapinstance above. Environment variable carrying the coordinator’s fingerprint to an out-of-process plugin:detcore::config_wire_fingerprint, which extendsconfig_wire_fingerprintwith Detcore’s global RPC definitions. - DEFAULT_
PRIORITY - The default priority for a thread. If chaos mode is not enabled, all threads have this priority.
- FIRST_
PRIORITY - The lowest/highest priority a thread can have.
- LAST_
PRIORITY - The last/lowest (numerically largest) priority a thread can have.
- LITEINST_
CONFIG_ FINGERPRINT_ ENV - Environment variable carrying the coordinator’s fingerprint
(
detcore::config_wire_fingerprint, which extendsconfig_wire_fingerprintwith Detcore’s global RPC definitions) to the in-guest LiteInst runtime (libdetcore_liteinst.so), which checks it before it decodes the configuration the coordinator sends. Without the check, a runtime built from another tree fails with a bare decoding error that names neither build (https://github.com/rrnewton/hermit/issues/3986). The runtime removes it once checked, as it removes its DETLOG variables: the value is zeroed in the environment block and the variable is unset, so the fingerprint never reaches the guest. - ROOT_
DETPID - A convention of how we set up our PID namespace leaves us with a starting pid of 3.
Traits§
- Open
File Control Transport - Carries one
OpenFileControlrequest to the global state and returns its answer, synchronously. A backend implements this over its existing coordinator connection. - Record
OrReplay - Helper trait.
- Shared
Open File Channel - Synchronous access to the canonical models of shared open file descriptions.
Functions§
- admit_
chosen_ input_ stream - Operational pre-start admission for raw embedding entrypoints. These have no CLI error classifier, so retain the existing policy-refusal exit 122. Pure Tool queries must use neither this function nor another exit path.
- all_
pinned_ syscalls - Every syscall in the pinned x86_64 table, including the final entry.
- cancel_
exec - Cancels a matching
prepare_execafter a native exec fails. Call this before returning to the old image, preserving its thread state and address space identity so frozen siblings can resume without an exec transition. - chosen_
id_ holder - What holds
idon the host, for a refusal: the task’s name and its process, or that only a process group or session holds it. - combine_
finalization - Combine an already evaluated operation with its already evaluated cleanup. Cleanup is never skipped, and failure of either operation prevents success.
- config_
fingerprint_ mismatch - What differs when a coordinator announced
expectedas itsconfig_wire_fingerprintand this build’s is another, orNonewhen they are equal. The runtimes report this before they decode the coordinator’s configuration (https://github.com/rrnewton/hermit/issues/3986). - config_
wire_ fingerprint detcore_model::config::config_wire_fingerprint, extended with the revision of Detcore’s global RPC (crate::tool_global::GLOBAL_RPC_REVISION).- cpu_
profile_ admission_ refusal - Why a CPU profile configuration cannot run at all, or
None. Host mode requires CPUID and time virtualization; Detcore answers a v3 guest from the qualified host’s facts, so a configuration without them is refused rather than given a guessed leaf 0xD. Whether those facts came from a real qualification is Hermit’s to check, at its launch functions (cpu_profile_admission::refuse_unadmitted_launch), before any backend starts (https://github.com/rrnewton/hermit/issues/4243). - decode_
backend_ config_ json - Read a legacy configuration or a versioned envelope with exact backend facts.
- encode_
backend_ config_ json - Preserve the exact backend facts alongside an already encoded legacy config.
- format_
unsupported_ syscall_ warning - Formats one deterministic warning for a set of unsupported syscall names.
- from_
legacy_ backend_ json - Parses JSON written by
to_legacy_backend_json, or any JSON in the form a serializedConfighad beforeConfig::backendexisted, and recoversConfig::backendfrom the fifteen legacy backend keys. - initial_
resource_ limit - The limit every guest process starts with for
resource, as(current, maximum)in theprlimit64ABI’s units, orNonefor an invalid resource number. - install_
shared_ open_ file_ channel - Installs this process’s channel to shared open file descriptions. Only the first channel installed in a process is retained; a later one is returned.
- is_
deterministically_ refused_ syscall - Returns whether Detcore deterministically refuses
sysnowith a fixed errno when the fail-closed policy is active, without consulting the host. - is_
determinized_ syscall - Returns whether the audited runtime policy classifies
sysnoasDeterminized— that is, Detcore either models the syscall with a handler or applies an explicit deterministic refusal policy to it. - is_
kernel_ keyring_ syscall - Returns whether
sysnois a kernel-keyring syscall (add_key,request_key,keyctl) that Detcore hides behind a deterministicCONFIG_KEYS-absent boundary under the default fail-closed policy. - is_
strict_ only_ deterministic_ refusal_ syscall - Returns whether
sysnois refused by the default fail-closed policy but forwarded under the explicit compatibility opt-out. The legacystrict_onlyname is retained for API compatibility. - is_
unsupported_ syscall - Returns whether the audited runtime policy classifies
sysnoas unsupported. - keep_
host_ status_ files_ open - Keep each traced thread’s
/proc/<pid>/task/<tid>/statusopen in this process and re-read it with pread(2), instead of opening it for every signal-state read. Call it only from a process that never shares a guest’s descriptor table: Hermit’s own binary, at startup. Detcore linked into a guest (the in-guest runtimes) must never call it, or the kept descriptors would be the guest’s. - needs_
directory_ placeholder - Whether a run on the backend whose capabilities are
backendneeds the placeholder directory hermit-cli mounts for Detcore (Config::directory_placeholder): where the guest’s procfs is not the kernel’s, as one capability says (procfs_inode::tool_can_name_guest_descriptors). Where it is the kernel’s, Detcore’s served/procdirectories are open on that procfs’s root, and hermit-cli mounts nothing for them. - observes_
sigreturns - Whether Detcore under
cfgreads the backend’s reports of the guest’srt_sigreturn, which a gdbserver turns off. A recording and its replays must all answer no, or they could take different signal continuations (ThreadState::returned_from_sigreturn). - prepare_
exec - Notifies the coordinator that
guestis about toexecve, recording the pre-exec address spacemmand any file-descriptor blocking overrides. A backend that handlesexecveoutside Detcore’s syscall handler must call this before the native syscall so the next image reconnects to the existing scheduler identity and logical clock. - require_
chosen_ input_ stream - Pure decision used by the operational static facility admission hook and typed public launch wrappers. Calling subscriptions is only a query and must never execute this policy’s exit path.
- set_
kernel_ signal_ facts - Sets
supports_blocked_wait_signal_interruptionand the four capabilities Detcore read from it until A5 step 3c.0 split them out (kernel_signal_state_is_guests,kernel_signal_targets_are_predictable,host_task_reads_reach_guest_threads,host_timed_signals_are_physical) toon, together. Every backend has the five equal, so a configuration that set or cleared the one field before the split sets or clears all five with this, and behaves as it did. - set_
replay_ refusal_ exit_ hook - Install (or, with
None, remove) theReplayRefusalExitHook. A process forked after this inherits it. - set_
terminal_ deadlock_ hook - Install (or, with
None, remove) the hook a terminal deadlock report is handed to just before the process exits. The exit cannot return an error to a caller, sorun --verifyuses this to record the run as failed by a deadlock instead of leaving its pending no-result stamp. - set_
virtual_ timeout_ exit_ hook - Install (or, with
None, remove) theVirtualTimeoutExitHook. A process forked after this inherits it. - shared_
open_ file_ reply - The answer to a
shared_open_file_request. - shared_
open_ file_ request - The global request that carries one shared open file control message. It is answered before any clock accounting, so its clock and address-space fields are placeholders. The sender is the thread the backend’s transport names for the request; for in-guest LiteInst that is the runtime’s own envelope, checked against the connecting process at admission, on a connection the guest cannot write to.
- thread_
rng_ from_ parent - Generate a new thread-local PRNG from the parent’s PRNG state, mixing in the new DetTid for some deterministic entropy. This ensures sequentially-spawned threads get distinct PRNG states.
- to_
legacy_ backend_ json - Serializes
configas JSON in the form it had beforeConfig::backendexisted. - two_
phase_ refusal - Why this configuration cannot keep the two-phase delivery protocol
(
Tool::announce_signal_event), if it cannot: a part of the commit would file a scheduler request, or would read what only exists after the kernel’s dequeue (the thread’s queues, or the delivery’s siginfo). - v3_
feature_ words - The feature words the x86-64-v3 table advertises, as
(leaf, subleaf, register, bits)with registers 0-3 for EAX-EDX, for the CLI’s check that the host has every one of them natively (https://github.com/rrnewton/hermit/issues/4243). Leaf 0xD, which comes from the host, is not among them. - virtual_
cpuid_ digest - The digest of the CPUID table and bound host xstate facts
cfgselects, which a recording carries so that replay can refuse a different table (https://github.com/rrnewton/hermit/issues/4243).
Type Aliases§
- DetTid
- Deterministic “virtual” version of
reverie::Tid - Priority
- The user-accessible priority of a thread. Lowest runs first.
- Replay
Refusal Exit Hook - What a process does with the number of late precise timer events it
recorded (Reverie’s skid-overshoot witness,
reverie::skid_overshoot_count) just before a replay refusal exits it withHERMIT_POLICY_REFUSAL_EXIT(exit_on_replay_refusal). The status is all that crosses the process boundary, and it is every refusal’s status, so a parent that forked the process learns through this hook that the refusal followed a late event. - Terminal
Deadlock Hook - What a process that drives the scheduler in-process does with a terminal deadlock report before the scheduler exits the process.
- Terminal
Outcome Unwind - How a run whose backend can unwind the parked guest ends it with a
TerminalOutcome, in place of the scheduler exiting the process: it asks the backend to tear the guest down and finish the run (the ptrace owner publishes a termination, as--timeoutdoes), and returns whether that request became the run’s cause. Called at most once, from the scheduler task with no scheduler lock held, after the outcome’s report is printed; it must not block. - Virtual
Timeout Exit Hook - What a process does with a
--virtual-timeoutbound, in virtual nanoseconds, just before the scheduler exits it with 124 because noTerminalOutcomeUnwindtook the outcome. The status is all that crosses the process boundary, and 124 is every deadline’s status, so a parent that forked the process learns of the virtual timeout through this hook instead.