Line data Source code
1 : #include "fd_vm.h"
2 : #include "../../ballet/sbpf/fd_sbpf_instr.h"
3 : #include "../../ballet/sbpf/fd_sbpf_opcodes.h"
4 :
5 : ulong
6 33 : fd_vm_trace_align( void ) {
7 33 : return 8UL;
8 33 : }
9 :
10 : ulong
11 : fd_vm_trace_footprint( ulong event_max,
12 18 : ulong event_data_max ) {
13 18 : if( FD_UNLIKELY( (event_max>(1UL<<60)) | (event_data_max>(1UL<<60)) ) ) return 0UL; /* FIXME: tune these bounds */
14 6 : return fd_ulong_align_up( sizeof(fd_vm_trace_t) + event_max, 8UL );
15 18 : }
16 :
17 : void *
18 : fd_vm_trace_new( void * shmem,
19 : ulong event_max,
20 15 : ulong event_data_max ) {
21 15 : fd_vm_trace_t * trace = (fd_vm_trace_t *)shmem;
22 :
23 15 : if( FD_UNLIKELY( !trace ) ) {
24 3 : FD_LOG_WARNING(( "NULL shmem" ));
25 3 : return NULL;
26 3 : }
27 :
28 12 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vm_trace_align() ) ) ) {
29 3 : FD_LOG_WARNING(( "misaligned shmem" ));
30 3 : return NULL;
31 3 : }
32 :
33 9 : ulong footprint = fd_vm_trace_footprint( event_max, event_data_max );
34 9 : if( FD_UNLIKELY( !footprint ) ) {
35 6 : FD_LOG_WARNING(( "bad event_max or event_data_max" ));
36 6 : return NULL;
37 6 : }
38 :
39 3 : memset( trace, 0, footprint );
40 :
41 3 : trace->event_max = event_max;
42 3 : trace->event_data_max = event_data_max;
43 3 : trace->event_sz = 0UL;
44 :
45 3 : FD_COMPILER_MFENCE();
46 3 : FD_VOLATILE( trace->magic ) = FD_VM_TRACE_MAGIC;
47 3 : FD_COMPILER_MFENCE();
48 :
49 3 : return trace;
50 9 : }
51 :
52 : fd_vm_trace_t *
53 12 : fd_vm_trace_join( void * _trace ) {
54 12 : fd_vm_trace_t * trace = (fd_vm_trace_t *)_trace;
55 :
56 12 : if( FD_UNLIKELY( !trace ) ) {
57 3 : FD_LOG_WARNING(( "NULL _trace" ));
58 3 : return NULL;
59 3 : }
60 :
61 9 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_trace, fd_vm_trace_align() ) ) ) {
62 3 : FD_LOG_WARNING(( "misaligned _trace" ));
63 3 : return NULL;
64 3 : }
65 :
66 6 : if( FD_UNLIKELY( trace->magic!=FD_VM_TRACE_MAGIC ) ) {
67 3 : FD_LOG_WARNING(( "bad magic" ));
68 3 : return NULL;
69 3 : }
70 :
71 3 : return trace;
72 6 : }
73 :
74 : void *
75 6 : fd_vm_trace_leave( fd_vm_trace_t * trace ) {
76 :
77 6 : if( FD_UNLIKELY( !trace ) ) {
78 3 : FD_LOG_WARNING(( "NULL trace" ));
79 3 : return NULL;
80 3 : }
81 :
82 3 : return (void *)trace;
83 6 : }
84 :
85 : void *
86 12 : fd_vm_trace_delete( void * _trace ) {
87 12 : fd_vm_trace_t * trace = (fd_vm_trace_t *)_trace;
88 :
89 12 : if( FD_UNLIKELY( !trace ) ) {
90 3 : FD_LOG_WARNING(( "NULL _trace" ));
91 3 : return NULL;
92 3 : }
93 :
94 9 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)_trace, fd_vm_trace_align() ) ) ) {
95 3 : FD_LOG_WARNING(( "misaligned _trace" ));
96 3 : return NULL;
97 3 : }
98 :
99 6 : if( FD_UNLIKELY( trace->magic!=FD_VM_TRACE_MAGIC ) ) {
100 3 : FD_LOG_WARNING(( "bad magic" ));
101 3 : return NULL;
102 3 : }
103 :
104 3 : FD_COMPILER_MFENCE();
105 3 : FD_VOLATILE( trace->magic ) = 0UL;
106 3 : FD_COMPILER_MFENCE();
107 :
108 3 : return (void *)trace;
109 6 : }
110 :
111 : int
112 : fd_vm_trace_event_exe( fd_vm_trace_t * trace,
113 : ulong pc,
114 : ulong ic,
115 : ulong cu,
116 : ulong reg[ FD_VM_REG_CNT ],
117 : ulong const * text,
118 : ulong text_cnt,
119 : ulong ic_correction,
120 21 : ulong frame_cnt ) {
121 :
122 : /* Acquire event storage */
123 :
124 21 : if( FD_UNLIKELY( (!trace) | (!reg) | (!text) | (!text_cnt) ) ) return FD_VM_ERR_INVAL;
125 :
126 18 : ulong text0 = text[0];
127 18 : int multiword = (text_cnt>1UL) & (fd_sbpf_instr( text0 ).opcode.any.op_class==FD_SBPF_OPCODE_CLASS_LD);
128 :
129 18 : ulong event_footprint = sizeof(fd_vm_trace_event_exe_t) - fd_ulong_if( !multiword, 8UL, 0UL );
130 :
131 18 : ulong event_sz = trace->event_sz;
132 18 : ulong event_rem = trace->event_max - event_sz;
133 18 : if( FD_UNLIKELY( event_footprint > event_rem ) ) return FD_VM_ERR_FULL;
134 :
135 15 : fd_vm_trace_event_exe_t * event = (fd_vm_trace_event_exe_t *)((ulong)(trace+1) + event_sz);
136 :
137 15 : trace->event_sz = event_sz + event_footprint;
138 :
139 : /* Record the event */
140 :
141 15 : event->info = fd_vm_trace_event_info( FD_VM_TRACE_EVENT_TYPE_EXE, multiword );
142 15 : event->pc = pc;
143 15 : event->ic = ic;
144 15 : event->cu = cu;
145 15 : memcpy( event->reg, reg, FD_VM_REG_CNT*sizeof(ulong) );
146 15 : event->text[0] = text0;
147 15 : event->ic_correction = ic_correction;
148 15 : event->frame_cnt = frame_cnt;
149 15 : if( FD_UNLIKELY( multiword ) ) event->text[1] = text[1];
150 :
151 15 : return FD_VM_SUCCESS;
152 18 : }
153 :
154 : int
155 : fd_vm_trace_event_mem( fd_vm_trace_t * trace,
156 : int write,
157 : ulong vaddr,
158 : ulong sz,
159 15 : void * data ) {
160 :
161 : /* Acquire event storage */
162 :
163 15 : if( FD_UNLIKELY( !trace ) ) return FD_VM_ERR_INVAL;
164 :
165 12 : int valid = (!!data) & (!!sz); /* FIXME: ponder sz==0 handling */
166 12 : ulong event_data_sz = fd_ulong_if( valid, fd_ulong_min( sz, trace->event_data_max ), 0UL );
167 12 : ulong event_footprint = fd_ulong_align_up( sizeof(fd_vm_trace_event_mem_t) + event_data_sz, 8UL );
168 :
169 12 : ulong event_sz = trace->event_sz;
170 12 : ulong event_rem = trace->event_max - event_sz;
171 12 : if( FD_UNLIKELY( event_footprint > event_rem ) ) return FD_VM_ERR_FULL;
172 :
173 12 : fd_vm_trace_event_mem_t * event = (fd_vm_trace_event_mem_t *)((ulong)(trace+1) + event_sz);
174 :
175 12 : trace->event_sz = event_sz + event_footprint;
176 :
177 : /* Record the event */
178 :
179 12 : event->info = fd_vm_trace_event_info( fd_int_if( write, FD_VM_TRACE_EVENT_TYPE_WRITE, FD_VM_TRACE_EVENT_TYPE_READ ), valid );
180 12 : event->vaddr = vaddr;
181 12 : event->sz = sz;
182 12 : if( FD_LIKELY( valid ) ) memcpy( event+1, data, event_data_sz );
183 :
184 12 : return FD_VM_SUCCESS;
185 12 : }
186 :
187 : #include <stdio.h>
188 :
189 : int
190 : fd_vm_trace_printf( fd_vm_trace_t const * trace,
191 6 : fd_sbpf_syscalls_t const * syscalls ) {
192 :
193 6 : if( FD_UNLIKELY( !trace ) ) {
194 3 : FD_LOG_WARNING(( "bad input args" ));
195 3 : return FD_VM_ERR_INVAL;
196 3 : }
197 :
198 3 : ulong data_max = fd_vm_trace_event_data_max( trace );
199 :
200 3 : uchar const * ptr = fd_vm_trace_event ( trace ); /* Note: this point is 8 byte aligned */
201 3 : ulong rem = fd_vm_trace_event_sz( trace );
202 30 : while( rem ) {
203 :
204 : /* Read the event info */
205 :
206 27 : if( FD_UNLIKELY( rem<7UL ) ) {
207 0 : FD_LOG_WARNING(( "truncated event (info)" ));
208 0 : return FD_VM_ERR_IO;
209 0 : }
210 :
211 27 : ulong info = *(ulong *)ptr; /* Note: this point is 8 byte aligned */
212 :
213 27 : ulong event_footprint;
214 :
215 27 : int event_type = fd_vm_trace_event_info_type( info );
216 27 : switch( event_type ) {
217 :
218 15 : case FD_VM_TRACE_EVENT_TYPE_EXE: {
219 15 : int multiword = fd_vm_trace_event_info_valid( info );
220 15 : event_footprint = sizeof( fd_vm_trace_event_exe_t ) - fd_ulong_if( !multiword, 8UL, 0UL );
221 15 : if( FD_UNLIKELY( rem < event_footprint ) ) {
222 0 : FD_LOG_WARNING(( "truncated event (exe)" ));
223 0 : return FD_VM_ERR_IO;
224 0 : }
225 :
226 15 : fd_vm_trace_event_exe_t * event = (fd_vm_trace_event_exe_t *)ptr;
227 :
228 15 : ulong event_pc = event->pc;
229 :
230 : /* Pretty print the architectural state before the instruction */
231 :
232 15 : printf( "%5lu [%016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX, %016lX] %5lu: ",
233 15 : event->ic,
234 15 : event->reg[ 0], event->reg[ 1], event->reg[ 2], event->reg[ 3],
235 15 : event->reg[ 4], event->reg[ 5], event->reg[ 6], event->reg[ 7],
236 15 : event->reg[ 8], event->reg[ 9], event->reg[10], event_pc );
237 :
238 : /* Print the instruction */
239 :
240 15 : ulong out_len = 0UL;
241 15 : char out[128];
242 15 : out[0] = '\0';
243 15 : int err = fd_vm_disasm_instr( event->text, fd_ulong_if( !multiword, 1UL, 2UL ), event_pc, syscalls, out, 128UL, &out_len );
244 15 : if( FD_UNLIKELY( err ) ) printf( "disasm failed (%i-%s)", err, fd_vm_strerror( err ) );
245 15 : else printf( "%s", out );
246 :
247 : /* Print CUs */
248 15 : printf( " %lu\n", event->cu );
249 15 : fflush( stdout );
250 15 : break;
251 15 : }
252 :
253 12 : case FD_VM_TRACE_EVENT_TYPE_READ:
254 12 : case FD_VM_TRACE_EVENT_TYPE_WRITE: {
255 :
256 12 : event_footprint = sizeof(fd_vm_trace_event_mem_t);
257 12 : if( FD_UNLIKELY( rem < event_footprint ) ) {
258 0 : FD_LOG_WARNING(( "truncated event (mem)" ));
259 0 : return FD_VM_ERR_IO;
260 0 : }
261 :
262 12 : fd_vm_trace_event_mem_t * event = (fd_vm_trace_event_mem_t *)ptr;
263 :
264 12 : int valid = fd_vm_trace_event_info_valid( info );
265 12 : ulong event_sz = event->sz;
266 12 : ulong data_sz = fd_ulong_if( valid, fd_ulong_min( event_sz, data_max ), 0UL );
267 :
268 12 : event_footprint = fd_ulong_align_up( event_footprint + data_sz, 8UL );
269 12 : if( FD_UNLIKELY( rem < event_footprint ) ) {
270 0 : FD_LOG_WARNING(( "truncated event (data)" ));
271 0 : return FD_VM_ERR_IO;
272 0 : }
273 :
274 12 : uchar * data = (uchar *)(event+1);
275 :
276 12 : ulong prev_ic = 0UL; /* FIXME: there was some commented out code originally to find the ic that previously modified */
277 :
278 12 : printf( " %s: vm_addr: 0x%016lX, sz: %8lu, prev_ic: %8lu, data: ",
279 12 : event_type==FD_VM_TRACE_EVENT_TYPE_READ ? "R" : "W", event->vaddr, event_sz, prev_ic );
280 :
281 12 : char buf[ 1024UL + 6UL*2048UL ]; /* 1KiB for overhead + 6 bytes for every byte of event_data_max */
282 :
283 12 : char * p = fd_cstr_init( buf );
284 12 : if( !valid ) p = fd_cstr_append_char( p, '-' );
285 12 : else {
286 492 : for( ulong data_off=0UL; data_off<data_sz; data_off++ ) {
287 480 : if( FD_UNLIKELY( (data_off & 0xfUL)==0UL ) ) p = fd_cstr_append_printf( p, "\n 0x%04lX:", data_off );
288 480 : if( FD_UNLIKELY( (data_off & 0xfUL)==8UL ) ) p = fd_cstr_append_char( p, ' ' );
289 480 : p = fd_cstr_append_printf( p, " %02X", (uint)data[ data_off ] );
290 480 : }
291 12 : if( FD_UNLIKELY( data_sz < event_sz ) )
292 0 : p = fd_cstr_append_printf( p, "\n ... omitted %lu bytes ...", event_sz - data_sz );
293 12 : }
294 12 : p = fd_cstr_append_char( p, '\n' );
295 12 : fd_cstr_fini( p );
296 :
297 12 : printf( "%s", buf );
298 12 : break;
299 12 : }
300 :
301 0 : default: {
302 0 : FD_LOG_WARNING(( "unexpected event type" ));
303 0 : return FD_VM_ERR_IO;
304 12 : }
305 :
306 27 : }
307 :
308 27 : ptr += event_footprint;
309 27 : rem -= event_footprint;
310 27 : }
311 :
312 3 : return FD_VM_SUCCESS;
313 3 : }
|