LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm_tool.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 228 0.0 %
Date: 2025-01-08 12:08:44 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : 
       3             : #include "../../util/fd_util_base.h"
       4             : #if defined(__linux__) && FD_HAS_X86
       5             : #define FD_VM_TOOL_HAS_JIT 1
       6             : #else
       7             : #define FD_VM_TOOL_HAS_JIT 0
       8             : #endif
       9             : 
      10             : #include "fd_vm_base.h"
      11             : #include "fd_vm_private.h"
      12             : 
      13             : #include <stdio.h>
      14             : #include <stdlib.h>
      15             : #include <errno.h>
      16             : #include <sys/stat.h>
      17             : 
      18             : #if FD_VM_TOOL_HAS_JIT
      19             : #include "jit/fd_jit.h"
      20             : #include <sys/mman.h>
      21             : #endif
      22             : 
      23             : struct fd_vm_tool_prog {
      24             :   void *               bin_buf;
      25             :   fd_sbpf_program_t *  prog;
      26             :   fd_sbpf_syscalls_t * syscalls;
      27             : };
      28             : 
      29             : typedef struct fd_vm_tool_prog fd_vm_tool_prog_t;
      30             : 
      31             : static fd_vm_tool_prog_t *
      32             : fd_vm_tool_prog_create( fd_vm_tool_prog_t * tool_prog,
      33           0 :                         char const *        bin_path ) {
      34             : 
      35             :   /* Open file */
      36             : 
      37           0 :   FILE * bin_file = fopen( bin_path, "r" );
      38           0 :   if( FD_UNLIKELY( !bin_file ) )
      39           0 :     FD_LOG_ERR(( "fopen(\"%s\") failed (%i-%s)", bin_path, errno, fd_io_strerror( errno ) ));
      40             : 
      41           0 :   struct stat bin_stat;
      42           0 :   if( FD_UNLIKELY( 0!=fstat( fileno( bin_file ), &bin_stat ) ) )
      43           0 :     FD_LOG_ERR(( "fstat() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      44           0 :   if( FD_UNLIKELY( !S_ISREG( bin_stat.st_mode ) ) )
      45           0 :     FD_LOG_ERR(( "File \"%s\" not a regular file", bin_path ));
      46             : 
      47             :   /* Allocate file buffer */
      48             : 
      49           0 :   ulong  bin_sz  = (ulong)bin_stat.st_size;
      50           0 :   void * bin_buf = malloc( bin_sz+8UL );
      51           0 :   if( FD_UNLIKELY( !bin_buf ) )
      52           0 :     FD_LOG_ERR(( "malloc(%#lx) failed (%i-%s)", bin_sz, errno, fd_io_strerror( errno ) ));
      53             : 
      54             :   /* Read program */
      55             : 
      56           0 :   if( FD_UNLIKELY( fread( bin_buf, bin_sz, 1UL, bin_file )!=1UL ) )
      57           0 :     FD_LOG_ERR(( "fread() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      58           0 :   FD_TEST( 0==fclose( bin_file ) );
      59             : 
      60             :   /* Extract ELF info */
      61             : 
      62           0 :   fd_sbpf_elf_info_t elf_info;
      63           0 :   FD_TEST( fd_sbpf_elf_peek( &elf_info, bin_buf, bin_sz, /* deploy checks */ 0, FD_SBPF_V0, FD_SBPF_V3 ) );
      64             : 
      65             :   /* Allocate rodata segment */
      66             : 
      67           0 :   void * rodata = malloc( elf_info.rodata_footprint );
      68           0 :   FD_TEST( rodata );
      69             : 
      70             :   /* Allocate program buffer */
      71             : 
      72           0 :   ulong  prog_align     = fd_sbpf_program_align();
      73           0 :   ulong  prog_footprint = fd_sbpf_program_footprint( &elf_info );
      74           0 :   fd_sbpf_program_t * prog = fd_sbpf_program_new( aligned_alloc( prog_align, prog_footprint ), &elf_info, rodata );
      75           0 :   FD_TEST( prog );
      76             : 
      77             :   /* Allocate syscalls */
      78           0 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new(
      79           0 :       aligned_alloc( fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ) );
      80           0 :   FD_TEST( syscalls );
      81             : 
      82           0 :   fd_vm_syscall_register_all( syscalls, 0 );
      83             : 
      84             :   /* Load program */
      85           0 :   if( FD_UNLIKELY( 0!=fd_sbpf_program_load( prog, bin_buf, bin_sz, syscalls, false ) ) )
      86           0 :     FD_LOG_ERR(( "fd_sbpf_program_load() failed: %s", fd_sbpf_strerror() ));
      87             : 
      88           0 :   tool_prog->bin_buf  = bin_buf;
      89           0 :   tool_prog->prog     = prog;
      90           0 :   tool_prog->syscalls = syscalls;
      91             : 
      92           0 :   return tool_prog;
      93           0 : }
      94             : 
      95             : static void
      96           0 : fd_vm_tool_prog_free( fd_vm_tool_prog_t * prog ) {
      97           0 :   free( prog->prog->rodata );
      98           0 :   free( prog->bin_buf      );
      99           0 :   free( fd_sbpf_program_delete ( prog->prog     ) );
     100           0 :   free( fd_sbpf_syscalls_delete( prog->syscalls ) );
     101           0 : }
     102             : 
     103             : int
     104           0 : cmd_disasm( char const * bin_path ) {
     105           0 :   fd_vm_tool_prog_t tool_prog;
     106           0 :   fd_vm_tool_prog_create( &tool_prog, bin_path ); /* FIXME: RENAME INIT? */
     107             : 
     108             :   /* FIXME: DOES DISASM NEED THE TEXT_OFF TOO FOR CALLS? */
     109             :   /* FIXME: WOULD DISASM BENEFIT BY ANNOTATING THE ENTRY PC AND/OR THE
     110             :      CALLDESTS? */
     111             : 
     112           0 :   ulong  out_max = 128UL*tool_prog.prog->text_cnt; /* FIXME: OVERFLOW */
     113           0 :   ulong  out_len = 0UL;
     114           0 :   char * out     = (char *)malloc( out_max ); /* FIXME: GROSS */
     115           0 :   if( FD_UNLIKELY( !out ) ) FD_LOG_ERR(( "malloc failed" ));
     116           0 :   out[0] = '\0';
     117             : 
     118           0 :   int err = fd_vm_disasm_program( tool_prog.prog->text, tool_prog.prog->text_cnt, tool_prog.syscalls, out, out_max, &out_len );
     119             : 
     120           0 :   puts( out );
     121             : 
     122           0 :   free( out ); /* FIXME: GROSS */
     123             : 
     124           0 :   fd_vm_tool_prog_free( &tool_prog ); /* FIXME: RENAME DESTROY (OR MAYBE FINI)*/
     125             : 
     126           0 :   return err;
     127           0 : }
     128             : 
     129             : int
     130           0 : cmd_validate( char const * bin_path ) {
     131             : 
     132           0 :   fd_vm_tool_prog_t tool_prog;
     133           0 :   fd_vm_tool_prog_create( &tool_prog, bin_path );
     134             : 
     135           0 :   fd_vm_t vm = {
     136           0 :     .text      = tool_prog.prog->text,
     137           0 :     .text_cnt  = tool_prog.prog->text_cnt,
     138           0 :     .text_off  = tool_prog.prog->text_off,
     139           0 :     .entry_pc  = tool_prog.prog->entry_pc,
     140           0 :     .calldests = tool_prog.prog->calldests,
     141           0 :     .syscalls  = tool_prog.syscalls,
     142           0 :     .trace     = NULL
     143           0 :   };
     144             : 
     145             :   /* FIXME: DO WE REALLY NEED THE WHOLE VM TO VALIDATE? */
     146             : 
     147           0 :   int err = fd_vm_validate( &vm );
     148             : 
     149           0 :   fd_vm_tool_prog_free( &tool_prog );
     150             : 
     151           0 :   return err;
     152           0 : }
     153             : 
     154             : static uchar *
     155           0 : read_input_file( char const * input_path, ulong * _input_sz ) {
     156           0 :   if( FD_UNLIKELY( !_input_sz ) ) FD_LOG_ERR(( "input_sz cannot be NULL" ));
     157             : 
     158             :   /* Open file */
     159             : 
     160           0 :   FILE * input_file = fopen( input_path, "r" );
     161           0 :   if( FD_UNLIKELY( !input_file ) )
     162           0 :     FD_LOG_ERR(( "fopen(\"%s\") failed (%i-%s)", input_path, errno, fd_io_strerror( errno ) ));
     163             : 
     164           0 :   struct stat input_stat;
     165           0 :   if( FD_UNLIKELY( 0!=fstat( fileno( input_file ), &input_stat ) ) )
     166           0 :     FD_LOG_ERR(( "fstat() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     167           0 :   if( FD_UNLIKELY( !S_ISREG( input_stat.st_mode ) ) )
     168           0 :     FD_LOG_ERR(( "File \"%s\" not a regular file", input_path ));
     169             : 
     170             :   /* Allocate file buffer */
     171             : 
     172           0 :   ulong input_sz  = (ulong)input_stat.st_size;
     173           0 :   void * input_buf = malloc( input_sz );
     174           0 :   if( FD_UNLIKELY( !input_buf ) )
     175           0 :     FD_LOG_ERR(( "malloc(%#lx) failed (%i-%s)", input_sz, errno, fd_io_strerror( errno ) ));
     176             : 
     177             :   /* Read input */
     178             : 
     179           0 :   if( FD_UNLIKELY( fread( input_buf, input_sz, 1UL, input_file )!=1UL ) )
     180           0 :     FD_LOG_ERR(( "fread() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     181           0 :   FD_TEST( 0==fclose( input_file ) );
     182             : 
     183           0 :   *_input_sz = input_sz;
     184             : 
     185           0 :   return input_buf;
     186           0 : }
     187             : 
     188             : int
     189             : cmd_trace( char const * bin_path,
     190           0 :            char const * input_path ) {
     191             : 
     192           0 :   fd_vm_tool_prog_t tool_prog;
     193           0 :   fd_vm_tool_prog_create( &tool_prog, bin_path );
     194             : 
     195           0 :   ulong   input_sz = 0UL;
     196           0 :   uchar * input    = read_input_file( input_path, &input_sz ); /* FIXME: WHERE IS INPUT FREED? */
     197             : 
     198             :   /* Turn input into a single memory region */
     199           0 :   fd_vm_input_region_t input_region = {
     200           0 :     .vaddr_offset = 0UL,
     201           0 :     .haddr        = (ulong)input,
     202           0 :     .region_sz    = (uint)input_sz,
     203           0 :     .is_writable  = 1U
     204           0 :   };
     205             : 
     206             : 
     207           0 :   ulong event_max      = 1UL<<30; /* 1 GiB default storage */
     208           0 :   ulong event_data_max = 2048UL;  /* 2 KiB memory range captures by default */
     209           0 :   fd_vm_trace_t * trace = fd_vm_trace_join( fd_vm_trace_new( aligned_alloc(
     210           0 :     fd_vm_trace_align(), fd_vm_trace_footprint( event_max, event_data_max ) ), event_max, event_data_max ) ); /* logs details */
     211           0 :   if( FD_UNLIKELY( !trace ) ) {
     212           0 :     FD_LOG_WARNING(( "unable to create trace" ));
     213           0 :     return FD_VM_ERR_INVAL; /* FIXME: ERR CODE */
     214           0 :   }
     215             : 
     216           0 :   fd_sha256_t _sha[1];
     217           0 :   fd_sha256_t * sha = fd_sha256_join( fd_sha256_new( _sha ) );
     218             : 
     219             :   /* FIXME: Gross init */
     220           0 :   fd_vm_t vm = {
     221           0 :     .instr_ctx             = NULL, /* FIXME */
     222           0 :     .heap_max              = FD_VM_HEAP_DEFAULT, /* FIXME: CONFIGURE */
     223           0 :     .entry_cu              = FD_VM_COMPUTE_UNIT_LIMIT, /* FIXME: CONFIGURE */
     224           0 :     .rodata                = tool_prog.prog->rodata,
     225           0 :     .rodata_sz             = tool_prog.prog->rodata_sz,
     226           0 :     .text                  = tool_prog.prog->text,
     227           0 :     .text_cnt              = tool_prog.prog->text_cnt,
     228           0 :     .text_off              = (ulong)tool_prog.prog->text - (ulong)tool_prog.prog->rodata,
     229           0 :     .entry_pc              = tool_prog.prog->entry_pc,
     230           0 :     .calldests             = tool_prog.prog->calldests,
     231           0 :     .syscalls              = tool_prog.syscalls,
     232           0 :     .input_mem_regions     = &input_region,
     233           0 :     .input_mem_regions_cnt = 1U,
     234           0 :     .trace                 = trace,
     235           0 :     .sha                   = sha,
     236           0 :   };
     237             : 
     238             :   /* FIXME: MOVE TO EXEC */
     239           0 :   vm.reg[ 1] = FD_VM_MEM_MAP_INPUT_REGION_START;
     240           0 :   vm.reg[10] = FD_VM_MEM_MAP_STACK_REGION_START + 0x1000;
     241             : 
     242           0 :   long dt = -fd_log_wallclock();
     243           0 :   int exec_err = fd_vm_exec( &vm );
     244           0 :   dt += fd_log_wallclock();
     245             : 
     246           0 :   printf( "Frame 0\n" );
     247           0 :   int err = fd_vm_trace_printf( vm.trace, vm.syscalls ); /* logs details */
     248           0 :   if( FD_UNLIKELY( err ) ) FD_LOG_WARNING(( "fd_vm_trace_printf failed (%i-%s)", err, fd_vm_strerror( err ) ));
     249             : 
     250           0 :   printf( "Interp_res:          %i (%s)\n", exec_err, fd_vm_strerror( exec_err ) );
     251           0 :   printf( "Return value:        %lu\n",     vm.reg[0]                            );
     252           0 :   printf( "Instruction counter: %lu\n",     vm.ic                                );
     253           0 :   printf( "Time:                %ld\n",     dt                                   );
     254             : 
     255           0 :   free( fd_vm_trace_delete( fd_vm_trace_leave( trace ) ) ); /* logs details */
     256             : 
     257           0 :   return err;
     258           0 : }
     259             : 
     260             : int
     261             : cmd_run( char const * bin_path,
     262             :          char const * input_path,
     263           0 :          int          use_jit /* in [0,1] */ ) {
     264             : 
     265           0 :   fd_vm_tool_prog_t tool_prog;
     266           0 :   fd_vm_tool_prog_create( &tool_prog, bin_path );
     267             : 
     268           0 :   ulong   input_sz = 0UL;
     269           0 :   uchar * input    = read_input_file( input_path, &input_sz ); /* FIXME: WHERE IS INPUT FREED? */
     270             : 
     271             :   /* Turn input into a single memory region */
     272           0 :   fd_vm_input_region_t input_region = {
     273           0 :     .vaddr_offset = 0UL,
     274           0 :     .haddr        = (ulong)input,
     275           0 :     .region_sz    = (uint)input_sz,
     276           0 :     .is_writable  = 1U
     277           0 :   };
     278             : 
     279           0 :   fd_sha256_t _sha[1];
     280           0 :   fd_sha256_t * sha = fd_sha256_join( fd_sha256_new( _sha ) );
     281             : 
     282           0 :   fd_vm_t vm = {
     283           0 :     .instr_ctx             = NULL, /* FIXME */
     284           0 :     .heap_max              = FD_VM_HEAP_DEFAULT, /* FIXME: CONFIGURE */
     285           0 :     .entry_cu              = FD_VM_COMPUTE_UNIT_LIMIT, /* FIXME: CONFIGURE */
     286           0 :     .rodata                = tool_prog.prog->rodata,
     287           0 :     .rodata_sz             = tool_prog.prog->rodata_sz,
     288           0 :     .text                  = tool_prog.prog->text,
     289           0 :     .text_cnt              = tool_prog.prog->text_cnt,
     290           0 :     .text_off              = (ulong)tool_prog.prog->text - (ulong)tool_prog.prog->rodata,
     291           0 :     .entry_pc              = tool_prog.prog->entry_pc,
     292           0 :     .calldests             = tool_prog.prog->calldests,
     293           0 :     .syscalls              = tool_prog.syscalls,
     294           0 :     .input_mem_regions     = &input_region,
     295           0 :     .input_mem_regions_cnt = 1U,
     296           0 :     .trace                 = NULL,
     297           0 :     .sha                   = sha,
     298           0 :   };
     299             : 
     300             :   /* FIXME: MOVE TO EXEC */
     301           0 :   vm.reg[ 1] = FD_VM_MEM_MAP_INPUT_REGION_START;
     302           0 :   vm.reg[10] = FD_VM_MEM_MAP_STACK_REGION_START + 0x1000;
     303             : 
     304           0 :   int exec_err    = FD_VM_ERR_UNSUP;
     305           0 :   long dt         = 0L;
     306           0 :   long compile_dt = 0L;
     307             : 
     308           0 :   if( use_jit ) {
     309           0 : #   if FD_VM_TOOL_HAS_JIT
     310             : 
     311           0 :     ulong   code_bufsz = fd_ulong_align_up( fd_jit_est_code_sz( tool_prog.prog->text_sz ), FD_SHMEM_NORMAL_PAGE_SZ );
     312           0 :     uchar * code_buf   = mmap( 0, code_bufsz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );
     313           0 :     if( FD_UNLIKELY( code_buf==MAP_FAILED ) ) FD_LOG_ERR(( "mmap failed" ));
     314             : 
     315           0 :     ulong  scratch_bufsz = fd_jit_est_scratch_sz( tool_prog.prog->text_sz );
     316           0 :     void * scratch_buf   = malloc( scratch_bufsz );
     317             : 
     318           0 :     for( ulong j=0; j<code_bufsz; j+=2 ) {
     319           0 :       code_buf[ j   ] = 0x0f;
     320           0 :       code_buf[ j+1 ] = 0x0b;
     321           0 :     }
     322           0 :     fd_memset( scratch_buf, 0, scratch_bufsz );
     323             : 
     324           0 :     compile_dt = -fd_log_wallclock();
     325           0 :     int compile_err = FD_VM_ERR_EBPF_JIT_NOT_COMPILED;
     326           0 :     fd_jit_prog_t _jit_prog[1];
     327           0 :     fd_jit_prog_t * jit_prog = fd_jit_prog_new(
     328           0 :         _jit_prog,
     329           0 :         tool_prog.prog,
     330           0 :         tool_prog.syscalls,
     331           0 :         code_buf, code_bufsz,
     332           0 :         scratch_buf, scratch_bufsz,
     333           0 :         &compile_err
     334           0 :     );
     335           0 :     if( FD_UNLIKELY( !jit_prog ) ) {
     336           0 :       FD_LOG_ERR(( "JIT compile failed (%d-%s)", compile_err, fd_vm_strerror( compile_err ) ));
     337           0 :     }
     338           0 :     compile_dt += fd_log_wallclock();
     339             : 
     340           0 :     free( scratch_buf );
     341           0 :     mprotect( code_buf, fd_ulong_align_up( jit_prog->code_sz, FD_SHMEM_NORMAL_PAGE_SZ ), PROT_READ | PROT_EXEC );
     342             : 
     343           0 :     dt = -fd_log_wallclock();
     344           0 :     exec_err = fd_jit_exec( jit_prog, &vm );
     345           0 :     dt += fd_log_wallclock();
     346             : 
     347           0 :     fd_jit_prog_delete( jit_prog );
     348           0 :     munmap( code_buf, code_bufsz );
     349             : 
     350           0 : #   endif
     351           0 :   } else {
     352             : 
     353           0 :     dt = -fd_log_wallclock();
     354           0 :     exec_err = fd_vm_exec( &vm );
     355           0 :     dt += fd_log_wallclock();
     356             : 
     357           0 :   }
     358             : 
     359           0 :   printf( "Interp_res:          %i (%s)\n", exec_err, fd_vm_strerror( exec_err ) );
     360           0 :   printf( "Return value:        %lu\n",     vm.reg[0]                            );
     361           0 :   printf( "Instruction counter: %lu\n",     vm.ic                                );
     362           0 :   printf( "Time:                %ld\n",     dt                                   );
     363           0 :   if( compile_dt ) {
     364           0 :     printf( "Compile time:        %ld\n",     compile_dt );
     365           0 :   }
     366             : 
     367           0 :   return FD_VM_SUCCESS;
     368           0 : }
     369             : 
     370             : int
     371             : main( int     argc,
     372             :       char ** argv ) {
     373             :   fd_boot( &argc, &argv );
     374             : 
     375             :   char const * cmd = fd_env_strip_cmdline_cstr( &argc, &argv, "--cmd", NULL, NULL );
     376             :   if( FD_UNLIKELY( !cmd ) ) FD_LOG_ERR(( "Please specify a command" ));
     377             : 
     378             :   if( !strcmp( cmd, "disasm" ) ) {
     379             : 
     380             :     char const * program_file = fd_env_strip_cmdline_cstr( &argc, &argv, "--program-file", NULL, NULL );
     381             : 
     382             :     if( FD_UNLIKELY( program_file==NULL ) ) FD_LOG_ERR(( "Please specify a --program-file" ));
     383             : 
     384             :     FD_LOG_NOTICE(( "disasm --program-file %s", program_file ));
     385             : 
     386             :     int err = cmd_disasm( program_file );
     387             :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "disasm failed (%i-%s)", err, fd_vm_strerror( err ) ));
     388             : 
     389             :     FD_LOG_NOTICE(( "disasm success" ));
     390             : 
     391             :   } else if( !strcmp( cmd, "validate" ) ) {
     392             : 
     393             :     char const * program_file = fd_env_strip_cmdline_cstr( &argc, &argv, "--program-file", NULL, NULL );
     394             : 
     395             :     if( FD_UNLIKELY( !program_file ) ) FD_LOG_ERR(( "Please specify a --program-file" ));
     396             : 
     397             :     FD_LOG_NOTICE(( "validate --program-file %s", program_file ));
     398             : 
     399             :     int err = cmd_validate( program_file );
     400             :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "validate failed (%i-%s)", err, fd_vm_strerror( err ) ));
     401             : 
     402             :     FD_LOG_NOTICE(( "validate success" ));
     403             : 
     404             :   } else if( !strcmp( cmd, "trace" ) ) {
     405             : 
     406             :     char const * program_file = fd_env_strip_cmdline_cstr( &argc, &argv, "--program-file", NULL, NULL );
     407             :     char const * input_file   = fd_env_strip_cmdline_cstr( &argc, &argv, "--input-file", NULL, NULL );
     408             : 
     409             :     if( FD_UNLIKELY( !program_file ) ) FD_LOG_ERR(( "Please specify a --program-file" ));
     410             :     if( FD_UNLIKELY( !input_file   ) ) FD_LOG_ERR(( "Please specify a --input-file"   ));
     411             : 
     412             :     FD_LOG_NOTICE(( "trace --program-file %s --input-file %s", program_file, input_file ));
     413             : 
     414             :     int err = cmd_trace( program_file, input_file );
     415             :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "trace failed (%i-%s)", err, fd_vm_strerror( err ) ));
     416             : 
     417             :     FD_LOG_NOTICE(( "trace success" ));
     418             : 
     419             :   } else if( !strcmp( cmd, "run" ) ) {
     420             : 
     421             :     char const * program_file = fd_env_strip_cmdline_cstr( &argc, &argv, "--program-file", NULL, NULL );
     422             :     char const * input_file   = fd_env_strip_cmdline_cstr( &argc, &argv, "--input-file",   NULL, NULL );
     423             :     char const * backend      = fd_env_strip_cmdline_cstr( &argc, &argv, "--backend", NULL, "interp" );
     424             :     int use_jit = 0;
     425             :     if( 0==strcmp( backend, "interp" ) ) {
     426             :       use_jit = 0;
     427             :     } else if( FD_VM_TOOL_HAS_JIT && 0==strcmp( backend, "jit" ) ) {
     428             :       use_jit = 1;
     429             :     } else {
     430             :       FD_LOG_ERR(( "Unsupported --backend \"%s\"", backend ));
     431             :     }
     432             : 
     433             :     if( FD_UNLIKELY( !program_file ) ) FD_LOG_ERR(( "Please specify a --program-file" ));
     434             :     if( FD_UNLIKELY( !input_file   ) ) FD_LOG_ERR(( "Please specify a --input-file"   ));
     435             : 
     436             :     FD_LOG_NOTICE(( "run --program-file %s --input-file %s --backend %s", program_file, input_file, backend ));
     437             : 
     438             :     int err = cmd_run( program_file, input_file, use_jit );
     439             :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "run failed (%i-%s)", err, fd_vm_strerror( err ) ));
     440             : 
     441             :     FD_LOG_NOTICE(( "run success" ));
     442             : 
     443             :   } else {
     444             : 
     445             :     FD_LOG_ERR(( "unknown command: %s", cmd ));
     446             : 
     447             :   }
     448             : 
     449             :   fd_halt();
     450             :   return 0;
     451             : }

Generated by: LCOV version 1.14