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-08-05 05:04:49 Functions: 4 126 3.2 %

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

Generated by: LCOV version 1.14