LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_runtime.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 276 335 82.4 %
Date: 2026-03-19 18:19:27 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : #include "../../runtime/program/fd_vote_program.h"
       3             : #include "../../runtime/context/fd_exec_instr_ctx.h"
       4             : #include "../../runtime/fd_system_ids.h"
       5             : #include "fd_vm_syscall_macros.h"
       6             : 
       7             : /* FIXME: In the original version of this code, there was an FD_TEST
       8             :    to check if the VM was attached to an instruction context (that
       9             :    would have crashed anyway because of pointer chasing).  If the VM
      10             :    is being run outside the Solana runtime, it should never invoke
      11             :    this syscall in the first place.  So we treat this as a SIGCALL in
      12             :    a non-crashing way for the time being. */
      13             : 
      14             : int
      15             : fd_vm_syscall_sol_get_clock_sysvar( /**/            void *  _vm,
      16             :                                     /**/            ulong   out_vaddr,
      17             :                                     FD_PARAM_UNUSED ulong   r2,
      18             :                                     FD_PARAM_UNUSED ulong   r3,
      19             :                                     FD_PARAM_UNUSED ulong   r4,
      20             :                                     FD_PARAM_UNUSED ulong   r5,
      21          81 :                                     /**/            ulong * _ret ) {
      22          81 :   fd_vm_t * vm = _vm;
      23          81 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      24          81 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
      25             : 
      26         162 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_clock_t) ) );
      27             : 
      28          81 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
      29           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
      30           0 :     return FD_VM_ERR_INVAL;
      31           0 :   }
      32             : 
      33          81 :   fd_vm_haddr_query_t var_query = {
      34          81 :     .vaddr    = out_vaddr,
      35          81 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_CLOCK,
      36          81 :     .sz       = sizeof(fd_sol_sysvar_clock_t),
      37          81 :     .is_slice = 0,
      38          81 :   };
      39             : 
      40          81 :   fd_vm_haddr_query_t * queries[] = { &var_query };
      41          81 :   FD_VM_TRANSLATE_MUT( vm, queries );
      42             : 
      43          81 :   fd_sol_sysvar_clock_t clock = fd_sysvar_cache_clock_read_nofail( instr_ctx->sysvar_cache );
      44           0 :   memcpy( var_query.haddr, &clock, sizeof(fd_sol_sysvar_clock_t) );
      45             : 
      46          81 :   *_ret = 0UL;
      47          81 :   return FD_VM_SUCCESS;
      48          81 : }
      49             : 
      50             : int
      51             : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/            void *  _vm,
      52             :                                              /**/            ulong   out_vaddr,
      53             :                                              FD_PARAM_UNUSED ulong   r2,
      54             :                                              FD_PARAM_UNUSED ulong   r3,
      55             :                                              FD_PARAM_UNUSED ulong   r4,
      56             :                                              FD_PARAM_UNUSED ulong   r5,
      57          46 :                                              /**/            ulong * _ret ) {
      58          46 :   fd_vm_t * vm = _vm;
      59          46 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      60          46 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
      61             : 
      62          92 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_epoch_schedule_t) ) );
      63             : 
      64          46 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
      65           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
      66           0 :     return FD_VM_ERR_INVAL;
      67           0 :   }
      68             : 
      69          46 :   fd_vm_haddr_query_t var_query = {
      70          46 :     .vaddr    = out_vaddr,
      71          46 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE,
      72          46 :     .sz       = sizeof(fd_epoch_schedule_t),
      73          46 :     .is_slice = 0,
      74          46 :   };
      75             : 
      76          46 :   fd_vm_haddr_query_t * queries[] = { &var_query };
      77          46 :   FD_VM_TRANSLATE_MUT( vm, queries );
      78             : 
      79          46 :   fd_epoch_schedule_t schedule;
      80          46 :   if( FD_UNLIKELY( !fd_sysvar_cache_epoch_schedule_read( instr_ctx->sysvar_cache, &schedule ) ) ) {
      81           0 :     FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
      82           0 :     return FD_VM_ERR_INVAL;
      83           0 :   }
      84          46 :   memcpy( var_query.haddr, &schedule, sizeof(fd_epoch_schedule_t) );
      85             : 
      86          46 :   *_ret = 0UL;
      87          46 :   return FD_VM_SUCCESS;
      88          46 : }
      89             : 
      90             : int
      91             : fd_vm_syscall_sol_get_rent_sysvar( /**/            void *  _vm,
      92             :                                    /**/            ulong   out_vaddr,
      93             :                                    FD_PARAM_UNUSED ulong   r2,
      94             :                                    FD_PARAM_UNUSED ulong   r3,
      95             :                                    FD_PARAM_UNUSED ulong   r4,
      96             :                                    FD_PARAM_UNUSED ulong   r5,
      97          98 :                                    /**/            ulong * _ret ) {
      98          98 :   fd_vm_t * vm = _vm;
      99             : 
     100             :   /* Unreachable in a real SVM, used for testing */
     101             : 
     102          98 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     103          98 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     104             : 
     105         196 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_rent_t) ) );
     106             : 
     107          98 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
     108           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
     109           0 :     return FD_VM_ERR_INVAL;
     110           0 :   }
     111             : 
     112          98 :   fd_vm_haddr_query_t var_query = {
     113          98 :     .vaddr    = out_vaddr,
     114          98 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_RENT,
     115          98 :     .sz       = sizeof(fd_rent_t),
     116          98 :     .is_slice = 0,
     117          98 :   };
     118             : 
     119          98 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     120          98 :   FD_VM_TRANSLATE_MUT( vm, queries );
     121             : 
     122          98 :   fd_rent_t rent = fd_sysvar_cache_rent_read_nofail( instr_ctx->sysvar_cache );
     123           0 :   memcpy( var_query.haddr, &rent, sizeof(fd_rent_t) );
     124             : 
     125          98 :   *_ret = 0UL;
     126          98 :   return FD_VM_SUCCESS;
     127          98 : }
     128             : 
     129             : /* https://github.com/anza-xyz/agave/blob/v2.3.2/programs/bpf_loader/src/syscalls/sysvar.rs#L149 */
     130             : int
     131             : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/            void *  _vm,
     132             :                                                 /**/            ulong   out_vaddr,
     133             :                                                 FD_PARAM_UNUSED ulong   r2,
     134             :                                                 FD_PARAM_UNUSED ulong   r3,
     135             :                                                 FD_PARAM_UNUSED ulong   r4,
     136             :                                                 FD_PARAM_UNUSED ulong   r5,
     137          76 :                                                 /**/            ulong * _ret ) {
     138          76 :   fd_vm_t * vm = _vm;
     139          76 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     140          76 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     141             : 
     142         152 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_last_restart_slot_t) ) );
     143             : 
     144          76 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
     145           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
     146           0 :     return FD_VM_ERR_INVAL;
     147           0 :   }
     148             : 
     149          76 :   fd_vm_haddr_query_t var_query = {
     150          76 :     .vaddr    = out_vaddr,
     151          76 :     .align    = FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT,
     152          76 :     .sz       = sizeof(fd_sol_sysvar_last_restart_slot_t),
     153          76 :     .is_slice = 0,
     154          76 :   };
     155             : 
     156          76 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     157          76 :   FD_VM_TRANSLATE_MUT( vm, queries );
     158             : 
     159          76 :   fd_sol_sysvar_last_restart_slot_t last_restart_slot;
     160          76 :   if( FD_UNLIKELY( !fd_sysvar_cache_last_restart_slot_read( vm->instr_ctx->sysvar_cache, &last_restart_slot ) ) ) {
     161           0 :     FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
     162           0 :     return FD_VM_ERR_INVAL;
     163           0 :   }
     164             : 
     165          76 :   memcpy( var_query.haddr, &last_restart_slot, sizeof(fd_sol_sysvar_last_restart_slot_t) );
     166             : 
     167          76 :   *_ret = 0UL;
     168          76 :   return FD_VM_SUCCESS;
     169          76 : }
     170             : 
     171             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L167-L232 */
     172             : int
     173             : fd_vm_syscall_sol_get_sysvar( /**/            void *  _vm,
     174             :                               /**/            ulong   sysvar_id_vaddr,
     175             :                               /**/            ulong   out_vaddr,
     176             :                               /**/            ulong   offset,
     177             :                               /**/            ulong   sz,
     178             :                               FD_PARAM_UNUSED ulong   r5,
     179         296 :                               /**/            ulong * _ret ) {
     180         296 :   fd_vm_t * vm = _vm;
     181         296 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     182         296 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     183             : 
     184             :   /* sysvar_id_cost seems to just always be 32 / 250 = 0...
     185             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L190-L197 */
     186         296 :   ulong sysvar_buf_cost = sz / FD_VM_CPI_BYTES_PER_UNIT;
     187         296 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, fd_ulong_max( sysvar_buf_cost, FD_VM_MEM_OP_BASE_COST ) ) );
     188             : 
     189         269 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
     190           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
     191           0 :     return FD_VM_ERR_INVAL;
     192           0 :   }
     193             : 
     194             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/sysvar.rs#L207-L211 */
     195         269 :   fd_vm_haddr_query_t var_query = {
     196         269 :     .vaddr    = out_vaddr,
     197         269 :     .align    = FD_VM_ALIGN_RUST_U8,
     198         269 :     .sz       = sz,
     199         269 :     .is_slice = 1,
     200         269 :   };
     201             : 
     202         269 :   fd_vm_haddr_query_t * queries[] = { &var_query };
     203         269 :   FD_VM_TRANSLATE_MUT( vm, queries );
     204             : 
     205             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L199-L200 */
     206         648 :   const fd_pubkey_t * sysvar_id = FD_VM_MEM_HADDR_LD( vm, sysvar_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     207             : 
     208             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L205-L208 */
     209           0 :   ulong offset_length;
     210         648 :   int err = fd_int_if( __builtin_uaddl_overflow( offset, sz, &offset_length ), FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW, FD_EXECUTOR_INSTR_SUCCESS );
     211         648 :   if( FD_UNLIKELY( err ) ) {
     212           0 :     FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     213           0 :     return FD_VM_SYSCALL_ERR_ABORT;
     214           0 :   }
     215             : 
     216             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L210-L213
     217             :      We don't need this, we already checked we can store in out_vaddr with requested sz. */
     218             : 
     219             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L215-L221 */
     220         216 :   if( FD_UNLIKELY( memcmp( sysvar_id->uc, fd_sysvar_clock_id.uc,             FD_PUBKEY_FOOTPRINT ) &&
     221         216 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_schedule_id.uc,    FD_PUBKEY_FOOTPRINT ) &&
     222         216 :                    memcmp( sysvar_id->uc, fd_sysvar_epoch_rewards_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     223         216 :                    memcmp( sysvar_id->uc, fd_sysvar_rent_id.uc,              FD_PUBKEY_FOOTPRINT ) &&
     224         216 :                    memcmp( sysvar_id->uc, fd_sysvar_slot_hashes_id.uc,       FD_PUBKEY_FOOTPRINT ) &&
     225         216 :                    memcmp( sysvar_id->uc, fd_sysvar_stake_history_id.uc,     FD_PUBKEY_FOOTPRINT ) &&
     226         216 :                    memcmp( sysvar_id->uc, fd_sysvar_last_restart_slot_id.uc, FD_PUBKEY_FOOTPRINT ) ) ) {
     227         164 :     *_ret = 2UL;
     228         164 :     return FD_VM_SUCCESS;
     229         164 :   }
     230             : 
     231          52 :   ulong         sysvar_buf_len;
     232          52 :   uchar const * sysvar_buf =
     233          52 :     fd_sysvar_cache_data_query( vm->instr_ctx->sysvar_cache, sysvar_id, &sysvar_buf_len );
     234          52 :   if( FD_UNLIKELY( !sysvar_buf ) ) {
     235           0 :     *_ret = 2UL;
     236           0 :     return FD_VM_SUCCESS;
     237           0 :   }
     238             : 
     239             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L223-L228
     240             :      Note the length check is at the very end to fail after performing sufficient checks. */
     241             : 
     242          52 :   if( FD_UNLIKELY( offset_length>sysvar_buf_len ) ) {
     243           0 :     *_ret = 1UL;
     244           0 :     return FD_VM_SUCCESS;
     245           0 :   }
     246             : 
     247          52 :   if( FD_UNLIKELY( sz==0UL ) ) {
     248          21 :     *_ret = 0UL;
     249          21 :     return FD_VM_SUCCESS;
     250          21 :   }
     251             : 
     252          31 :   fd_memcpy( var_query.haddr, sysvar_buf + offset, sz );
     253          31 :   *_ret = 0;
     254          31 :   return FD_VM_SUCCESS;
     255          52 : }
     256             : 
     257             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2043-L2118 */
     258             : int
     259             : fd_vm_syscall_sol_get_epoch_stake( /**/            void *  _vm,
     260             :                                    /**/            ulong   var_addr,
     261             :                                    FD_PARAM_UNUSED ulong   r2,
     262             :                                    FD_PARAM_UNUSED ulong   r3,
     263             :                                    FD_PARAM_UNUSED ulong   r4,
     264             :                                    FD_PARAM_UNUSED ulong   r5,
     265          16 :                                    /**/            ulong * _ret ) {
     266          16 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     267             : 
     268             :   /* Var addr of 0 returns the total active stake on the cluster.
     269             : 
     270             :      https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2057-L2075 */
     271          16 :   if( FD_UNLIKELY( var_addr==0UL ) ) {
     272             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2065-L2066 */
     273           0 :     FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     274             : 
     275             :     /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2074 */
     276           0 :     *_ret = fd_bank_total_epoch_stake_get( vm->instr_ctx->bank );
     277           0 :     return FD_VM_SUCCESS;
     278           0 :   }
     279             : 
     280             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2083-L2091
     281             :      FD_PUBKEY_FOOTPRINT/FD_VM_CPI_BYTES_PER_UNIT is always 32/250 = 0,
     282             :      so we can omit it */
     283             : 
     284          32 :   FD_VM_CU_UPDATE( vm, FD_VM_MEM_OP_BASE_COST + FD_VM_SYSCALL_BASE_COST );
     285             : 
     286             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2103-L2104 */
     287          16 :   fd_pubkey_t const * vote_address = FD_VM_MEM_HADDR_LD( vm, var_addr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
     288             : 
     289             :   /* https://github.com/anza-xyz/agave/blob/v2.2.14/runtime/src/bank.rs#L6954 */
     290           0 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes_locking_modify( vm->instr_ctx->bank );
     291             : 
     292          16 :   ulong       stake;
     293          16 :   fd_pubkey_t node_account;
     294          16 :   int found = fd_vote_stakes_query_t_1( vote_stakes, vm->instr_ctx->bank->data->vote_stakes_fork_id, vote_address, &stake, &node_account );
     295          16 :   *_ret = found ? stake : 0UL;
     296          16 :   fd_bank_vote_stakes_end_locking_modify( vm->instr_ctx->bank );
     297             : 
     298          16 :   return FD_VM_SUCCESS;
     299          32 : }
     300             : 
     301             : int
     302             : fd_vm_syscall_sol_get_stack_height( /**/            void *  _vm,
     303             :                                     FD_PARAM_UNUSED ulong   r1,
     304             :                                     FD_PARAM_UNUSED ulong   r2,
     305             :                                     FD_PARAM_UNUSED ulong   r3,
     306             :                                     FD_PARAM_UNUSED ulong   r4,
     307             :                                     FD_PARAM_UNUSED ulong   r5,
     308          86 :                                     /**/            ulong * _ret ) {
     309             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
     310          86 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     311             : 
     312          86 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     313             : 
     314           0 :   *_ret = vm->instr_ctx->runtime->instr.stack_sz;
     315          86 :   return FD_VM_SUCCESS;
     316          86 : }
     317             : 
     318             : int
     319             : fd_vm_syscall_sol_get_return_data( /**/            void *  _vm,
     320             :                                    /**/            ulong   return_data_vaddr,
     321             :                                    /**/            ulong   sz,
     322             :                                    /**/            ulong   program_id_vaddr,
     323             :                                    FD_PARAM_UNUSED ulong   r4,
     324             :                                    FD_PARAM_UNUSED ulong   r5,
     325         105 :                                    /**/            ulong * _ret ) {
     326         105 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     327             : 
     328             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1465 */
     329         105 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     330             : 
     331             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1467 */
     332           0 :   fd_txn_return_data_t const * return_data = &vm->instr_ctx->txn_out->details.return_data;
     333             : 
     334             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1468 */
     335         105 :   ulong length = fd_ulong_min( return_data->len, sz );
     336             : 
     337             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1469-L1492 */
     338         105 :   if( FD_LIKELY( length ) ) {
     339             : 
     340             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1470-L1474 */
     341          24 :     FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( length, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
     342             : 
     343             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1476-L1481 */
     344           0 :     fd_vm_haddr_query_t return_data_query = {
     345          24 :       .vaddr    = return_data_vaddr,
     346          24 :       .align    = FD_VM_ALIGN_RUST_U8,
     347          24 :       .sz       = length,
     348          24 :       .is_slice = 1
     349          24 :     };
     350             : 
     351          24 :     fd_vm_haddr_query_t program_id_query = {
     352          24 :       .vaddr    = program_id_vaddr,
     353          24 :       .align    = FD_VM_ALIGN_RUST_PUBKEY,
     354          24 :       .sz       = sizeof(fd_pubkey_t),
     355          24 :       .is_slice = 0
     356          24 :     };
     357             : 
     358          24 :     fd_vm_haddr_query_t * queries[] = { &return_data_query, &program_id_query };
     359          24 :     FD_VM_TRANSLATE_MUT( vm, queries );
     360             : 
     361             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1490-L1491 */
     362          22 :     memcpy( return_data_query.haddr, return_data->data, length );
     363          22 :     memcpy( program_id_query.haddr, &return_data->program_id, sizeof(fd_pubkey_t) );
     364          22 :   }
     365             : 
     366             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1495 */
     367         103 :   *_ret = return_data->len;
     368         103 :   return FD_VM_SUCCESS;
     369         105 : }
     370             : 
     371             : int
     372             : fd_vm_syscall_sol_set_return_data( /**/            void *  _vm,
     373             :                                    /**/            ulong   src_vaddr,
     374             :                                    /**/            ulong   src_sz,
     375             :                                    FD_PARAM_UNUSED ulong   r3,
     376             :                                    FD_PARAM_UNUSED ulong   r4,
     377             :                                    FD_PARAM_UNUSED ulong   r5,
     378         116 :                                    /**/            ulong * _ret ) {
     379             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
     380         116 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     381             : 
     382             :   /* In the original version of this code, there was an FD_TEST
     383             :      to check if the VM was attached to an instruction context (that
     384             :      would have crashed anyway because of pointer chasing).  If the VM
     385             :      is being run outside the Solana runtime, it should never invoke
     386             :      this syscall in the first place.  So we treat this as a SIGCALL in
     387             :      a non-crashing way for the time being. */
     388         116 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     389         116 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     390             : 
     391         232 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
     392             : 
     393             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
     394         116 :   if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
     395             :     /* TODO: this is a bit annoying, we may want to unify return codes...
     396             :        - FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE is Agave's return code,
     397             :          also used for logging */
     398           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE );
     399           0 :     return FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE;
     400           0 :   }
     401             : 
     402             :   /* src_sz == 0 is ok */
     403         232 :   void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
     404             : 
     405             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/bpf_loader/src/syscalls/mod.rs#L1480-L1484 */
     406           0 :   fd_pubkey_t const * program_id = NULL;
     407         232 :   int err = fd_exec_instr_ctx_get_last_program_key( vm->instr_ctx, &program_id );
     408         232 :   if( FD_UNLIKELY( err ) ) {
     409           0 :     FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     410           0 :     return err;
     411           0 :   }
     412             : 
     413         116 :   fd_txn_return_data_t * return_data = &instr_ctx->txn_out->details.return_data;
     414             : 
     415         116 :   return_data->len = src_sz;
     416         116 :   if( FD_LIKELY( src_sz!=0UL ) ) {
     417         116 :     fd_memcpy( return_data->data, src, src_sz );
     418         116 :   }
     419         116 :   return_data->program_id = *program_id;
     420             : 
     421         116 :   *_ret = 0;
     422         116 :   return FD_VM_SUCCESS;
     423         232 : }
     424             : 
     425             : /* Used to query and convey information about the sibling instruction
     426             :    https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
     427             : 
     428             :     */
     429             : struct fd_vm_syscall_processed_sibling_instruction {
     430             :   /* Length of the instruction data */
     431             :   ulong data_len;
     432             :   /* Number of accounts */
     433             :   ulong accounts_len;
     434             : };
     435             : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
     436             : 
     437           2 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE  (16UL)
     438           2 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
     439             : 
     440             : /* https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402 */
     441             : int
     442             : fd_vm_syscall_sol_get_processed_sibling_instruction(
     443             :     void * _vm,
     444             :     ulong index,
     445             :     ulong result_meta_vaddr,
     446             :     ulong result_program_id_vaddr,
     447             :     ulong result_data_vaddr,
     448             :     ulong result_accounts_vaddr,
     449             :     ulong * _ret
     450          75 : ) {
     451          75 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     452             : 
     453             :   /* Consume base compute cost
     454             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1513 */
     455          75 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     456             : 
     457             :   /* Get the current instruction stack height.  This value is 1-indexed
     458             :      (top level instruction has a stack height of 1).
     459             :     https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1517 */
     460           0 :   ulong stack_height = vm->instr_ctx->runtime->instr.stack_sz;
     461             : 
     462             :   /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
     463             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1518-L1522 */
     464          75 :   ulong instruction_trace_length = vm->instr_ctx->runtime->instr.trace_length;
     465          75 :   ulong reverse_index_at_stack_height = 0UL;
     466          75 :   fd_instr_info_t * found_instruction_context = NULL;
     467         191 :   for( ulong index_in_trace=instruction_trace_length; index_in_trace>0UL; index_in_trace-- ) {
     468             : 
     469             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1524-L1526
     470             :        This error can never happen */
     471             : 
     472             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1527-L1529 */
     473         147 :     fd_instr_info_t * instruction_context = &vm->instr_ctx->runtime->instr.trace[ index_in_trace-1UL ];
     474         147 :     if( FD_LIKELY( instruction_context->stack_height<stack_height ) ) {
     475          29 :       break;
     476          29 :     }
     477             : 
     478             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1530-L1536 */
     479         118 :     if( FD_UNLIKELY( instruction_context->stack_height==stack_height ) ) {
     480          85 :       if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL )==reverse_index_at_stack_height ) ) {
     481           2 :         found_instruction_context = instruction_context;
     482           2 :         break;
     483           2 :       }
     484          83 :       reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
     485          83 :     }
     486         118 :   }
     487             : 
     488             :   /* If we have found an entry, then copy the instruction into the
     489             :      result addresses.
     490             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1539-L1588
     491             :    */
     492          75 :   if( FD_LIKELY( found_instruction_context != NULL ) ) {
     493           2 :     fd_vm_haddr_query_t result_header_query = {
     494           2 :       .vaddr    = result_meta_vaddr,
     495           2 :       .align    = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
     496           2 :       .sz       = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     497           2 :       .is_slice = 0,
     498           2 :     };
     499             : 
     500           2 :     fd_vm_haddr_query_t * queries[] = { &result_header_query };
     501           2 :     FD_VM_TRANSLATE_MUT( vm, queries );
     502             : 
     503           2 :     fd_vm_syscall_processed_sibling_instruction_t * result_header = result_header_query.haddr;
     504             : 
     505             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1546-L1583 */
     506           2 :     if( result_header->data_len==found_instruction_context->data_sz && result_header->accounts_len==found_instruction_context->acct_cnt ) {
     507           1 :       fd_vm_haddr_query_t program_id_query = {
     508           1 :         .vaddr    = result_program_id_vaddr,
     509           1 :         .align    = FD_VM_ALIGN_RUST_PUBKEY,
     510           1 :         .sz       = sizeof(fd_pubkey_t),
     511           1 :         .is_slice = 0,
     512           1 :       };
     513             : 
     514           1 :       fd_vm_haddr_query_t data_query = {
     515           1 :         .vaddr    = result_data_vaddr,
     516           1 :         .align    = FD_VM_ALIGN_RUST_U8,
     517           1 :         .sz       = result_header->data_len,
     518           1 :         .is_slice = 1,
     519           1 :       };
     520             : 
     521           1 :       fd_vm_haddr_query_t accounts_query = {
     522           1 :         .vaddr    = result_accounts_vaddr,
     523           1 :         .align    = FD_VM_RUST_ACCOUNT_META_ALIGN,
     524           1 :         .sz       = fd_ulong_sat_mul( result_header->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE ),
     525           1 :         .is_slice = 1,
     526           1 :       };
     527             : 
     528           1 :       fd_vm_haddr_query_t * queries[] = { &program_id_query, &data_query, &accounts_query, &result_header_query };
     529           1 :       FD_VM_TRANSLATE_MUT( vm, queries );
     530             : 
     531           1 :       fd_pubkey_t *               program_id = program_id_query.haddr;
     532           1 :       uchar *                     data       = data_query.haddr;
     533           1 :       fd_vm_rust_account_meta_t * accounts   = accounts_query.haddr;
     534             : 
     535             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1561-L1562 */
     536           1 :       fd_pubkey_t const * instr_ctx_program_id = NULL;
     537           1 :       int err = fd_runtime_get_key_of_account_at_index(
     538           1 :           vm->instr_ctx->txn_out,
     539           1 :           found_instruction_context->program_id,
     540           1 :           &instr_ctx_program_id
     541           1 :       );
     542           1 :       if( FD_UNLIKELY( err ) ) {
     543           0 :         FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     544           0 :         return err;
     545           0 :       }
     546           1 :       fd_memcpy( program_id, instr_ctx_program_id, sizeof(fd_pubkey_t) );
     547             : 
     548             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1563 */
     549           1 :       fd_memcpy( data, found_instruction_context->data, found_instruction_context->data_sz );
     550             : 
     551             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1564-L1581 */
     552         259 :       for( ushort i=0; i<found_instruction_context->acct_cnt; i++ ) {
     553         258 :         fd_pubkey_t const * account_key;
     554         258 :         ushort txn_idx = found_instruction_context->accounts[ i ].index_in_transaction;
     555         258 :         err            = fd_runtime_get_key_of_account_at_index( vm->instr_ctx->txn_out, txn_idx, &account_key );
     556         258 :         if( FD_UNLIKELY( err ) ) {
     557           0 :           FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     558           0 :           return err;
     559           0 :         }
     560             : 
     561         258 :         fd_memcpy( accounts[ i ].pubkey, account_key, sizeof(fd_pubkey_t) );
     562         258 :         accounts[ i ].is_signer   = !!(found_instruction_context->accounts[ i ].is_signer );
     563         258 :         accounts[ i ].is_writable = !!(found_instruction_context->accounts[ i ].is_writable );
     564         258 :       }
     565           1 :     } else {
     566             :       /* Copy the actual metadata into the result meta struct
     567             :          https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1584-L1586 */
     568           1 :       result_header->data_len     = found_instruction_context->data_sz;
     569           1 :       result_header->accounts_len = found_instruction_context->acct_cnt;
     570           1 :     }
     571             : 
     572             :     /* Return true as we found a sibling instruction
     573             :        https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1588 */
     574           2 :     *_ret = 1UL;
     575           2 :     return FD_VM_SUCCESS;
     576           2 :   }
     577             : 
     578             :   /* Return false if we didn't find a sibling instruction
     579             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1590 */
     580          73 :   *_ret = 0UL;
     581          73 :   return FD_VM_SUCCESS;
     582          75 : }
     583             : 
     584             : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/sysvar.rs#L80 */
     585             : int
     586             : fd_vm_syscall_sol_get_epoch_rewards_sysvar( /**/            void *  _vm,
     587             :                                             /**/            ulong   out_vaddr,
     588             :                                             FD_PARAM_UNUSED ulong   r2,
     589             :                                             FD_PARAM_UNUSED ulong   r3,
     590             :                                             FD_PARAM_UNUSED ulong   r4,
     591             :                                             FD_PARAM_UNUSED ulong   r5,
     592        3425 :                                             /**/            ulong * _ret ) {
     593        3425 :   fd_vm_t * vm = _vm;
     594        3425 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     595        3425 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
     596             : 
     597        6850 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sysvar_epoch_rewards_t) ) );
     598             : 
     599        3425 :   if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
     600           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
     601           0 :     return FD_VM_ERR_INVAL;
     602           0 :   }
     603             : 
     604        3425 :   uchar * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_REWARDS, sizeof(fd_sysvar_epoch_rewards_t) );
     605             : 
     606           0 :   fd_sysvar_epoch_rewards_t epoch_rewards;
     607        3420 :   if( FD_UNLIKELY( !fd_sysvar_cache_epoch_rewards_read( instr_ctx->sysvar_cache, &epoch_rewards ) ) ) {
     608        3267 :     FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
     609        3267 :     return FD_VM_ERR_INVAL;
     610        3267 :   }
     611         153 :   memcpy( out, &epoch_rewards, sizeof(fd_sysvar_epoch_rewards_t) );
     612         153 :   memset( out+81, 0, 15 ); /* padding */
     613             : 
     614         153 :   *_ret = 0UL;
     615         153 :   return FD_VM_SUCCESS;
     616        3420 : }

Generated by: LCOV version 1.14