Skip to main content

Crate detcore

Crate detcore 

Source
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 are detcore_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>/exe link 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 for hermit --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_ROUTE link 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§

BackendFailureCleanup
Separate terminal cleanup outcomes; neither replaces the backend failure.
ChosenBinaryInputRefusal
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.
ChunkedOpenFileChannel
A SharedOpenFileChannel that moves models in chunks over an OpenFileControlTransport.
Config
Configuration options for detcore.
Detcore
The detcore tool and its per-process state.
Digest
A SHA-256 content digest.
FatalCoreCapture
Where and how much Config::fatal_core_capture may write.
FileMetadata
The metadata associated with the file system view of a particular process.
FinalizationFailure
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.
GlobalState
Global state associated with the detcore tool.
LaunchImage
What a launch tells Detcore about the guest’s first image (Config::launch_image).
Namespace
A namespace that may be unshared with Command::unshare.
OpenFileLease
The canonical model of one shared open file description, taken by one process for the length of one synchronous DetFd method call.
OpenFileModel
The canonical model of an open file description that several guest processes share. Detcore’s global state stores it, and a SharedOpenFileChannel carries it to and from the process that holds the lease. Its contents are private to Detcore.
PriorityHistoryRefusal
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.
ReplayDepartureError
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.
SharedOpenFileError
A failure to take or publish a shared open file description.
TerminalOutcomeUnwindGuard
Installs a run’s TerminalOutcomeUnwind on the calling thread while it lives. Without one a terminal outcome exits the process with TerminalOutcome::exit_status, which the parent recognises the same way. Whether, and with which outcome, the run ended is then GlobalState::terminal_outcome.
TerminalReplayRefusal
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.
ThreadState
The Detcore per-thread state.
ThreadStats
Various measurements of one guest thread’s execution. This is useful for printing context in logs as we go and printing a final summary.
UnsupportedSyscallError
Identifies an unsupported syscall that a backend must terminate without unwinding.

Enums§

BlockingMode
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.
GuestIds
How the guest’s process and thread IDs are numbered (Config::guest_ids).
InheritedSeccomp
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) and prctl(PR_SET_SECCOMP), so these and the backend’s own filter are the only filters a guest has.
OpenFileControl
One control request about a shared open file description.
OpenFileControlReply
The answer to an OpenFileControl request.
RunsPostFork
Which side of an ordinary fork/clone receives the first post-registration turn.
SchedHeuristic
Apply a specialized scheduling heuristic which may help exercise certain bugs.
SyscallObservationGap
Why the accounting point did not see every syscall the guest made.
TerminalOutcome
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 and analyze do 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 Clap instance above. Environment variable carrying the coordinator’s fingerprint to an out-of-process plugin: detcore::config_wire_fingerprint, which extends config_wire_fingerprint with 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 extends config_wire_fingerprint with 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§

OpenFileControlTransport
Carries one OpenFileControl request to the global state and returns its answer, synchronously. A backend implements this over its existing coordinator connection.
RecordOrReplay
Helper trait.
SharedOpenFileChannel
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_exec after 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 id on 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 expected as its config_wire_fingerprint and this build’s is another, or None when 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 serialized Config had before Config::backend existed, and recovers Config::backend from the fifteen legacy backend keys.
initial_resource_limit
The limit every guest process starts with for resource, as (current, maximum) in the prlimit64 ABI’s units, or None for 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 sysno with a fixed errno when the fail-closed policy is active, without consulting the host.
is_determinized_syscall
Returns whether the audited runtime policy classifies sysno as Determinized — 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 sysno is a kernel-keyring syscall (add_key, request_key, keyctl) that Detcore hides behind a deterministic CONFIG_KEYS-absent boundary under the default fail-closed policy.
is_strict_only_deterministic_refusal_syscall
Returns whether sysno is refused by the default fail-closed policy but forwarded under the explicit compatibility opt-out. The legacy strict_only name is retained for API compatibility.
is_unsupported_syscall
Returns whether the audited runtime policy classifies sysno as unsupported.
keep_host_status_files_open
Keep each traced thread’s /proc/<pid>/task/<tid>/status open 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 backend needs 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 /proc directories are open on that procfs’s root, and hermit-cli mounts nothing for them.
observes_sigreturns
Whether Detcore under cfg reads the backend’s reports of the guest’s rt_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 guest is about to execve, recording the pre-exec address space mm and any file-descriptor blocking overrides. A backend that handles execve outside 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_interruption and 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) to on, 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) the ReplayRefusalExitHook. 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, so run --verify uses 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) the VirtualTimeoutExitHook. 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 config as JSON in the form it had before Config::backend existed.
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 cfg selects, 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.
ReplayRefusalExitHook
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 with HERMIT_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.
TerminalDeadlockHook
What a process that drives the scheduler in-process does with a terminal deadlock report before the scheduler exits the process.
TerminalOutcomeUnwind
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 --timeout does), 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.
VirtualTimeoutExitHook
What a process does with a --virtual-timeout bound, in virtual nanoseconds, just before the scheduler exits it with 124 because no TerminalOutcomeUnwind took 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.