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

Generated by: LCOV version 1.14