LCOV - code coverage report
Current view: top level - ballet/sbpf - fd_sbpf_loader.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 31 64 48.4 %
Date: 2026-05-15 07:18:56 Functions: 10 2730 0.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h
       2             : #define HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h
       3             : 
       4             : /* fd_sbpf_loader prepares an sBPF program for execution.  This involves
       5             :    parsing and dynamic relocation.
       6             : 
       7             :    Due to historical reasons, this loader is neither a pure static
       8             :    linker nor a real dynamic loader.  For instance, it will ignore the
       9             :    program header table and instead load specific sections at predefined
      10             :    addresses.  However, it will perform dynamic relocation. */
      11             : 
      12             : #include "../../util/fd_util_base.h"
      13             : #include "../elf/fd_elf64.h"
      14             : 
      15             : /* Error types ********************************************************/
      16             : 
      17             : /* FIXME make error types more specific */
      18             : #define FD_SBPF_ERR_INVALID_ELF (1)
      19          12 : #define FD_SBPF_PROG_RODATA_ALIGN 8UL
      20             : 
      21             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/elf_parser/mod.rs#L17 */
      22             : #define FD_SBPF_ELF_PARSER_SUCCESS                           ( 0)
      23          24 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_FILE_HEADER           (-1)
      24          12 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_PROGRAM_HEADER        (-2)
      25           0 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_SECTION_HEADER        (-3)
      26             : #define FD_SBPF_ELF_PARSER_ERR_INVALID_STRING                (-4)
      27           3 : #define FD_SBPF_ELF_PARSER_ERR_STRING_TOO_LONG               (-5)
      28           6 : #define FD_SBPF_ELF_PARSER_ERR_OUT_OF_BOUNDS                 (-6)
      29           0 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_SIZE                  (-7)
      30           0 : #define FD_SBPF_ELF_PARSER_ERR_OVERLAP                       (-8)
      31           0 : #define FD_SBPF_ELF_PARSER_ERR_SECTION_NOT_IN_ORDER          (-9)
      32           0 : #define FD_SBPF_ELF_PARSER_ERR_NO_SECTION_NAME_STRING_TABLE  (-10)
      33           0 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_DYNAMIC_SECTION_TABLE (-11)
      34             : #define FD_SBPF_ELF_PARSER_ERR_INVALID_RELOCATION_TABLE      (-12)
      35           0 : #define FD_SBPF_ELF_PARSER_ERR_INVALID_ALIGNMENT             (-13)
      36             : #define FD_SBPF_ELF_PARSER_ERR_NO_STRING_TABLE               (-14)
      37             : #define FD_SBPF_ELF_PARSER_ERR_NO_DYNAMIC_STRING_TABLE       (-15)
      38             : 
      39             : /* Map Rust ElfError (elf.rs v0.12.2) to C error codes */
      40             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/elf.rs#L40-L66 */
      41       89124 : #define FD_SBPF_ELF_SUCCESS                                  (  0)
      42          27 : #define FD_SBPF_ELF_ERR_FAILED_TO_PARSE                      ( -1)
      43           0 : #define FD_SBPF_ELF_ERR_ENTRYPOINT_OUT_OF_BOUNDS             ( -2)
      44           0 : #define FD_SBPF_ELF_ERR_INVALID_ENTRYPOINT                   ( -3)
      45             : #define FD_SBPF_ELF_ERR_FAILED_TO_GET_SECTION                ( -4)
      46           0 : #define FD_SBPF_ELF_ERR_UNRESOLVED_SYMBOL                    ( -5)
      47             : #define FD_SBPF_ELF_ERR_SECTION_NOT_FOUND                    ( -6)
      48           0 : #define FD_SBPF_ELF_ERR_RELATIVE_JUMP_OUT_OF_BOUNDS          ( -7)
      49           0 : #define FD_SBPF_ELF_ERR_SYMBOL_HASH_COLLISION                ( -8)
      50           0 : #define FD_SBPF_ELF_ERR_WRONG_ENDIANNESS                     ( -9)
      51           0 : #define FD_SBPF_ELF_ERR_WRONG_ABI                            (-10)
      52           0 : #define FD_SBPF_ELF_ERR_WRONG_MACHINE                        (-11)
      53           0 : #define FD_SBPF_ELF_ERR_WRONG_CLASS                          (-12)
      54           0 : #define FD_SBPF_ELF_ERR_NOT_ONE_TEXT_SECTION                 (-13)
      55           0 : #define FD_SBPF_ELF_ERR_WRITABLE_SECTION_NOT_SUPPORTED       (-14)
      56             : #define FD_SBPF_ELF_ERR_ADDRESS_OUTSIDE_LOADABLE_SECTION     (-15)
      57           0 : #define FD_SBPF_ELF_ERR_INVALID_VIRTUAL_ADDRESS              (-16)
      58           0 : #define FD_SBPF_ELF_ERR_UNKNOWN_RELOCATION                   (-17)
      59             : #define FD_SBPF_ELF_ERR_FAILED_TO_READ_RELOCATION_INFO       (-18)
      60           0 : #define FD_SBPF_ELF_ERR_WRONG_TYPE                           (-19)
      61           0 : #define FD_SBPF_ELF_ERR_UNKNOWN_SYMBOL                       (-20)
      62           3 : #define FD_SBPF_ELF_ERR_VALUE_OUT_OF_BOUNDS                  (-21)
      63          51 : #define FD_SBPF_ELF_ERR_UNSUPPORTED_SBPF_VERSION             (-22)
      64           6 : #define FD_SBPF_ELF_ERR_INVALID_PROGRAM_HEADER               (-23)
      65             : 
      66             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/program.rs */
      67        2736 : #define FD_SBPF_VERSION_COUNT (5U)
      68        5256 : #define FD_SBPF_V0            (0U)
      69      106173 : #define FD_SBPF_V1            (1U)
      70     3503640 : #define FD_SBPF_V2            (2U)
      71     1117155 : #define FD_SBPF_V3            (3U)
      72             : #define FD_SBPF_V4            (4U)
      73          39 : #define FD_SBPF_RESERVED      (FD_SBPF_VERSION_COUNT)
      74             : 
      75             : /* Hardcoded constant for the murmur3_32 hash of the entrypoint. */
      76       27264 : #define FD_SBPF_ENTRYPOINT_PC   (0xb00c380U)
      77        2586 : #define FD_SBPF_ENTRYPOINT_HASH (0x71e3cf81U) /* fd_pchash( FD_SBPF_ENTRYPOINT_PC ) */
      78             : 
      79             : #define E_FLAGS_SBPF_V2         (0x20U)
      80             : 
      81             : /* Program struct *****************************************************/
      82             : 
      83             : /* fd_sbpf_calldests is a bit vector of valid call destinations.
      84             :    Should be configured to fit any possible program counter.  The max
      85             :    program counter is <size of ELF binary> divided by 8. */
      86             : 
      87             : #define SET_NAME fd_sbpf_calldests
      88             : #include "../../util/tmpl/fd_set_dynamic.c"
      89             : 
      90             : /* The sbpf program footprint is large when stricter elf headers are
      91             :    not enabled due to the calldests bitmap being included.  So, the
      92             :    total footprint of the sbpf_program is the size of the sbpf_program
      93             :    struct plus the calldests bitmap.
      94             : 
      95             :    The calldests bitmap is variable with the text_cnt.  A loose bound on
      96             :    the textcnt is the max size of an account / 8.  So, the max possible
      97             :    text_cnt is 1310720.  So the footprint of the sbpf_calldests is as
      98             :    follows:
      99             :    sizeof(SET_(private_t))-sizeof(SET_(t)) + sizeof(SET_(t))*SET_(private_word_cnt)( max )
     100             :    private_word_cnt(1310720) = 20480
     101             :    sizeof(SET_(t)) = 8 (ulong)
     102             :    sizeof(SET_(private_t)) = 32
     103             :    */
     104             : #define FD_SBPF_TEXT_CNT_MAX (FD_RUNTIME_ACC_SZ_MAX / 8UL)
     105             : #define FD_SBPF_CALLDESTS_PRIVATE_WORD_CNT ( (FD_SBPF_TEXT_CNT_MAX +63UL)>>6 )
     106             : #define FD_SBPF_PROGRAM_FOOTPRINT (sizeof(fd_sbpf_program_t) + sizeof(fd_sbpf_calldests_private_t)-sizeof(ulong) + sizeof(ulong)*FD_SBPF_CALLDESTS_PRIVATE_WORD_CNT )
     107             : 
     108             : /* fd_sbpf_syscall_func_t is a callback implementing an sBPF syscall.
     109             :    vm is a handle to the running VM.  Returns 0 on success or an integer
     110             :    error code on failure.
     111             : 
     112             :    IMPORTANT SAFETY TIP!  See notes in
     113             :    flamenco/vm/syscall/fd_vm_syscall.h on what a syscall should expect
     114             :    to see and expect to return. */
     115             : 
     116             : /* FIXME: THIS BELONGS IN FLAMENCO/VM */
     117             : 
     118             : typedef int
     119             : (*fd_sbpf_syscall_func_t)( void *  vm,
     120             :                            ulong   arg0,
     121             :                            ulong   arg1,
     122             :                            ulong   arg2,
     123             :                            ulong   arg3,
     124             :                            ulong   arg4,
     125             :                            ulong * _ret );
     126             : 
     127             : /* fd_sbpf_syscalls_t maps syscall IDs => a name and a VM specific
     128             :    context.  FIXME: THIS ALSO PROBABLY BELONGS IN FLAMENCO/VM */
     129             : 
     130     2855805 : #define FD_SBPF_SYSCALLS_LG_SLOT_CNT (7)
     131             : #define FD_SBPF_SYSCALLS_SLOT_CNT    (1UL<<FD_SBPF_SYSCALLS_LG_SLOT_CNT)
     132             : 
     133             : /* The syscalls map keys should technically be of type uint since they are
     134             :    just murmur32 hashes. However, Agave's BTree allows the full range to be
     135             :    used as a key [0, UINT_MAX]. So we need to define a wider key type to
     136             :    allow for a NULL value that is outside this range. We use ulong here. */
     137             : 
     138             : struct fd_sbpf_syscalls {
     139             :   ulong                  key;  /* Murmur3-32 hash of function name */
     140             :   fd_sbpf_syscall_func_t func; /* Function pointer */
     141             :   char const *           name; /* Infinite lifetime pointer to function name */
     142             : };
     143             : 
     144             : typedef struct fd_sbpf_syscalls fd_sbpf_syscalls_t;
     145             : 
     146             : #define MAP_NAME              fd_sbpf_syscalls
     147      212862 : #define MAP_T                 fd_sbpf_syscalls_t
     148      199341 : #define MAP_HASH_T            ulong
     149     2371608 : #define MAP_KEY_NULL          ULONG_MAX         /* Any number greater than UINT_MAX works */
     150      273705 : #define MAP_KEY_INVAL(k)      ( k > UINT_MAX )  /* Force keys to uint size */
     151       89532 : #define MAP_KEY_EQUAL(k0,k1)  (k0)==(k1)
     152             : #define MAP_KEY_EQUAL_IS_SLOW 0
     153      199341 : #define MAP_KEY_HASH(k)       (k)
     154             : #define MAP_MEMOIZE           0
     155     2855418 : #define MAP_LG_SLOT_CNT       FD_SBPF_SYSCALLS_LG_SLOT_CNT
     156             : #include "../../util/tmpl/fd_map.c"
     157             : 
     158             : #define FD_SBPF_SYSCALLS_FOOTPRINT (sizeof(fd_sbpf_syscalls_t) * (1UL<<FD_SBPF_SYSCALLS_LG_SLOT_CNT))
     159             : #define FD_SBPF_SYSCALLS_ALIGN     alignof(fd_sbpf_syscalls_t)
     160             : 
     161             : /* fd_sbpf_elf_info_t contains basic information extracted from an ELF
     162             :    binary. Indicates how much scratch memory and buffer size is required
     163             :    to fully load the program. */
     164             : 
     165             : struct fd_sbpf_elf_info {
     166             :   ulong bin_sz;   /* size of ELF binary */
     167             : 
     168             :   ulong calldests_max;  /* Size of calldests set */
     169             :   uint  text_off;       /* File offset of .text section (overlaps rodata segment) */
     170             :   uint  text_cnt;       /* Instruction count */
     171             :   ulong text_sz;        /* size of text segment. Guaranteed to be <= bin_sz. */
     172             : 
     173             :   /* Known section indices
     174             :      In [-1,USHORT_MAX) where -1 means "not found" */
     175             :   int shndx_text;
     176             :   int shndx_symtab;
     177             :   int shndx_strtab;
     178             :   int shndx_dyn;
     179             :   int shndx_dynstr;
     180             :   int shndx_dynsymtab; /* Section header index of the dynamic symbol table */
     181             : 
     182             :   /* Known program header indices (like shndx_*) */
     183             :   int phndx_dyn;
     184             : 
     185             :   /* Dynamic relocation table entries */
     186             :   uint dt_rel_off; /* File offset of dynamic relocation table */
     187             :   uint dt_rel_sz;  /* Number of dynamic relocation table entries */
     188             : 
     189             :   /* SBPF version, SIMD-0161 */
     190             :   ulong sbpf_version;
     191             : };
     192             : typedef struct fd_sbpf_elf_info fd_sbpf_elf_info_t;
     193             : 
     194             : /* fd_sbpf_program_t describes a loaded program in memory.
     195             : 
     196             :    [rodata,rodata+bin_sz) is an externally allocated buffer holding
     197             :    the read-only segment to be loaded into the VM.  WARNING: The rodata
     198             :    area required doing load (bin_sz) is larger than the area mapped into
     199             :    the VM (rodata_sz).
     200             : 
     201             :    [text,text+8*text_cnt) is a sub-region of the read-only segment
     202             :    containing executable code.
     203             : 
     204             :    We need to maintain a separate value tracking the entrypoint calldest
     205             :    because we lay out our calldests in a set instead of a map (like
     206             :    Agave does), which is more performant but comes with a few footguns.
     207             :    Since we only store the target PC and not a keypair of <hash, target
     208             :    PC>, we need to make sure we unregister the correct target PC from
     209             :    the map. For all other cases besides the b"entrypoint" string, we can
     210             :    simply check for membership within the calldests set because the
     211             :    32-bit murmur3 hash function is bijective, implying key collision iff
     212             :    value collision. However, the b"entrypoint" string is a special case
     213             :    because the key is the hardcoded hash of the b"entrypoint" string,
     214             :    but the value can correspond to any target PC. This means that
     215             :    someone could register several different target PCs with the same
     216             :    entrypoint PC, and we cannot figure out which target PC we must
     217             :    unregister. Additionally, we would not be able to check for
     218             :    collisions for multiple registered b"entrypoint" strings with
     219             :    different target PCs.
     220             : 
     221             :    Once entry_pc is set, any future calls to set the entry_pc within the
     222             :    loader will error out with FD_SBPF_ELF_ERR_SYMBOL_HASH_COLLISION. */
     223             : 
     224             : struct __attribute__((aligned(32UL))) fd_sbpf_program {
     225             :   fd_sbpf_elf_info_t info;
     226             : 
     227             :   /* rodata segment to be mapped into VM memory */
     228             :   void * rodata;     /* rodata segment data */
     229             :   ulong  rodata_sz;  /* size of read-only data */
     230             : 
     231             :   /* text section within rodata segment */
     232             :   ulong * text;
     233             :   ulong   entry_pc;  /* entrypoint PC (at text[ entry_pc ]). ULONG_MAX if not set. */
     234             : 
     235             :   /* Bit vector of valid call destinations (bit count is text_cnt). */
     236             :   void * calldests_shmem;
     237             :   /* Local join to bit vector of valid call destinations (target PCs) */
     238             :   fd_sbpf_calldests_t * calldests;
     239             : };
     240             : typedef struct fd_sbpf_program fd_sbpf_program_t;
     241             : 
     242             : struct fd_sbpf_loader_config {
     243             :   union {
     244             :    int elf_deploy_checks;
     245             :    int reject_broken_elfs;
     246             :   };
     247             :   uint sbpf_min_version;
     248             :   uint sbpf_max_version;
     249             : };
     250             : typedef struct fd_sbpf_loader_config fd_sbpf_loader_config_t;
     251             : 
     252             : /* Prototypes *********************************************************/
     253             : 
     254             : FD_PROTOTYPES_BEGIN
     255             : 
     256             : /* fd_sbpf_elf_peek partially parses the given ELF file in memory region
     257             :    [bin,bin+bin_sz)  Populates `info`.  Returns `info` on success.  On
     258             :    failure, returns NULL.
     259             : 
     260             :    elf_deploy_checks: The Agave ELF loader introduced additional checks
     261             :    that would fail on (certain) existing mainnet programs. Since it is
     262             :    impossible to retroactively enforce these checks on already deployed programs,
     263             :    a guard flag is used to enable these checks only when deploying programs.
     264             : 
     265             :    sbpf_min_version, sbpf_max_version: determine the min, max SBPF version
     266             :    allowed, version is retrieved from the ELF header. See SIMD-0161. */
     267             : 
     268             : int
     269             : fd_sbpf_elf_peek( fd_sbpf_elf_info_t *            info,
     270             :                   void const *                    bin,
     271             :                   ulong                           bin_sz,
     272             :                   fd_sbpf_loader_config_t const * config );
     273             : 
     274             : /* fd_sbpf_program_{align,footprint} return the alignment and size
     275             :    requirements of the memory region backing the fd_sbpf_program_t
     276             :    object. */
     277             : 
     278             : FD_FN_CONST ulong
     279             : fd_sbpf_program_align( void );
     280             : 
     281             : FD_FN_PURE ulong
     282             : fd_sbpf_program_footprint( fd_sbpf_elf_info_t const * info );
     283             : 
     284             : /* fd_sbpf_program_new formats prog_mem to hold an fd_sbpf_program_t.
     285             :    prog_mem must match footprint requirements of the given elf_info.
     286             :    elf_info may be deallocated on return.
     287             : 
     288             :    rodata is the read-only segment buffer that the program is configured
     289             :    against and must be valid for the lifetime of the program object. It
     290             :    should also meet the alignment requirements of the program object.
     291             :    */
     292             : 
     293             : fd_sbpf_program_t *
     294             : fd_sbpf_program_new( void *                     prog_mem,
     295             :                      fd_sbpf_elf_info_t const * elf_info,
     296             :                      void *                     rodata );
     297             : 
     298             : /* fd_sbpf_program_load loads an eBPF program for execution.
     299             : 
     300             :    prog is a program object allocated with fd_sbpf_program_new and must
     301             :    match the footprint requirements of this ELF file.
     302             : 
     303             :    Initializes and populates the program struct with information about
     304             :    the program and prepares the read-only segment provided in
     305             :    fd_sbpf_program_new. This includes performing relocations in the
     306             :    ELF file and zeroing gaps between rodata sections.
     307             : 
     308             :    Memory region [bin,bin+bin_sz) contains the ELF file to be loaded.
     309             : 
     310             :    syscalls should be a pointer to a map of registered syscalls and
     311             :    will be checked against when registering calldests for potential
     312             :    symbol collisions.
     313             : 
     314             :    scratch should be a pointer to a scratch area with size scratch_sz,
     315             :    used to allocate a temporary buffer for the parsed rodata sections
     316             :    before copying it back into the rodata.  recommended size is bin_sz.
     317             : 
     318             :    On success, returns 0.
     319             :    On error, returns FD_SBPF_ERR_*.
     320             : 
     321             :    ### Compliance
     322             : 
     323             :    As of writing, this loader is conformant with Solana SBPF v0.12.2,
     324             :    SBPF versions V0, V1, and V2.
     325             :    */
     326             : 
     327             : int
     328             : fd_sbpf_program_load( fd_sbpf_program_t *             prog,
     329             :                       void const *                    bin,
     330             :                       ulong                           bin_sz,
     331             :                       fd_sbpf_syscalls_t *            syscalls,
     332             :                       fd_sbpf_loader_config_t const * config,
     333             :                       void *                          scratch,
     334             :                       ulong                           scratch_sz );
     335             : 
     336             : /* fd_sbpf_program_delete destroys the program object and unformats the
     337             :    memory regions holding it. */
     338             : 
     339             : void *
     340             : fd_sbpf_program_delete( fd_sbpf_program_t * program );
     341             : 
     342             : /* SBPF versions and features. This should stay in sync with the macro
     343             :    definitions in fd_vm_private.h until they are removed (once Agave
     344             :    cleans up the jump table).
     345             :    https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/program.rs#L28 */
     346             : 
     347          12 : #define FD_VM_SBPF_DYNAMIC_STACK_FRAMES_ALIGN (64U)
     348             : 
     349             : /* SIMD-0166 */
     350             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L32-L34 */
     351         315 : static inline int fd_sbpf_manual_stack_frame_bump_enabled            ( ulong v ) { return v==FD_SBPF_V1 || v==FD_SBPF_V2; }
     352             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L36-L38 */
     353           0 : static inline int fd_sbpf_stack_frame_gaps_enabled                   ( ulong v ) { return v==FD_SBPF_V0; }
     354             : 
     355             : /* SIMD-0174 */
     356             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L41-L43 */
     357           0 : static inline int fd_sbpf_enable_pqr_enabled                         ( ulong v ) { return v==FD_SBPF_V2; }
     358             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L45-L47 */
     359           0 : static inline int fd_sbpf_explicit_sign_extension_of_results_enabled ( ulong v ) { return v==FD_SBPF_V2; }
     360             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L49-L51 */
     361           0 : static inline int fd_sbpf_swap_sub_reg_imm_operands_enabled          ( ulong v ) { return v==FD_SBPF_V2; }
     362             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L53-L55 */
     363           0 : static inline int fd_sbpf_disable_neg_enabled                        ( ulong v ) { return v==FD_SBPF_V2; }
     364             : 
     365             : /* SIMD-0173 */
     366             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L58-L60 */
     367          45 : static inline int fd_sbpf_callx_uses_src_reg_enabled                 ( ulong v ) { return v==FD_SBPF_V2; }
     368             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L62-L64 */
     369           0 : static inline int fd_sbpf_disable_lddw_enabled                       ( ulong v ) { return v==FD_SBPF_V2; }
     370             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L66-L68 */
     371           0 : static inline int fd_sbpf_disable_le_enabled                         ( ulong v ) { return v==FD_SBPF_V2; }
     372             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L70-L72 */
     373           0 : static inline int fd_sbpf_move_memory_ix_classes_enabled             ( ulong v ) { return v==FD_SBPF_V2; }
     374             : 
     375             : /* SIMD-0178 */
     376             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L75-L77 */
     377           0 : static inline int fd_sbpf_static_syscalls_enabled                    ( ulong v ) { return v>=FD_SBPF_V3; }
     378             : 
     379             : /* SIMD-0189 */
     380             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L79-L81 */
     381       21411 : static inline int fd_sbpf_enable_stricter_elf_headers_enabled        ( ulong v ) { return v>=FD_SBPF_V3; }
     382             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L83-L85 */
     383           0 : static inline int fd_sbpf_enable_lower_rodata_vaddr_enabled          ( ulong v ) { return v>=FD_SBPF_V3; }
     384             : 
     385             : /* SIMD-0377 */
     386             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L87-L89 */
     387           0 : static inline int fd_sbpf_enable_jmp32_enabled                       ( ulong v ) { return v>=FD_SBPF_V3; }
     388             : /* https://github.com/anza-xyz/sbpf/blob/v0.14.4/src/program.rs#L91-L93 */
     389          24 : static inline int fd_sbpf_callx_uses_dst_reg_enabled                 ( ulong v ) { return v>=FD_SBPF_V3; }
     390             : 
     391             : FD_PROTOTYPES_END
     392             : 
     393             : #endif /* HEADER_fd_src_ballet_sbpf_fd_sbpf_loader_h */

Generated by: LCOV version 1.14