Merge pull request #820 from brendanzagaeski/master
[mono.git] / tools / sgen / sgen-grep-binprot.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <glib.h>
5
6 #define SGEN_BINARY_PROTOCOL
7 #define MONO_INTERNAL
8
9 #include <mono/metadata/sgen-protocol.h>
10
11 #define SGEN_PROTOCOL_EOF       255
12
13 #define TYPE(t)         ((t) & 0x7f)
14 #define WORKER(t)       ((t) & 0x80)
15
16 static int
17 read_entry (FILE *in, void **data)
18 {
19         unsigned char type;
20         int size;
21
22         if (fread (&type, 1, 1, in) != 1)
23                 return SGEN_PROTOCOL_EOF;
24         switch (TYPE (type)) {
25         case SGEN_PROTOCOL_COLLECTION_FORCE: size = sizeof (SGenProtocolCollectionForce); break;
26         case SGEN_PROTOCOL_COLLECTION_BEGIN: size = sizeof (SGenProtocolCollection); break;
27         case SGEN_PROTOCOL_COLLECTION_END: size = sizeof (SGenProtocolCollection); break;
28         case SGEN_PROTOCOL_ALLOC: size = sizeof (SGenProtocolAlloc); break;
29         case SGEN_PROTOCOL_ALLOC_PINNED: size = sizeof (SGenProtocolAlloc); break;
30         case SGEN_PROTOCOL_ALLOC_DEGRADED: size = sizeof (SGenProtocolAlloc); break;
31         case SGEN_PROTOCOL_COPY: size = sizeof (SGenProtocolCopy); break;
32         case SGEN_PROTOCOL_PIN: size = sizeof (SGenProtocolPin); break;
33         case SGEN_PROTOCOL_MARK: size = sizeof (SGenProtocolMark); break;
34         case SGEN_PROTOCOL_SCAN_BEGIN: size = sizeof (SGenProtocolScanBegin); break;
35         case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: size = sizeof (SGenProtocolScanVTypeBegin); break;
36         case SGEN_PROTOCOL_WBARRIER: size = sizeof (SGenProtocolWBarrier); break;
37         case SGEN_PROTOCOL_GLOBAL_REMSET: size = sizeof (SGenProtocolGlobalRemset); break;
38         case SGEN_PROTOCOL_PTR_UPDATE: size = sizeof (SGenProtocolPtrUpdate); break;
39         case SGEN_PROTOCOL_CLEANUP: size = sizeof (SGenProtocolCleanup); break;
40         case SGEN_PROTOCOL_EMPTY: size = sizeof (SGenProtocolEmpty); break;
41         case SGEN_PROTOCOL_THREAD_SUSPEND: size = sizeof (SGenProtocolThreadSuspend); break;
42         case SGEN_PROTOCOL_THREAD_RESTART: size = sizeof (SGenProtocolThreadRestart); break;
43         case SGEN_PROTOCOL_THREAD_REGISTER: size = sizeof (SGenProtocolThreadRegister); break;
44         case SGEN_PROTOCOL_THREAD_UNREGISTER: size = sizeof (SGenProtocolThreadUnregister); break;
45         case SGEN_PROTOCOL_MISSING_REMSET: size = sizeof (SGenProtocolMissingRemset); break;
46         case SGEN_PROTOCOL_CARD_SCAN: size = sizeof (SGenProtocolCardScan); break;
47         case SGEN_PROTOCOL_CEMENT: size = sizeof (SGenProtocolCement); break;
48         case SGEN_PROTOCOL_CEMENT_RESET: size = 0; break;
49         case SGEN_PROTOCOL_DISLINK_UPDATE: size = sizeof (SGenProtocolDislinkUpdate); break;
50         case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: size = sizeof (SGenProtocolDislinkUpdateStaged); break;
51         case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: size = sizeof (SGenProtocolDislinkProcessStaged); break;
52         case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: size = sizeof (SGenProtocolDomainUnload); break;
53         case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: size = sizeof (SGenProtocolDomainUnload); break;
54         default: assert (0);
55         }
56
57         if (size) {
58                 *data = malloc (size);
59                 if (fread (*data, size, 1, in) != 1)
60                         assert (0);
61         } else {
62                 *data = NULL;
63         }
64
65         return (int)type;
66 }
67
68 #define WORKER_PREFIX(t)        (WORKER ((t)) ? "w" : " ")
69
70 static void
71 print_entry (int type, void *data)
72 {
73         switch (TYPE (type)) {
74         case SGEN_PROTOCOL_COLLECTION_FORCE: {
75                 SGenProtocolCollectionForce *entry = data;
76                 printf ("%s collection force generation %d\n", WORKER_PREFIX (type), entry->generation);
77                 break;
78         }
79         case SGEN_PROTOCOL_COLLECTION_BEGIN: {
80                 SGenProtocolCollection *entry = data;
81                 printf ("%s collection begin %d generation %d\n", WORKER_PREFIX (type), entry->index, entry->generation);
82                 break;
83         }
84         case SGEN_PROTOCOL_COLLECTION_END: {
85                 SGenProtocolCollection *entry = data;
86                 printf ("%s collection end %d generation %d\n", WORKER_PREFIX (type), entry->index, entry->generation);
87                 break;
88         }
89         case SGEN_PROTOCOL_ALLOC: {
90                 SGenProtocolAlloc *entry = data;
91                 printf ("%s alloc obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
92                 break;
93         }
94         case SGEN_PROTOCOL_ALLOC_PINNED: {
95                 SGenProtocolAlloc *entry = data;
96                 printf ("%s alloc pinned obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
97                 break;
98         }
99         case SGEN_PROTOCOL_ALLOC_DEGRADED: {
100                 SGenProtocolAlloc *entry = data;
101                 printf ("%s alloc degraded obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
102                 break;
103         }
104         case SGEN_PROTOCOL_COPY: {
105                 SGenProtocolCopy *entry = data;
106                 printf ("%s copy from %p to %p vtable %p size %d\n", WORKER_PREFIX (type), entry->from, entry->to, entry->vtable, entry->size);
107                 break;
108         }
109         case SGEN_PROTOCOL_PIN: {
110                 SGenProtocolPin *entry = data;
111                 printf ("%s pin obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
112                 break;
113         }
114         case SGEN_PROTOCOL_MARK: {
115                 SGenProtocolMark *entry = data;
116                 printf ("%s mark obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
117                 break;
118         }
119         case SGEN_PROTOCOL_SCAN_BEGIN: {
120                 SGenProtocolScanBegin *entry = data;
121                 printf ("%s scan_begin obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
122                 break;
123         }
124         case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
125                 SGenProtocolScanVTypeBegin *entry = data;
126                 printf ("%s scan_vtype_begin obj %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->size);
127                 break;
128         }
129         case SGEN_PROTOCOL_WBARRIER: {
130                 SGenProtocolWBarrier *entry = data;
131                 printf ("%s wbarrier ptr %p value %p value_vtable %p\n", WORKER_PREFIX (type), entry->ptr, entry->value, entry->value_vtable);
132                 break;
133         }
134         case SGEN_PROTOCOL_GLOBAL_REMSET: {
135                 SGenProtocolGlobalRemset *entry = data;
136                 printf ("%s global_remset ptr %p value %p value_vtable %p\n", WORKER_PREFIX (type), entry->ptr, entry->value, entry->value_vtable);
137                 break;
138         }
139         case SGEN_PROTOCOL_PTR_UPDATE: {
140                 SGenProtocolPtrUpdate *entry = data;
141                 printf ("%s ptr_update ptr %p old_value %p new_value %p vtable %p size %d\n", WORKER_PREFIX (type),
142                                 entry->ptr, entry->old_value, entry->new_value, entry->vtable, entry->size);
143                 break;
144         }
145         case SGEN_PROTOCOL_CLEANUP: {
146                 SGenProtocolCleanup *entry = data;
147                 printf ("%s cleanup ptr %p vtable %p size %d\n", WORKER_PREFIX (type), entry->ptr, entry->vtable, entry->size);
148                 break;
149         }
150         case SGEN_PROTOCOL_EMPTY: {
151                 SGenProtocolEmpty *entry = data;
152                 printf ("%s empty start %p size %d\n", WORKER_PREFIX (type), entry->start, entry->size);
153                 break;
154         }
155         case SGEN_PROTOCOL_THREAD_SUSPEND: {
156                 SGenProtocolThreadSuspend *entry = data;
157                 printf ("%s thread_suspend thread %p ip %p\n", WORKER_PREFIX (type), entry->thread, entry->stopped_ip);
158                 break;
159         }
160         case SGEN_PROTOCOL_THREAD_RESTART: {
161                 SGenProtocolThreadRestart *entry = data;
162                 printf ("%s thread_restart thread %p\n", WORKER_PREFIX (type), entry->thread);
163                 break;
164         }
165         case SGEN_PROTOCOL_THREAD_REGISTER: {
166                 SGenProtocolThreadRegister *entry = data;
167                 printf ("%s thread_register thread %p\n", WORKER_PREFIX (type), entry->thread);
168                 break;
169         }
170         case SGEN_PROTOCOL_THREAD_UNREGISTER: {
171                 SGenProtocolThreadUnregister *entry = data;
172                 printf ("%s thread_unregister thread %p\n", WORKER_PREFIX (type), entry->thread);
173                 break;
174         }
175         case SGEN_PROTOCOL_MISSING_REMSET: {
176                 SGenProtocolMissingRemset *entry = data;
177                 printf ("%s missing_remset obj %p obj_vtable %p offset %d value %p value_vtable %p value_pinned %d\n", WORKER_PREFIX (type),
178                                 entry->obj, entry->obj_vtable, entry->offset, entry->value, entry->value_vtable, entry->value_pinned);
179                 break;
180         }
181         case SGEN_PROTOCOL_CARD_SCAN: {
182                 SGenProtocolCardScan *entry = data;
183                 printf ("%s card_scan start %p size %d\n", WORKER_PREFIX (type), entry->start, entry->size);
184                 break;
185         }
186         case SGEN_PROTOCOL_CEMENT: {
187                 SGenProtocolCement *entry = data;
188                 printf ("%s cement obj %p vtable %p size %d\n", WORKER_PREFIX (type), entry->obj, entry->vtable, entry->size);
189                 break;
190         }
191         case SGEN_PROTOCOL_CEMENT_RESET: {
192                 printf ("%s cement_reset\n", WORKER_PREFIX (type));
193                 break;
194         }
195         case SGEN_PROTOCOL_DISLINK_UPDATE: {
196                 SGenProtocolDislinkUpdate *entry = data;
197                 printf ("%s dislink_update link %p obj %p staged %d", WORKER_PREFIX (type), entry->link, entry->obj, entry->staged);
198                 if (entry->obj)
199                         printf (" track %d\n", entry->track);
200                 else
201                         printf ("\n");
202                 break;
203         }
204         case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
205                 SGenProtocolDislinkUpdateStaged *entry = data;
206                 printf ("%s dislink_update_staged link %p obj %p index %d", WORKER_PREFIX (type), entry->link, entry->obj, entry->index);
207                 if (entry->obj)
208                         printf (" track %d\n", entry->track);
209                 else
210                         printf ("\n");
211                 break;
212         }
213         case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
214                 SGenProtocolDislinkProcessStaged *entry = data;
215                 printf ("%s dislink_process_staged link %p obj %p index %d\n", WORKER_PREFIX (type), entry->link, entry->obj, entry->index);
216                 break;
217         }
218         case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN: {
219                 SGenProtocolDomainUnload *entry = data;
220                 printf ("%s dislink_unload_begin domain %p\n", WORKER_PREFIX (type), entry->domain);
221                 break;
222         }
223         case SGEN_PROTOCOL_DOMAIN_UNLOAD_END: {
224                 SGenProtocolDomainUnload *entry = data;
225                 printf ("%s dislink_unload_end domain %p\n", WORKER_PREFIX (type), entry->domain);
226                 break;
227         }
228         default:
229                 assert (0);
230         }
231 }
232
233 static gboolean
234 matches_interval (gpointer ptr, gpointer start, int size)
235 {
236         return ptr >= start && (char*)ptr < (char*)start + size;
237 }
238
239 static gboolean
240 is_match (gpointer ptr, int type, void *data)
241 {
242         switch (TYPE (type)) {
243         case SGEN_PROTOCOL_COLLECTION_FORCE:
244         case SGEN_PROTOCOL_COLLECTION_BEGIN:
245         case SGEN_PROTOCOL_COLLECTION_END:
246         case SGEN_PROTOCOL_THREAD_SUSPEND:
247         case SGEN_PROTOCOL_THREAD_RESTART:
248         case SGEN_PROTOCOL_THREAD_REGISTER:
249         case SGEN_PROTOCOL_THREAD_UNREGISTER:
250         case SGEN_PROTOCOL_CEMENT_RESET:
251         case SGEN_PROTOCOL_DOMAIN_UNLOAD_BEGIN:
252         case SGEN_PROTOCOL_DOMAIN_UNLOAD_END:
253                 return TRUE;
254         case SGEN_PROTOCOL_ALLOC:
255         case SGEN_PROTOCOL_ALLOC_PINNED:
256         case SGEN_PROTOCOL_ALLOC_DEGRADED: {
257                 SGenProtocolAlloc *entry = data;
258                 return matches_interval (ptr, entry->obj, entry->size);
259         }
260         case SGEN_PROTOCOL_COPY: {
261                 SGenProtocolCopy *entry = data;
262                 return matches_interval (ptr, entry->from, entry->size) || matches_interval (ptr, entry->to, entry->size);
263         }
264         case SGEN_PROTOCOL_PIN: {
265                 SGenProtocolPin *entry = data;
266                 return matches_interval (ptr, entry->obj, entry->size);
267         }
268         case SGEN_PROTOCOL_MARK: {
269                 SGenProtocolMark *entry = data;
270                 return matches_interval (ptr, entry->obj, entry->size);
271         }
272         case SGEN_PROTOCOL_SCAN_BEGIN: {
273                 SGenProtocolScanBegin *entry = data;
274                 return matches_interval (ptr, entry->obj, entry->size);
275         }
276         case SGEN_PROTOCOL_SCAN_VTYPE_BEGIN: {
277                 SGenProtocolScanVTypeBegin *entry = data;
278                 return matches_interval (ptr, entry->obj, entry->size);
279         }
280         case SGEN_PROTOCOL_WBARRIER: {
281                 SGenProtocolWBarrier *entry = data;
282                 return ptr == entry->ptr || ptr == entry->value;
283         }
284         case SGEN_PROTOCOL_GLOBAL_REMSET: {
285                 SGenProtocolGlobalRemset *entry = data;
286                 return ptr == entry->ptr || ptr == entry->value;
287         }
288         case SGEN_PROTOCOL_PTR_UPDATE: {
289                 SGenProtocolPtrUpdate *entry = data;
290                 return ptr == entry->ptr ||
291                         matches_interval (ptr, entry->old_value, entry->size) ||
292                         matches_interval (ptr, entry->new_value, entry->size);
293         }
294         case SGEN_PROTOCOL_CLEANUP: {
295                 SGenProtocolCleanup *entry = data;
296                 return matches_interval (ptr, entry->ptr, entry->size);
297         }
298         case SGEN_PROTOCOL_EMPTY: {
299                 SGenProtocolEmpty *entry = data;
300                 return matches_interval (ptr, entry->start, entry->size);
301         }
302         case SGEN_PROTOCOL_MISSING_REMSET: {
303                 SGenProtocolMissingRemset *entry = data;
304                 return ptr == entry->obj || ptr == entry->value || ptr == (char*)entry->obj + entry->offset;
305         }
306         case SGEN_PROTOCOL_CARD_SCAN: {
307                 SGenProtocolCardScan *entry = data;
308                 return matches_interval (ptr, entry->start, entry->size);
309         }
310         case SGEN_PROTOCOL_CEMENT: {
311                 SGenProtocolCement *entry = data;
312                 return matches_interval (ptr, entry->obj, entry->size);
313         }
314         case SGEN_PROTOCOL_DISLINK_UPDATE: {
315                 SGenProtocolDislinkUpdate *entry = data;
316                 return ptr == entry->obj || ptr == entry->link;
317         }
318         case SGEN_PROTOCOL_DISLINK_UPDATE_STAGED: {
319                 SGenProtocolDislinkUpdateStaged *entry = data;
320                 return ptr == entry->obj || ptr == entry->link;
321         }
322         case SGEN_PROTOCOL_DISLINK_PROCESS_STAGED: {
323                 SGenProtocolDislinkProcessStaged *entry = data;
324                 return ptr == entry->obj || ptr == entry->link;
325         }
326         default:
327                 assert (0);
328         }
329 }
330
331 static gboolean
332 is_vtable_match (gpointer ptr, int type, void *data)
333 {
334         switch (TYPE (type)) {
335         case SGEN_PROTOCOL_ALLOC:
336         case SGEN_PROTOCOL_ALLOC_PINNED:
337         case SGEN_PROTOCOL_ALLOC_DEGRADED: {
338                 SGenProtocolAlloc *entry = data;
339                 return ptr == entry->vtable;
340         }
341         case SGEN_PROTOCOL_COPY: {
342                 SGenProtocolCopy *entry = data;
343                 return ptr == entry->vtable;
344         }
345         case SGEN_PROTOCOL_PIN: {
346                 SGenProtocolPin *entry = data;
347                 return ptr == entry->vtable;
348         }
349         case SGEN_PROTOCOL_SCAN_BEGIN: {
350                 SGenProtocolScanBegin *entry = data;
351                 return ptr == entry->vtable;
352         }
353         case SGEN_PROTOCOL_WBARRIER: {
354                 SGenProtocolWBarrier *entry = data;
355                 return ptr == entry->value_vtable;
356         }
357         case SGEN_PROTOCOL_GLOBAL_REMSET: {
358                 SGenProtocolGlobalRemset *entry = data;
359                 return ptr == entry->value_vtable;
360         }
361         case SGEN_PROTOCOL_PTR_UPDATE: {
362                 SGenProtocolPtrUpdate *entry = data;
363                 return ptr == entry->vtable;
364         }
365         case SGEN_PROTOCOL_CLEANUP: {
366                 SGenProtocolCleanup *entry = data;
367                 return ptr == entry->vtable;
368         }
369         case SGEN_PROTOCOL_MISSING_REMSET: {
370                 SGenProtocolMissingRemset *entry = data;
371                 return ptr == entry->obj_vtable || ptr == entry->value_vtable;
372         }
373         case SGEN_PROTOCOL_CEMENT: {
374                 SGenProtocolCement *entry = data;
375                 return ptr == entry->vtable;
376         }
377         default:
378                 return FALSE;
379         }
380 }
381
382 static gboolean dump_all = FALSE;
383
384 int
385 main (int argc, char *argv[])
386 {
387         int type;
388         void *data;
389         int num_args = argc - 1;
390         int num_nums = 0;
391         int num_vtables = 0;
392         int i;
393         long nums [num_args];
394         long vtables [num_args];
395
396         for (i = 0; i < num_args; ++i) {
397                 char *arg = argv [i + 1];
398                 char *next_arg = argv [i + 2];
399                 if (!strcmp (arg, "--all")) {
400                         dump_all = TRUE;
401                 } else if (!strcmp (arg, "-v") || !strcmp (arg, "--vtable")) {
402                         vtables [num_vtables++] = strtoul (next_arg, NULL, 16);
403                         ++i;
404                 } else {
405                         nums [num_nums++] = strtoul (arg, NULL, 16);
406                 }
407         }
408
409         while ((type = read_entry (stdin, &data)) != SGEN_PROTOCOL_EOF) {
410                 gboolean match = FALSE;
411                 for (i = 0; i < num_nums; ++i) {
412                         if (is_match ((gpointer) nums [i], type, data)) {
413                                 match = TRUE;
414                                 break;
415                         }
416                 }
417                 if (!match) {
418                         for (i = 0; i < num_vtables; ++i) {
419                                 if (is_vtable_match ((gpointer) vtables [i], type, data)) {
420                                         match = TRUE;
421                                         break;
422                                 }
423                         }
424                 }
425                 if (dump_all)
426                         printf (match ? "* " : "  ");
427                 if (match || dump_all)
428                         print_entry (type, data);
429                 free (data);
430         }
431
432         return 0;
433 }