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: 50 189 26.5 %
Date: 2024-11-13 11:58:15 Functions: 5 9 55.6 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : #include "../../runtime/sysvar/fd_sysvar.h"
       3             : #include "../../runtime/sysvar/fd_sysvar_clock.h"
       4             : #include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h"
       5             : #include "../../runtime/sysvar/fd_sysvar_fees.h"
       6             : #include "../../runtime/sysvar/fd_sysvar_rent.h"
       7             : #include "../../runtime/sysvar/fd_sysvar_last_restart_slot.h"
       8             : #include "../../runtime/context/fd_exec_txn_ctx.h"
       9             : #include "../../runtime/context/fd_exec_instr_ctx.h"
      10             : 
      11             : int
      12             : fd_vm_syscall_sol_get_clock_sysvar( /**/            void *  _vm,
      13             :                                     /**/            ulong   out_vaddr,
      14             :                                     FD_PARAM_UNUSED ulong   r2,
      15             :                                     FD_PARAM_UNUSED ulong   r3,
      16             :                                     FD_PARAM_UNUSED ulong   r4,
      17             :                                     FD_PARAM_UNUSED ulong   r5,
      18          90 :                                     /**/            ulong * _ret ) {
      19          90 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      20             : 
      21             :   /* FIXME: In the original version of this code, there was an FD_TEST
      22             :      to check if the VM was attached to an instruction context (that
      23             :      would have crashed anyway because of pointer chasing).  If the VM
      24             :      is being run outside the Solana runtime, it should never invoke
      25             :      this syscall in the first place.  So we treat this as a SIGCALL in
      26             :      a non-crashing way. */
      27             : 
      28          90 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      29          90 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
      30             : 
      31         180 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SOL_SYSVAR_CLOCK_FOOTPRINT ) );
      32             : 
      33          90 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_CLOCK, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
      34             : 
      35             :   /* FIXME: is it possible to do the read in-place? */
      36           0 :   fd_sol_sysvar_clock_t clock[1];
      37          90 :   fd_sol_sysvar_clock_new( clock ); /* FIXME: probably should be init as not a distributed persistent object */
      38          90 :   fd_sysvar_clock_read( clock, instr_ctx->slot_ctx );
      39             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
      40             : 
      41          90 :   memcpy( out, clock, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
      42             : 
      43          90 :   *_ret = 0UL;
      44          90 :   return FD_VM_SUCCESS;
      45         180 : }
      46             : 
      47             : int
      48             : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/            void *  _vm,
      49             :                                              /**/            ulong   out_vaddr,
      50             :                                              FD_PARAM_UNUSED ulong   r2,
      51             :                                              FD_PARAM_UNUSED ulong   r3,
      52             :                                              FD_PARAM_UNUSED ulong   r4,
      53             :                                              FD_PARAM_UNUSED ulong   r5,
      54           6 :                                              /**/            ulong * _ret ) {
      55           6 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      56             : 
      57             :   /* FIXME: In the original version of this code, there was an FD_TEST
      58             :      to check if the VM was attached to an instruction context (that
      59             :      would have crashed anyway because of pointer chasing).  If the VM
      60             :      is being run outside the Solana runtime, it should never invoke
      61             :      this syscall in the first place.  So we treat this as a SIGCALL in
      62             :      a non-crashing way for the time being. */
      63             : 
      64           6 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
      65           6 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
      66             : 
      67          12 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_EPOCH_SCHEDULE_FOOTPRINT ) );
      68             : 
      69           6 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE, FD_EPOCH_SCHEDULE_FOOTPRINT );
      70             : 
      71             :   /* FIXME: is it possible to do the read in-place? */
      72           0 :   fd_epoch_schedule_t schedule[1];
      73           6 :   fd_epoch_schedule_new( schedule ); /* FIXME: probably should be init as not a distributed persistent object */
      74           6 :   fd_sysvar_epoch_schedule_read( schedule, instr_ctx->slot_ctx );
      75             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
      76             : 
      77           6 :   memcpy( out, schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
      78             : 
      79           6 :   *_ret = 0UL;
      80           6 :   return FD_VM_SUCCESS;
      81          12 : }
      82             : 
      83             : int
      84             : fd_vm_syscall_sol_get_fees_sysvar( /**/            void *  _vm,
      85             :                                    /**/            ulong   out_vaddr,
      86             :                                    FD_PARAM_UNUSED ulong   r2,
      87             :                                    FD_PARAM_UNUSED ulong   r3,
      88             :                                    FD_PARAM_UNUSED ulong   r4,
      89             :                                    FD_PARAM_UNUSED ulong   r5,
      90           0 :                                    /**/            ulong * _ret ) {
      91           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      92             : 
      93             :   /* FIXME: In the original version of this code, there was an FD_TEST
      94             :      to check if the VM was attached to an instruction context (that
      95             :      would have crashed anyway because of pointer chasing).  If the VM
      96             :      is being run outside the Solana runtime, it should never invoke
      97             :      this syscall in the first place.  So we treat this as a SIGCALL in
      98             :      a non-crashing way for the time being. */
      99             : 
     100           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     101           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
     102             : 
     103           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SYSVAR_FEES_FOOTPRINT ) );
     104             : 
     105           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_FEES, FD_SYSVAR_FEES_FOOTPRINT );
     106             : 
     107             :   /* FIXME: is it possible to do the read in-place? */
     108           0 :   fd_sysvar_fees_t fees[1];
     109           0 :   fd_sysvar_fees_new( fees ); /* FIXME: probably should be init as not a distributed persistent object */
     110           0 :   fd_sysvar_fees_read( fees, instr_ctx->slot_ctx );
     111             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
     112             : 
     113           0 :   memcpy( out, fees, FD_SYSVAR_FEES_FOOTPRINT );
     114             : 
     115           0 :   *_ret = 0UL;
     116           0 :   return FD_VM_SUCCESS;
     117           0 : }
     118             : 
     119             : int
     120             : fd_vm_syscall_sol_get_rent_sysvar( /**/            void *  _vm,
     121             :                                    /**/            ulong   out_vaddr,
     122             :                                    FD_PARAM_UNUSED ulong   r2,
     123             :                                    FD_PARAM_UNUSED ulong   r3,
     124             :                                    FD_PARAM_UNUSED ulong   r4,
     125             :                                    FD_PARAM_UNUSED ulong   r5,
     126           0 :                                    /**/            ulong * _ret ) {
     127           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     128             : 
     129             :   /* FIXME: In the original version of this code, there was an FD_TEST
     130             :      to check if the VM was attached to an instruction context (that
     131             :      would have crashed anyway because of pointer chasing).  If the VM
     132             :      is being run outside the Solana runtime, it should never invoke
     133             :      this syscall in the first place.  So we treat this as a SIGCALL in
     134             :      a non-crashing way for the time being. */
     135             : 
     136           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     137           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
     138             : 
     139           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_RENT_FOOTPRINT ) );
     140             : 
     141           0 :   void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_RENT, FD_RENT_FOOTPRINT );
     142             : 
     143             :   /* FIXME: is it possible to do the read in-place? */
     144           0 :   fd_rent_t rent[1];
     145           0 :   fd_rent_new( rent ); /* FIXME: probably should be init as not a distributed persistent object */
     146           0 :   fd_sysvar_rent_read( rent, instr_ctx->slot_ctx );
     147             :   /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
     148             : 
     149           0 :   memcpy( out, rent, FD_RENT_FOOTPRINT );
     150             : 
     151           0 :   *_ret = 0UL;
     152           0 :   return FD_VM_SUCCESS;
     153           0 : }
     154             : 
     155             : /* https://github.com/anza-xyz/agave/blob/36323b6dcd3e29e4d6fe6d73d716a3f33927148b/programs/bpf_loader/src/syscalls/sysvar.rs#L144 */
     156             : int
     157             : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/            void *  _vm,
     158             :                                                 /**/            ulong   out_vaddr,
     159             :                                                 FD_PARAM_UNUSED ulong   r2,
     160             :                                                 FD_PARAM_UNUSED ulong   r3,
     161             :                                                 FD_PARAM_UNUSED ulong   r4,
     162             :                                                 FD_PARAM_UNUSED ulong   r5,
     163           3 :                                                 /**/            ulong * _ret ) {
     164           3 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     165             : 
     166           3 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ) );
     167             : 
     168           0 :   fd_sol_sysvar_last_restart_slot_t * out =
     169           9 :     FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT );
     170           3 :   if( FD_UNLIKELY( fd_sysvar_last_restart_slot_read( out, vm->instr_ctx->slot_ctx ) == NULL ) ) {
     171           0 :     return FD_VM_ERR_ABORT;
     172           0 :   }
     173             : 
     174           3 :   *_ret = 0UL;
     175           3 :   return FD_VM_SUCCESS;
     176           9 : }
     177             : 
     178             : int
     179             : fd_vm_syscall_sol_get_stack_height( /**/            void *  _vm,
     180             :                                     FD_PARAM_UNUSED ulong   r1,
     181             :                                     FD_PARAM_UNUSED ulong   r2,
     182             :                                     FD_PARAM_UNUSED ulong   r3,
     183             :                                     FD_PARAM_UNUSED ulong   r4,
     184             :                                     FD_PARAM_UNUSED ulong   r5,
     185           3 :                                     /**/            ulong * _ret ) {
     186             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
     187           3 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     188             : 
     189           3 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     190             : 
     191           0 :   *_ret = vm->instr_ctx->txn_ctx->instr_stack_sz;
     192           3 :   return FD_VM_SUCCESS;
     193           3 : }
     194             : 
     195             : int
     196             : fd_vm_syscall_sol_get_return_data( /**/            void *  _vm,
     197             :                                    /**/            ulong   dst_vaddr,
     198             :                                    /**/            ulong   dst_max,
     199             :                                    /**/            ulong   program_id_vaddr,
     200             :                                    FD_PARAM_UNUSED ulong   r4,
     201             :                                    FD_PARAM_UNUSED ulong   r5,
     202           6 :                                    /**/            ulong * _ret ) {
     203             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1345 */
     204           6 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     205             : 
     206           6 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     207             : 
     208           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     209           6 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
     210             : 
     211           6 :   fd_txn_return_data_t const * return_data    = &instr_ctx->txn_ctx->return_data;
     212           6 :   ulong                        return_data_sz = return_data->len;
     213             : 
     214           6 :   ulong cpy_sz = fd_ulong_min( return_data_sz, dst_max );
     215             : 
     216           6 :   if( FD_LIKELY( cpy_sz ) ) {
     217             : 
     218           6 :     FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( cpy_sz, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
     219             : 
     220          12 :     void * dst        = FD_VM_MEM_SLICE_HADDR_ST( vm, dst_vaddr, FD_VM_ALIGN_RUST_U8, cpy_sz );
     221             : 
     222           0 :     memcpy( dst,         return_data->data,       cpy_sz              );
     223             : 
     224             :     /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1376-L1381
     225             :        These can never happen. */
     226             : 
     227          12 :     void * program_id = FD_VM_MEM_HADDR_ST( vm, program_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, sizeof(fd_pubkey_t) );
     228             : 
     229           3 :     FD_VM_MEM_CHECK_NON_OVERLAPPING( vm, (ulong)dst, cpy_sz, (ulong)program_id, sizeof(fd_pubkey_t) );
     230             : 
     231           0 :     memcpy( program_id, &return_data->program_id, sizeof(fd_pubkey_t) );
     232           0 :   }
     233             : 
     234           0 :   *_ret = return_data_sz;
     235           0 :   return FD_VM_SUCCESS;
     236           6 : }
     237             : 
     238             : int
     239             : fd_vm_syscall_sol_set_return_data( /**/            void *  _vm,
     240             :                                    /**/            ulong   src_vaddr,
     241             :                                    /**/            ulong   src_sz,
     242             :                                    FD_PARAM_UNUSED ulong   r3,
     243             :                                    FD_PARAM_UNUSED ulong   r4,
     244             :                                    FD_PARAM_UNUSED ulong   r5,
     245           0 :                                    /**/            ulong * _ret ) {
     246             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
     247           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     248             : 
     249           0 :   fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
     250           0 :   if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
     251             : 
     252           0 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
     253             : 
     254             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
     255           0 :   if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
     256             :     /* TODO: this is a bit annoying, we may want to unify return codes...
     257             :        - FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE is Agave's return code,
     258             :          also used for logging
     259             :        - FD_VM_ERR_RETURN_DATA_TOO_LARGE is Firedancer return code */
     260           0 :     FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE );
     261           0 :     return FD_VM_ERR_RETURN_DATA_TOO_LARGE;
     262           0 :   }
     263             : 
     264             :   /* src_sz == 0 is ok */
     265           0 :   void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
     266             : 
     267           0 :   fd_pubkey_t const    * program_id  = &instr_ctx->instr->program_id_pubkey;
     268           0 :   fd_txn_return_data_t * return_data = &instr_ctx->txn_ctx->return_data;
     269             : 
     270           0 :   return_data->len = src_sz;
     271           0 :   if( FD_LIKELY( src_sz!=0UL ) ) {
     272           0 :     fd_memcpy( return_data->data, src, src_sz );
     273           0 :   }
     274           0 :   memcpy( &return_data->program_id, program_id, sizeof(fd_pubkey_t) );
     275             : 
     276           0 :   *_ret = 0;
     277           0 :   return FD_VM_SUCCESS;
     278           0 : }
     279             : 
     280             : /* Used to query and convey information about the sibling instruction
     281             :    https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
     282             : 
     283             :     */
     284             : struct fd_vm_syscall_processed_sibling_instruction {
     285             :   /* Length of the instruction data */
     286             :   ulong data_len;
     287             :   /* Number of accounts */
     288             :   ulong accounts_len;
     289             : };
     290             : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
     291             : 
     292             : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE  (16UL)
     293             : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
     294             : 
     295             : /*
     296             : sol_get_last_processed_sibling_instruction returns the last element from a reverse-ordered
     297             : list of successfully processed sibling instructions: the "processed sibling instruction list".
     298             : 
     299             : For example, given the call flow:
     300             : A
     301             : B -> C -> D
     302             : B
     303             : B -> F          (current execution point)
     304             : 
     305             : B's processed sibling instruction list is [A]
     306             : F's processed sibling instruction list is [E, C]
     307             : 
     308             : This allows the current instruction to know what the last processed sibling instruction was.
     309             : This is useful to check that critical preceeding instructions have actually executed: for example
     310             : ensuring that an assert instruction has successfully executed.
     311             : 
     312             : Parameters:
     313             : - index:
     314             : - result_meta_vaddr: virtual address of the object where metadata about the last processed sibling instruction will be stored upon successful execution (the length of the arrays in the result).
     315             :   Has the type solana_program::instruction::ProcessedSiblingInstruction
     316             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L672-L681
     317             : - result_program_id_vaddr: virtual address where the pubkey of the program ID of the last processed sibling instruction will be stored upon successful execution
     318             : - result_data_vaddr: virtual address where the instruction data of the last processed sibling instruction will be stored upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.data_len
     319             : - result_accounts_vaddr: virtual address where an array of account meta structures will be stored into upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.accounts_len
     320             :   Each account meta has the type solana_program::instruction::AccountMeta
     321             :     https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L525-L548
     322             : 
     323             : Result:
     324             : If a processed sibling instruction is found then 1 will be written into r0, and the result_* data structures
     325             : above will be populated with the last processed sibling instruction.
     326             : If there is no processed sibling instruction, 0 will be written into r0.
     327             : 
     328             : Syscall entrypoint: https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402
     329             : */
     330             : int
     331             : fd_vm_syscall_sol_get_processed_sibling_instruction(
     332             :     void * _vm,
     333             :     ulong index,
     334             :     ulong result_meta_vaddr,
     335             :     ulong result_program_id_vaddr,
     336             :     ulong result_data_vaddr,
     337             :     ulong result_accounts_vaddr,
     338             :     ulong * ret
     339           0 : ) {
     340             : 
     341           0 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     342             : 
     343             :   /* Consume base compute cost
     344             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1414 */
     345           0 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     346             : 
     347             :   /*
     348             :     Get the current instruction stack height.
     349             : 
     350             :     Top-level instructions in Agave's invocation stack have a depth of 1
     351             :     https://github.com/anza-xyz/agave/blob/d87e23d8d91c32d5f2be2bb3557c730bee1e9434/sdk/program/src/instruction.rs#L732-L733
     352             :     Ours have a depth of 0, so we need to add 1 to account for the difference
     353             :    */
     354           0 :   ulong stack_height = fd_ulong_sat_add( vm->instr_ctx->depth, 1UL );
     355             : 
     356             :   /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
     357             :   https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1422 */
     358           0 :   ulong instruction_trace_length = vm->instr_ctx->txn_ctx->instr_trace_length;
     359           0 :   ulong reverse_index_at_stack_height = 0UL;
     360           0 :   fd_exec_instr_trace_entry_t * trace_entry = NULL;
     361           0 :   for( ulong index_in_trace = instruction_trace_length; index_in_trace > 0UL; index_in_trace-- ) {
     362             : 
     363             :     /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1432-L1434
     364             :        This error can never happen */
     365             : 
     366           0 :     fd_exec_instr_trace_entry_t * candidate_trace_entry = &vm->instr_ctx->txn_ctx->instr_trace[ index_in_trace - 1UL ];
     367           0 :     if( FD_LIKELY( candidate_trace_entry->stack_height < stack_height ) ) {
     368           0 :       break;
     369           0 :     }
     370             : 
     371           0 :     if( FD_UNLIKELY( candidate_trace_entry->stack_height == stack_height ) ) {
     372           0 :       if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL ) == reverse_index_at_stack_height ) ) {
     373           0 :         trace_entry = candidate_trace_entry;
     374           0 :         break;
     375           0 :       }
     376           0 :       reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
     377           0 :     }
     378           0 :   }
     379             : 
     380             :   /* If we have found an entry, then copy the instruction into the result addresses
     381             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1440-L1533
     382             :    */
     383           0 :   if( FD_LIKELY( trace_entry != NULL ) ) {
     384           0 :     fd_instr_info_t * instr_info = trace_entry->instr_info;
     385             : 
     386           0 :     fd_vm_syscall_processed_sibling_instruction_t * result_meta_haddr = FD_VM_MEM_HADDR_ST(
     387           0 :       vm,
     388           0 :       result_meta_vaddr,
     389           0 :       FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
     390           0 :       FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE );
     391             : 
     392             :     /* https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1447 */
     393           0 :     if( ( result_meta_haddr->data_len == trace_entry->instr_info->data_sz ) &&
     394           0 :         ( result_meta_haddr->accounts_len == trace_entry->instr_info->acct_cnt ) ) {
     395             : 
     396           0 :       fd_pubkey_t * result_program_id_haddr = FD_VM_MEM_HADDR_ST(
     397           0 :         vm,
     398           0 :         result_program_id_vaddr,
     399           0 :         FD_VM_ALIGN_RUST_PUBKEY,
     400           0 :         sizeof(fd_pubkey_t) );
     401             : 
     402           0 :       uchar * result_data_haddr = FD_VM_MEM_SLICE_HADDR_ST(
     403           0 :         vm,
     404           0 :         result_data_vaddr,
     405           0 :         FD_VM_ALIGN_RUST_U8,
     406           0 :         result_meta_haddr->data_len);
     407             : 
     408           0 :       ulong accounts_meta_total_size = fd_ulong_sat_mul( result_meta_haddr->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE );
     409           0 :       fd_vm_rust_account_meta_t * result_accounts_haddr = FD_VM_MEM_SLICE_HADDR_ST(
     410           0 :         vm,
     411           0 :         result_accounts_vaddr,
     412           0 :         FD_VM_RUST_ACCOUNT_META_ALIGN,
     413           0 :         accounts_meta_total_size);
     414             : 
     415             :       /* Check for memory overlaps
     416             :          https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1469 */
     417             : 
     418           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     419           0 :         result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     420           0 :         result_program_id_vaddr, sizeof(fd_pubkey_t) );
     421           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     422           0 :         result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     423           0 :         result_accounts_vaddr, accounts_meta_total_size );
     424           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     425           0 :         result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
     426           0 :         result_data_vaddr, result_meta_haddr->data_len );
     427           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     428           0 :         result_program_id_vaddr, sizeof(fd_pubkey_t),
     429           0 :         result_data_vaddr, result_meta_haddr->data_len );
     430           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     431           0 :         result_program_id_vaddr, sizeof(fd_pubkey_t),
     432           0 :         result_accounts_vaddr, accounts_meta_total_size );
     433           0 :       FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
     434           0 :         result_data_vaddr, result_meta_haddr->data_len,
     435           0 :         result_accounts_vaddr, accounts_meta_total_size );
     436             : 
     437             :       /* Copy the instruction into the result addresses
     438             :          https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1506-L1528
     439             : 
     440             :          Note: we assume that the instr accounts are already correct at this point.
     441             :          Agave has many error checks. */
     442           0 :       fd_memcpy( result_program_id_haddr->key, instr_info->program_id_pubkey.key, FD_PUBKEY_FOOTPRINT );
     443           0 :       fd_memcpy( result_data_haddr, instr_info->data, instr_info->data_sz );
     444           0 :       for( ulong i = 0UL; i < instr_info->acct_cnt; i++ ) {
     445           0 :         fd_memcpy( result_accounts_haddr[ i ].pubkey,
     446           0 :                    vm->instr_ctx->txn_ctx->accounts[ instr_info->acct_txn_idxs[ i ] ].key,
     447           0 :                    FD_PUBKEY_FOOTPRINT );
     448           0 :         result_accounts_haddr[ i ].is_signer   = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
     449           0 :         result_accounts_haddr[ i ].is_writable = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
     450           0 :       }
     451           0 :     }
     452             : 
     453             :     /* Copy the actual metadata into the result meta struct
     454             :        https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1529-L1531 */
     455           0 :     result_meta_haddr->data_len     = instr_info->data_sz;
     456           0 :     result_meta_haddr->accounts_len = instr_info->acct_cnt;
     457             : 
     458             :     /* Return true as we found a sibling instruction
     459             :        https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1532 */
     460           0 :     *ret = 1UL;
     461           0 :     return FD_VM_SUCCESS;
     462           0 :   }
     463             : 
     464             :   /* Return false if we didn't find a sibling instruction
     465             :      https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1534 */
     466           0 :   *ret = 0UL;
     467           0 :   return FD_VM_SUCCESS;
     468           0 : }

Generated by: LCOV version 1.14