LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_cpi.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 248 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 12 0.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : #include "../../../ballet/ed25519/fd_curve25519.h"
       3             : #include "../../../util/bits/fd_uwide.h"
       4             : #include "../../runtime/fd_borrowed_account.h"
       5             : #include "../../runtime/fd_executor.h"
       6             : #include <stdio.h>
       7             : 
       8             : /* FIXME: ALGO EFFICIENCY */
       9             : static inline int
      10             : fd_vm_syscall_cpi_is_signer( fd_pubkey_t const * account,
      11             :            fd_pubkey_t const * signers,
      12           0 :            ulong               signers_cnt ) {
      13           0 :   for( ulong i=0UL; i<signers_cnt; i++ ) if( !memcmp( account->uc, signers[i].uc, sizeof(fd_pubkey_t) ) ) return 1;
      14           0 :   return 0;
      15           0 : }
      16             : 
      17             : /*
      18             : fd_vm_prepare_instruction populates instruction_accounts and instruction_accounts_cnt
      19             : with the instruction accounts ready for execution.
      20             : 
      21             : The majority of this logic is taken from
      22             : https://github.com/solana-labs/solana/blob/v1.17.22/program-runtime/src/invoke_context.rs#L535,
      23             : and is not vm-specific, but a part of the runtime.
      24             : TODO: should we move this out of the CPI section?
      25             : 
      26             : The bulk of the logic is concerned with unifying the privileges for each duplicated account,
      27             : ensuring that each duplicate account referenced has the same privileges. It also performs some
      28             : priviledge checks, for example ensuring the necessary signatures are present.
      29             : 
      30             : TODO: instruction calling convention: const parameters after non-const.
      31             : 
      32             : Assumptions:
      33             : - We do not have more than 256 unique accounts in the callee_instr.
      34             :   This limit comes from the fact that a Solana transaction cannot
      35             :   refefence more than 256 unique accounts, due to the transaction
      36             :   serialization format.
      37             : - callee_instr is not null.
      38             : - callee_instr->acct_pubkeys is at least as long as callee_instr->acct_cnt
      39             : - instr_ctx->txn_ctx->accounts_cnt is less than UCHAR_MAX.
      40             :   This is likely because the transaction is limited to 256 accounts.
      41             : - callee_instr->program_id is set to UCHAR_MAX if account is not in instr_ctx->txn_ctx.
      42             : - instruction_accounts is a 256-length empty array.
      43             : 
      44             : Parameters:
      45             : - callee_instr
      46             : - instr_ctx
      47             : - instruction_accounts
      48             : - instruction_accounts_cnt
      49             : - signers
      50             : - signers_cnt
      51             : 
      52             : Returns:
      53             : - instruction_accounts
      54             : - instruction_accounts_cnt
      55             : Populated with the instruction accounts with normalized permissions.
      56             : 
      57             : TODO: is it possible to pass the transaction indexes of the accounts in?
      58             : This would allow us to make some of these algorithms more efficient.
      59             : */
      60             : int
      61             : fd_vm_prepare_instruction( fd_instr_info_t *        callee_instr,
      62             :                            fd_exec_instr_ctx_t *    instr_ctx,
      63             :                            fd_pubkey_t const *      callee_program_id_pubkey,
      64             :                            fd_pubkey_t const        instr_acct_keys[ FD_INSTR_ACCT_MAX ],
      65             :                            fd_instruction_account_t instruction_accounts[ FD_INSTR_ACCT_MAX ],
      66             :                            ulong *                  instruction_accounts_cnt,
      67             :                            fd_pubkey_t const *      signers,
      68           0 :                            ulong                    signers_cnt ) {
      69             : 
      70             :   /* De-duplicate the instruction accounts, using the same logic as Solana */
      71           0 :   ulong deduplicated_instruction_accounts_cnt = 0;
      72           0 :   fd_instruction_account_t deduplicated_instruction_accounts[256] = {0};
      73           0 :   ulong duplicate_indicies_cnt = 0;
      74           0 :   ulong duplicate_indices[256] = {0};
      75             : 
      76             :   /* Normalize the privileges of each instruction account in the callee, after de-duping
      77             :      the account references.
      78             :     https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L540-L595 */
      79           0 :   for( ulong i=0UL; i<callee_instr->acct_cnt; i++ ) {
      80           0 :     ushort index_in_transaction = callee_instr->accounts[i].index_in_transaction;
      81           0 :     ushort index_in_caller      = callee_instr->accounts[i].index_in_caller;
      82             : 
      83           0 :     if( index_in_transaction==USHORT_MAX ) {
      84             :       /* In this case the callee instruction is referencing an unknown account not listed in the
      85             :          transactions accounts. */
      86           0 :       FD_BASE58_ENCODE_32_BYTES( instr_acct_keys[i].uc, id_b58 );
      87           0 :       fd_log_collector_msg_many( instr_ctx, 2, "Instruction references an unknown account ", 42UL, id_b58, id_b58_len );
      88           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
      89           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
      90           0 :     }
      91             : 
      92           0 :     fd_pubkey_t const * callee_pubkey = &instr_ctx->txn_ctx->account_keys[ index_in_transaction ];
      93             : 
      94             :     /* If there was an instruction account before this one which referenced the same
      95             :        transaction account index, find it's index in the deduplicated_instruction_accounts
      96             :        array. */
      97           0 :     ulong duplicate_index = ULONG_MAX;
      98           0 :     for( ulong j=0UL; j<deduplicated_instruction_accounts_cnt; j++ ) {
      99           0 :       if( deduplicated_instruction_accounts[j].index_in_transaction==index_in_transaction ) {
     100           0 :         duplicate_index = j;
     101           0 :         break;
     102           0 :       }
     103           0 :     }
     104             : 
     105             :     /* If this was account referenced in a previous iteration, update the flags to include those set
     106             :        in this iteration. This ensures that after all the iterations, the de-duplicated account flags
     107             :        for each account are the union of all the flags in all the references to that account in this instruction. */
     108             : 
     109             :     /* TODO: FD_UNLIKELY? Need to check which branch is more common by running against a larger mainnet ledger */
     110             :     /* TODO: this code would maybe be easier to read if we inverted the branches */
     111           0 :     if( duplicate_index!=ULONG_MAX ) {
     112           0 :       if ( FD_UNLIKELY( duplicate_index >= deduplicated_instruction_accounts_cnt ) ) {
     113           0 :         FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS, instr_ctx->txn_ctx->instr_err_idx );
     114           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     115           0 :       }
     116             : 
     117           0 :       duplicate_indices[duplicate_indicies_cnt++] = duplicate_index;
     118           0 :       fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[duplicate_index];
     119           0 :       instruction_account->is_signer   = !!(instruction_account->is_signer   | callee_instr->accounts[i].is_signer);
     120           0 :       instruction_account->is_writable = !!(instruction_account->is_writable | callee_instr->accounts[i].is_writable);
     121           0 :     } else {
     122             :       /* In the case where the callee instruction is NOT a duplicate, we need to
     123             :          create the deduplicated_instruction_accounts fd_instruction_account_t object. */
     124             : 
     125             :       /* index_in_caller is set to USHORT_MAX in VM_SYSCALL_CPI_INSTRUCTION_TO_INSTR_FUNC if not found */
     126           0 :       if( index_in_caller == USHORT_MAX ) {
     127           0 :         FD_BASE58_ENCODE_32_BYTES( callee_pubkey->uc, id_b58 );
     128           0 :         fd_log_collector_msg_many( instr_ctx, 2, "Instruction references an unknown account ", 42UL, id_b58, id_b58_len );
     129           0 :         FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     130           0 :         return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     131           0 :       }
     132             : 
     133             :       /* Add the instruction account to the duplicate indicies array */
     134           0 :       duplicate_indices[duplicate_indicies_cnt++] = deduplicated_instruction_accounts_cnt;
     135             : 
     136             :       /* Initialize the instruction account in the deduplicated_instruction_accounts array */
     137           0 :       fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[deduplicated_instruction_accounts_cnt++];
     138           0 :       *instruction_account = fd_instruction_account_init( index_in_transaction,
     139           0 :                                                           index_in_caller,
     140           0 :                                                           (ushort)i,
     141           0 :                                                           !!(callee_instr->accounts[i].is_writable),
     142           0 :                                                           !!(callee_instr->accounts[i].is_signer) );
     143           0 :     }
     144           0 :   }
     145             : 
     146             :   /* Check the normalized account permissions for privilege escalation.
     147             :      https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L596-L624 */
     148           0 :   for( ulong i = 0; i < deduplicated_instruction_accounts_cnt; i++ ) {
     149           0 :     fd_instruction_account_t * instruction_account = &deduplicated_instruction_accounts[i];
     150             : 
     151             :     /* https://github.com/anza-xyz/agave/blob/v2.1.14/program-runtime/src/invoke_context.rs#L390-L393 */
     152           0 :     fd_guarded_borrowed_account_t borrowed_caller_acct;
     153           0 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, instruction_account->index_in_caller, &borrowed_caller_acct );
     154             : 
     155             :     /* Check that the account is not read-only in the caller but writable in the callee */
     156           0 :     if( FD_UNLIKELY( instruction_account->is_writable && !fd_borrowed_account_is_writable( &borrowed_caller_acct ) ) ) {
     157           0 :       FD_BASE58_ENCODE_32_BYTES( borrowed_caller_acct.acct->pubkey->uc, id_b58 );
     158           0 :       fd_log_collector_msg_many( instr_ctx, 2, id_b58, id_b58_len, "'s writable privilege escalated", 31UL );
     159           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION, instr_ctx->txn_ctx->instr_err_idx );
     160           0 :       return FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION;
     161           0 :     }
     162             : 
     163             :     /* If the account is signed in the callee, it must be signed by the caller or the program */
     164           0 :     if ( FD_UNLIKELY( instruction_account->is_signer && !( fd_borrowed_account_is_signer( &borrowed_caller_acct ) || fd_vm_syscall_cpi_is_signer( borrowed_caller_acct.acct->pubkey, signers, signers_cnt) ) ) ) {
     165           0 :       FD_BASE58_ENCODE_32_BYTES( borrowed_caller_acct.acct->pubkey->uc, id_b58 );
     166           0 :       fd_log_collector_msg_many( instr_ctx, 2, id_b58, id_b58_len, "'s signer privilege escalated", 29UL );
     167           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION, instr_ctx->txn_ctx->instr_err_idx );
     168           0 :       return FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION;
     169           0 :     }
     170           0 :   }
     171             : 
     172             :   /* Copy the accounts with their normalized permissions over to the final instruction_accounts array,
     173             :      and set the callee_instr acct_flags. */
     174           0 :   for (ulong i = 0; i < duplicate_indicies_cnt; i++) {
     175           0 :     ulong duplicate_index = duplicate_indices[i];
     176             : 
     177             :     /* Failing this condition is technically impossible, but it is probably safest to keep this in
     178             :        so that we throw InstructionError::NotEnoughAccountKeys at the same point at Solana does,
     179             :        in the event any surrounding code is changed.
     180             :        https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/program-runtime/src/invoke_context.rs#L625-L633 */
     181           0 :     if ( FD_LIKELY( duplicate_index < deduplicated_instruction_accounts_cnt ) ) {
     182           0 :       instruction_accounts[i] = deduplicated_instruction_accounts[duplicate_index];
     183           0 :       callee_instr->accounts[i].is_writable = !!(instruction_accounts[i].is_writable);
     184           0 :       callee_instr->accounts[i].is_signer   = !!(instruction_accounts[i].is_signer);
     185           0 :     } else {
     186           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS, instr_ctx->txn_ctx->instr_err_idx );
     187           0 :       return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     188           0 :     }
     189           0 :   }
     190             : 
     191           0 :   if( FD_FEATURE_ACTIVE( instr_ctx->txn_ctx->slot, &instr_ctx->txn_ctx->features, lift_cpi_caller_restriction ) ) {
     192           0 :     if( FD_UNLIKELY( -1==fd_exec_txn_ctx_find_index_of_account( instr_ctx->txn_ctx, callee_program_id_pubkey ) ) ) {
     193           0 :       FD_BASE58_ENCODE_32_BYTES( callee_program_id_pubkey->uc, id_b58 );
     194           0 :       fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
     195           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     196           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     197           0 :     }
     198           0 :   } else {
     199             :     /* Obtain the program account index and return a MissingAccount error if not found.
     200             :        https://github.com/anza-xyz/agave/blob/v2.1.14/program-runtime/src/invoke_context.rs#L430-L435 */
     201           0 :     int program_idx = fd_exec_instr_ctx_find_idx_of_instr_account( instr_ctx, callee_program_id_pubkey );
     202           0 :     if( FD_UNLIKELY( program_idx == -1 ) ) {
     203           0 :       FD_BASE58_ENCODE_32_BYTES( callee_program_id_pubkey->uc, id_b58 );
     204           0 :       fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
     205           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     206           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     207           0 :     }
     208             : 
     209             :     /* Caller is in charge of setting an appropriate sentinel value (i.e., UCHAR_MAX) for callee_instr->program_id if not found.
     210             :        Borrow the program account here.
     211             :        https://github.com/anza-xyz/agave/blob/v2.1.14/program-runtime/src/invoke_context.rs#L436-L437 */
     212           0 :     fd_guarded_borrowed_account_t borrowed_program_account;
     213           0 :     int err = fd_exec_instr_ctx_try_borrow_instr_account( instr_ctx, (ushort)program_idx, &borrowed_program_account );
     214           0 :     if( FD_UNLIKELY( err ) ) {
     215           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, err, instr_ctx->txn_ctx->instr_err_idx );
     216           0 :       return err;
     217           0 :     }
     218             : 
     219           0 :     if( FD_UNLIKELY( err ) ) {
     220             :       /* https://github.com/anza-xyz/agave/blob/a9ac3f55fcb2bc735db0d251eda89897a5dbaaaa/program-runtime/src/invoke_context.rs#L434 */
     221           0 :       FD_BASE58_ENCODE_32_BYTES( callee_program_id_pubkey->uc, id_b58 );
     222           0 :       fd_log_collector_msg_many( instr_ctx, 2, "Unknown program ", 16UL, id_b58, id_b58_len );
     223           0 :       FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_MISSING_ACC, instr_ctx->txn_ctx->instr_err_idx );
     224           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     225           0 :     }
     226             :     /* Check that the program account is executable. We need to ensure that the
     227             :        program account is a valid instruction account.
     228             :        https://github.com/anza-xyz/agave/blob/v2.1.14/program-runtime/src/invoke_context.rs#L438 */
     229           0 :     if( !FD_FEATURE_ACTIVE( instr_ctx->txn_ctx->slot, &instr_ctx->txn_ctx->features, remove_accounts_executable_flag_checks ) ) {
     230           0 :       if( FD_UNLIKELY( !fd_borrowed_account_is_executable( &borrowed_program_account ) ) ) {
     231           0 :         FD_BASE58_ENCODE_32_BYTES( callee_program_id_pubkey->uc, id_b58 );
     232           0 :         fd_log_collector_msg_many( instr_ctx, 3, "Account ", 8UL, id_b58, id_b58_len, " is not executable", 18UL );
     233           0 :         FD_TXN_ERR_FOR_LOG_INSTR( instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE, instr_ctx->txn_ctx->instr_err_idx );
     234           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
     235           0 :       }
     236           0 :     }
     237           0 :   }
     238             : 
     239           0 :   *instruction_accounts_cnt = duplicate_indicies_cnt;
     240             : 
     241           0 :   return 0;
     242           0 : }
     243             : 
     244             : /**********************************************************************
     245             :    CROSS PROGRAM INVOCATION (Generic logic)
     246             :  **********************************************************************/
     247             : 
     248             : /* FD_CPI_MAX_SIGNER_CNT is the max amount of PDA signer addresses that
     249             :    a cross-program invocation can include in an instruction.
     250             : 
     251             :    https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/syscalls/mod.rs#L80 */
     252             : 
     253             : #define FD_CPI_MAX_SIGNER_CNT              (16UL)
     254             : 
     255             : /* "Maximum number of account info structs that can be used in a single CPI
     256             :    invocation. A limit on account info structs is effectively the same as
     257             :    limiting the number of unique accounts. 128 was chosen to match the max
     258             :    number of locked accounts per transaction (MAX_TX_ACCOUNT_LOCKS)."
     259             : 
     260             :    https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L25
     261             :    https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/programs/bpf_loader/src/syscalls/cpi.rs#L1011 */
     262             : 
     263           0 : #define FD_CPI_MAX_ACCOUNT_INFOS           (128UL)
     264             : /* This is just encoding what Agave says in their code comments into a
     265             :    compile-time check, so if anyone ever inadvertently changes one of
     266             :    the limits, they will have to take a look. */
     267             : FD_STATIC_ASSERT( FD_CPI_MAX_ACCOUNT_INFOS==MAX_TX_ACCOUNT_LOCKS, cpi_max_account_info );
     268             : static inline ulong
     269           0 : get_cpi_max_account_infos( fd_exec_txn_ctx_t const * txn_ctx ) {
     270           0 :   return fd_ulong_if( FD_FEATURE_ACTIVE( txn_ctx->slot, &txn_ctx->features, increase_tx_account_lock_limit ), FD_CPI_MAX_ACCOUNT_INFOS, 64UL );
     271           0 : }
     272             : 
     273             : /* Maximum CPI instruction data size. 10 KiB was chosen to ensure that CPI
     274             :    instructions are not more limited than transaction instructions if the size
     275             :    of transactions is doubled in the future.
     276             : 
     277             :    https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L14 */
     278             : 
     279             : #define FD_CPI_MAX_INSTRUCTION_DATA_LEN    (10240UL)
     280             : 
     281             : /* Maximum CPI instruction accounts. 255 was chosen to ensure that instruction
     282             :    accounts are always within the maximum instruction account limit for BPF
     283             :    program instructions.
     284             : 
     285             :    https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/sdk/program/src/syscalls/mod.rs#L19
     286             :    https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/serialization.rs#L26 */
     287             : 
     288             : #define FD_CPI_MAX_INSTRUCTION_ACCOUNTS    (255UL)
     289             : 
     290             : 
     291             : /* fd_vm_syscall_cpi_check_instruction contains common instruction acct
     292             :    count and data sz checks.  Also consumes compute units proportional
     293             :    to instruction data size. */
     294             : 
     295             : static int
     296             : fd_vm_syscall_cpi_check_instruction( fd_vm_t const * vm,
     297             :                                      ulong           acct_cnt,
     298           0 :                                      ulong           data_sz ) {
     299             :   /* https://github.com/solana-labs/solana/blob/eb35a5ac1e7b6abe81947e22417f34508f89f091/programs/bpf_loader/src/syscalls/cpi.rs#L958-L959 */
     300           0 :   if( FD_FEATURE_ACTIVE( vm->instr_ctx->txn_ctx->slot, &vm->instr_ctx->txn_ctx->features, loosen_cpi_size_restriction ) ) {
     301           0 :     if( FD_UNLIKELY( data_sz > FD_CPI_MAX_INSTRUCTION_DATA_LEN ) ) {
     302           0 :       FD_LOG_WARNING(( "cpi: data too long (%#lx)", data_sz ));
     303             :       // SyscallError::MaxInstructionDataLenExceeded
     304           0 :       return FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_DATA_LEN_EXCEEDED;
     305           0 :     }
     306           0 :     if( FD_UNLIKELY( acct_cnt > FD_CPI_MAX_INSTRUCTION_ACCOUNTS ) ) {
     307           0 :       FD_LOG_WARNING(( "cpi: too many accounts (%#lx)", acct_cnt ));
     308             :       // SyscallError::MaxInstructionAccountsExceeded
     309           0 :       return FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNTS_EXCEEDED;
     310           0 :     }
     311           0 :   } else {
     312             :     // https://github.com/solana-labs/solana/blob/dbf06e258ae418097049e845035d7d5502fe1327/programs/bpf_loader/src/syscalls/cpi.rs#L1114
     313           0 :     ulong tot_sz = fd_ulong_sat_add( fd_ulong_sat_mul( FD_VM_RUST_ACCOUNT_META_SIZE, acct_cnt ), data_sz );
     314           0 :     if ( FD_UNLIKELY( tot_sz > FD_VM_MAX_CPI_INSTRUCTION_SIZE ) ) {
     315           0 :       FD_LOG_WARNING(( "cpi: instruction too long (%#lx)", tot_sz ));
     316             :       // SyscallError::InstructionTooLarge
     317           0 :       return FD_VM_SYSCALL_ERR_INSTRUCTION_TOO_LARGE;
     318           0 :     }
     319           0 :   }
     320             : 
     321           0 :   return FD_VM_SUCCESS;
     322           0 : }
     323             : 
     324             : /**********************************************************************
     325             :   CROSS PROGRAM INVOCATION HELPERS
     326             :  **********************************************************************/
     327             : 
     328             : static inline int
     329             : fd_vm_syscall_cpi_check_id( fd_pubkey_t const * program_id,
     330           0 :           uchar const * loader ) {
     331           0 :   return !memcmp( program_id, loader, sizeof(fd_pubkey_t) );
     332           0 : }
     333             : 
     334             : /* fd_vm_syscall_cpi_is_precompile returns true if the given program_id
     335             :    corresponds to a precompile. It does this by checking against a hardcoded
     336             :    list of known pre-compiles.
     337             : 
     338             :    This mirrors the behaviour in solana_sdk::precompiles::is_precompile
     339             :    https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/sdk/src/precompiles.rs#L93
     340             :  */
     341             : static inline int
     342           0 : fd_vm_syscall_cpi_is_precompile( fd_pubkey_t const * program_id, fd_exec_txn_ctx_t const * txn_ctx ) {
     343           0 :   return fd_vm_syscall_cpi_check_id(program_id, fd_solana_keccak_secp_256k_program_id.key) |
     344           0 :          fd_vm_syscall_cpi_check_id(program_id, fd_solana_ed25519_sig_verify_program_id.key) |
     345           0 :          ( fd_vm_syscall_cpi_check_id(program_id, fd_solana_secp256r1_program_id.key) &&
     346           0 :            FD_FEATURE_ACTIVE( txn_ctx->slot, &txn_ctx->features, enable_secp256r1_precompile ) );
     347           0 : }
     348             : 
     349             : /* fd_vm_syscall_cpi_check_authorized_program corresponds to
     350             : solana_bpf_loader_program::syscalls::cpi::check_authorized_program:
     351             : https://github.com/solana-labs/solana/blob/2afde1b028ed4593da5b6c735729d8994c4bfac6/programs/bpf_loader/src/syscalls/cpi.rs#L1032
     352             : 
     353             : It determines if the given program_id is authorized to execute a CPI call.
     354             : 
     355             : FIXME: return type
     356             :  */
     357             : static inline ulong
     358             : fd_vm_syscall_cpi_check_authorized_program( fd_pubkey_t const *       program_id,
     359             :                                             fd_exec_txn_ctx_t const * txn_ctx,
     360             :                                             uchar const *             instruction_data,
     361           0 :                                             ulong                     instruction_data_len ) {
     362             :   /* FIXME: do this in a branchless manner? using bitwise comparison would probably be faster */
     363           0 :   return ( fd_vm_syscall_cpi_check_id(program_id, fd_solana_native_loader_id.key)
     364           0 :             || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_program_id.key)
     365           0 :             || fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_deprecated_program_id.key)
     366           0 :             || (fd_vm_syscall_cpi_check_id(program_id, fd_solana_bpf_loader_upgradeable_program_id.key)
     367           0 :                 && !((instruction_data_len != 0 && instruction_data[0] == 3)  /* is_upgrade_instruction() */
     368           0 :                     || (instruction_data_len != 0 && instruction_data[0] == 4)  /* is_set_authority_instruction() */
     369           0 :                     || (FD_FEATURE_ACTIVE( txn_ctx->slot, &txn_ctx->features, enable_bpf_loader_set_authority_checked_ix )
     370           0 :                         && (instruction_data_len != 0 && instruction_data[0] == 7)) /* is_set_authority_checked_instruction() */
     371           0 :                     || (instruction_data_len != 0 && instruction_data[0] == 5))) /* is_close_instruction */
     372           0 :             || fd_vm_syscall_cpi_is_precompile( program_id, txn_ctx ) );
     373           0 : }
     374             : 
     375             : /* Helper functions to get the absolute vaddrs of the serialized accounts pubkey, lamports and owner.
     376             : 
     377             :    For the accounts not owned by the deprecated loader, all of these offsets into the accounts metadata region
     378             :    are static from fd_vm_acc_region_meta->metadata_region_offset.
     379             : 
     380             :    For accounts owned by the deprecated loader, the unaligned serializer is used, which means only the pubkey
     381             :    and lamports offsets are static from the metadata_region_offset. The owner is serialized into the region
     382             :    immediately following the account data region (if present) at a fixed offset.
     383             :  */
     384           0 : #define VM_SERIALIZED_PUBKEY_OFFSET   (8UL)
     385           0 : #define VM_SERIALIZED_OWNER_OFFSET    (40UL)
     386           0 : #define VM_SERIALIZED_LAMPORTS_OFFSET (72UL)
     387             : 
     388           0 : #define VM_SERIALIZED_UNALIGNED_PUBKEY_OFFSET   (3UL)
     389           0 : #define VM_SERIALIZED_UNALIGNED_LAMPORTS_OFFSET (35UL)
     390             : 
     391             : static inline
     392           0 : ulong serialized_pubkey_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
     393           0 :   return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset +
     394           0 :     (vm->is_deprecated ? VM_SERIALIZED_UNALIGNED_PUBKEY_OFFSET : VM_SERIALIZED_PUBKEY_OFFSET);
     395           0 : }
     396             : 
     397             : static inline
     398           0 : ulong serialized_owner_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
     399           0 :   if ( vm->is_deprecated ) {
     400             :     /* For deprecated loader programs, the owner is serialized into the start of the region
     401             :        following the account data region (if present) at a fixed offset.
     402             :        If the account data region is not present, the owner is
     403             :        serialized into the same fixed offset following the account's
     404             :        metadata region.
     405             :      */
     406           0 :     return FD_VM_MEM_MAP_INPUT_REGION_START + vm->input_mem_regions[
     407           0 :       acc_region_meta->has_data_region ? acc_region_meta->region_idx+1U : acc_region_meta->region_idx
     408           0 :     ].vaddr_offset;
     409           0 :   }
     410             : 
     411           0 :   return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset + VM_SERIALIZED_OWNER_OFFSET;
     412           0 : }
     413             : 
     414             : static inline
     415           0 : ulong serialized_lamports_vaddr( fd_vm_t * vm, fd_vm_acc_region_meta_t * acc_region_meta ) {
     416           0 :   return FD_VM_MEM_MAP_INPUT_REGION_START + acc_region_meta->metadata_region_offset +
     417           0 :     (vm->is_deprecated ? VM_SERIALIZED_UNALIGNED_LAMPORTS_OFFSET : VM_SERIALIZED_LAMPORTS_OFFSET);
     418           0 : }
     419             : 
     420             : /* The data and lamports fields are in an Rc<Refcell<T>> in the Rust ABI AccountInfo.
     421             :    These macros perform the equivalent of Rc<Refcell<T>>.as_ptr() in Agave.
     422             :    This function doesn't actually touch any memory.
     423             :    It performs pointer arithmetic.
     424             :  */
     425             : FD_FN_CONST static inline
     426           0 : ulong vm_syscall_cpi_acc_info_rc_refcell_as_ptr( ulong rc_refcell_vaddr ) {
     427           0 :   return (ulong) &(((fd_vm_rc_refcell_t *)rc_refcell_vaddr)->payload);
     428           0 : }
     429             : 
     430             : /* https://github.com/anza-xyz/agave/blob/v2.1.6/programs/bpf_loader/src/syscalls/cpi.rs#L327
     431             :  */
     432             : FD_FN_CONST static inline
     433           0 : ulong vm_syscall_cpi_data_len_vaddr_c( ulong acct_info_vaddr, ulong data_len_haddr, ulong acct_info_haddr ) {
     434           0 :   return fd_ulong_sat_sub( fd_ulong_sat_add( acct_info_vaddr, data_len_haddr ), acct_info_haddr );
     435           0 : }
     436             : 
     437             : /**********************************************************************
     438             :   CROSS PROGRAM INVOCATION (C ABI)
     439             :  **********************************************************************/
     440             : 
     441             : #define VM_SYSCALL_CPI_ABI                     c
     442           0 : #define VM_SYSCALL_CPI_INSTR_T                 fd_vm_c_instruction_t
     443             : #define VM_SYSCALL_CPI_INSTR_ALIGN             (FD_VM_C_INSTRUCTION_ALIGN)
     444             : #define VM_SYSCALL_CPI_INSTR_SIZE              (FD_VM_C_INSTRUCTION_SIZE)
     445           0 : #define VM_SYSCALL_CPI_ACC_META_T              fd_vm_c_account_meta_t
     446             : #define VM_SYSCALL_CPI_ACC_META_ALIGN          (FD_VM_C_ACCOUNT_META_ALIGN)
     447             : #define VM_SYSCALL_CPI_ACC_META_SIZE           (FD_VM_C_ACCOUNT_META_SIZE)
     448           0 : #define VM_SYSCALL_CPI_ACC_INFO_T              fd_vm_c_account_info_t
     449             : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN          (FD_VM_C_ACCOUNT_INFO_ALIGN)
     450           0 : #define VM_SYSCALL_CPI_ACC_INFO_SIZE           (FD_VM_C_ACCOUNT_INFO_SIZE)
     451             : 
     452             : /* VM_SYSCALL_CPI_INSTR_T accessors */
     453             : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data_addr
     454           0 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr )  instr->data_len
     455             : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts_addr
     456           0 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr )  instr->accounts_len
     457             : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) \
     458           0 :   FD_VM_MEM_HADDR_LD( vm, instr->program_id_addr, alignof(uchar), sizeof(fd_pubkey_t)  )
     459             : 
     460             : /* VM_SYSCALL_CPI_ACC_META_T accessors */
     461           0 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
     462           0 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
     463             : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) \
     464           0 :   FD_VM_MEM_HADDR_LD( vm, acc_meta->pubkey_addr, alignof(uchar), sizeof(fd_pubkey_t) )
     465             : 
     466             : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
     467             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR( vm, acc_info, decl ) \
     468           0 :   ulong decl = acc_info->lamports_addr;
     469             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl ) \
     470           0 :   ulong * decl = FD_VM_MEM_HADDR_ST( vm, acc_info->lamports_addr, alignof(ulong), sizeof(ulong) );
     471             : 
     472             : #define VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR( vm, acc_info, decl ) \
     473           0 :   ulong decl = acc_info->data_addr;
     474             : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl ) \
     475           0 :   uchar * decl = FD_VM_MEM_SLICE_HADDR_ST( vm, acc_info->data_addr, alignof(uchar), acc_info->data_sz ); \
     476           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
     477           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
     478             : 
     479             : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl ) \
     480           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = acc_info->data_addr; \
     481           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
     482             : 
     483             : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_GET_LEN( vm, acc_info, decl ) \
     484           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = acc_info->data_sz;
     485             : 
     486             : #include "fd_vm_syscall_cpi_common.c"
     487             : 
     488             : #undef VM_SYSCALL_CPI_ABI
     489             : #undef VM_SYSCALL_CPI_INSTR_T
     490             : #undef VM_SYSCALL_CPI_INSTR_ALIGN
     491             : #undef VM_SYSCALL_CPI_INSTR_SIZE
     492             : #undef VM_SYSCALL_CPI_ACC_META_T
     493             : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
     494             : #undef VM_SYSCALL_CPI_ACC_META_SIZE
     495             : #undef VM_SYSCALL_CPI_ACC_INFO_T
     496             : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
     497             : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
     498             : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
     499             : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
     500             : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
     501             : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
     502             : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
     503             : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
     504             : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
     505             : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
     506             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR
     507             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
     508             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR
     509             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
     510             : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
     511             : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_GET_LEN
     512             : 
     513             : /**********************************************************************
     514             :    CROSS PROGRAM INVOCATION (Rust ABI)
     515             :  **********************************************************************/
     516             : 
     517             : #define VM_SYSCALL_CPI_ABI                     rust
     518           0 : #define VM_SYSCALL_CPI_INSTR_T                 fd_vm_rust_instruction_t
     519             : #define VM_SYSCALL_CPI_INSTR_ALIGN             (FD_VM_RUST_INSTRUCTION_ALIGN)
     520             : #define VM_SYSCALL_CPI_INSTR_SIZE              (FD_VM_RUST_INSTRUCTION_SIZE)
     521           0 : #define VM_SYSCALL_CPI_ACC_META_T              fd_vm_rust_account_meta_t
     522             : #define VM_SYSCALL_CPI_ACC_META_ALIGN          (FD_VM_RUST_ACCOUNT_META_ALIGN)
     523             : #define VM_SYSCALL_CPI_ACC_META_SIZE           (FD_VM_RUST_ACCOUNT_META_SIZE)
     524           0 : #define VM_SYSCALL_CPI_ACC_INFO_T              fd_vm_rust_account_info_t
     525             : #define VM_SYSCALL_CPI_ACC_INFO_ALIGN          (FD_VM_RUST_ACCOUNT_INFO_ALIGN)
     526           0 : #define VM_SYSCALL_CPI_ACC_INFO_SIZE           (FD_VM_RUST_ACCOUNT_INFO_SIZE)
     527             : 
     528             : /* VM_SYSCALL_CPI_INSTR_T accessors */
     529             : #define VM_SYSCALL_CPI_INSTR_DATA_ADDR( instr ) instr->data.addr
     530           0 : #define VM_SYSCALL_CPI_INSTR_DATA_LEN( instr )  instr->data.len
     531             : #define VM_SYSCALL_CPI_INSTR_ACCS_ADDR( instr ) instr->accounts.addr
     532           0 : #define VM_SYSCALL_CPI_INSTR_ACCS_LEN( instr )  instr->accounts.len
     533           0 : #define VM_SYSCALL_CPI_INSTR_PROGRAM_ID( vm, instr ) instr->pubkey
     534             : 
     535             : /* VM_SYSCALL_CPI_ACC_META_T accessors */
     536           0 : #define VM_SYSCALL_CPI_ACC_META_IS_WRITABLE( acc_meta ) acc_meta->is_writable
     537           0 : #define VM_SYSCALL_CPI_ACC_META_IS_SIGNER( acc_meta ) acc_meta->is_signer
     538           0 : #define VM_SYSCALL_CPI_ACC_META_PUBKEY( vm, acc_meta ) acc_meta->pubkey
     539             : 
     540             : /* VM_SYSCALL_CPI_ACC_INFO_T accessors */
     541             : 
     542             : /* The lamports and the account data are stored behind RefCells,
     543             :    so we have an additional layer of indirection to unwrap. */
     544             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR( vm, acc_info, decl )                                                                             \
     545           0 :     ulong const * FD_EXPAND_THEN_CONCAT2(decl, _hptr_) =                                                                                         \
     546           0 :       FD_VM_MEM_HADDR_LD( vm, vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->lamports_box_addr ), FD_VM_RC_REFCELL_ALIGN, sizeof(ulong) ); \
     547           0 :     /* Extract the vaddr embedded in the RefCell */                                                                                              \
     548           0 :     ulong decl = *FD_EXPAND_THEN_CONCAT2(decl, _hptr_);
     549             : 
     550             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS( vm, acc_info, decl )                                                                                                     \
     551           0 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _vaddr_) =                                                                                                                  \
     552           0 :       *((ulong const *)FD_VM_MEM_HADDR_LD( vm, vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->lamports_box_addr ), FD_VM_RC_REFCELL_ALIGN, sizeof(ulong) )); \
     553           0 :     ulong * decl = FD_VM_MEM_HADDR_ST( vm, FD_EXPAND_THEN_CONCAT2(decl, _vaddr_), alignof(ulong), sizeof(ulong) );
     554             : 
     555             : #define VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR( vm, acc_info, decl )                                                                                   \
     556             :     /* Translate the vaddr to the slice */                                                                                                         \
     557           0 :     fd_vm_vec_t const * FD_EXPAND_THEN_CONCAT2(decl, _hptr_) =                                                                                     \
     558           0 :       FD_VM_MEM_HADDR_LD( vm, vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->data_box_addr ), FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_vec_t) ); \
     559           0 :     /* Extract the vaddr embedded in the slice */                                                                                                  \
     560           0 :     ulong decl = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->addr;
     561             : 
     562             : #define VM_SYSCALL_CPI_ACC_INFO_DATA_LEN_VADDR( vm, acc_info, decl ) \
     563           0 :     ulong decl = fd_ulong_sat_add( vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->data_box_addr ), sizeof(ulong) );
     564             : 
     565             : #define VM_SYSCALL_CPI_ACC_INFO_DATA( vm, acc_info, decl )                                                                                         \
     566             :     /* Translate the vaddr to the slice */                                                                                                         \
     567           0 :     fd_vm_vec_t const * FD_EXPAND_THEN_CONCAT2(decl, _hptr_) =                                                                                     \
     568           0 :       FD_VM_MEM_HADDR_LD( vm, vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->data_box_addr ), FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_vec_t) ); \
     569           0 :     /* Declare the vaddr of the slice's underlying byte array */                                                                                   \
     570           0 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->addr;                                                     \
     571           0 :     /* Declare the size of the slice's underlying byte array */                                                                                    \
     572           0 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->len;                                                          \
     573           0 :     /* Translate the vaddr to the underlying byte array */                                                                                         \
     574           0 :     uchar * decl = FD_VM_MEM_SLICE_HADDR_ST(                                                                                                       \
     575           0 :       vm, FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->addr, alignof(uchar), FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->len );
     576             : 
     577             : #define VM_SYSCALL_CPI_ACC_INFO_METADATA( vm, acc_info, decl )                                                                                     \
     578             :     /* Translate the vaddr to the slice */                                                                                                         \
     579           0 :     fd_vm_vec_t const * FD_EXPAND_THEN_CONCAT2(decl, _hptr_) =                                                                                     \
     580           0 :       FD_VM_MEM_HADDR_LD( vm, vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->data_box_addr ), FD_VM_RC_REFCELL_ALIGN, sizeof(fd_vm_vec_t) ); \
     581           0 :     /* Declare the vaddr of the slice's underlying byte array */                                                                                   \
     582           0 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _vm_addr) = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->addr;                                                     \
     583           0 :     /* Declare the size of the slice's underlying byte array */                                                                                    \
     584           0 :     ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->len;
     585             : 
     586             : #define VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_RC_REFCELL_VADDR( vm, acc_info, decl ) \
     587           0 :     ulong decl = vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->lamports_box_addr );
     588             : 
     589             : #define VM_SYSCALL_CPI_ACC_INFO_DATA_RC_REFCELL_VADDR( vm, acc_info, decl ) \
     590           0 :     ulong decl = vm_syscall_cpi_acc_info_rc_refcell_as_ptr( acc_info->data_box_addr );
     591             : 
     592             : #define VM_SYSCALL_CPI_SET_ACC_INFO_DATA_GET_LEN( vm, acc_info, decl ) \
     593           0 :   ulong FD_EXPAND_THEN_CONCAT2(decl, _len) = FD_EXPAND_THEN_CONCAT2(decl, _hptr_)->len;
     594             : 
     595             : #include "fd_vm_syscall_cpi_common.c"
     596             : 
     597             : #undef VM_SYSCALL_CPI_ABI
     598             : #undef VM_SYSCALL_CPI_INSTR_T
     599             : #undef VM_SYSCALL_CPI_INSTR_ALIGN
     600             : #undef VM_SYSCALL_CPI_INSTR_SIZE
     601             : #undef VM_SYSCALL_CPI_ACC_META_T
     602             : #undef VM_SYSCALL_CPI_ACC_META_ALIGN
     603             : #undef VM_SYSCALL_CPI_ACC_META_SIZE
     604             : #undef VM_SYSCALL_CPI_ACC_INFO_T
     605             : #undef VM_SYSCALL_CPI_ACC_INFO_ALIGN
     606             : #undef VM_SYSCALL_CPI_ACC_INFO_SIZE
     607             : #undef VM_SYSCALL_CPI_INSTR_DATA_ADDR
     608             : #undef VM_SYSCALL_CPI_INSTR_DATA_LEN
     609             : #undef VM_SYSCALL_CPI_INSTR_ACCS_ADDR
     610             : #undef VM_SYSCALL_CPI_INSTR_ACCS_LEN
     611             : #undef VM_SYSCALL_CPI_INSTR_PROGRAM_ID
     612             : #undef VM_SYSCALL_CPI_ACC_META_IS_WRITABLE
     613             : #undef VM_SYSCALL_CPI_ACC_META_IS_SIGNER
     614             : #undef VM_SYSCALL_CPI_ACC_META_PUBKEY
     615             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_VADDR
     616             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS
     617             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_VADDR
     618             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA
     619             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_LEN_VADDR
     620             : #undef VM_SYSCALL_CPI_ACC_INFO_METADATA
     621             : #undef VM_SYSCALL_CPI_ACC_INFO_LAMPORTS_RC_REFCELL_VADDR
     622             : #undef VM_SYSCALL_CPI_ACC_INFO_DATA_RC_REFCELL_VADDR
     623             : #undef VM_SYSCALL_CPI_SET_ACC_INFO_DATA_GET_LEN

Generated by: LCOV version 1.14