LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 351 453 77.5 %
Date: 2026-07-11 05:27:41 Functions: 10 11 90.9 %

          Line data    Source code
       1             : #include "fd_vm_private.h"
       2             : #include "../../ballet/sbpf/fd_sbpf_instr.h"
       3             : #include "../../ballet/sbpf/fd_sbpf_opcodes.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 "Invalid parameters.";
      45           0 :   case FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS:            return "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           6 : fd_vm_ebpf_strerror( int err ) {
      59             : 
      60           6 :   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           6 :   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_MEMORY_REGION:       return "Invalid memory region at index"; // truncated
      73           0 :   case FD_VM_ERR_EBPF_ACCESS_VIOLATION:            return "Access violation"; // truncated
      74           0 :   case FD_VM_ERR_EBPF_STACK_ACCESS_VIOLATION:      return "Access violation in stack frame"; // truncated
      75           0 :   case FD_VM_ERR_EBPF_INVALID_INSTRUCTION:         return "invalid BPF instruction";
      76           0 :   case FD_VM_ERR_EBPF_UNSUPPORTED_INSTRUCTION:     return "unsupported BPF instruction";
      77           0 :   case FD_VM_ERR_EBPF_EXHAUSTED_TEXT_SEGMENT:      return "Compilation exhausted text segment at BPF instruction"; // truncated
      78           0 :   case FD_VM_ERR_EBPF_LIBC_INVOCATION_FAILED:      return "Libc calling returned error code"; // truncated
      79           0 :   case FD_VM_ERR_EBPF_VERIFIER_ERROR:              return "Verifier error"; // truncated
      80           0 :   case FD_VM_ERR_EBPF_SYSCALL_ERROR:               return ""; // handled explicitly via fd_vm_syscall_strerror()
      81             : 
      82           0 :   default: break;
      83           6 :   }
      84             : 
      85           0 :   return "";
      86           6 : }
      87             : 
      88             : /* fd_vm_strerror() returns the error message corresponding to err, used internally
      89             :    for system logs, NOT for log_collector / transaction logs. */
      90             : char const *
      91          42 : fd_vm_strerror( int err ) {
      92             : 
      93          42 :   switch( err ) {
      94             : 
      95             :   /* "Standard" Firedancer error codes */
      96             : 
      97           3 :   case FD_VM_SUCCESS:   return "SUCCESS success";
      98           3 :   case FD_VM_ERR_INVAL: return "INVAL invalid request";
      99           3 :   case FD_VM_ERR_UNSUP: return "UNSUP unsupported request";
     100           3 :   case FD_VM_ERR_FULL:  return "FULL storage full";
     101           3 :   case FD_VM_ERR_EMPTY: return "EMPTY nothing to do";
     102           3 :   case FD_VM_ERR_IO:    return "IO input-output error";
     103             : 
     104             :   /* VM exec error codes */
     105             : 
     106           0 :   case FD_VM_ERR_SIGFPE:      return "SIGFPE division by zero";
     107             : 
     108             :   /* VM validate error codes */
     109             : 
     110           3 :   case FD_VM_ERR_INVALID_OPCODE:    return "INVALID_OPCODE detected an invalid opcode";
     111           3 :   case FD_VM_ERR_INVALID_SRC_REG:   return "INVALID_SRC_REG detected an invalid source register";
     112           3 :   case FD_VM_ERR_INVALID_DST_REG:   return "INVALID_DST_REG detected an invalid destination register";
     113           3 :   case FD_VM_ERR_JMP_OUT_OF_BOUNDS: return "JMP_OUT_OF_BOUNDS detected an out of bounds jump";
     114           3 :   case FD_VM_ERR_JMP_TO_ADDL_IMM:   return "JMP_TO_ADDL_IMM detected a jump to an addl imm";
     115           3 :   case FD_VM_ERR_INVALID_END_IMM:   return "INVALID_END_IMM detected an invalid immediate for an endianness conversion instruction";
     116           3 :   case FD_VM_ERR_INCOMPLETE_LDQ:    return "INCOMPLETE_LDQ detected an incomplete ldq at program end";
     117           3 :   case FD_VM_ERR_LDQ_NO_ADDL_IMM:   return "LDQ_NO_ADDL_IMM detected a ldq without an addl imm following it";
     118           0 :   case FD_VM_ERR_INVALID_REG:       return "INVALID_REG detected an invalid register number in a callx instruction";
     119           0 :   case FD_VM_ERR_BAD_TEXT:          return "BAD_TEXT detected a bad text section";
     120           0 :   case FD_VM_SH_OVERFLOW:           return "SH_OVERFLOW detected a shift overflow in an instruction";
     121           0 :   case FD_VM_TEXT_SZ_UNALIGNED:     return "TEXT_SZ_UNALIGNED detected an unaligned text section size (not a multiple of 8)";
     122             : 
     123           0 :   default: break;
     124          42 :   }
     125             : 
     126           0 :   return "UNKNOWN probably not a FD_VM_ERR code";
     127          42 : }
     128             : 
     129             : /* FIXME: add a pedantic version of this validation that does things
     130             :    like:
     131             :   - only 0 imms when the instruction does not use an imm
     132             :   - same as above but for src/dst reg, offset */
     133             : /* FIXME: HANDLING OF LDQ ON NEWER SBPF VERSUS OLDER SBPF (AND WITH CALL
     134             :    REG) */
     135             : /* FIXME: LINK TO SOLANA CODE VALIDATE AND DOUBLE CHECK THIS BEHAVES
     136             :    IDENTICALLY! */
     137             : 
     138             : int
     139       11529 : fd_vm_validate( fd_vm_t const * vm ) {
     140             : 
     141       11529 :   ulong sbpf_version = vm->sbpf_version;
     142             : 
     143             :   /* A mapping of all the possible 1-byte sBPF opcodes to their
     144             :      validation criteria. */
     145             : 
     146   645785994 : # define FD_VALID               ((uchar)0)  /* Valid opcode */
     147      356628 : # define FD_CHECK_JMP           ((uchar)1)  /* Validation should check that the instruction is a valid jump */
     148       18852 : # define FD_CHECK_END           ((uchar)2)  /* Validation should check that the instruction is a valid endianness conversion */
     149      334350 : # define FD_CHECK_ST            ((uchar)3)  /* Validation should check that the instruction is a valid store */
     150       51114 : # define FD_CHECK_LDQ           ((uchar)4)  /* Validation should check that the instruction is a valid load-quad */
     151    64609248 : # define FD_CHECK_DIV           ((uchar)5)  /* Validation should check that the instruction is a valid division by immediate */
     152    48343005 : # define FD_CHECK_SH32          ((uchar)6)  /* Validation should check that the immediate is a valid 32-bit shift exponent */
     153    48382416 : # define FD_CHECK_SH64          ((uchar)7)  /* Validation should check that the immediate is a valid 64-bit shift exponent */
     154     2417844 : # define FD_INVALID             ((uchar)8)  /* The opcode is invalid */
     155       15885 : # define FD_CHECK_CALL_REG_SRC  ((uchar)9)  /* Validation should check that callx has valid register number in src */
     156       11529 : # define FD_CHECK_CALL_REG_DST  ((uchar)13) /* Validation should check that callx has a valid register number in dst */
     157       25227 : # define FD_CHECK_CALL_REG_IMM  ((uchar)10) /* Validation should check that callx has a valid register number in imm */
     158             : 
     159       11529 :   uchar validation_map[ 256 ] = {
     160       11529 :     /* 0x00 */ FD_INVALID,    /* 0x01 */ FD_INVALID,    /* 0x02 */ FD_INVALID,    /* 0x03 */ FD_INVALID,
     161       11529 :     /* 0x04 */ FD_VALID,      /* 0x05 */ FD_CHECK_JMP,  /* 0x06 */ FD_INVALID,    /* 0x07 */ FD_VALID,
     162       11529 :     /* 0x08 */ FD_INVALID,    /* 0x09 */ FD_INVALID,    /* 0x0a */ FD_INVALID,    /* 0x0b */ FD_INVALID,
     163       11529 :     /* 0x0c */ FD_VALID,      /* 0x0d */ FD_INVALID,    /* 0x0e */ FD_INVALID,    /* 0x0f */ FD_VALID,
     164       11529 :     /* 0x10 */ FD_INVALID,    /* 0x11 */ FD_INVALID,    /* 0x12 */ FD_INVALID,    /* 0x13 */ FD_INVALID,
     165       11529 :     /* 0x14 */ FD_VALID,      /* 0x15 */ FD_CHECK_JMP,  /* 0x16 */ FD_INVALID,    /* 0x17 */ FD_VALID,
     166       11529 :     /* 0x18 */ FD_INVALID,    /* 0x19 */ FD_INVALID,    /* 0x1a */ FD_INVALID,    /* 0x1b */ FD_INVALID,
     167       11529 :     /* 0x1c */ FD_VALID,      /* 0x1d */ FD_CHECK_JMP,  /* 0x1e */ FD_INVALID,    /* 0x1f */ FD_VALID,
     168       11529 :     /* 0x20 */ FD_INVALID,    /* 0x21 */ FD_INVALID,    /* 0x22 */ FD_INVALID,    /* 0x23 */ FD_INVALID,
     169       11529 :     /* 0x24 */ FD_INVALID,    /* 0x25 */ FD_CHECK_JMP,  /* 0x26 */ FD_INVALID,    /* 0x27 */ FD_CHECK_ST,
     170       11529 :     /* 0x28 */ FD_INVALID,    /* 0x29 */ FD_INVALID,    /* 0x2a */ FD_INVALID,    /* 0x2b */ FD_INVALID,
     171       11529 :     /* 0x2c */ FD_VALID,      /* 0x2d */ FD_CHECK_JMP,  /* 0x2e */ FD_INVALID,    /* 0x2f */ FD_CHECK_ST,
     172       11529 :     /* 0x30 */ FD_INVALID,    /* 0x31 */ FD_INVALID,    /* 0x32 */ FD_INVALID,    /* 0x33 */ FD_INVALID,
     173       11529 :     /* 0x34 */ FD_INVALID,    /* 0x35 */ FD_CHECK_JMP,  /* 0x36 */ FD_VALID,      /* 0x37 */ FD_CHECK_ST,
     174       11529 :     /* 0x38 */ FD_INVALID,    /* 0x39 */ FD_INVALID,    /* 0x3a */ FD_INVALID,    /* 0x3b */ FD_INVALID,
     175       11529 :     /* 0x3c */ FD_VALID,      /* 0x3d */ FD_CHECK_JMP,  /* 0x3e */ FD_VALID,      /* 0x3f */ FD_CHECK_ST,
     176       11529 :     /* 0x40 */ FD_INVALID,    /* 0x41 */ FD_INVALID,    /* 0x42 */ FD_INVALID,    /* 0x43 */ FD_INVALID,
     177       11529 :     /* 0x44 */ FD_VALID,      /* 0x45 */ FD_CHECK_JMP,  /* 0x46 */ FD_CHECK_DIV,  /* 0x47 */ FD_VALID,
     178       11529 :     /* 0x48 */ FD_INVALID,    /* 0x49 */ FD_INVALID,    /* 0x4a */ FD_INVALID,    /* 0x4b */ FD_INVALID,
     179       11529 :     /* 0x4c */ FD_VALID,      /* 0x4d */ FD_CHECK_JMP,  /* 0x4e */ FD_VALID,      /* 0x4f */ FD_VALID,
     180       11529 :     /* 0x50 */ FD_INVALID,    /* 0x51 */ FD_INVALID,    /* 0x52 */ FD_INVALID,    /* 0x53 */ FD_INVALID,
     181       11529 :     /* 0x54 */ FD_VALID,      /* 0x55 */ FD_CHECK_JMP,  /* 0x56 */ FD_CHECK_DIV,  /* 0x57 */ FD_VALID,
     182       11529 :     /* 0x58 */ FD_INVALID,    /* 0x59 */ FD_INVALID,    /* 0x5a */ FD_INVALID,    /* 0x5b */ FD_INVALID,
     183       11529 :     /* 0x5c */ FD_VALID,      /* 0x5d */ FD_CHECK_JMP,  /* 0x5e */ FD_VALID,      /* 0x5f */ FD_VALID,
     184       11529 :     /* 0x60 */ FD_INVALID,    /* 0x61 */ FD_INVALID,    /* 0x62 */ FD_INVALID,    /* 0x63 */ FD_INVALID,
     185       11529 :     /* 0x64 */ FD_CHECK_SH32, /* 0x65 */ FD_CHECK_JMP,  /* 0x66 */ FD_CHECK_DIV,  /* 0x67 */ FD_CHECK_SH64,
     186       11529 :     /* 0x68 */ FD_INVALID,    /* 0x69 */ FD_INVALID,    /* 0x6a */ FD_INVALID,    /* 0x6b */ FD_INVALID,
     187       11529 :     /* 0x6c */ FD_VALID,      /* 0x6d */ FD_CHECK_JMP,  /* 0x6e */ FD_VALID,      /* 0x6f */ FD_VALID,
     188       11529 :     /* 0x70 */ FD_INVALID,    /* 0x71 */ FD_INVALID,    /* 0x72 */ FD_INVALID,    /* 0x73 */ FD_INVALID,
     189       11529 :     /* 0x74 */ FD_CHECK_SH32, /* 0x75 */ FD_CHECK_JMP,  /* 0x76 */ FD_CHECK_DIV,  /* 0x77 */ FD_CHECK_SH64,
     190       11529 :     /* 0x78 */ FD_INVALID,    /* 0x79 */ FD_INVALID,    /* 0x7a */ FD_INVALID,    /* 0x7b */ FD_INVALID,
     191       11529 :     /* 0x7c */ FD_VALID,      /* 0x7d */ FD_CHECK_JMP,  /* 0x7e */ FD_VALID,      /* 0x7f */ FD_VALID,
     192       11529 :     /* 0x80 */ FD_INVALID,    /* 0x81 */ FD_INVALID,    /* 0x82 */ FD_INVALID,    /* 0x83 */ FD_INVALID,
     193       11529 :     /* 0x84 */ FD_INVALID,    /* 0x85 */ FD_VALID,      /* 0x86 */ FD_VALID,      /* 0x87 */ FD_CHECK_ST,
     194       11529 :     /* 0x88 */ FD_INVALID,    /* 0x89 */ FD_INVALID,    /* 0x8a */ FD_INVALID,    /* 0x8b */ FD_INVALID,
     195       11529 :     /* 0x8c */ FD_VALID,      /* 0x8d */ FD_CHECK_CALL_REG_SRC,/*0x8e*/FD_VALID,      /* 0x8f */ FD_CHECK_ST,
     196       11529 :     /* 0x90 */ FD_INVALID,    /* 0x91 */ FD_INVALID,    /* 0x92 */ FD_INVALID,    /* 0x93 */ FD_INVALID,
     197       11529 :     /* 0x94 */ FD_INVALID,    /* 0x95 */ FD_VALID,      /* 0x96 */ FD_VALID,      /* 0x97 */ FD_CHECK_ST,
     198       11529 :     /* 0x98 */ FD_INVALID,    /* 0x99 */ FD_INVALID,    /* 0x9a */ FD_INVALID,    /* 0x9b */ FD_INVALID,
     199       11529 :     /* 0x9c */ FD_VALID,      /* 0x9d */ FD_INVALID,    /* 0x9e */ FD_VALID,      /* 0x9f */ FD_CHECK_ST,
     200       11529 :     /* 0xa0 */ FD_INVALID,    /* 0xa1 */ FD_INVALID,    /* 0xa2 */ FD_INVALID,    /* 0xa3 */ FD_INVALID,
     201       11529 :     /* 0xa4 */ FD_VALID,      /* 0xa5 */ FD_CHECK_JMP,  /* 0xa6 */ FD_INVALID,    /* 0xa7 */ FD_VALID,
     202       11529 :     /* 0xa8 */ FD_INVALID,    /* 0xa9 */ FD_INVALID,    /* 0xaa */ FD_INVALID,    /* 0xab */ FD_INVALID,
     203       11529 :     /* 0xac */ FD_VALID,      /* 0xad */ FD_CHECK_JMP,  /* 0xae */ FD_INVALID,    /* 0xaf */ FD_VALID,
     204       11529 :     /* 0xb0 */ FD_INVALID,    /* 0xb1 */ FD_INVALID,    /* 0xb2 */ FD_INVALID,    /* 0xb3 */ FD_INVALID,
     205       11529 :     /* 0xb4 */ FD_VALID,      /* 0xb5 */ FD_CHECK_JMP,  /* 0xb6 */ FD_VALID,      /* 0xb7 */ FD_VALID,
     206       11529 :     /* 0xb8 */ FD_INVALID,    /* 0xb9 */ FD_INVALID,    /* 0xba */ FD_INVALID,    /* 0xbb */ FD_INVALID,
     207       11529 :     /* 0xbc */ FD_VALID,      /* 0xbd */ FD_CHECK_JMP,  /* 0xbe */ FD_VALID,      /* 0xbf */ FD_VALID,
     208       11529 :     /* 0xc0 */ FD_INVALID,    /* 0xc1 */ FD_INVALID,    /* 0xc2 */ FD_INVALID,    /* 0xc3 */ FD_INVALID,
     209       11529 :     /* 0xc4 */ FD_CHECK_SH32, /* 0xc5 */ FD_CHECK_JMP,  /* 0xc6 */ FD_CHECK_DIV,  /* 0xc7 */ FD_CHECK_SH64,
     210       11529 :     /* 0xc8 */ FD_INVALID,    /* 0xc9 */ FD_INVALID,    /* 0xca */ FD_INVALID,    /* 0xcb */ FD_INVALID,
     211       11529 :     /* 0xcc */ FD_VALID,      /* 0xcd */ FD_CHECK_JMP,  /* 0xce */ FD_VALID,      /* 0xcf */ FD_VALID,
     212       11529 :     /* 0xd0 */ FD_INVALID,    /* 0xd1 */ FD_INVALID,    /* 0xd2 */ FD_INVALID,    /* 0xd3 */ FD_INVALID,
     213       11529 :     /* 0xd4 */ FD_INVALID,    /* 0xd5 */ FD_CHECK_JMP,  /* 0xd6 */ FD_CHECK_DIV,  /* 0xd7 */ FD_INVALID,
     214       11529 :     /* 0xd8 */ FD_INVALID,    /* 0xd9 */ FD_INVALID,    /* 0xda */ FD_INVALID,    /* 0xdb */ FD_INVALID,
     215       11529 :     /* 0xdc */ FD_CHECK_END,  /* 0xdd */ FD_CHECK_JMP,  /* 0xde */ FD_VALID,      /* 0xdf */ FD_INVALID,
     216       11529 :     /* 0xe0 */ FD_INVALID,    /* 0xe1 */ FD_INVALID,    /* 0xe2 */ FD_INVALID,    /* 0xe3 */ FD_INVALID,
     217       11529 :     /* 0xe4 */ FD_INVALID,    /* 0xe5 */ FD_INVALID,    /* 0xe6 */ FD_CHECK_DIV,  /* 0xe7 */ FD_INVALID,
     218       11529 :     /* 0xe8 */ FD_INVALID,    /* 0xe9 */ FD_INVALID,    /* 0xea */ FD_INVALID,    /* 0xeb */ FD_INVALID,
     219       11529 :     /* 0xec */ FD_INVALID,    /* 0xed */ FD_INVALID,    /* 0xee */ FD_VALID,      /* 0xef */ FD_INVALID,
     220       11529 :     /* 0xf0 */ FD_INVALID,    /* 0xf1 */ FD_INVALID,    /* 0xf2 */ FD_INVALID,    /* 0xf3 */ FD_INVALID,
     221       11529 :     /* 0xf4 */ FD_INVALID,    /* 0xf5 */ FD_INVALID,    /* 0xf6 */ FD_CHECK_DIV,  /* 0xf7 */ FD_VALID,
     222       11529 :     /* 0xf8 */ FD_INVALID,    /* 0xf9 */ FD_INVALID,    /* 0xfa */ FD_INVALID,    /* 0xfb */ FD_INVALID,
     223       11529 :     /* 0xfc */ FD_INVALID,    /* 0xfd */ FD_INVALID,    /* 0xfe */ FD_VALID,      /* 0xff */ FD_INVALID,
     224       11529 :   };
     225             : 
     226             :   /* SIMD-0173: LDDW
     227             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L232-L235 */
     228       11529 :   validation_map[ 0x18 ] = !FD_VM_SBPF_DISABLE_LDDW(sbpf_version) ? FD_CHECK_LDQ : FD_INVALID;
     229             :   /* HOR64 https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L325 */
     230       11529 :   validation_map[ 0xf7 ] = FD_VM_SBPF_DISABLE_LDDW(sbpf_version) ? FD_VALID   :    FD_INVALID;
     231             : 
     232             :   /* SIMD-0173: LE
     233             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L285 */
     234       11529 :   validation_map[ 0xd4 ] = !FD_VM_SBPF_DISABLE_LE(sbpf_version) ? FD_CHECK_END : FD_INVALID;
     235             : 
     236             :   /* SIMD-0173: LDXW, STW, STXW */
     237       11529 :   validation_map[ 0x61 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     238       11529 :   validation_map[ 0x62 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     239       11529 :   validation_map[ 0x63 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     240       11529 :   validation_map[ 0x8c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_INVALID;
     241       11529 :   validation_map[ 0x87 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID; /* VALID because it's NEG64 */
     242       11529 :   validation_map[ 0x8f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_INVALID;
     243             : 
     244             :   /* SIMD-0173: LDXH, STH, STXH */
     245       11529 :   validation_map[ 0x69 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     246       11529 :   validation_map[ 0x6a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     247       11529 :   validation_map[ 0x6b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     248       11529 :   validation_map[ 0x3c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     249       11529 :   validation_map[ 0x37 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_CHECK_DIV;
     250       11529 :   validation_map[ 0x3f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     251             : 
     252             :   /* SIMD-0173: LDXB, STB, STXB */
     253       11529 :   validation_map[ 0x71 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     254       11529 :   validation_map[ 0x72 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     255       11529 :   validation_map[ 0x73 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     256       11529 :   validation_map[ 0x2c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     257       11529 :   validation_map[ 0x27 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     258       11529 :   validation_map[ 0x2f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     259             : 
     260             :   /* SIMD-0173: LDXDW, STDW, STXDW */
     261       11529 :   validation_map[ 0x79 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_VALID;
     262       11529 :   validation_map[ 0x7a ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     263       11529 :   validation_map[ 0x7b ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_INVALID   : FD_CHECK_ST;
     264       11529 :   validation_map[ 0x9c ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_VALID     : FD_VALID;
     265       11529 :   validation_map[ 0x97 ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_CHECK_DIV;
     266       11529 :   validation_map[ 0x9f ] = FD_VM_SBPF_MOVE_MEMORY_IX_CLASSES(sbpf_version) ? FD_CHECK_ST  : FD_VALID;
     267             : 
     268             :   /* SIMD-0173 / SIMD-0377: CALLX references valid register numbers
     269             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L198-L214 */
     270       11529 :   validation_map[ 0x8d ] = FD_VM_SBPF_CALLX_USES_SRC_REG(sbpf_version)  ? FD_CHECK_CALL_REG_SRC
     271       11529 :                           : FD_VM_SBPF_CALLX_USES_DST_REG(sbpf_version) ? FD_CHECK_CALL_REG_DST
     272        7194 :                           : FD_CHECK_CALL_REG_IMM;
     273             : 
     274             :   /* SIMD-0174: MUL, DIV, MOD */
     275       11529 :   validation_map[ 0x24 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_VALID;
     276       11529 :   validation_map[ 0x34 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
     277       11529 :   validation_map[ 0x94 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_INVALID : FD_CHECK_DIV;
     278             :   /* note: 0x?c, 0x?7, 0x?f should not be overwritten because they're now load/store ix */
     279             : 
     280             :   /* SIMD-0174: NEG
     281             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L274 */
     282       11529 :   validation_map[ 0x84 ] = !FD_VM_SBPF_DISABLE_NEG(sbpf_version) ? FD_VALID : FD_INVALID;
     283             :   /* note: 0x87 should not be overwritten because it was NEG64 and it becomes STW */
     284             : 
     285             :   /* SIMD-0174: MUL, DIV, MOD */
     286       11529 :   validation_map[ 0x36 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* UHMUL64 */
     287       11529 :   validation_map[ 0x3e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     288       11529 :   validation_map[ 0x46 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV32 */
     289       11529 :   validation_map[ 0x4e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     290       11529 :   validation_map[ 0x56 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UDIV64 */
     291       11529 :   validation_map[ 0x5e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     292       11529 :   validation_map[ 0x66 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM32 */
     293       11529 :   validation_map[ 0x6e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     294       11529 :   validation_map[ 0x76 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* UREM64 */
     295       11529 :   validation_map[ 0x7e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     296       11529 :   validation_map[ 0x86 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* LMUL32 */
     297       11529 :   validation_map[ 0x8e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     298       11529 :   validation_map[ 0x96 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* LMUL64 */
     299       11529 :   validation_map[ 0x9e ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     300       11529 :   validation_map[ 0xb6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID; /* SHMUL64 */
     301       11529 :   validation_map[ 0xbe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     302       11529 :   validation_map[ 0xc6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV32 */
     303       11529 :   validation_map[ 0xce ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     304       11529 :   validation_map[ 0xd6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SDIV64 */
     305       11529 :   validation_map[ 0xde ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     306       11529 :   validation_map[ 0xe6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM32 */
     307       11529 :   validation_map[ 0xee ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     308       11529 :   validation_map[ 0xf6 ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_CHECK_DIV : FD_INVALID; /* SREM64 */
     309       11529 :   validation_map[ 0xfe ] = FD_VM_SBPF_ENABLE_PQR (sbpf_version) ? FD_VALID     : FD_INVALID;
     310             : 
     311             :   /* SIMD-0377: JMP32
     312             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L354-L375
     313             : 
     314             :      Note that these override some opcodes that conflict with PQR, so
     315             :      these must come AFTER PQR. */
     316       11529 :   if( FD_VM_SBPF_ENABLE_JMP32( sbpf_version ) ) {
     317         639 :     validation_map[ 0x16 ] = FD_CHECK_JMP;  /* JEQ32_IMM  */
     318         639 :     validation_map[ 0x1e ] = FD_CHECK_JMP;  /* JEQ32_REG  */
     319         639 :     validation_map[ 0x26 ] = FD_CHECK_JMP;  /* JGT32_IMM  */
     320         639 :     validation_map[ 0x2e ] = FD_CHECK_JMP;  /* JGT32_REG  */
     321         639 :     validation_map[ 0x36 ] = FD_CHECK_JMP;  /* JGE32_IMM  */
     322         639 :     validation_map[ 0x3e ] = FD_CHECK_JMP;  /* JGE32_REG  */
     323         639 :     validation_map[ 0x46 ] = FD_CHECK_JMP;  /* JSET32_IMM */
     324         639 :     validation_map[ 0x4e ] = FD_CHECK_JMP;  /* JSET32_REG */
     325         639 :     validation_map[ 0x56 ] = FD_CHECK_JMP;  /* JNE32_IMM  */
     326         639 :     validation_map[ 0x5e ] = FD_CHECK_JMP;  /* JNE32_REG  */
     327         639 :     validation_map[ 0x66 ] = FD_CHECK_JMP;  /* JSGT32_IMM */
     328         639 :     validation_map[ 0x6e ] = FD_CHECK_JMP;  /* JSGT32_REG */
     329         639 :     validation_map[ 0x76 ] = FD_CHECK_JMP;  /* JSGE32_IMM */
     330         639 :     validation_map[ 0x7e ] = FD_CHECK_JMP;  /* JSGE32_REG */
     331         639 :     validation_map[ 0xa6 ] = FD_CHECK_JMP;  /* JLT32_IMM  */
     332         639 :     validation_map[ 0xae ] = FD_CHECK_JMP;  /* JLT32_REG  */
     333         639 :     validation_map[ 0xb6 ] = FD_CHECK_JMP;  /* JLE32_IMM  */
     334         639 :     validation_map[ 0xbe ] = FD_CHECK_JMP;  /* JLE32_REG  */
     335         639 :     validation_map[ 0xc6 ] = FD_CHECK_JMP;  /* JSLT32_IMM */
     336         639 :     validation_map[ 0xce ] = FD_CHECK_JMP;  /* JSLT32_REG */
     337         639 :     validation_map[ 0xd6 ] = FD_CHECK_JMP;  /* JSLE32_IMM */
     338         639 :     validation_map[ 0xde ] = FD_CHECK_JMP;  /* JSLE32_REG */
     339         639 :   }
     340             : 
     341             :   /* FIXME: These checks are not necessary assuming fd_vm_t is populated by metadata
     342             :      generated in fd_sbpf_elf_peek (which performs these checks). But there is no guarantee, and
     343             :      this non-guarantee is (rightfully) exploited by the fuzz harnesses.
     344             :      Agave doesn't perform these checks explicitly due to Rust's guarantees  */
     345       11529 :   if( FD_UNLIKELY( vm->text_sz / 8UL != vm->text_cnt ||
     346       11529 :                    (const uchar *)vm->text < vm->rodata ||
     347       11529 :                    (ulong)vm->text > (ulong)vm->text + vm->text_sz || /* Overflow chk */
     348       11529 :                    (const uchar *)vm->text + vm->text_sz > vm->rodata + vm->rodata_sz +
     349       11529 :                      ( FD_VM_SBPF_ENABLE_STRICTER_ELF_HEADERS( sbpf_version ) ? vm->text_sz : 0UL ) ) )
     350           0 :     return FD_VM_ERR_BAD_TEXT;
     351             : 
     352       11529 :   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 */
     353           0 :     return FD_VM_TEXT_SZ_UNALIGNED;
     354             : 
     355       11529 :   if ( FD_UNLIKELY( vm->text_cnt == 0UL ) ) /* https://github.com/solana-labs/rbpf/blob/v0.8.0/src/verifier.rs#L112 */
     356           0 :     return FD_VM_ERR_EMPTY;
     357             : 
     358       11529 :   ulong const * text     = vm->text;
     359       11529 :   ulong         text_cnt = vm->text_cnt;
     360             : 
     361   806093244 :   for( ulong i=0UL; i<text_cnt; i++ ) {
     362   806084481 :     fd_sbpf_instr_t instr = fd_sbpf_instr( text[i] );
     363             : 
     364   806084481 :     uchar validation_code = validation_map[ instr.opcode.raw ];
     365   806084481 :     switch( validation_code ) {
     366             : 
     367   644833329 :     case FD_VALID: break;
     368             : 
     369             :     /* Store ops are special because they allow dreg==r10.
     370             :        We use a special validation_code, used later in the
     371             :        "Check registers" section.
     372             :        But there's nothing to do at this time. */
     373       57654 :     case FD_CHECK_ST: break;
     374             : 
     375       77403 :     case FD_CHECK_JMP: {
     376       77403 :       long jmp_dst = (long)i + (long)instr.offset + 1L;
     377       77403 :       if( FD_UNLIKELY( (jmp_dst<0) | (jmp_dst>=(long)text_cnt)                          ) ) return FD_VM_ERR_JMP_OUT_OF_BOUNDS;
     378             :       //FIXME: this shouldn't be here?
     379       77256 :       if( FD_UNLIKELY( fd_sbpf_instr( text[ jmp_dst ] ).opcode.raw==FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_JMP_TO_ADDL_IMM;
     380       77256 :       break;
     381       77256 :     }
     382             : 
     383       77256 :     case FD_CHECK_END: {
     384         129 :       if( FD_UNLIKELY( !((instr.imm==16) | (instr.imm==32) | (instr.imm==64)) ) ) return FD_VM_ERR_INVALID_END_IMM;
     385         111 :       break;
     386         129 :     }
     387             : 
     388             :     /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L244 */
     389       43920 :     case FD_CHECK_LDQ: {
     390             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L131 */
     391       43920 :       if( FD_UNLIKELY( (i+1UL)>=text_cnt ) ) return FD_VM_ERR_INCOMPLETE_LDQ;
     392             : 
     393             :       /* https://github.com/solana-labs/rbpf/blob/b503a1867a9cfa13f93b4d99679a17fe219831de/src/verifier.rs#L137-L139 */
     394       43920 :       fd_sbpf_instr_t addl_imm = fd_sbpf_instr( text[ i+1UL ] );
     395       43920 :       if( FD_UNLIKELY( addl_imm.opcode.raw!=FD_SBPF_OP_ADDL_IMM ) ) return FD_VM_ERR_LDQ_NO_ADDL_IMM;
     396             : 
     397             :       /* FIXME: SET A BIT MAP HERE OF ADDL_IMM TO DENOTE * AS FORBIDDEN
     398             :          BRANCH TARGETS OF CALL_REG?? */
     399             : 
     400       43920 :       i++; /* Skip the addl imm */
     401       43920 :       break;
     402       43920 :     }
     403             : 
     404    64407444 :     case FD_CHECK_DIV: {
     405    64407444 :       if( FD_UNLIKELY( instr.imm==0 ) ) return FD_VM_ERR_SIGFPE;
     406    64407384 :       break;
     407    64407444 :     }
     408             : 
     409    64407384 :     case FD_CHECK_SH32: {
     410    48308418 :       if( FD_UNLIKELY( instr.imm>=32 ) ) return FD_VM_SH_OVERFLOW;
     411    48308328 :       break;
     412    48308418 :     }
     413             : 
     414    48347829 :     case FD_CHECK_SH64: {
     415    48347829 :       if( FD_UNLIKELY( instr.imm>=64 ) ) return FD_VM_SH_OVERFLOW;
     416    48347721 :       break;
     417    48347829 :     }
     418             : 
     419             :     /* https://github.com/anza-xyz/sbpf/blob/v0.11.1/src/verifier.rs#L220 */
     420    48347721 :     case FD_CHECK_CALL_REG_SRC: {
     421          21 :       if( FD_UNLIKELY( instr.src_reg > 9 ) ) {
     422           9 :         return FD_VM_ERR_INVALID_REG;
     423           9 :       }
     424          12 :       break;
     425          21 :     }
     426        7143 :     case FD_CHECK_CALL_REG_IMM: {
     427        7143 :       if( FD_UNLIKELY( instr.imm > 9 ) ) {
     428           9 :         return FD_VM_ERR_INVALID_REG;
     429           9 :       }
     430        7134 :       break;
     431        7143 :     }
     432             :     /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/verifier.rs#L205-L206 */
     433        7134 :     case FD_CHECK_CALL_REG_DST: {
     434           9 :       if( FD_UNLIKELY( instr.dst_reg > 9 ) ) {
     435           3 :         return FD_VM_ERR_INVALID_REG;
     436           3 :       }
     437           6 :       break;
     438           9 :     }
     439             : 
     440        1182 :     case FD_INVALID: default: return FD_VM_ERR_INVALID_OPCODE;
     441   806084481 :     }
     442             : 
     443             :     /* Check registers
     444             :        https://github.com/solana-labs/rbpf/blob/v0.8.5/src/verifier.rs#L177 */
     445             : 
     446             :     /* Source register */
     447   806082855 :     if( FD_UNLIKELY( instr.src_reg>10 ) ) return FD_VM_ERR_INVALID_SRC_REG;
     448             : 
     449             :     /* Special R10 register allowed for ADD64_IMM */
     450   806082387 :     if( instr.dst_reg==10U
     451   806082387 :         && FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( sbpf_version )
     452   806082387 :         && instr.opcode.raw == 0x07
     453   806082387 :         && ( instr.imm % FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN )==0 )
     454           9 :         continue;
     455             : 
     456             :     /* Destination register. */
     457   806082378 :     if( FD_UNLIKELY( instr.dst_reg==10U && validation_code != FD_CHECK_ST ) ) return FD_VM_ERR_INVALID_DST_REG;
     458   806081919 :     if( FD_UNLIKELY( instr.dst_reg > 10U ) ) return FD_VM_ERR_INVALID_DST_REG;
     459   806081919 :   }
     460             : 
     461        8763 :   return FD_VM_SUCCESS;
     462       11529 : }
     463             : 
     464             : FD_FN_CONST ulong
     465       11364 : fd_vm_align( void ) {
     466       11364 :   return FD_VM_ALIGN;
     467       11364 : }
     468             : 
     469             : FD_FN_CONST ulong
     470        5703 : fd_vm_footprint( void ) {
     471        5703 :   return FD_VM_FOOTPRINT;
     472        5703 : }
     473             : 
     474             : void *
     475        5595 : fd_vm_new( void * shmem ) {
     476             : 
     477        5595 :   if( FD_UNLIKELY( !shmem ) ) {
     478           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     479           0 :     return NULL;
     480           0 :   }
     481             : 
     482        5595 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     483           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     484           0 :     return NULL;
     485           0 :   }
     486             : 
     487        5595 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     488        5595 :   fd_memset( vm, 0, fd_vm_footprint() );
     489             : 
     490        5595 :   FD_COMPILER_MFENCE();
     491        5595 :   FD_VOLATILE( vm->magic ) = FD_VM_MAGIC;
     492        5595 :   FD_COMPILER_MFENCE();
     493             : 
     494        5595 :   return shmem;
     495        5595 : }
     496             : 
     497             : fd_vm_t *
     498        5595 : fd_vm_join( void * shmem ) {
     499             : 
     500        5595 :   if( FD_UNLIKELY( !shmem ) ) {
     501           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     502           0 :     return NULL;
     503           0 :   }
     504             : 
     505        5595 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     506           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     507           0 :     return NULL;
     508           0 :   }
     509             : 
     510        5595 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     511             : 
     512        5595 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     513           0 :     FD_LOG_WARNING(( "bad magic" ));
     514           0 :     return NULL;
     515           0 :   }
     516             : 
     517        5595 :   return vm;
     518        5595 : }
     519             : 
     520             : void *
     521          66 : fd_vm_leave( fd_vm_t * vm ) {
     522             : 
     523          66 :   if( FD_UNLIKELY( !vm ) ) {
     524           0 :     FD_LOG_WARNING(( "NULL vm" ));
     525           0 :     return NULL;
     526           0 :   }
     527             : 
     528          66 :   return (void *)vm;
     529          66 : }
     530             : 
     531             : void *
     532          66 : fd_vm_delete( void * shmem ) {
     533             : 
     534          66 :   if( FD_UNLIKELY( !shmem ) ) {
     535           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     536           0 :     return NULL;
     537           0 :   }
     538             : 
     539          66 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_align() ) ) ) {
     540           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     541           0 :     return NULL;
     542           0 :   }
     543             : 
     544          66 :   fd_vm_t * vm = (fd_vm_t *)shmem;
     545             : 
     546          66 :   if( FD_UNLIKELY( vm->magic!=FD_VM_MAGIC ) ) {
     547           0 :     FD_LOG_WARNING(( "bad magic" ));
     548           0 :     return NULL;
     549           0 :   }
     550             : 
     551          66 :   FD_COMPILER_MFENCE();
     552          66 :   FD_VOLATILE( vm->magic ) = 0UL;
     553          66 :   FD_COMPILER_MFENCE();
     554             : 
     555          66 :   return (void *)vm;
     556          66 : }
     557             : 
     558             : fd_vm_t *
     559             : fd_vm_init(
     560             :    fd_vm_t *                 vm,
     561             :    fd_exec_instr_ctx_t *     instr_ctx,
     562             :    ulong                     heap_max,
     563             :    ulong                     entry_cu,
     564             :    uchar const *             rodata,
     565             :    ulong                     rodata_sz,
     566             :    ulong const *             text,
     567             :    ulong                     text_cnt,
     568             :    ulong                     text_off,
     569             :    ulong                     text_sz,
     570             :    ulong                     entry_pc,
     571             :    ulong const *             calldests,
     572             :    ulong                     sbpf_version,
     573             :    fd_sbpf_syscalls_t *      syscalls,
     574             :    fd_vm_trace_t *           trace,
     575             :    fd_sha256_t *             sha,
     576             :    fd_vm_input_region_t *    mem_regions,
     577             :    uint                      mem_regions_cnt,
     578             :    fd_vm_acc_region_meta_t * acc_region_metas,
     579             :    uchar                     is_deprecated,
     580             :    int                       direct_mapping,
     581             :    int                       syscall_parameter_address_restrictions,
     582             :    int                       virtual_address_space_adjustments,
     583             :    int                       dump_syscall_to_pb,
     584       17262 :    ulong                     r2_initial_value ) {
     585             : 
     586       17262 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     587           0 :     FD_LOG_WARNING(( "NULL vm" ));
     588           0 :     return NULL;
     589           0 :   }
     590             : 
     591       17262 :   if ( FD_UNLIKELY( vm->magic != FD_VM_MAGIC ) ) {
     592           0 :     FD_LOG_WARNING(( "bad magic" ));
     593           0 :     return NULL;
     594           0 :   }
     595             : 
     596       17262 :   if ( FD_UNLIKELY( heap_max > FD_VM_HEAP_MAX ) ) {
     597           0 :     FD_LOG_WARNING(( "heap_max > FD_VM_HEAP_MAX" ));
     598           0 :     return NULL;
     599           0 :   }
     600             : 
     601             :   /* We do support calldests==NULL for tests that do not require
     602             :      program execution, e.g. just testing some interpreter functionality
     603             :      or syscalls.
     604             :      SBPF v3+ no longer needs calldests, so we enforce it to be NULL. */
     605       17262 :   if( FD_UNLIKELY( calldests && FD_VM_SBPF_ENABLE_STRICTER_ELF_HEADERS( sbpf_version ) ) ) {
     606           0 :     return NULL;
     607           0 :   }
     608             : 
     609             :   // Set the vm fields
     610       17262 :   vm->instr_ctx                              = instr_ctx;
     611       17262 :   vm->heap_max                               = heap_max;
     612       17262 :   vm->entry_cu                               = entry_cu;
     613       17262 :   vm->rodata                                 = rodata;
     614       17262 :   vm->rodata_sz                              = rodata_sz;
     615       17262 :   vm->text                                   = text;
     616       17262 :   vm->text_cnt                               = text_cnt;
     617             :   /* In SBPF V3, bytecode starts at vaddr 0x100000000 exactly, so
     618             :      text_off from the POV of the VM is 0.
     619             :      https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/interpreter.rs#L539 */
     620       17262 :   vm->text_off                               = FD_VM_SBPF_ENABLE_LOWER_RODATA_VADDR( sbpf_version ) ? 0UL : text_off;
     621       17262 :   vm->text_sz                                = text_sz;
     622       17262 :   vm->entry_pc                               = entry_pc;
     623       17262 :   vm->calldests                              = calldests;
     624       17262 :   vm->sbpf_version                           = sbpf_version;
     625       17262 :   vm->syscalls                               = syscalls;
     626       17262 :   vm->trace                                  = trace;
     627       17262 :   vm->sha                                    = sha;
     628       17262 :   vm->input_mem_regions                      = mem_regions;
     629       17262 :   vm->input_mem_regions_cnt                  = mem_regions_cnt;
     630       17262 :   vm->acc_region_metas                       = acc_region_metas;
     631       17262 :   vm->is_deprecated                          = is_deprecated;
     632       17262 :   vm->direct_mapping                         = direct_mapping;
     633       17262 :   vm->syscall_parameter_address_restrictions = syscall_parameter_address_restrictions;
     634       17262 :   vm->virtual_address_space_adjustments      = virtual_address_space_adjustments;
     635             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/vm.rs#L99-L103 */
     636       17262 :   if( FD_UNLIKELY( FD_VM_SBPF_STACK_FRAME_GAPS( sbpf_version ) && !virtual_address_space_adjustments ) ) {
     637        8274 :     vm->stack_frame_sz                       = FD_VM_STACK_FRAME_SZ;
     638        8274 :     vm->stack_push_frame_count               = 2UL;
     639        8988 :   } else if ( FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( sbpf_version ) ) {
     640        4341 :     vm->stack_frame_sz                       = 0UL;
     641        4341 :     vm->stack_push_frame_count               = 0UL;
     642        4647 :   } else {
     643        4647 :     vm->stack_frame_sz                       = FD_VM_STACK_FRAME_SZ;
     644        4647 :     vm->stack_push_frame_count               = 1UL;
     645        4647 :   }
     646             : 
     647       17262 :   vm->segv_vaddr                             = ULONG_MAX;
     648       17262 :   vm->segv_access_len                        = 0UL;
     649       17262 :   vm->segv_access_type                       = 0;
     650       17262 :   vm->dump_syscall_to_pb                     = dump_syscall_to_pb;
     651             : 
     652             :   /* Unpack input and rodata */
     653       17262 :   fd_vm_mem_cfg( vm );
     654             : 
     655             :   /* Initialize registers */
     656             :   /* FIXME: Zero out shadow, stack and heap here? */
     657       17262 :   fd_memset( vm->reg, 0, FD_VM_REG_MAX * sizeof(ulong) );
     658       17262 :   vm->reg[1]  = FD_VM_MEM_MAP_INPUT_REGION_START;
     659       17262 :   vm->reg[2]  = r2_initial_value;
     660             :   /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/vm.rs#L325-L330 */
     661       17262 :   vm->reg[10] = FD_VM_MEM_MAP_STACK_REGION_START +
     662       17262 :     ( FD_VM_SBPF_MANUAL_STACK_FRAME_BUMP( vm->sbpf_version ) ? FD_VM_STACK_MAX : vm->stack_frame_sz );
     663             :   /* Note: Agave uses r11 as pc, we don't */
     664             : 
     665             :   /* Set execution state */
     666       17262 :   vm->pc        = vm->entry_pc;
     667       17262 :   vm->ic        = 0UL;
     668       17262 :   vm->cu        = vm->entry_cu;
     669       17262 :   vm->frame_cnt = 0UL;
     670             : 
     671       17262 :   vm->heap_sz = 0UL;
     672             : 
     673             :   /* Do NOT reset logs */
     674             : 
     675       17262 :   return vm;
     676       17262 : }

Generated by: LCOV version 1.14