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