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 : }
|