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