LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 266 412 64.6 %
Date: 2025-07-01 05:00:49 Functions: 10 12 83.3 %

          Line data    Source code
       1             : #include "fd_vm_private.h"
       2             : #include "../runtime/context/fd_exec_slot_ctx.h"
       3             : #include "../features/fd_features.h"
       4             : 
       5             : /* fd_vm_syscall_strerror() returns the error message corresponding to err,
       6             :    intended to be logged by log_collector, or an empty string if the error code
       7             :    should be omitted in logs for whatever reason.  Omitted examples are success,
       8             :    panic (logged in place)...
       9             :    See also fd_log_collector_program_failure(). */
      10             : char const *
      11           0 : fd_vm_syscall_strerror( int err ) {
      12             : 
      13           0 :   switch( err ) {
      14             : 
      15           0 :   case FD_VM_SYSCALL_ERR_INVALID_STRING:                         return "invalid utf-8 sequence"; // truncated
      16           0 :   case FD_VM_SYSCALL_ERR_ABORT:                                  return "SBF program panicked";
      17           0 :   case FD_VM_SYSCALL_ERR_PANIC:                                  return "SBF program Panicked in..."; // truncated
      18           0 :   case FD_VM_SYSCALL_ERR_INVOKE_CONTEXT_BORROW_FAILED:           return "Cannot borrow invoke context";
      19           0 :   case FD_VM_SYSCALL_ERR_MALFORMED_SIGNER_SEED:                  return "Malformed signer seed"; // truncated
      20           0 :   case FD_VM_SYSCALL_ERR_BAD_SEEDS:                              return "Could not create program address with signer seeds"; // truncated
      21           0 :   case FD_VM_SYSCALL_ERR_PROGRAM_NOT_SUPPORTED:                  return "Program not supported by inner instructions"; // truncated
      22           0 :   case FD_VM_SYSCALL_ERR_UNALIGNED_POINTER:                      return "Unaligned pointer";
      23           0 :   case FD_VM_SYSCALL_ERR_TOO_MANY_SIGNERS:                       return "Too many signers";
      24           0 :   case FD_VM_SYSCALL_ERR_INSTRUCTION_TOO_LARGE:                  return "Instruction passed to inner instruction is too large"; // truncated
      25           0 :   case FD_VM_SYSCALL_ERR_TOO_MANY_ACCOUNTS:                      return "Too many accounts passed to inner instruction";
      26           0 :   case FD_VM_SYSCALL_ERR_COPY_OVERLAPPING:                       return "Overlapping copy";
      27           0 :   case FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE:                  return "Return data too large"; // truncated
      28           0 :   case FD_VM_SYSCALL_ERR_TOO_MANY_SLICES:                        return "Hashing too many sequences";
      29           0 :   case FD_VM_SYSCALL_ERR_INVALID_LENGTH:                         return "InvalidLength";
      30           0 :   case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_DATA_LEN_EXCEEDED:      return "Invoked an instruction with data that is too large"; // truncated
      31           0 :   case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED:      return "Invoked an instruction with too many accounts"; // truncated
      32           0 :   case FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED: return "Invoked an instruction with too many account info's"; // truncated
      33           0 :   case FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE:                      return "InvalidAttribute";
      34           0 :   case FD_VM_SYSCALL_ERR_INVALID_POINTER:                        return "Invalid pointer";
      35           0 :   case FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW:                    return "Arithmetic overflow";
      36             : 
      37           0 :   case FD_VM_SYSCALL_ERR_INSTR_ERR:                              return "Instruction error";
      38           0 :   case FD_VM_SYSCALL_ERR_INVALID_PDA:                            return "Invalid PDA";
      39           0 :   case FD_VM_SYSCALL_ERR_COMPUTE_BUDGET_EXCEEDED:                return "Compute budget exceeded";
      40           0 :   case FD_VM_SYSCALL_ERR_SEGFAULT:                               return "Segmentation fault";
      41           0 :   case FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME:                        return "Syscall executed outside runtime";
      42             : 
      43             : 
      44           0 :   case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS:                return "Syscall error: Invalid parameters.";
      45           0 :   case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS:            return "Syscall error: Invalid endianness.";
      46             : 
      47           0 :   default: break;
      48           0 :   }
      49             : 
      50           0 :   return "";
      51           0 : }
      52             : 
      53             : /* fd_vm_ebpf_strerror() returns the error message corresponding to err,
      54             :    intended to be logged by log_collector, or an empty string if the error code
      55             :    should be omitted in logs for whatever reason.
      56             :    See also fd_log_collector_program_failure(). */
      57             : char const *
      58           0 : fd_vm_ebpf_strerror( int err ) {
      59             : 
      60           0 :   switch( err ) {
      61             : 
      62           0 :   case FD_VM_ERR_EBPF_ELF_ERROR:                   return "ELF error"; // truncated
      63           0 :   case FD_VM_ERR_EBPF_FUNCTION_ALREADY_REGISTERED: return "function was already registered"; // truncated
      64           0 :   case FD_VM_ERR_EBPF_CALL_DEPTH_EXCEEDED:         return "exceeded max BPF to BPF call depth";
      65           0 :   case FD_VM_ERR_EBPF_EXIT_ROOT_CALL_FRAME:        return "attempted to exit root call frame";
      66           0 :   case FD_VM_ERR_EBPF_DIVIDE_BY_ZERO:              return "divide by zero at BPF instruction";
      67           0 :   case FD_VM_ERR_EBPF_DIVIDE_OVERFLOW:             return "division overflow at BPF instruction";
      68           0 :   case FD_VM_ERR_EBPF_EXECUTION_OVERRUN:           return "attempted to execute past the end of the text segment at BPF instruction";
      69           0 :   case FD_VM_ERR_EBPF_CALL_OUTSIDE_TEXT_SEGMENT:   return "callx attempted to call outside of the text segment";
      70           0 :   case FD_VM_ERR_EBPF_EXCEEDED_MAX_INSTRUCTIONS:   return "exceeded CUs meter at BPF instruction";
      71           0 :   case FD_VM_ERR_EBPF_JIT_NOT_COMPILED:            return "program has not been JIT-compiled";
      72           0 :   case FD_VM_ERR_EBPF_INVALID_VIRTUAL_ADDRESS:     return "invalid virtual address"; // truncated
      73           0 :   case FD_VM_ERR_EBPF_INVALID_MEMORY_REGION:       return "Invalid memory region at index"; // truncated
      74           0 :   case FD_VM_ERR_EBPF_ACCESS_VIOLATION:            return "Access violation"; // truncated
      75           0 :   case FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION:      return "Access violation in stack frame"; // truncated
      76           0 :   case FD_VM_ERR_EBPF_INVALID_INSTRUCTION:         return "invalid BPF instruction";
      77           0 :   case FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION:     return "unsupported BPF instruction";
      78           0 :   case FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT:      return "Compilation exhausted text segment at BPF instruction"; // truncated
      79           0 :   case FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED:      return "Libc calling returned error code"; // truncated
      80           0 :   case FD_VM_ERR_EBPF_VERIFIER_ERROR:              return "Verifier error"; // truncated
      81           0 :   case FD_VM_ERR_EBPF_SYSCALL_ERROR:               return ""; // handled explicitly via fd_vm_syscall_strerror()
      82             : 
      83           0 :   default: break;
      84           0 :   }
      85             : 
      86           0 :   return "";
      87           0 : }
      88             : 
      89             : /* fd_vm_strerror() returns the error message corresponding to err, used internally
      90             :    for system logs, NOT for log_collector / transaction logs. */
      91             : char const *
      92          81 : fd_vm_strerror( int err ) {
      93             : 
      94          81 :   switch( err ) {
      95             : 
      96             :   /* "Standard" Firedancer error codes */
      97             : 
      98           3 :   case FD_VM_SUCCESS:   return "SUCCESS success";
      99           3 :   case FD_VM_ERR_INVAL: return "INVAL invalid request";
     100           3 :   case FD_VM_ERR_UNSUP: return "UNSUP unsupported request";
     101           3 :   case FD_VM_ERR_PERM:  return "PERM unauthorized request";
     102           3 :   case FD_VM_ERR_FULL:  return "FULL storage full";
     103           3 :   case FD_VM_ERR_EMPTY: return "EMPTY nothing to do";
     104           3 :   case FD_VM_ERR_IO:    return "IO input-output error";
     105           3 :   case FD_VM_ERR_AGAIN: return "AGAIN try again later";
     106             : 
     107             :   /* VM exec error codes */
     108             : 
     109           3 :   case FD_VM_ERR_SIGTEXT:     return "SIGTEXT illegal program counter";
     110           3 :   case FD_VM_ERR_SIGSPLIT:    return "SIGSPLIT split multiword instruction";
     111           3 :   case FD_VM_ERR_SIGCALL:     return "unsupported BPF instruction";
     112           3 :   case FD_VM_ERR_SIGSTACK:    return "SIGSTACK call depth limit exceeded";
     113           3 :   case FD_VM_ERR_SIGILL:      return "SIGILL illegal instruction";
     114           3 :   case FD_VM_ERR_SIGSEGV:     return "SIGSEGV illegal memory address";
     115           3 :   case FD_VM_ERR_SIGBUS:      return "SIGBUS misaligned memory address";
     116           3 :   case FD_VM_ERR_SIGRDONLY:   return "SIGRDONLY illegal write";
     117           3 :   case FD_VM_ERR_SIGCOST:     return "SIGCOST compute unit limit exceeded";
     118           0 :   case FD_VM_ERR_SIGFPE:      return "SIGFPE division by zero";
     119           0 :   case FD_VM_ERR_SIGFPE_OF:   return "SIGFPE division overflow";
     120           0 :   case FD_VM_ERR_SIGSYSCALL:  return "SIGSYSCALL syscall error";
     121           0 :   case FD_VM_ERR_SIGABORT:    return "SIGABORT abort error";
     122             : 
     123             :   /* VM validate error codes */
     124             : 
     125           3 :   case FD_VM_ERR_INVALID_OPCODE:    return "INVALID_OPCODE detected an invalid opcode";
     126           3 :   case FD_VM_ERR_INVALID_SRC_REG:   return "INVALID_SRC_REG detected an invalid source register";
     127           3 :   case FD_VM_ERR_INVALID_DST_REG:   return "INVALID_DST_REG detected an invalid destination register";
     128           3 :   case FD_VM_ERR_INF_LOOP:          return "INF_LOOP detected an infinite loop";
     129           3 :   case FD_VM_ERR_JMP_OUT_OF_BOUNDS: return "JMP_OUT_OF_BOUNDS detected an out of bounds jump";
     130           3 :   case FD_VM_ERR_JMP_TO_ADDL_IMM:   return "JMP_TO_ADDL_IMM detected a jump to an addl imm";
     131           3 :   case FD_VM_ERR_INVALID_END_IMM:   return "INVALID_END_IMM detected an invalid immediate for an endianness conversion instruction";
     132           3 :   case FD_VM_ERR_INCOMPLETE_LDQ:    return "INCOMPLETE_LDQ detected an incomplete ldq at program end";
     133           3 :   case FD_VM_ERR_LDQ_NO_ADDL_IMM:   return "LDQ_NO_ADDL_IMM detected a ldq without an addl imm following it";
     134           3 :   case FD_VM_ERR_NO_SUCH_EXT_CALL:  return "NO_SUCH_EXT_CALL detected a call imm with no function was registered for that immediate";
     135           0 :   case FD_VM_ERR_INVALID_REG:       return "INVALID_REG detected an invalid register number in a callx instruction";
     136           0 :   case FD_VM_ERR_BAD_TEXT:          return "BAD_TEXT detected a bad text section";
     137           0 :   case FD_VM_SH_OVERFLOW:           return "SH_OVERFLOW detected a shift overflow in an instruction";
     138           0 :   case FD_VM_TEXT_SZ_UNALIGNED:     return "TEXT_SZ_UNALIGNED detected an unaligned text section size (not a multiple of 8)";
     139             : 
     140           0 :   default: break;
     141          81 :   }
     142             : 
     143           0 :   return "UNKNOWN probably not a FD_VM_ERR code";
     144          81 : }
     145             : 
     146             : /* FIXME: add a pedantic version of this validation that does things
     147             :    like:
     148             :   - only 0 imms when the instruction does not use an imm
     149             :   - same as above but for src/dst reg, offset */
     150             : /* FIXME: HANDLING OF LDQ ON NEWER SBPF VERSUS OLDER SBPF (AND WITH CALL
     151             :    REG) */
     152             : /* FIXME: LINK TO SOLANA CODE VALIDATE AND DOUBLE CHECK THIS BEHAVES
     153             :    IDENTICALLY! */
     154             : 
     155             : int
     156        7848 : fd_vm_validate( fd_vm_t const * vm ) {
     157             : 
     158        7848 :   ulong sbpf_version = vm->sbpf_version;
     159             : 
     160             :   /* A mapping of all the possible 1-byte sBPF opcodes to their
     161             :      validation criteria. */
     162             : 
     163   644984100 : # define FD_VALID               ((uchar)0) /* Valid opcode */
     164        7848 : # define FD_CHECK_JMP_V3        ((uchar)1) /* Validation should check that the instruction is a valid jump (v3+) */
     165       11676 : # define FD_CHECK_END           ((uchar)2) /* Validation should check that the instruction is a valid endianness conversion */
     166      192042 : # define FD_CHECK_ST            ((uchar)3) /* Validation should check that the instruction is a valid store */
     167        7848 : # define FD_CHECK_LDQ           ((uchar)4) /* Validation should check that the instruction is a valid load-quad */
     168    64548912 : # define FD_CHECK_DIV           ((uchar)5) /* Validation should check that the instruction is a valid division by immediate */
     169    48331824 : # define FD_CHECK_SH32          ((uchar)6) /* Validation should check that the immediate is a valid 32-bit shift exponent */
     170    48356103 : # define FD_CHECK_SH64          ((uchar)7) /* Validation should check that the immediate is a valid 64-bit shift exponent */
     171     1635756 : # define FD_INVALID             ((uchar)8) /* The opcode is invalid */
     172       11985 : # define FD_CHECK_CALL_REG      ((uchar)9) /* Validation should check that callx has valid register number */
     173       12087 : # define FD_CHECK_CALL_REG_DEPR ((uchar)10) /* Older / deprecated FD_CHECK_CALLX */
     174        7848 : # define FD_CHECK_CALL_IMM      ((uchar)11) /* Check call against functions registry */
     175        7848 : # define FD_CHECK_SYSCALL       ((uchar)12) /* Check call against syscalls registry */
     176       22431 : # define FD_CHECK_JMP_V0        ((uchar)13) /* Validation should check that the instruction is a valid jump (v0..v2) */
     177             : 
     178        7848 :   uchar FD_CHECK_JMP = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_JMP_V3 : FD_CHECK_JMP_V0;
     179             : 
     180        7848 :   uchar validation_map[ 256 ] = {
     181             :     /* 0x00 */ FD_INVALID,    /* 0x01 */ FD_INVALID,    /* 0x02 */ FD_INVALID,    /* 0x03 */ FD_INVALID,
     182             :     /* 0x04 */ FD_VALID,      /* 0x05 */ FD_CHECK_JMP,  /* 0x06 */ FD_INVALID,    /* 0x07 */ FD_VALID,
     183             :     /* 0x08 */ FD_INVALID,    /* 0x09 */ FD_INVALID,    /* 0x0a */ FD_INVALID,    /* 0x0b */ FD_INVALID,
     184             :     /* 0x0c */ FD_VALID,      /* 0x0d */ FD_INVALID,    /* 0x0e */ FD_INVALID,    /* 0x0f */ FD_VALID,
     185             :     /* 0x10 */ FD_INVALID,    /* 0x11 */ FD_INVALID,    /* 0x12 */ FD_INVALID,    /* 0x13 */ FD_INVALID,
     186             :     /* 0x14 */ FD_VALID,      /* 0x15 */ FD_CHECK_JMP,  /* 0x16 */ FD_INVALID,    /* 0x17 */ FD_VALID,
     187             :     /* 0x18 */ FD_INVALID,    /* 0x19 */ FD_INVALID,    /* 0x1a */ FD_INVALID,    /* 0x1b */ FD_INVALID,
     188             :     /* 0x1c */ FD_VALID,      /* 0x1d */ FD_CHECK_JMP,  /* 0x1e */ FD_INVALID,    /* 0x1f */ FD_VALID,
     189             :     /* 0x20 */ FD_INVALID,    /* 0x21 */ FD_INVALID,    /* 0x22 */ FD_INVALID,    /* 0x23 */ FD_INVALID,
     190             :     /* 0x24 */ FD_INVALID,    /* 0x25 */ FD_CHECK_JMP,  /* 0x26 */ FD_INVALID,    /* 0x27 */ FD_CHECK_ST,
     191             :     /* 0x28 */ FD_INVALID,    /* 0x29 */ FD_INVALID,    /* 0x2a */ FD_INVALID,    /* 0x2b */ FD_INVALID,
     192             :     /* 0x2c */ FD_VALID,      /* 0x2d */ FD_CHECK_JMP,  /* 0x2e */ FD_INVALID,    /* 0x2f */ FD_CHECK_ST,
     193             :     /* 0x30 */ FD_INVALID,    /* 0x31 */ FD_INVALID,    /* 0x32 */ FD_INVALID,    /* 0x33 */ FD_INVALID,
     194             :     /* 0x34 */ FD_INVALID,    /* 0x35 */ FD_CHECK_JMP,  /* 0x36 */ FD_VALID,      /* 0x37 */ FD_CHECK_ST,
     195             :     /* 0x38 */ FD_INVALID,    /* 0x39 */ FD_INVALID,    /* 0x3a */ FD_INVALID,    /* 0x3b */ FD_INVALID,
     196             :     /* 0x3c */ FD_VALID,      /* 0x3d */ FD_CHECK_JMP,  /* 0x3e */ FD_VALID,      /* 0x3f */ FD_CHECK_ST,
     197             :     /* 0x40 */ FD_INVALID,    /* 0x41 */ FD_INVALID,    /* 0x42 */ FD_INVALID,    /* 0x43 */ FD_INVALID,
     198             :     /* 0x44 */ FD_VALID,      /* 0x45 */ FD_CHECK_JMP,  /* 0x46 */ FD_CHECK_DIV,  /* 0x47 */ FD_VALID,
     199             :     /* 0x48 */ FD_INVALID,    /* 0x49 */ FD_INVALID,    /* 0x4a */ FD_INVALID,    /* 0x4b */ FD_INVALID,
     200             :     /* 0x4c */ FD_VALID,      /* 0x4d */ FD_CHECK_JMP,  /* 0x4e */ FD_VALID,      /* 0x4f */ FD_VALID,
     201             :     /* 0x50 */ FD_INVALID,    /* 0x51 */ FD_INVALID,    /* 0x52 */ FD_INVALID,    /* 0x53 */ FD_INVALID,
     202             :     /* 0x54 */ FD_VALID,      /* 0x55 */ FD_CHECK_JMP,  /* 0x56 */ FD_CHECK_DIV,  /* 0x57 */ FD_VALID,
     203             :     /* 0x58 */ FD_INVALID,    /* 0x59 */ FD_INVALID,    /* 0x5a */ FD_INVALID,    /* 0x5b */ FD_INVALID,
     204             :     /* 0x5c */ FD_VALID,      /* 0x5d */ FD_CHECK_JMP,  /* 0x5e */ FD_VALID,      /* 0x5f */ FD_VALID,
     205             :     /* 0x60 */ FD_INVALID,    /* 0x61 */ FD_INVALID,    /* 0x62 */ FD_INVALID,    /* 0x63 */ FD_INVALID,
     206             :     /* 0x64 */ FD_CHECK_SH32, /* 0x65 */ FD_CHECK_JMP,  /* 0x66 */ FD_CHECK_DIV,  /* 0x67 */ FD_CHECK_SH64,
     207             :     /* 0x68 */ FD_INVALID,    /* 0x69 */ FD_INVALID,    /* 0x6a */ FD_INVALID,    /* 0x6b */ FD_INVALID,
     208             :     /* 0x6c */ FD_VALID,      /* 0x6d */ FD_CHECK_JMP,  /* 0x6e */ FD_VALID,      /* 0x6f */ FD_VALID,
     209             :     /* 0x70 */ FD_INVALID,    /* 0x71 */ FD_INVALID,    /* 0x72 */ FD_INVALID,    /* 0x73 */ FD_INVALID,
     210             :     /* 0x74 */ FD_CHECK_SH32, /* 0x75 */ FD_CHECK_JMP,  /* 0x76 */ FD_CHECK_DIV,  /* 0x77 */ FD_CHECK_SH64,
     211             :     /* 0x78 */ FD_INVALID,    /* 0x79 */ FD_INVALID,    /* 0x7a */ FD_INVALID,    /* 0x7b */ FD_INVALID,
     212             :     /* 0x7c */ FD_VALID,      /* 0x7d */ FD_CHECK_JMP,  /* 0x7e */ FD_VALID,      /* 0x7f */ FD_VALID,
     213             :     /* 0x80 */ FD_INVALID,    /* 0x81 */ FD_INVALID,    /* 0x82 */ FD_INVALID,    /* 0x83 */ FD_INVALID,
     214             :     /* 0x84 */ FD_INVALID,    /* 0x85 */ FD_CHECK_CALL_IMM,/*0x86*/FD_VALID,      /* 0x87 */ FD_CHECK_ST,
     215             :     /* 0x88 */ FD_INVALID,    /* 0x89 */ FD_INVALID,    /* 0x8a */ FD_INVALID,    /* 0x8b */ FD_INVALID,
     216             :     /* 0x8c */ FD_VALID,      /* 0x8d */ FD_CHECK_CALL_REG,/*0x8e*/FD_VALID,      /* 0x8f */ FD_CHECK_ST,
     217             :     /* 0x90 */ FD_INVALID,    /* 0x91 */ FD_INVALID,    /* 0x92 */ FD_INVALID,    /* 0x93 */ FD_INVALID,
     218             :     /* 0x94 */ FD_INVALID,    /* 0x95 */ FD_CHECK_SYSCALL,/*0x96*/ FD_VALID,      /* 0x97 */ FD_CHECK_ST,
     219             :     /* 0x98 */ FD_INVALID,    /* 0x99 */ FD_INVALID,    /* 0x9a */ FD_INVALID,    /* 0x9b */ FD_INVALID,
     220             :     /* 0x9c */ FD_VALID,      /* 0x9d */ FD_VALID,      /* 0x9e */ FD_VALID,      /* 0x9f */ FD_CHECK_ST,
     221             :     /* 0xa0 */ FD_INVALID,    /* 0xa1 */ FD_INVALID,    /* 0xa2 */ FD_INVALID,    /* 0xa3 */ FD_INVALID,
     222             :     /* 0xa4 */ FD_VALID,      /* 0xa5 */ FD_CHECK_JMP,  /* 0xa6 */ FD_INVALID,    /* 0xa7 */ FD_VALID,
     223             :     /* 0xa8 */ FD_INVALID,    /* 0xa9 */ FD_INVALID,    /* 0xaa */ FD_INVALID,    /* 0xab */ FD_INVALID,
     224             :     /* 0xac */ FD_VALID,      /* 0xad */ FD_CHECK_JMP,  /* 0xae */ FD_INVALID,    /* 0xaf */ FD_VALID,
     225             :     /* 0xb0 */ FD_INVALID,    /* 0xb1 */ FD_INVALID,    /* 0xb2 */ FD_INVALID,    /* 0xb3 */ FD_INVALID,
     226             :     /* 0xb4 */ FD_VALID,      /* 0xb5 */ FD_CHECK_JMP,  /* 0xb6 */ FD_VALID,      /* 0xb7 */ FD_VALID,
     227             :     /* 0xb8 */ FD_INVALID,    /* 0xb9 */ FD_INVALID,    /* 0xba */ FD_INVALID,    /* 0xbb */ FD_INVALID,
     228             :     /* 0xbc */ FD_VALID,      /* 0xbd */ FD_CHECK_JMP,  /* 0xbe */ FD_VALID,      /* 0xbf */ FD_VALID,
     229             :     /* 0xc0 */ FD_INVALID,    /* 0xc1 */ FD_INVALID,    /* 0xc2 */ FD_INVALID,    /* 0xc3 */ FD_INVALID,
     230             :     /* 0xc4 */ FD_CHECK_SH32, /* 0xc5 */ FD_CHECK_JMP,  /* 0xc6 */ FD_CHECK_DIV,  /* 0xc7 */ FD_CHECK_SH64,
     231             :     /* 0xc8 */ FD_INVALID,    /* 0xc9 */ FD_INVALID,    /* 0xca */ FD_INVALID,    /* 0xcb */ FD_INVALID,
     232             :     /* 0xcc */ FD_VALID,      /* 0xcd */ FD_CHECK_JMP,  /* 0xce */ FD_VALID,      /* 0xcf */ FD_VALID,
     233             :     /* 0xd0 */ FD_INVALID,    /* 0xd1 */ FD_INVALID,    /* 0xd2 */ FD_INVALID,    /* 0xd3 */ FD_INVALID,
     234             :     /* 0xd4 */ FD_INVALID,    /* 0xd5 */ FD_CHECK_JMP,  /* 0xd6 */ FD_CHECK_DIV,  /* 0xd7 */ FD_INVALID,
     235             :     /* 0xd8 */ FD_INVALID,    /* 0xd9 */ FD_INVALID,    /* 0xda */ FD_INVALID,    /* 0xdb */ FD_INVALID,
     236             :     /* 0xdc */ FD_CHECK_END,  /* 0xdd */ FD_CHECK_JMP,  /* 0xde */ FD_VALID,      /* 0xdf */ FD_INVALID,
     237             :     /* 0xe0 */ FD_INVALID,    /* 0xe1 */ FD_INVALID,    /* 0xe2 */ FD_INVALID,    /* 0xe3 */ FD_INVALID,
     238             :     /* 0xe4 */ FD_INVALID,    /* 0xe5 */ FD_INVALID,    /* 0xe6 */ FD_CHECK_DIV,  /* 0xe7 */ FD_INVALID,
     239             :     /* 0xe8 */ FD_INVALID,    /* 0xe9 */ FD_INVALID,    /* 0xea */ FD_INVALID,    /* 0xeb */ FD_INVALID,
     240             :     /* 0xec */ FD_INVALID,    /* 0xed */ FD_INVALID,    /* 0xee */ FD_VALID,      /* 0xef */ FD_INVALID,
     241             :     /* 0xf0 */ FD_INVALID,    /* 0xf1 */ FD_INVALID,    /* 0xf2 */ FD_INVALID,    /* 0xf3 */ FD_INVALID,
     242             :     /* 0xf4 */ FD_INVALID,    /* 0xf5 */ FD_INVALID,    /* 0xf6 */ FD_CHECK_DIV,  /* 0xf7 */ FD_VALID,
     243             :     /* 0xf8 */ FD_INVALID,    /* 0xf9 */ FD_INVALID,    /* 0xfa */ FD_INVALID,    /* 0xfb */ FD_INVALID,
     244             :     /* 0xfc */ FD_INVALID,    /* 0xfd */ FD_INVALID,    /* 0xfe */ FD_VALID,      /* 0xff */ FD_INVALID,
     245        7848 :   };
     246             : 
     247             :   /* SIMD-0173: LDDW */
     248        7848 :   validation_map[ 0x18 ] = FD_VM_SBPF_ENABLE_LDDW(sbpf_version) ? FD_CHECK_LDQ : FD_INVALID;
     249        7848 :   validation_map[ 0xf7 ] = FD_VM_SBPF_ENABLE_LDDW(sbpf_version) ? FD_INVALID   : FD_VALID; /* HOR64 */
     250             : 
     251             :   /* SIMD-0173: LE */
     252        7848 :   validation_map[ 0xd4 ] = FD_VM_SBPF_ENABLE_LE  (sbpf_version) ? FD_CHECK_END : FD_INVALID;
     253             : 
     254             :   /* SIMD-0173: LDXW, STW, STXW */
     255        7848 :   validation_map[ 0x61 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     256        7848 :   validation_map[ 0x62 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     257        7848 :   validation_map[ 0x63 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     258        7848 :   validation_map[ 0x8c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_INVALID;
     259        7848 :   validation_map[ 0x87 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID; /* VALID because it's NEG64 */
     260        7848 :   validation_map[ 0x8f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_INVALID;
     261             : 
     262             :   /* SIMD-0173: LDXH, STH, STXH */
     263        7848 :   validation_map[ 0x69 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     264        7848 :   validation_map[ 0x6a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     265        7848 :   validation_map[ 0x6b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     266        7848 :   validation_map[ 0x3c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     267        7848 :   validation_map[ 0x37 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_CHECK_DIV;
     268        7848 :   validation_map[ 0x3f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     269             : 
     270             :   /* SIMD-0173: LDXB, STB, STXB */
     271        7848 :   validation_map[ 0x71 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     272        7848 :   validation_map[ 0x72 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     273        7848 :   validation_map[ 0x73 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     274        7848 :   validation_map[ 0x2c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     275        7848 :   validation_map[ 0x27 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     276        7848 :   validation_map[ 0x2f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     277             : 
     278             :   /* SIMD-0173: LDXDW, STDW, STXDW */
     279        7848 :   validation_map[ 0x79 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     280        7848 :   validation_map[ 0x7a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     281        7848 :   validation_map[ 0x7b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     282        7848 :   validation_map[ 0x9c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     283        7848 :   validation_map[ 0x97 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_CHECK_DIV;
     284        7848 :   validation_map[ 0x9f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     285             : 
     286             :   /* SIMD-0173: CALLX */
     287        7848 :   validation_map[ 0x8d ] = FD_VM_SBPF_CALLX_USES_SRC_REG(sbpf_version) ? FD_CHECK_CALL_REG : FD_CHECK_CALL_REG_DEPR;
     288             : 
     289             :   /* SIMD-0174: MUL, DIV, MOD */
     290        7848 :   validation_map[ 0x24 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_VALID;
     291        7848 :   validation_map[ 0x34 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
     292        7848 :   validation_map[ 0x94 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
     293             :   /* note: 0x?c, 0x?7, 0x?f should not be overwritten because they're now load/store ix */
     294             : 
     295             :   /* SIMD-0174: NEG */
     296        7848 :   validation_map[ 0x84 ] = FD_VM_SBPF_ENABLE_NEG (sbpf_version) ? FD_VALID : FD_INVALID;
     297             :   /* note: 0x87 should not be overwritten because it was NEG64 and it becomes STW */
     298             : 
     299             :   /* SIMD-0174: MUL, DIV, MOD */
     300        7848 :   validation_map[ 0x36 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* UHMUL64 */
     301        7848 :   validation_map[ 0x3e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     302        7848 :   validation_map[ 0x46 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV32 */
     303        7848 :   validation_map[ 0x4e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     304        7848 :   validation_map[ 0x56 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV64 */
     305        7848 :   validation_map[ 0x5e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     306        7848 :   validation_map[ 0x66 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM32 */
     307        7848 :   validation_map[ 0x6e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     308        7848 :   validation_map[ 0x76 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM64 */
     309        7848 :   validation_map[ 0x7e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     310        7848 :   validation_map[ 0x86 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* LMUL32 */
     311        7848 :   validation_map[ 0x8e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     312        7848 :   validation_map[ 0x96 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* LMUL64 */
     313        7848 :   validation_map[ 0x9e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     314        7848 :   validation_map[ 0xb6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* SHMUL64 */
     315        7848 :   validation_map[ 0xbe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     316        7848 :   validation_map[ 0xc6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV32 */
     317        7848 :   validation_map[ 0xce ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     318        7848 :   validation_map[ 0xd6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV64 */
     319        7848 :   validation_map[ 0xde ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     320        7848 :   validation_map[ 0xe6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM32 */
     321        7848 :   validation_map[ 0xee ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     322        7848 :   validation_map[ 0xf6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM64 */
     323        7848 :   validation_map[ 0xfe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     324             : 
     325             :   /* SIMD-0178: static syscalls */
     326        7848 :   validation_map[ 0x85 ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_CALL_IMM : FD_VALID;
     327        7848 :   validation_map[ 0x95 ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_CHECK_SYSCALL : FD_VALID;
     328        7848 :   validation_map[ 0x9d ] = FD_VM_SBPF_STATIC_SYSCALLS (sbpf_version) ? FD_VALID : FD_INVALID;
     329             : 
     330             :   /* FIXME: These checks are not necessary assuming fd_vm_t is populated by metadata
     331             :      generated in fd_sbpf_elf_peek (which performs these checks). But there is no guarantee, and
     332             :      this non-guarantee is (rightfully) exploited by the fuzz harnesses.
     333             :      Agave doesn't perform these checks explicitly due to Rust's guarantees  */
     334        7848 :   if( FD_UNLIKELY( vm->text_sz / 8UL != vm->text_cnt ||
     335        7848 :                    (const uchar *)vm->text < vm->rodata ||
     336        7848 :                    (ulong)vm->text > (ulong)vm->text + vm->text_sz || /* Overflow chk */
     337        7848 :                    (const uchar *)vm->text + vm->text_sz > vm->rodata + vm->rodata_sz ) )
     338           0 :     return FD_VM_ERR_BAD_TEXT;
     339             : 
     340        7848 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( vm->text_sz, 8UL ) ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L109 */
     341           0 :     return FD_VM_TEXT_SZ_UNALIGNED;
     342             : 
     343        7848 :   if ( FD_UNLIKELY( vm->text_cnt == 0UL ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L112 */
     344           0 :     return FD_VM_ERR_EMPTY;
     345             : 
     346        7848 :   ulong function_start = 0UL;
     347        7848 :   ulong function_next = 0UL;
     348        7848 :   if( FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) ) {
     349           0 :     function_next = fd_sbpf_calldests_const_iter_init( vm->calldests );
     350           0 :     FD_TEST( function_next==0UL ); /* assert that the first function always starts at 0. */
     351           0 :   }
     352             : 
     353        7848 :   ulong const * text     = vm->text;
     354        7848 :   ulong         text_cnt = vm->text_cnt;
     355   805362735 :   for( ulong i=0UL; i<text_cnt; i++ ) {
     356   805357341 :     fd_sbpf_instr_t instr = fd_sbpf_instr( text[i] );
     357             : 
     358             :     /* Validate functions, stored in vm->calldests.
     359             :        https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L253-L263
     360             :        At the start of a function, we check that the function ends with JA(0x05) or RETURN(0x9D).
     361             :        As a side effect, the range of the function is [function_start, function_next-1],
     362             :        used to validate jumps.
     363             :        Note that the first function always starts at 0, and similarly the last function
     364             :        always ends at text_cnt-1. */
     365   805357341 :     if( FD_UNLIKELY( FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) && i==function_next ) ) {
     366           0 :       function_start = function_next;
     367           0 :       function_next = fd_sbpf_calldests_const_iter_next( vm->calldests, function_start );
     368           0 :       if( fd_sbpf_calldests_const_iter_done( function_next ) ) {
     369           0 :         function_next = text_cnt;
     370           0 :       }
     371           0 :       fd_sbpf_instr_t end_instr = fd_sbpf_instr( text[function_next-1] );
     372           0 :       if( FD_UNLIKELY( end_instr.opcode.raw!=0x05 && end_instr.opcode.raw!=0x9D ) ) {
     373           0 :         return FD_VM_INVALID_FUNCTION;
     374           0 :       }
     375           0 :     }
     376             : 
     377   805357341 :     uchar validation_code = validation_map[ instr.opcode.raw ];
     378   805357341 :     switch( validation_code ) {
     379             : 
     380   644296056 :     case FD_VALID: break;
     381             : 
     382             :     /* Store ops are special because they allow dreg==r10.
     383             :        We use a special validation_code, used later in the
     384             :        "Check registers" section.
     385             :        But there's nothing to do at this time. */
     386        3690 :     case FD_CHECK_ST: break;
     387             : 
     388        6735 :     case FD_CHECK_JMP_V0: {
     389        6735 :       long jmp_dst = (long)i + (long)instr.offset + 1L;
     390        6735 :       if( FD_UNLIKELY( (jmp_dst<0) | (jmp_dst>=(long)text_cnt)                          ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
     391             :       //FIXME: this shouldn't be here?
     392        6597 :       if( FD_UNLIKELY( fd_sbpf_instr( text[ jmp_dst ] ).opcode.raw==FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_JMP_TO_ADDL_IMM;
     393        6597 :       break;
     394        6597 :     }
     395             : 
     396        6597 :     case FD_CHECK_JMP_V3: {
     397           0 :       long jmp_dst = (long)i + (long)instr.offset + 1L;
     398           0 :       if( FD_UNLIKELY( (jmp_dst<(long)function_start) | (jmp_dst>=(long)function_next) ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
     399           0 :       break;
     400           0 :     }
     401             : 
     402          96 :     case FD_CHECK_END: {
     403          96 :       if( FD_UNLIKELY( !((instr.imm==16) | (instr.imm==32) | (instr.imm==64)) ) ) return FD_VM_ERR_INVALID_END_IMM;
     404          78 :       break;
     405          96 :     }
     406             : 
     407             :     /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L244 */
     408        1341 :     case FD_CHECK_LDQ: {
     409             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L131 */
     410        1341 :       if( FD_UNLIKELY( (i+1UL)>=text_cnt ) ) return FD_VM_ERR_INCOMPLETE_LDQ;
     411             : 
     412             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L137-L139 */
     413        1341 :       fd_sbpf_instr_t addl_imm = fd_sbpf_instr( text[ i+1UL ] );
     414        1341 :       if( FD_UNLIKELY( addl_imm.opcode.raw!=FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_LDQ_NO_ADDL_IMM;
     415             : 
     416             :       /* FIXME: SET A BIT MAP HERE OF ADDL_IMM TO DENOTE * AS FORBIDDEN
     417             :          BRANCH TARGETS OF CALL_REG?? */
     418             : 
     419        1341 :       i++; /* Skip the addl imm */
     420        1341 :       break;
     421        1341 :     }
     422             : 
     423    64406880 :     case FD_CHECK_DIV: {
     424    64406880 :       if( FD_UNLIKELY( instr.imm==0 ) ) return FD_VM_ERR_SIGFPE;
     425    64406820 :       break;
     426    64406880 :     }
     427             : 
     428    64406820 :     case FD_CHECK_SH32: {
     429    48308280 :       if( FD_UNLIKELY( instr.imm>=32 ) ) return FD_VM_SH_OVERFLOW;
     430    48308250 :       break;
     431    48308280 :     }
     432             : 
     433    48332559 :     case FD_CHECK_SH64: {
     434    48332559 :       if( FD_UNLIKELY( instr.imm>=64 ) ) return FD_VM_SH_OVERFLOW;
     435    48332517 :       break;
     436    48332559 :     }
     437             : 
     438             :     /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L220 */
     439    48332517 :     case FD_CHECK_CALL_REG: {
     440          21 :       if( FD_UNLIKELY( instr.src_reg > 9 ) ) {
     441           9 :         return FD_VM_ERR_INVALID_REG;
     442           9 :       }
     443          12 :       break;
     444          21 :     }
     445         507 :     case FD_CHECK_CALL_REG_DEPR: {
     446         507 :       if( FD_UNLIKELY( instr.imm > 9 ) ) {
     447           9 :         return FD_VM_ERR_INVALID_REG;
     448           9 :       }
     449         498 :       break;
     450         507 :     }
     451             : 
     452             :     /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L411-L418 */
     453         498 :     case FD_CHECK_CALL_IMM: {
     454           0 :       ulong target_pc = (ulong)( fd_long_sat_add( (long)i, fd_long_sat_add( (long)(int)instr.imm, 1 ) ) );
     455           0 :       if( FD_UNLIKELY( target_pc>=text_cnt || !fd_sbpf_calldests_test( vm->calldests, target_pc ) ) ) {
     456           0 :         return FD_VM_INVALID_FUNCTION;
     457           0 :       }
     458           0 :       break;
     459           0 :     }
     460             : 
     461             :     /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L423-L428 */
     462           0 :     case FD_CHECK_SYSCALL: {
     463             :       /* check active syscall */
     464           0 :       fd_sbpf_syscalls_t const * syscall = fd_sbpf_syscalls_query_const( vm->syscalls, (ulong)instr.imm, NULL );
     465           0 :       if( FD_UNLIKELY( !syscall ) ) {
     466           0 :         return FD_VM_INVALID_SYSCALL;
     467           0 :       }
     468           0 :       break;
     469           0 :     }
     470             : 
     471        1176 :     case FD_INVALID: default: return FD_VM_ERR_INVALID_OPCODE;
     472   805357341 :     }
     473             : 
     474             :     /* Check registers
     475             :        https://github.com/solana-labs/rbpf/blob/v0.8.5/src/verifier.rs#L177 */
     476             : 
     477             :     /* Source register */
     478   805355859 :     if( FD_UNLIKELY( instr.src_reg>10 ) ) return FD_VM_ERR_INVALID_SRC_REG;
     479             : 
     480             :     /* Special R10 register allowed for ADD64_IMM */
     481   805355469 :     if( instr.dst_reg==10U
     482   805355469 :         && FD_VM_SBPF_DYNAMIC_STACK_FRAMES( sbpf_version )
     483   805355469 :         && instr.opcode.raw == 0x07
     484   805355469 :         && ( instr.imm % FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN )==0 )
     485           9 :         continue;
     486             : 
     487             :     /* Destination register. */
     488   805355460 :     if( FD_UNLIKELY( instr.dst_reg==10U && validation_code != FD_CHECK_ST ) ) return FD_VM_ERR_INVALID_DST_REG;
     489   805355079 :     if( FD_UNLIKELY( instr.dst_reg > 10U ) ) return FD_VM_ERR_INVALID_DST_REG;
     490   805355079 :   }
     491             : 
     492        5394 :   return FD_VM_SUCCESS;
     493        7848 : }
     494             : 
     495             : FD_FN_CONST ulong
     496         411 : fd_vm_align( void ) {
     497         411 :   return FD_VM_ALIGN;
     498         411 : }
     499             : 
     500             : FD_FN_CONST ulong
     501         201 : fd_vm_footprint( void ) {
     502         201 :   return FD_VM_FOOTPRINT;
     503         201 : }
     504             : 
     505             : void *
     506         201 : fd_vm_new( void * shmem ) {
     507             : 
     508         201 :   if( FD_UNLIKELY( !shmem ) ) {
     509           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     510           0 :     return NULL;
     511           0 :   }
     512             : 
     513         201 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     514           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     515           0 :     return NULL;
     516           0 :   }
     517             : 
     518         201 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     519         201 :   fd_memset( vm, 0, fd_vm_footprint() );
     520             : 
     521         201 :   FD_COMPILER_MFENCE();
     522         201 :   FD_VOLATILE( vm->magic ) = FD_VM_MAGIC;
     523         201 :   FD_COMPILER_MFENCE();
     524             : 
     525         201 :   return shmem;
     526         201 : }
     527             : 
     528             : fd_vm_t *
     529         201 : fd_vm_join( void * shmem ) {
     530             : 
     531         201 :   if( FD_UNLIKELY( !shmem ) ) {
     532           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     533           0 :     return NULL;
     534           0 :   }
     535             : 
     536         201 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     537           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     538           0 :     return NULL;
     539           0 :   }
     540             : 
     541         201 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     542             : 
     543         201 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     544           0 :     FD_LOG_WARNING(( "bad magic" ));
     545           0 :     return NULL;
     546           0 :   }
     547             : 
     548         201 :   return vm;
     549         201 : }
     550             : 
     551             : void *
     552           9 : fd_vm_leave( fd_vm_t * vm ) {
     553             : 
     554           9 :   if( FD_UNLIKELY( !vm ) ) {
     555           0 :     FD_LOG_WARNING(( "NULL vm" ));
     556           0 :     return NULL;
     557           0 :   }
     558             : 
     559           9 :   return (void *)vm;
     560           9 : }
     561             : 
     562             : void *
     563           9 : fd_vm_delete( void * shmem ) {
     564             : 
     565           9 :   if( FD_UNLIKELY( !shmem ) ) {
     566           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     567           0 :     return NULL;
     568           0 :   }
     569             : 
     570           9 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     571           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     572           0 :     return NULL;
     573           0 :   }
     574             : 
     575           9 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     576             : 
     577           9 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     578           0 :     FD_LOG_WARNING(( "bad magic" ));
     579           0 :     return NULL;
     580           0 :   }
     581             : 
     582           9 :   FD_COMPILER_MFENCE();
     583           9 :   FD_VOLATILE( vm->magic ) = 0UL;
     584           9 :   FD_COMPILER_MFENCE();
     585             : 
     586           9 :   return (void *)vm;
     587           9 : }
     588             : 
     589             : fd_vm_t *
     590             : fd_vm_init(
     591             :    fd_vm_t * vm,
     592             :    fd_exec_instr_ctx_t *instr_ctx,
     593             :    ulong heap_max,
     594             :    ulong entry_cu,
     595             :    uchar const * rodata,
     596             :    ulong rodata_sz,
     597             :    ulong const * text,
     598             :    ulong text_cnt,
     599             :    ulong text_off,
     600             :    ulong text_sz,
     601             :    ulong entry_pc,
     602             :    ulong * calldests,
     603             :    ulong sbpf_version,
     604             :    fd_sbpf_syscalls_t * syscalls,
     605             :    fd_vm_trace_t * trace,
     606             :    fd_sha256_t * sha,
     607             :    fd_vm_input_region_t * mem_regions,
     608             :    uint mem_regions_cnt,
     609             :    fd_vm_acc_region_meta_t * acc_region_metas,
     610             :    uchar is_deprecated,
     611             :    int direct_mapping,
     612        7854 :    int dump_syscall_to_pb ) {
     613             : 
     614        7854 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     615           0 :     FD_LOG_WARNING(( "NULL vm" ));
     616           0 :     return NULL;
     617           0 :   }
     618             : 
     619        7854 :   if ( FD_UNLIKELY( vm->magic != FD_VM_MAGIC ) ) {
     620           0 :     FD_LOG_WARNING(( "bad magic" ));
     621           0 :     return NULL;
     622           0 :   }
     623             : 
     624        7854 :   if ( FD_UNLIKELY( heap_max > FD_VM_HEAP_MAX ) ) {
     625           0 :     FD_LOG_WARNING(( "heap_max > FD_VM_HEAP_MAX" ));
     626           0 :     return NULL;
     627           0 :   }
     628             : 
     629             :   /* We do support calldests==NULL for tests that do not require
     630             :      program execution, e.g. just testing some interpreter functionality
     631             :      or syscalls.
     632             :      However in v3, if calldests is specified, it must be a valid calldests.
     633             :      In particular, the bit 0 should be always set to 1.
     634             :      This property is derived from:
     635             :      https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/elf.rs#L529
     636             :      and it's used by fd_vm_validate() */
     637        7854 :   if( FD_LIKELY( calldests && FD_VM_SBPF_STATIC_SYSCALLS(sbpf_version) ) ) {
     638           0 :     fd_sbpf_calldests_insert( calldests, 0 );
     639           0 :   }
     640             : 
     641             :   // Set the vm fields
     642        7854 :   vm->instr_ctx = instr_ctx;
     643        7854 :   vm->heap_max = heap_max;
     644        7854 :   vm->entry_cu = entry_cu;
     645        7854 :   vm->rodata = rodata;
     646        7854 :   vm->rodata_sz = rodata_sz;
     647        7854 :   vm->text = text;
     648        7854 :   vm->text_cnt = text_cnt;
     649        7854 :   vm->text_off = text_off;
     650        7854 :   vm->text_sz = text_sz;
     651        7854 :   vm->entry_pc = entry_pc;
     652        7854 :   vm->calldests = calldests;
     653        7854 :   vm->sbpf_version = sbpf_version;
     654        7854 :   vm->syscalls = syscalls;
     655        7854 :   vm->trace = trace;
     656        7854 :   vm->sha = sha;
     657        7854 :   vm->input_mem_regions = mem_regions;
     658        7854 :   vm->input_mem_regions_cnt = mem_regions_cnt;
     659        7854 :   vm->acc_region_metas = acc_region_metas;
     660        7854 :   vm->is_deprecated = is_deprecated;
     661        7854 :   vm->direct_mapping = direct_mapping;
     662        7854 :   vm->stack_frame_size = FD_VM_STACK_FRAME_SZ + ( direct_mapping ? 0UL : FD_VM_STACK_GUARD_SZ );
     663        7854 :   vm->segv_store_vaddr = ULONG_MAX;
     664        7854 :   vm->dump_syscall_to_pb = dump_syscall_to_pb;
     665             : 
     666             :   /* Unpack the configuration */
     667        7854 :   int err = fd_vm_setup_state_for_execution( vm );
     668        7854 :   if( FD_UNLIKELY( err != FD_VM_SUCCESS ) ) {
     669           0 :     return NULL;
     670           0 :   }
     671             : 
     672        7854 :   return vm;
     673        7854 : }
     674             : 
     675             : int
     676        7854 : fd_vm_setup_state_for_execution( fd_vm_t * vm ) {
     677             : 
     678        7854 :   if ( FD_UNLIKELY( !vm ) ) {
     679           0 :     FD_LOG_WARNING(( "NULL vm" ));
     680           0 :     return FD_VM_ERR_INVAL;
     681           0 :   }
     682             : 
     683             :   /* Unpack input and rodata */
     684        7854 :   fd_vm_mem_cfg( vm );
     685             : 
     686             :   /* Initialize registers */
     687             :   /* FIXME: Zero out shadow, stack and heap here? */
     688        7854 :   fd_memset( vm->reg, 0, FD_VM_REG_MAX * sizeof(ulong) );
     689        7854 :   vm->reg[ 1] = FD_VM_MEM_MAP_INPUT_REGION_START;
     690             :   /* https://github.com/solana-labs/rbpf/blob/4ad935be45e5663be23b30cfc750b1ae1ad03c44/src/vm.rs#L326-L333 */
     691        7854 :   vm->reg[10] = FD_VM_MEM_MAP_STACK_REGION_START +
     692        7854 :     ( FD_VM_SBPF_DYNAMIC_STACK_FRAMES( vm->sbpf_version ) ? FD_VM_STACK_MAX : FD_VM_STACK_FRAME_SZ );
     693             :   /* Note: Agave uses r11 as pc, we don't */
     694             : 
     695             :   /* Set execution state */
     696        7854 :   vm->pc        = vm->entry_pc;
     697        7854 :   vm->ic        = 0UL;
     698        7854 :   vm->cu        = vm->entry_cu;
     699        7854 :   vm->frame_cnt = 0UL;
     700             : 
     701        7854 :   vm->heap_sz = 0UL;
     702             : 
     703             :   /* Do NOT reset logs */
     704             : 
     705        7854 :   return FD_VM_SUCCESS;
     706        7854 : }

Generated by: LCOV version 1.14