LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 11 14 78.6 %
Date: 2025-11-18 04:32:32 Functions: 4 99 4.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_vm_fd_vm_h
       2             : #define HEADER_fd_src_flamenco_vm_fd_vm_h
       3             : 
       4             : #include "fd_vm_base.h"
       5             : #include "../../ballet/sha256/fd_sha256.h"
       6             : 
       7             : /* A fd_vm_t is an opaque handle of a virtual machine that can execute
       8             :    sBPF programs. */
       9             : 
      10             : struct fd_vm;
      11             : typedef struct fd_vm fd_vm_t;
      12             : 
      13             : /**********************************************************************/
      14             : /* FIXME: MOVE TO FD_VM_PRIVATE WHEN CONSTRUCTORS READY */
      15             : 
      16             : /* A fd_vm_shadow_t holds stack frame information not accessible from
      17             :    within a program. */
      18             : 
      19             : struct fd_vm_shadow { ulong r6; ulong r7; ulong r8; ulong r9; ulong r10; ulong pc; };
      20             : typedef struct fd_vm_shadow fd_vm_shadow_t;
      21             : 
      22             : /* fd_vm_input_region_t holds information about fragmented memory regions
      23             :    within the larger input region. */
      24             : 
      25             : struct __attribute__((aligned(8UL))) fd_vm_input_region {
      26             :    ulong vaddr_offset;           /* Represents offset from the start of the input region. */
      27             :    ulong haddr;                  /* Host address corresponding to the start of the mem region. */
      28             :    uint  region_sz;              /* Size of the memory region. */
      29             :    ulong address_space_reserved; /* The amount of address space reserved for the region. */
      30             :    uchar is_writable;            /* If the region can be written to or is read-only */
      31             :    ulong acc_region_meta_idx;    /* Index of the acc_region_meta_t struct for the account corresponding to this region. */
      32             : };
      33             : typedef struct fd_vm_input_region fd_vm_input_region_t;
      34             : 
      35             : /* fd_vm_acc_region_meta_t holds metadata about a given account.  An array of these
      36             :    structs will map an instruction account index to its respective input memory
      37             :    region location. */
      38             : 
      39             : struct __attribute((aligned(8UL))) fd_vm_acc_region_meta {
      40             :    uint               region_idx;
      41             :    /* FIXME: We can get rid of this field once DM is activated.  This is
      42             :       only a hack to make the non-DM code path happy.  When DM is
      43             :       activated, we could query the input_mem_region array for the
      44             :       original data len. */
      45             :    ulong              original_data_len;
      46             :    /* The transaction account corresponding to this account. */
      47             :    fd_txn_account_t * acct;
      48             :    /* The expected virtual offsets of the serialized pubkey, lamports and owner
      49             :       for the account corresponding to this region. Relative to the start of the
      50             :       account's input region vaddr.
      51             :       Used for CPI security checks. */
      52             :    uint               expected_pubkey_offset;
      53             :    uint               expected_lamports_offset;
      54             :    uint               expected_owner_offset;
      55             : };
      56             : typedef struct fd_vm_acc_region_meta fd_vm_acc_region_meta_t;
      57             : 
      58             : /* In Agave, all the regions are 16-byte aligned in host address space. There is then an alignment check
      59             :    which is done inside each syscall memory translation, checking if the data is aligned in host address
      60             :    space. This is a layering violation, as it leaks the host address layout into the consensus model.
      61             : 
      62             :    In the future we will change this alignment check in the vm to purely operate on the virtual address space,
      63             :    taking advantage of the fact that Agave regions are known to be aligned. For now, we align our regions to
      64             :    either 8 or 16 bytes, as there are no 16-byte alignment translations in the syscalls currently:
      65             :    stack:  16 byte aligned
      66             :    heap:   16 byte aligned
      67             :    input:  8 byte aligned
      68             :    rodata: 8 byte aligned
      69             : 
      70             :     https://github.com/solana-labs/rbpf/blob/cd19a25c17ec474e6fa01a3cc3efa325f44cd111/src/ebpf.rs#L39-L40  */
      71         483 : #define FD_VM_HOST_REGION_ALIGN                   (16UL)
      72             : 
      73             : struct __attribute__((aligned(FD_VM_HOST_REGION_ALIGN))) fd_vm {
      74             : 
      75             :   /* VM configuration */
      76             : 
      77             :   /* FIXME: suspect these three should be replaced by some kind of VM
      78             :      enabled feature struct (though syscalls do seem to make additional
      79             :      non-trivial use of instr_ctx). */
      80             : 
      81             :   fd_exec_instr_ctx_t * instr_ctx;   /* FIXME: DOCUMENT */
      82             : 
      83             :   /* FIXME: frame_max should be run time configurable by compute budget.
      84             :      If there is no reasonable upper bound on this, shadow and stack
      85             :      will need to be provided by users. */
      86             : 
      87             : //ulong frame_max; /* Maximum number of stack frames, in [0,FD_VM_STACK_FRAME_MAX] */
      88             :   ulong heap_max;  /* Maximum amount of heap in bytes, in [0,FD_VM_HEAP_MAX] */
      89             :   ulong entry_cu;  /* Initial number of compute units for this program, in [0,FD_VM_COMPUTE_UNIT_LIMIT] */
      90             : 
      91             :   /* FIXME: The below are practically an exact match to the
      92             :      fields of an fd_sbpf_program_t (sans ELF info) */
      93             : 
      94             :   uchar const * rodata;    /* Program read only data, indexed [0,rodata_sz), aligned 8 */
      95             :   ulong         rodata_sz; /* Program read only data size in bytes, FIXME: BOUNDS? */
      96             :   ulong const * text;      /* Program sBPF words, indexed [0,text_cnt), aligned 8 */
      97             :   ulong         text_cnt;  /* Program sBPF word count, all text words are inside the rodata */
      98             :   ulong         text_off;  /* ==(ulong)text - (ulong)rodata, relocation offset in bytes we must apply to indirect calls
      99             :                               (callx/CALL_REGs), IMPORTANT SAFETY TIP!  THIS IS IN BYTES, NOT WORDS! */
     100             :   ulong         text_sz;   /* Program sBPF size in bytes, == text_cnt*8 */
     101             : 
     102             :   ulong         entry_pc;  /* Initial program counter, in [0,text_cnt)
     103             :                               FIXME: MAKE SURE NOT INTO MW INSTRUCTION, MAKE SURE VALID CALLDEST? */
     104             :   ulong const * calldests; /* Bit vector of local functions that can be called into, bit indexed in [0,text_cnt) */
     105             :   /* FIXME: ADD BIT VECTOR OF FORBIDDEN BRANCH TARGETS (E.G.
     106             :      INTO THE MIDDLE OF A MULTIWORD INSTRUCTION) */
     107             : 
     108             :   fd_sbpf_syscalls_t const * syscalls; /* The map of syscalls (sharable over multiple concurrently running vm) */
     109             : 
     110             :   fd_vm_trace_t * trace; /* Location to stream traces (no tracing if NULL) */
     111             : 
     112             :   /* VM execution and syscall state */
     113             : 
     114             :   /* These are used to communicate the execution and syscall state to
     115             :      users and syscalls.  These are initialized based on the above when
     116             :      a program starts executing.  When program halts or faults, these
     117             :      provide precise execution diagnostics to the user (and potential
     118             :      breakpoint/continue functionality in the future).  When the vm
     119             :      makes a syscall, the vm will set these precisely and, when a
     120             :      syscall returns, the vm will update its internal execution state
     121             :      appropriately. */
     122             : 
     123             :   /* IMPORTANT SAFETY TIP!  THE BEHAVIOR OF THE SYSCALL ALLOCATOR FOR
     124             :      HEAP_SZ MUST EXACTLY MATCH THE SOLANA VALIDATOR ALLOCATOR:
     125             : 
     126             :      https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/invoke_context.rs#L122-L148
     127             : 
     128             :      BIT-FOR-BIT AND BUG-FOR-BUG.  SEE THE SYSCALL_ALLOC_FREE FOR MORE
     129             :      DETAILS. */
     130             : 
     131             :   ulong pc;        /* The current instruction, in [0,text_cnt) in normal execution, may be out of bounds in a fault */
     132             :   ulong ic;        /* The number of instructions which have been executed */
     133             :   ulong cu;        /* The remaining CUs left for the transaction, positive in normal execution, may be zero in a fault */
     134             :   ulong frame_cnt; /* The current number of stack frames pushed, in [0,frame_max] */
     135             : 
     136             :   ulong heap_sz; /* Heap size in bytes, in [0,heap_max] */
     137             : 
     138             :   /* VM memory */
     139             : 
     140             :   /* The vm classifies the 64-bit vm address space into 6 regions:
     141             : 
     142             :        0 - unmapped lo
     143             :        1 - program  -> [FD_VM_MEM_MAP_PROGRAM_REGION_START,FD_VM_MEM_MAP_PROGRAM_REGION_START+4GiB)
     144             :        2 - stack    -> [FD_VM_MEM_MAP_STACK_REGION_START,  FD_VM_MEM_MAP_STACK_REGION_START  +4GiB)
     145             :        3 - heap     -> [FD_VM_MEM_MAP_HEAP_REGION_START,   FD_VM_MEM_MAP_HEAP_REGION_START   +4GiB)
     146             :        4 - input    -> [FD_VM_MEM_MAP_INPUT_REGION_START,  FD_VM_MEM_MAP_INPUT_REGION_START  +4GiB)
     147             :        5 - unmapped hi
     148             : 
     149             :      These mappings are encoded in a software TLB consisting of three
     150             :      6-element arrays: region_haddr, region_ld_sz and region_st_sz.
     151             : 
     152             :      region_haddr[i] gives the location in host address space of the
     153             :      first byte in region i.  region_{ld,st}_sz[i] gives the number of
     154             :      mappable bytes in this region for {loads,stores}.  Note that
     155             :      region_{ld,st}_sz[i]<2^32.  Further note that
     156             :      [region_haddr[i],region_haddr[i]+region_{ld,st}_sz[i]) does not
     157             :      wrap around in host address space and does not overlap with any
     158             :      other usages.
     159             : 
     160             :      region_{ld,st}_sz[0] and region_{ld,st}_sz[5] are zero such that
     161             :      requests to access data from a positive sz range in these regions
     162             :      will fail, making regions 0 and 5 unreadable and unwritable.  As
     163             :      such, region_haddr[0] and region_haddr[5] are arbitrary; NULL is
     164             :      used as the obvious default.
     165             : 
     166             :      region_st_sz[1] is also zero such that requests to store data to
     167             :      any positive sz range in this region will fail, making region 1
     168             :      unwritable.
     169             : 
     170             :      When the direct mapping feature is enabled, the input region will
     171             :      no longer be a contigious buffer of host memory.  Instead
     172             :      it will compose of several fragmented regions of memory each with
     173             :      its own read/write privleges and size.  Address translation to the
     174             :      input region will now have to rely on a binary search lookup of the
     175             :      start of the appropriate area of physical memory. It also involves
     176             :      doing a check against if the region can be written to. */
     177             : 
     178             :    /* FIXME: If accessing memory beyond the end of the current heap
     179             :       region is not allowed, sol_alloc_free will need to update the tlb
     180             :       arrays during program execution (this is trivial).  At the same
     181             :       time, given sol_alloc_free is deprecated, this is unlikely to be
     182             :       the case. */
     183             : 
     184             :   ulong region_haddr[6];
     185             :   uint  region_ld_sz[6];
     186             :   uint  region_st_sz[6];
     187             : 
     188             :   /* fd_vm_input_region_t and fd_vm_acc_to_mem arrays are passed in by the bpf
     189             :      loaders into fd_vm_init.
     190             :      TODO: It might make more sense to allocate space for these in the VM. */
     191             :   fd_vm_input_region_t *    input_mem_regions;               /* An array of input mem regions represent the input region.
     192             :                                                                 The virtual addresses of each region are contigiuous and
     193             :                                                                 strictly increasing. */
     194             :   uint                      input_mem_regions_cnt;
     195             :   fd_vm_acc_region_meta_t * acc_region_metas;                /* Represents a mapping from the instruction account indicies
     196             :                                                                 from the instruction context to the input memory region index
     197             :                                                                 of the account's data region in the input space. */
     198             :   uchar                     is_deprecated;                   /* The vm requires additional checks in certain CPIs if the
     199             :                                                                 vm's current instance was initialized by a deprecated program. */
     200             : 
     201             :   ulong                     reg   [ FD_VM_REG_MAX         ]; /* registers, indexed [0,FD_VM_REG_CNT).  Note that FD_VM_REG_MAX>FD_VM_REG_CNT.
     202             :                                                                 As such, malformed instructions, which can have src/dst reg index in
     203             :                                                                 [0,FD_VM_REG_MAX), cannot access info outside reg.  Aligned 8. */
     204             :   fd_vm_shadow_t            shadow[ FD_VM_STACK_FRAME_MAX ]; /* shadow stack, indexed [0,frame_cnt), if frame_cnt>0, 0/frame_cnt-1 is
     205             :                                                                 bottom/top.  Aligned 16. */
     206             :   uchar                     stack [ FD_VM_STACK_MAX       ]; /* stack, indexed [0,FD_VM_STACK_MAX).  Divided into FD_VM_STACK_FRAME_MAX
     207             :                                                                 frames.  Each frame has a FD_VM_STACK_GUARD_SZ region followed by a
     208             :                                                                 FD_VM_STACK_FRAME_SZ region.  reg[10] gives the offset of the start of the
     209             :                                                                 current stack frame.  Aligned 16. */
     210             :   uchar                     heap  [ FD_VM_HEAP_MAX        ]; /* syscall heap, [0,heap_sz) used, [heap_sz,heap_max) free.  Aligned 8. */
     211             : 
     212             :   fd_sha256_t * sha; /* Pre-joined SHA instance. This should be re-initialised before every use. */
     213             : 
     214             :   ulong magic;    /* ==FD_VM_MAGIC */
     215             : 
     216             :   int   direct_mapping;                       /* If direct mapping feature flag is enabled */
     217             :   int   stricter_abi_and_runtime_constraints; /* If stricter_abi_and_runtime_constraints feature flag is enabled */
     218             : 
     219             :   /* Agave uses the segv vaddr in several different cases, including:
     220             :      - Determining whether or not to return a regular or stack access violation
     221             :      - (If direct mapping is enabled) determining the instruction error
     222             :        code to return on store operations. */
     223             :   ulong segv_vaddr;
     224             :   ulong segv_access_len;
     225             :   uchar segv_access_type;
     226             : 
     227             :   ulong sbpf_version;     /* SBPF version, SIMD-0161 */
     228             : 
     229             :   int dump_syscall_to_pb; /* If true, syscalls will be dumped to the specified output directory */
     230             : };
     231             : 
     232             : /* FIXME: MOVE ABOVE INTO PRIVATE WHEN CONSTRUCTORS READY */
     233             : /**********************************************************************/
     234             : 
     235             : FD_PROTOTYPES_BEGIN
     236             : 
     237             : /* FIXME: FD_VM_T NEEDS PROPER CONSTRUCTORS */
     238             : 
     239             : /* FD_VM_{ALIGN,FOOTPRINT} describe the alignment and footprint needed
     240             :    for a memory region to hold a fd_vm_t.  ALIGN is a positive
     241             :    integer power of 2.  FOOTPRINT is a multiple of align.
     242             :    These are provided to facilitate compile time declarations. */
     243         483 : #define FD_VM_ALIGN     FD_VM_HOST_REGION_ALIGN
     244         237 : #define FD_VM_FOOTPRINT (527824UL)
     245             : 
     246             : /* fd_vm_{align,footprint} give the needed alignment and footprint
     247             :    of a memory region suitable to hold an fd_vm_t.
     248             :    Declaration / aligned_alloc / fd_alloca friendly (e.g. a memory
     249             :    region declared as "fd_vm_t _vm[1];", or created by
     250             :    "aligned_alloc(alignof(fd_vm_t),sizeof(fd_vm_t))" or created
     251             :    by "fd_alloca(alignof(fd_vm_t),sizeof(fd_vm_t))" will all
     252             :    automatically have the needed alignment and footprint).
     253             :    fd_vm_{align,footprint} return the same value as
     254             :    FD_VM_{ALIGN,FOOTPRINT}. */
     255             : FD_FN_CONST ulong
     256             : fd_vm_align( void );
     257             : 
     258             : FD_FN_CONST ulong
     259             : fd_vm_footprint( void );
     260             : 
     261         237 : #define FD_VM_MAGIC (0xF17EDA2CEF0) /* FIREDANCE SBPF V0 */
     262             : 
     263             : /* fd_vm_new formats memory region with suitable alignment and
     264             :    footprint suitable for holding a fd_vm_t.  Assumes
     265             :    shmem points on the caller to the first byte of the memory region
     266             :    owned by the caller to use.  Returns shmem on success and NULL on
     267             :    failure (logs details).  The memory region will be owned by the state
     268             :    on successful return.  The caller is not joined on return. */
     269             : 
     270             : void *
     271             : fd_vm_new( void * shmem );
     272             : 
     273             : /* fd_vm_join joins the caller to a vm.
     274             :    Assumes shmem points to the first byte of the memory region holding
     275             :    the vm.  Returns a local handle to the join on success (this is
     276             :    not necessarily a simple cast of the address) and NULL on failure
     277             :    (logs details). */
     278             : fd_vm_t *
     279             : fd_vm_join( void * shmem );
     280             : 
     281             : /* fd_vm_init initializes the given fd_vm_t struct, checking that it is
     282             :    not null and has the correct magic value.
     283             : 
     284             :    It modifies the vm object and also returns the object for convenience.
     285             : 
     286             :    FIXME: we should split out the memory mapping setup from this function
     287             :           to handle those errors separately. */
     288             : fd_vm_t *
     289             : fd_vm_init(
     290             :    fd_vm_t * vm,
     291             :    fd_exec_instr_ctx_t *instr_ctx,
     292             :    ulong heap_max,
     293             :    ulong entry_cu,
     294             :    uchar const * rodata,
     295             :    ulong rodata_sz,
     296             :    ulong const * text,
     297             :    ulong text_cnt,
     298             :    ulong text_off,
     299             :    ulong text_sz,
     300             :    ulong entry_pc,
     301             :    ulong const * calldests,
     302             :    ulong sbpf_version,
     303             :    fd_sbpf_syscalls_t * syscalls,
     304             :    fd_vm_trace_t * trace,
     305             :    fd_sha256_t * sha,
     306             :    fd_vm_input_region_t * mem_regions,
     307             :    uint mem_regions_cnt,
     308             :    fd_vm_acc_region_meta_t * acc_region_metas,
     309             :    uchar is_deprecated,
     310             :    int direct_mapping,
     311             :    int stricter_abi_and_runtime_constraints,
     312             :    int dump_syscall_to_pb );
     313             : 
     314             : /* fd_vm_leave leaves the caller's current local join to a vm.
     315             :    Returns a pointer to the memory region holding the vm on success
     316             :    (this is not necessarily a simple cast of the
     317             :    address) and NULL on failure (logs details).  The caller is not
     318             :    joined on successful return. */
     319             : void *
     320             : fd_vm_leave( fd_vm_t * vm );
     321             : 
     322             : /* fd_vm_delete unformats a memory region that holds a vm.
     323             :    Assumes shmem points on the caller to the first
     324             :    byte of the memory region holding the state and that nobody is
     325             :    joined.  Returns a pointer to the memory region on success and NULL
     326             :    on failure (logs details).  The caller has ownership of the memory
     327             :    region on successful return. */
     328             : void *
     329             : fd_vm_delete( void * shmem );
     330             : 
     331             : /* fd_vm_validate validates the sBPF program in the given vm.  Returns
     332             :    success or an error code.  Called before executing a sBPF program.
     333             :    FIXME: DOCUMENT BETTER */
     334             : 
     335             : FD_FN_PURE int
     336             : fd_vm_validate( fd_vm_t const * vm );
     337             : 
     338             : /* fd_vm_is_check_align_enabled returns 1 if the vm should check alignment
     339             :    when doing memory translation. */
     340             : FD_FN_PURE static inline int
     341         309 : fd_vm_is_check_align_enabled( fd_vm_t const * vm ) {
     342         309 :    return !vm->is_deprecated;
     343         309 : }
     344             : 
     345             : /* fd_vm_is_check_size_enabled returns 1 if the vm should check size
     346             :    when doing memory translation. */
     347             : FD_FN_PURE static inline int
     348           0 : fd_vm_is_check_size_enabled( fd_vm_t const * vm ) {
     349           0 :    return !vm->is_deprecated;
     350           0 : }
     351             : 
     352             : /* FIXME: make this trace-aware, and move into fd_vm_init
     353             :    This is a temporary hack to make the fuzz harness work. */
     354             : int
     355             : fd_vm_setup_state_for_execution( fd_vm_t * vm ) ;
     356             : 
     357             : /* fd_vm_exec runs vm from program start to program halt or program
     358             :    fault, appending an execution trace if vm is attached to a trace.
     359             : 
     360             :    Since this is running from program start, this will init r1 and r10,
     361             :    pop all stack frames and free all heap allocations.
     362             : 
     363             :    IMPORTANT SAFETY TIP!  This currently does not zero out any other
     364             :    registers, the user stack region or the user heap.  (FIXME: SHOULD
     365             :    IT??)
     366             : 
     367             :    Returns FD_VM_SUCCESS (0) on success and an FD_VM_ERR code (negative)
     368             :    on failure.  Reasons for failure include:
     369             : 
     370             :      INVAL     - NULL vm (or, for fd_vm_exec_trace, the vm is not
     371             :                  attached to trace).  FIXME: ADD OTHER INPUT ARG CHECKS?
     372             : 
     373             :      SIGTEXT   - A jump/call set the program counter outside the text
     374             :                  region or the program counter incremented beyond the
     375             :                  text region.  pc will be at the out of bounds location.
     376             :                  ic and cu will not include the out of bounds location.
     377             :                  For a call, the call stack frame was allocated.
     378             : 
     379             :      SIGSPLIT  - A jump/call set the program counter into the middle of
     380             :                  a multiword instruction or a multiword instruction went
     381             :                  past the text region end.  pc will be at the split.  ic
     382             :                  and cu will not include the split.  For a call, the
     383             :                  call stack frame was allocated.
     384             : 
     385             :      SIGCALL   - A call set the program counter to a non-function
     386             :                  location.  pc will be at the non-function location.  ic
     387             :                  and cu will include the call but not include the
     388             :                  non-function location.  The call stack frame was
     389             :                  allocated.
     390             : 
     391             :      SIGSTACK  - The call depth limit was exceeded.  pc will be at the
     392             :                  call.  ic and cu will include the call but not the call
     393             :                  target.  The call stack frame was not allocated.
     394             : 
     395             :      SIGILL    - An invalid instruction was encountered (including an
     396             :                  invalid opcode and an endian swap with an invalid bit
     397             :                  width).  pc will be at the invalid instruction.  ic and
     398             :                  cu will not include the invalid instruction.
     399             : 
     400             :      SIGSEGV   - An invalid memory access (outside the program memory
     401             :                  map) was encountered.  pc will be at the faulting
     402             :                  instruction.  ic and cu will not include the faulting
     403             :                  instruction.
     404             : 
     405             :      SIGBUS    - An unaligned memory access was encountered.  pc will be
     406             :                  at the faulting instruction.  ic and cu will not
     407             :                  include the faulting instruction.  (Note: currently
     408             :                  mapped to SIGSEGV and then only if check_align is
     409             :                  enabled.)
     410             : 
     411             :      SIGRDONLY - A write to read-only memory address was encountered.
     412             :                  pc will be at the faulting instruction.  ic and cu will
     413             :                  not include the faulting instruction.  (Note: currently
     414             :                  mapped to SIGSEGV.)
     415             : 
     416             :      SIGCOST   - The compute limit was exceeded.  pc will be at the
     417             :                  first non-executed instruction (if pc is a syscall, the
     418             :                  syscall might have been partially executed when it ran
     419             :                  out of budget .. see safety tip below).  ic will cover
     420             :                  all executed instructions.  cu will be zero.
     421             : 
     422             :    This will considers any error returned by a syscall as a fault and
     423             :    returns the syscall error code here.  See syscall documentation for
     424             :    details here.  When a syscall faults, pc will be at the syscall, ic
     425             :    will include the syscall and cu will include the syscall and any
     426             :    additional costs the syscall might have incurred up to that point of
     427             :    the fault.
     428             : 
     429             :    IMPORTANT SAFETY TIP!  Ideally, a syscall should only modify vm's
     430             :    state when it knows its overall syscall will be successful.
     431             :    Unfortunately, this is often not practical (e.g. a syscall starts
     432             :    processing a list of user provided commands and discovers an error
     433             :    condition late in the command list that did not exist at syscall
     434             :    start because the error condition was created by successfully
     435             :    executed commands earlier in the list).  As such, vm's state on a
     436             :    faulting syscall may not be clean.
     437             : 
     438             :    FIXME: SINCE MOST SYSCALLS CAN BE IMPLEMENTED TO HAVE CLEAN FAULTING
     439             :    BEHAVIOR, PROVIDE A MECHANISM SO USERS CAN EASILY DETECT UNCLEAN
     440             :    SYSCALL FAULTS?
     441             : 
     442             :    For SIGCOST, note that the vm can speculate ahead when processing
     443             :    instructions.  This makes it is possible to have a situation where
     444             :    a vm faults with, for example, SIGSEGV from a speculatively
     445             :    executed memory access while a non-speculative execution would have
     446             :    faulted with SIGCOST on an earlier instruction.  In these situations,
     447             :    pc will be at the faulting speculatively executed instruction, ic
     448             :    will include all the speculatively executed instructions, cu will be
     449             :    zero and vm's state will include the impact of all the speculation.
     450             : 
     451             :    IMPORTANT SAFETY TIP!  While different vm implementations can
     452             :    disagree on why a program faulted (e.g. SIGCOST versus SIGSEGV in the
     453             :    example above), they cannot disagree on whether or not a program
     454             :    faulted.  As a result, the specific fault reason must never be
     455             :    allowed to be part of consensus.
     456             : 
     457             :    fd_vm_exec_trace runs with tracing and requires vm to be attached to
     458             :    a trace.  fd_vm_exec_notrace runs without without tracing even if vm
     459             :    is attached to a trace. */
     460             : 
     461             : int
     462             : fd_vm_exec_trace( fd_vm_t * vm );
     463             : 
     464             : int
     465             : fd_vm_exec_notrace( fd_vm_t * vm );
     466             : 
     467             : static inline int
     468         186 : fd_vm_exec( fd_vm_t * vm ) {
     469         186 :   if( FD_UNLIKELY( vm->trace ) ) return fd_vm_exec_trace  ( vm );
     470         186 :   else                           return fd_vm_exec_notrace( vm );
     471         186 : }
     472             : 
     473             : FD_PROTOTYPES_END
     474             : 
     475             : #endif /* HEADER_fd_src_flamenco_vm_fd_vm_h */

Generated by: LCOV version 1.14