LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_rec.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 129 136 94.9 %
Date: 2026-03-31 06:22:16 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "fd_progcache.h"
       2             : #include "../vm/fd_vm.h" /* fd_vm_syscall_register_slot, fd_vm_validate */
       3             : #include "../../util/alloc/fd_alloc.h"
       4             : #include <stdlib.h>
       5             : 
       6             : /* Can be overridden by test executables */
       7             : __attribute__((weak)) int const fd_progcache_use_malloc = 0;
       8             : static inline _Bool
       9         159 : use_malloc( void ) {
      10         159 :   _Bool use_malloc = !!fd_progcache_use_malloc;
      11         159 :   FD_COMPILER_FORGET( use_malloc ); /* prevent constant propagation */
      12         159 :   return use_malloc;
      13         159 : }
      14             : 
      15             : void *
      16             : fd_progcache_val_alloc( fd_progcache_rec_t *  rec,
      17             :                         fd_progcache_join_t * join,
      18             :                         ulong                 val_align,
      19          81 :                         ulong                 val_footprint ) {
      20          81 :   if( rec->data_gaddr ) fd_progcache_val_free( rec, join );
      21          81 :   ulong  val_max = 0UL;
      22          81 :   void * mem;
      23          81 :   ulong  gaddr;
      24          81 :   if( FD_UNLIKELY( use_malloc() ) ) { /* test only */
      25           0 :     mem = aligned_alloc( val_align, val_footprint );
      26           0 :     if( FD_UNLIKELY( !mem ) ) return NULL;
      27           0 :     val_max = val_footprint;
      28           0 :     gaddr   = (ulong)mem;
      29          81 :   } else {
      30          81 :     mem = fd_alloc_malloc_at_least( join->alloc, val_align, val_footprint, &val_max );
      31          81 :     if( FD_UNLIKELY( !mem ) ) return NULL;
      32          81 :     FD_CRIT( val_max<=UINT_MAX, "massive" ); /* unreachable */
      33          81 :     gaddr = fd_wksp_gaddr_fast( join->data_base, mem );
      34          81 :   }
      35          81 :   rec->data_gaddr = gaddr;
      36          81 :   rec->data_max   = (uint)val_max;
      37          81 :   return mem;
      38          81 : }
      39             : 
      40             : void
      41             : fd_progcache_val_free1( fd_progcache_rec_t * rec,
      42             :                         void *               val,
      43          78 :                         fd_alloc_t *         alloc ) {
      44          78 :   if( FD_UNLIKELY( use_malloc() ) ) { /* test only */
      45           0 :     free( val );
      46          78 :   } else {
      47          78 :     fd_alloc_free( alloc, val );
      48          78 :   }
      49          78 :   rec->data_gaddr = 0UL;
      50          78 :   rec->data_max   = 0U;
      51          78 :   rec->rodata_off = 0U;
      52          78 :   rec->rodata_sz  = 0U;
      53          78 : }
      54             : 
      55             : void
      56             : fd_progcache_val_free( fd_progcache_rec_t *  rec,
      57          54 :                        fd_progcache_join_t * join ) {
      58          54 :   if( !rec->data_gaddr ) return;
      59          54 :   void * mem = fd_wksp_laddr_fast( join->data_base, rec->data_gaddr );
      60             : 
      61             :   /* Illegal to call val_free on a spill-allocated buffer */
      62          54 :   FD_TEST( !( (ulong)mem >= (ulong)join->shmem->spill.spad &&
      63          54 :               (ulong)mem <  (ulong)join->shmem->spill.spad+FD_PROGCACHE_SPAD_MAX ) );
      64             : 
      65          54 :   fd_progcache_val_free1( rec, mem, join->alloc );
      66          54 : }
      67             : 
      68             : FD_FN_PURE ulong
      69         162 : fd_progcache_val_footprint( fd_sbpf_elf_info_t const * elf_info ) {
      70         162 :   int   has_calldests = !fd_sbpf_enable_stricter_elf_headers_enabled( elf_info->sbpf_version );
      71         162 :   ulong pc_max        = fd_ulong_max( 1UL, elf_info->text_cnt );
      72             : 
      73         162 :   ulong l = FD_LAYOUT_INIT;
      74         162 :   if( has_calldests ) {
      75         162 :     l = FD_LAYOUT_APPEND( l, fd_sbpf_calldests_align(), fd_sbpf_calldests_footprint( pc_max ) );
      76         162 :   }
      77         162 :   l = FD_LAYOUT_APPEND( l, 8UL, elf_info->bin_sz );
      78         162 :   return FD_LAYOUT_FINI( l, fd_progcache_val_align() );
      79         162 : }
      80             : 
      81             : /* Program loader wrapper */
      82             : 
      83             : fd_progcache_rec_t *
      84             : fd_progcache_rec_load( fd_progcache_rec_t *            rec,
      85             :                        fd_wksp_t *                     wksp,
      86             :                        fd_sbpf_elf_info_t const *      elf_info,
      87             :                        fd_sbpf_loader_config_t const * config,
      88             :                        ulong                           load_slot,
      89             :                        fd_features_t const *           features,
      90             :                        void const *                    progdata,
      91             :                        ulong                           progdata_sz,
      92             :                        void *                          scratch,
      93          81 :                        ulong                           scratch_sz ) {
      94             : 
      95             :   /* Format object */
      96             : 
      97          81 :   int has_calldests = !fd_sbpf_enable_stricter_elf_headers_enabled( elf_info->sbpf_version );
      98             : 
      99          81 :   void * val = fd_wksp_laddr_fast( wksp, rec->data_gaddr );
     100          81 :   FD_SCRATCH_ALLOC_INIT( l, val );
     101          81 :   void *               calldests_mem = NULL;
     102          81 :   if( has_calldests ) {
     103          81 :     /*               */calldests_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_sbpf_calldests_align(), fd_sbpf_calldests_footprint( fd_ulong_max( 1UL, elf_info->text_cnt ) ) );
     104          81 :   }
     105          81 :   void *               rodata_mem    = FD_SCRATCH_ALLOC_APPEND( l, 8UL, elf_info->bin_sz );
     106          81 :   FD_SCRATCH_ALLOC_FINI( l, fd_progcache_val_align() );
     107          81 :   FD_TEST( _l-(ulong)val == fd_progcache_val_footprint( elf_info ) );
     108             : 
     109          81 :   rec->calldests_off = has_calldests ? (uint)( (ulong)calldests_mem - (ulong)val ) : 0U;
     110          81 :   rec->rodata_off    = (uint)( (ulong)rodata_mem - (ulong)val );
     111          81 :   rec->entry_pc      = 0;
     112          81 :   rec->rodata_sz     = 0;
     113             : 
     114          81 :   rec->text_cnt      = elf_info->text_cnt;
     115          81 :   rec->text_off      = elf_info->text_off;
     116          81 :   rec->text_sz       = (uint)elf_info->text_sz;
     117          81 :   rec->sbpf_version  = (uchar)elf_info->sbpf_version;
     118             : 
     119             :   /* Set up sbpf_loader (redirect writes into progcache_rec object) */
     120             : 
     121          81 :   fd_sbpf_program_t prog[1] = {{
     122          81 :     .info     = *elf_info,
     123          81 :     .rodata   = rodata_mem,
     124          81 :     .text     = (ulong *)((ulong)rodata_mem + elf_info->text_off), /* FIXME: WHAT IF MISALIGNED */
     125          81 :     .entry_pc = ULONG_MAX
     126          81 :   }};
     127          81 :   if( has_calldests && elf_info->text_cnt>0UL ) {
     128          81 :     prog->calldests_shmem = calldests_mem;
     129          81 :     prog->calldests = fd_sbpf_calldests_join( fd_sbpf_calldests_new( calldests_mem, elf_info->text_cnt ) );
     130          81 :   }
     131             : 
     132             :   /* Loader requires syscall table */
     133             : 
     134          81 :   fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
     135          81 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
     136          81 :   int syscalls_err = fd_vm_syscall_register_slot( syscalls, load_slot, features, /* is_deploy */ 0 );
     137          81 :   if( FD_UNLIKELY( syscalls_err!=FD_VM_SUCCESS ) ) FD_LOG_CRIT(( "fd_vm_syscall_register_slot failed" ));
     138             : 
     139             :   /* Run ELF loader */
     140             : 
     141          81 :   if( FD_UNLIKELY( 0!=fd_sbpf_program_load( prog, progdata, progdata_sz, syscalls, config, scratch, scratch_sz ) ) ) {
     142           0 :     return NULL;
     143           0 :   }
     144             : 
     145          81 :   rec->entry_pc  = (uint)prog->entry_pc;
     146          81 :   rec->rodata_sz = (uint)prog->rodata_sz;
     147             : 
     148             :   /* Run bytecode validator */
     149             : 
     150          81 :   fd_vm_t _vm[1];
     151          81 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     152          81 :   if( FD_UNLIKELY( !vm ) ) FD_LOG_CRIT(( "fd_vm_new failed" ));
     153          81 :   vm = fd_vm_init( vm,
     154          81 :                    NULL, /* OK since unused in `fd_vm_validate()` */
     155          81 :                    0UL,
     156          81 :                    0UL,
     157          81 :                    prog->rodata,
     158          81 :                    prog->rodata_sz,
     159          81 :                    prog->text,
     160          81 :                    prog->info.text_cnt,
     161          81 :                    prog->info.text_off,
     162          81 :                    prog->info.text_sz,
     163          81 :                    prog->entry_pc,
     164          81 :                    prog->calldests,
     165          81 :                    elf_info->sbpf_version,
     166          81 :                    syscalls,
     167          81 :                    NULL,
     168          81 :                    NULL,
     169          81 :                    NULL,
     170          81 :                    0U,
     171          81 :                    NULL,
     172          81 :                    0,
     173          81 :                    FD_FEATURE_ACTIVE( load_slot, features, account_data_direct_mapping ),
     174          81 :                    FD_FEATURE_ACTIVE( load_slot, features, syscall_parameter_address_restrictions ),
     175          81 :                    FD_FEATURE_ACTIVE( load_slot, features, virtual_address_space_adjustments ),
     176          81 :                    0,
     177          81 :                    0UL );
     178          81 :   if( FD_UNLIKELY( !vm ) ) FD_LOG_CRIT(( "fd_vm_init failed" ));
     179             : 
     180          81 :   if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return NULL;
     181             : 
     182          78 :   return rec;
     183          81 : }
     184             : 
     185             : fd_progcache_rec_t *
     186           3 : fd_progcache_rec_nx( fd_progcache_rec_t * rec ) {
     187           3 :   rec->data_gaddr    = 0UL;
     188           3 :   rec->data_max      = 0U;
     189           3 :   rec->entry_pc      = 0;
     190           3 :   rec->text_cnt      = 0;
     191           3 :   rec->text_off      = 0;
     192           3 :   rec->text_sz       = 0;
     193           3 :   rec->rodata_sz     = 0;
     194           3 :   rec->calldests_off = 0;
     195           3 :   rec->rodata_off    = 0;
     196           3 :   rec->sbpf_version  = 0;
     197           3 :   return rec;
     198           3 : }

Generated by: LCOV version 1.14