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: 2026-04-09 06:23:31 Functions: 6 141 4.3 %

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

Generated by: LCOV version 1.14