LCOV - code coverage report
Current view: top level - flamenco/vm - fd_vm_trace.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 182 198 91.9 %
Date: 2025-12-22 05:12:07 Functions: 9 9 100.0 %

          Line data    Source code
       1             : #include "fd_vm.h"
       2             : #include "../../ballet/sbpf/fd_sbpf_instr.h"
       3             : #include "../../ballet/sbpf/fd_sbpf_opcodes.h"
       4             : 
       5             : ulong
       6          33 : fd_vm_trace_align( void ) {
       7          33 :   return 8UL;
       8          33 : }
       9             : 
      10             : ulong
      11             : fd_vm_trace_footprint( ulong event_max,
      12          18 :                        ulong event_data_max ) {
      13          18 :   if( FD_UNLIKELY( (event_max>(1UL<<60)) | (event_data_max>(1UL<<60)) ) ) return 0UL; /* FIXME: tune these bounds */
      14           6 :   return fd_ulong_align_up( sizeof(fd_vm_trace_t) + event_max, 8UL );
      15          18 : }
      16             : 
      17             : void *
      18             : fd_vm_trace_new( void * shmem,
      19             :                  ulong  event_max,
      20          15 :                  ulong  event_data_max ) {
      21          15 :   fd_vm_trace_t * trace = (fd_vm_trace_t *)shmem;
      22             : 
      23          15 :   if( FD_UNLIKELY( !trace ) ) {
      24           3 :     FD_LOG_WARNING(( "NULL shmem" ));
      25           3 :     return NULL;
      26           3 :   }
      27             : 
      28          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_trace_align() ) ) ) {
      29           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
      30           3 :     return NULL;
      31           3 :   }
      32             : 
      33           9 :   ulong footprint = fd_vm_trace_footprint( event_max, event_data_max );
      34           9 :   if( FD_UNLIKELY( !footprint ) ) {
      35           6 :     FD_LOG_WARNING(( "bad event_max or event_data_max" ));
      36           6 :     return NULL;
      37           6 :   }
      38             : 
      39           3 :   memset( trace, 0, footprint );
      40             : 
      41           3 :   trace->event_max      = event_max;
      42           3 :   trace->event_data_max = event_data_max;
      43           3 :   trace->event_sz       = 0UL;
      44             : 
      45           3 :   FD_COMPILER_MFENCE();
      46           3 :   FD_VOLATILE( trace->magic ) = FD_VM_TRACE_MAGIC;
      47           3 :   FD_COMPILER_MFENCE();
      48             : 
      49           3 :   return trace;
      50           9 : }
      51             : 
      52             : fd_vm_trace_t *
      53          12 : fd_vm_trace_join( void * _trace ) {
      54          12 :   fd_vm_trace_t * trace = (fd_vm_trace_t *)_trace;
      55             : 
      56          12 :   if( FD_UNLIKELY( !trace ) ) {
      57           3 :     FD_LOG_WARNING(( "NULL _trace" ));
      58           3 :     return NULL;
      59           3 :   }
      60             : 
      61           9 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_trace, fd_vm_trace_align() ) ) ) {
      62           3 :     FD_LOG_WARNING(( "misaligned _trace" ));
      63           3 :     return NULL;
      64           3 :   }
      65             : 
      66           6 :   if( FD_UNLIKELY( trace->magic!=FD_VM_TRACE_MAGIC ) ) {
      67           3 :     FD_LOG_WARNING(( "bad magic" ));
      68           3 :     return NULL;
      69           3 :   }
      70             : 
      71           3 :   return trace;
      72           6 : }
      73             : 
      74             : void *
      75           6 : fd_vm_trace_leave( fd_vm_trace_t * trace ) {
      76             : 
      77           6 :   if( FD_UNLIKELY( !trace ) ) {
      78           3 :     FD_LOG_WARNING(( "NULL trace" ));
      79           3 :     return NULL;
      80           3 :   }
      81             : 
      82           3 :   return (void *)trace;
      83           6 : }
      84             : 
      85             : void *
      86          12 : fd_vm_trace_delete( void * _trace ) {
      87          12 :   fd_vm_trace_t * trace = (fd_vm_trace_t *)_trace;
      88             : 
      89          12 :   if( FD_UNLIKELY( !trace ) ) {
      90           3 :     FD_LOG_WARNING(( "NULL _trace" ));
      91           3 :     return NULL;
      92           3 :   }
      93             : 
      94           9 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_trace, fd_vm_trace_align() ) ) ) {
      95           3 :     FD_LOG_WARNING(( "misaligned _trace" ));
      96           3 :     return NULL;
      97           3 :   }
      98             : 
      99           6 :   if( FD_UNLIKELY( trace->magic!=FD_VM_TRACE_MAGIC ) ) {
     100           3 :     FD_LOG_WARNING(( "bad magic" ));
     101           3 :     return NULL;
     102           3 :   }
     103             : 
     104           3 :   FD_COMPILER_MFENCE();
     105           3 :   FD_VOLATILE( trace->magic ) = 0UL;
     106           3 :   FD_COMPILER_MFENCE();
     107             : 
     108           3 :   return (void *)trace;
     109           6 : }
     110             : 
     111             : int
     112             : fd_vm_trace_event_exe( fd_vm_trace_t * trace,
     113             :                        ulong           pc,
     114             :                        ulong           ic,
     115             :                        ulong           cu,
     116             :                        ulong           reg[ FD_VM_REG_CNT ],
     117             :                        ulong const *   text,
     118             :                        ulong           text_cnt,
     119             :                        ulong           ic_correction,
     120          21 :                        ulong           frame_cnt ) {
     121             : 
     122             :   /* Acquire event storage */
     123             : 
     124          21 :   if( FD_UNLIKELY( (!trace) | (!reg) | (!text) | (!text_cnt) ) ) return FD_VM_ERR_INVAL;
     125             : 
     126          18 :   ulong text0     = text[0];
     127          18 :   int   multiword = (text_cnt>1UL) & (fd_sbpf_instr( text0 ).opcode.any.op_class==FD_SBPF_OPCODE_CLASS_LD);
     128             : 
     129          18 :   ulong event_footprint = sizeof(fd_vm_trace_event_exe_t) - fd_ulong_if( !multiword, 8UL, 0UL );
     130             : 
     131          18 :   ulong event_sz  = trace->event_sz;
     132          18 :   ulong event_rem = trace->event_max - event_sz;
     133          18 :   if( FD_UNLIKELY( event_footprint > event_rem ) ) return FD_VM_ERR_FULL;
     134             : 
     135          15 :   fd_vm_trace_event_exe_t * event = (fd_vm_trace_event_exe_t *)((ulong)(trace+1) + event_sz);
     136             : 
     137          15 :   trace->event_sz = event_sz + event_footprint;
     138             : 
     139             :   /* Record the event */
     140             : 
     141          15 :   event->info    = fd_vm_trace_event_info( FD_VM_TRACE_EVENT_TYPE_EXE, multiword );
     142          15 :   event->pc      = pc;
     143          15 :   event->ic      = ic;
     144          15 :   event->cu      = cu;
     145          15 :   memcpy( event->reg, reg, FD_VM_REG_CNT*sizeof(ulong) );
     146          15 :   event->text[0] = text0;
     147          15 :   event->ic_correction = ic_correction;
     148          15 :   event->frame_cnt = frame_cnt;
     149          15 :   if( FD_UNLIKELY( multiword ) ) event->text[1] = text[1];
     150             : 
     151          15 :   return FD_VM_SUCCESS;
     152          18 : }
     153             : 
     154             : int
     155             : fd_vm_trace_event_mem( fd_vm_trace_t * trace,
     156             :                        int             write,
     157             :                        ulong           vaddr,
     158             :                        ulong           sz,
     159          15 :                        void *          data ) {
     160             : 
     161             :   /* Acquire event storage */
     162             : 
     163          15 :   if( FD_UNLIKELY( !trace ) ) return FD_VM_ERR_INVAL;
     164             : 
     165          12 :   int   valid           = (!!data) & (!!sz); /* FIXME: ponder sz==0 handling */
     166          12 :   ulong event_data_sz   = fd_ulong_if( valid, fd_ulong_min( sz, trace->event_data_max ), 0UL );
     167          12 :   ulong event_footprint = fd_ulong_align_up( sizeof(fd_vm_trace_event_mem_t) + event_data_sz, 8UL );
     168             : 
     169          12 :   ulong event_sz  = trace->event_sz;
     170          12 :   ulong event_rem = trace->event_max - event_sz;
     171          12 :   if( FD_UNLIKELY( event_footprint > event_rem ) ) return FD_VM_ERR_FULL;
     172             : 
     173          12 :   fd_vm_trace_event_mem_t * event = (fd_vm_trace_event_mem_t *)((ulong)(trace+1) + event_sz);
     174             : 
     175          12 :   trace->event_sz = event_sz + event_footprint;
     176             : 
     177             :   /* Record the event */
     178             : 
     179          12 :   event->info  = fd_vm_trace_event_info( fd_int_if( write, FD_VM_TRACE_EVENT_TYPE_WRITE, FD_VM_TRACE_EVENT_TYPE_READ ), valid );
     180          12 :   event->vaddr = vaddr;
     181          12 :   event->sz    = sz;
     182          12 :   if( FD_LIKELY( valid ) ) memcpy( event+1, data, event_data_sz );
     183             : 
     184          12 :   return FD_VM_SUCCESS;
     185          12 : }
     186             : 
     187             : #include <stdio.h>
     188             : 
     189             : int
     190             : fd_vm_trace_printf( fd_vm_trace_t const *      trace,
     191           6 :                     fd_sbpf_syscalls_t const * syscalls ) {
     192             : 
     193           6 :   if( FD_UNLIKELY( !trace ) ) {
     194           3 :     FD_LOG_WARNING(( "bad input args" ));
     195           3 :     return FD_VM_ERR_INVAL;
     196           3 :   }
     197             : 
     198           3 :   ulong data_max = fd_vm_trace_event_data_max( trace );
     199             : 
     200           3 :   uchar const * ptr = fd_vm_trace_event   ( trace ); /* Note: this point is 8 byte aligned */
     201           3 :   ulong         rem = fd_vm_trace_event_sz( trace );
     202          30 :   while( rem ) {
     203             : 
     204             :     /* Read the event info */
     205             : 
     206          27 :     if( FD_UNLIKELY( rem<7UL ) ) {
     207           0 :       FD_LOG_WARNING(( "truncated event (info)" ));
     208           0 :       return FD_VM_ERR_IO;
     209           0 :     }
     210             : 
     211          27 :     ulong info = *(ulong *)ptr; /* Note: this point is 8 byte aligned */
     212             : 
     213          27 :     ulong event_footprint;
     214             : 
     215          27 :     int event_type = fd_vm_trace_event_info_type( info );
     216          27 :     switch( event_type ) {
     217             : 
     218          15 :     case FD_VM_TRACE_EVENT_TYPE_EXE: {
     219          15 :       int multiword = fd_vm_trace_event_info_valid( info );
     220          15 :       event_footprint = sizeof( fd_vm_trace_event_exe_t ) - fd_ulong_if( !multiword, 8UL, 0UL );
     221          15 :       if( FD_UNLIKELY( rem < event_footprint ) ) {
     222           0 :         FD_LOG_WARNING(( "truncated event (exe)" ));
     223           0 :         return FD_VM_ERR_IO;
     224           0 :       }
     225             : 
     226          15 :       fd_vm_trace_event_exe_t * event = (fd_vm_trace_event_exe_t *)ptr;
     227             : 
     228          15 :       ulong event_pc = event->pc;
     229             : 
     230             :       /* Pretty print the architectural state before the instruction */
     231             : 
     232          15 :       printf( "%5lu [%016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX] %5lu: ",
     233          15 :               event->ic,
     234          15 :               event->reg[ 0], event->reg[ 1], event->reg[ 2], event->reg[ 3],
     235          15 :               event->reg[ 4], event->reg[ 5], event->reg[ 6], event->reg[ 7],
     236          15 :               event->reg[ 8], event->reg[ 9], event->reg[10], event_pc );
     237             : 
     238             :       /* Print the instruction */
     239             : 
     240          15 :       ulong out_len = 0UL;
     241          15 :       char  out[128];
     242          15 :       out[0] = '\0';
     243          15 :       int err = fd_vm_disasm_instr( event->text, fd_ulong_if( !multiword, 1UL, 2UL ), event_pc, syscalls, out, 128UL, &out_len );
     244          15 :       if( FD_UNLIKELY( err ) ) printf( "disasm failed (%i-%s)", err, fd_vm_strerror( err ) );
     245          15 :       else                     printf( "%s", out );
     246             : 
     247             :       /* Print CUs  */
     248          15 :       printf( " %lu\n", event->cu );
     249          15 :       fflush( stdout );
     250          15 :       break;
     251          15 :     }
     252             : 
     253          12 :     case FD_VM_TRACE_EVENT_TYPE_READ:
     254          12 :     case FD_VM_TRACE_EVENT_TYPE_WRITE: {
     255             : 
     256          12 :       event_footprint = sizeof(fd_vm_trace_event_mem_t);
     257          12 :       if( FD_UNLIKELY( rem < event_footprint ) ) {
     258           0 :         FD_LOG_WARNING(( "truncated event (mem)" ));
     259           0 :         return FD_VM_ERR_IO;
     260           0 :       }
     261             : 
     262          12 :       fd_vm_trace_event_mem_t * event = (fd_vm_trace_event_mem_t *)ptr;
     263             : 
     264          12 :       int   valid    = fd_vm_trace_event_info_valid( info );
     265          12 :       ulong event_sz = event->sz;
     266          12 :       ulong data_sz  = fd_ulong_if( valid, fd_ulong_min( event_sz, data_max ), 0UL );
     267             : 
     268          12 :       event_footprint = fd_ulong_align_up( event_footprint + data_sz, 8UL );
     269          12 :       if( FD_UNLIKELY( rem < event_footprint ) ) {
     270           0 :         FD_LOG_WARNING(( "truncated event (data)" ));
     271           0 :         return FD_VM_ERR_IO;
     272           0 :       }
     273             : 
     274          12 :       uchar * data = (uchar *)(event+1);
     275             : 
     276          12 :       ulong prev_ic = 0UL; /* FIXME: there was some commented out code originally to find the ic that previously modified */
     277             : 
     278          12 :       printf( "        %s: vm_addr: 0x%016lX, sz: %8lu, prev_ic: %8lu, data: ",
     279          12 :               event_type==FD_VM_TRACE_EVENT_TYPE_READ ? "R" : "W", event->vaddr, event_sz, prev_ic );
     280             : 
     281          12 :       char buf[ 1024UL + 6UL*2048UL ]; /* 1KiB for overhead + 6 bytes for every byte of event_data_max */
     282             : 
     283          12 :       char * p = fd_cstr_init( buf );
     284          12 :       if( !valid ) p = fd_cstr_append_char( p, '-' );
     285          12 :       else {
     286         492 :         for( ulong data_off=0UL; data_off<data_sz; data_off++ ) {
     287         480 :           if( FD_UNLIKELY( (data_off & 0xfUL)==0UL ) ) p = fd_cstr_append_printf( p, "\n                0x%04lX:", data_off );
     288         480 :           if( FD_UNLIKELY( (data_off & 0xfUL)==8UL ) ) p = fd_cstr_append_char( p, ' ' );
     289         480 :           p = fd_cstr_append_printf( p, " %02X", (uint)data[ data_off ] );
     290         480 :         }
     291          12 :         if( FD_UNLIKELY( data_sz < event_sz ) )
     292           0 :           p = fd_cstr_append_printf( p, "\n                ... omitted %lu bytes ...", event_sz - data_sz );
     293          12 :       }
     294          12 :       p = fd_cstr_append_char( p, '\n' );
     295          12 :       fd_cstr_fini( p );
     296             : 
     297          12 :       printf( "%s", buf );
     298          12 :       break;
     299          12 :     }
     300             : 
     301           0 :     default: {
     302           0 :       FD_LOG_WARNING(( "unexpected event type" ));
     303           0 :       return FD_VM_ERR_IO;
     304          12 :     }
     305             : 
     306          27 :     }
     307             : 
     308          27 :     ptr += event_footprint;
     309          27 :     rem -= event_footprint;
     310          27 :   }
     311             : 
     312           3 :   return FD_VM_SUCCESS;
     313           3 : }

Generated by: LCOV version 1.14