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