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