[sgen] Clean exit if we can't read binprot file due to unsupported version
[mono.git] / tools / sgen / sgen-grep-binprot.c
1 /*
2  * sgen-grep-binprot.c: Platform specific binary protocol entries reader
3  *
4  * Copyright (C) 2016 Xamarin Inc
5  *
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <assert.h>
12 #include <glib.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <stdint.h>
16 #include <inttypes.h>
17 #include <config.h>
18 #include "sgen-entry-stream.h"
19 #include "sgen-grep-binprot.h"
20
21 #ifdef BINPROT_HAS_HEADER
22 #define PACKED_SUFFIX   p
23 #else
24 #define PROTOCOL_STRUCT_ATTR
25 #define PACKED_SUFFIX
26 #endif
27
28 #ifndef BINPROT_SIZEOF_VOID_P
29 #define BINPROT_SIZEOF_VOID_P SIZEOF_VOID_P
30 #define ARCH_SUFFIX
31 #endif
32
33 #if BINPROT_SIZEOF_VOID_P == 4
34 typedef int32_t mword;
35 #define MWORD_FORMAT_SPEC_D PRId32
36 #define MWORD_FORMAT_SPEC_P PRIx32
37 #ifndef ARCH_SUFFIX
38 #define ARCH_SUFFIX     32
39 #endif
40 #else
41 typedef int64_t mword;
42 #define MWORD_FORMAT_SPEC_D PRId64
43 #define MWORD_FORMAT_SPEC_P PRIx64
44 #ifndef ARCH_SUFFIX
45 #define ARCH_SUFFIX     64
46 #endif
47 #endif
48 #define TYPE_SIZE       mword
49 #define TYPE_POINTER    mword
50 #include <mono/sgen/sgen-protocol.h>
51
52 #define SGEN_PROTOCOL_EOF       255
53
54 #define TYPE(t)         ((t) & 0x7f)
55 #define WORKER(t)       ((t) & 0x80)
56
57 #define MAX_ENTRY_SIZE (1 << 10)
58
59 static int
60 read_entry (EntryStream *stream, void *data)
61 {
62         unsigned char type;
63         ssize_t size;
64
65         if (read_stream (stream, &type, 1) <= 0)
66                 return SGEN_PROTOCOL_EOF;
67         switch (TYPE (type)) {
68
69 #define BEGIN_PROTOCOL_ENTRY0(method) \
70         case PROTOCOL_ID(method): size = 0; break;
71 #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \
72         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
73 #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \
74         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
75 #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \
76         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
77 #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
78         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
79 #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
80         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
81 #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
82         case PROTOCOL_ID(method): size = sizeof (PROTOCOL_STRUCT(method)); break;
83
84 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
85         BEGIN_PROTOCOL_ENTRY0 (method)
86 #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \
87         BEGIN_PROTOCOL_ENTRY1 (method,t1,f1)
88 #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \
89         BEGIN_PROTOCOL_ENTRY2 (method,t1,f1,t2,f2)
90 #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \
91         BEGIN_PROTOCOL_ENTRY3 (method,t1,f1,t2,f2,t3,f3)
92 #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
93         BEGIN_PROTOCOL_ENTRY4 (method,t1,f1,t2,f2,t3,f3,t4,f4)
94 #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
95         BEGIN_PROTOCOL_ENTRY5 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5)
96 #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
97         BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6)
98
99 #define DEFAULT_PRINT()
100 #define CUSTOM_PRINT(_)
101
102 #define IS_ALWAYS_MATCH(_)
103 #define MATCH_INDEX(_)
104 #define IS_VTABLE_MATCH(_)
105
106 #define END_PROTOCOL_ENTRY
107 #define END_PROTOCOL_ENTRY_FLUSH
108 #define END_PROTOCOL_ENTRY_HEAVY
109
110 #include <mono/sgen/sgen-protocol-def.h>
111
112         default: assert (0);
113         }
114
115         if (size) {
116                 size_t size_read = read_stream (stream, data, size);
117                 g_assert (size_read == size);
118         }
119
120         return (int)type;
121 }
122
123 static gboolean
124 is_always_match (int type)
125 {
126         switch (TYPE (type)) {
127 #define BEGIN_PROTOCOL_ENTRY0(method) \
128         case PROTOCOL_ID(method):
129 #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \
130         case PROTOCOL_ID(method):
131 #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \
132         case PROTOCOL_ID(method):
133 #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \
134         case PROTOCOL_ID(method):
135 #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
136         case PROTOCOL_ID(method):
137 #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
138         case PROTOCOL_ID(method):
139 #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
140         case PROTOCOL_ID(method):
141
142 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
143         BEGIN_PROTOCOL_ENTRY0 (method)
144 #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \
145         BEGIN_PROTOCOL_ENTRY1 (method,t1,f1)
146 #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \
147         BEGIN_PROTOCOL_ENTRY2 (method,t1,f1,t2,f2)
148 #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \
149         BEGIN_PROTOCOL_ENTRY3 (method,t1,f1,t2,f2,t3,f3)
150 #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
151         BEGIN_PROTOCOL_ENTRY4 (method,t1,f1,t2,f2,t3,f3,t4,f4)
152 #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
153         BEGIN_PROTOCOL_ENTRY5 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5)
154 #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
155         BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6)
156
157 #define DEFAULT_PRINT()
158 #define CUSTOM_PRINT(_)
159
160 #define IS_ALWAYS_MATCH(is_always_match) \
161                 return is_always_match;
162 #define MATCH_INDEX(_)
163 #define IS_VTABLE_MATCH(_)
164
165 #define END_PROTOCOL_ENTRY
166 #define END_PROTOCOL_ENTRY_FLUSH
167 #define END_PROTOCOL_ENTRY_HEAVY
168
169 #include <mono/sgen/sgen-protocol-def.h>
170
171         default: assert (0);
172         }
173 }
174
175 #define WORKER_PREFIX(t)        (WORKER ((t)) ? "w" : " ")
176
177 enum { NO_COLOR = -1 };
178
179 typedef struct {
180         int type;
181         const char *name;
182         void *data;
183         /* The index of the ANSI color with which to highlight
184          * this entry, or NO_COLOR for no highlighting.
185          */
186         int color;
187 } PrintEntry;
188
189
190 #define TYPE_INT 0
191 #define TYPE_LONGLONG 1
192 #define TYPE_SIZE 2
193 #define TYPE_POINTER 3
194 #define TYPE_BOOL 4
195
196 static void
197 print_entry_content (int entries_size, PrintEntry *entries, gboolean color_output)
198 {
199         int i;
200         for (i = 0; i < entries_size; ++i) {
201                 printf ("%s%s ", i == 0 ? "" : " ", entries [i].name);
202                 if (color_output && entries [i].color != NO_COLOR)
203                         /* Set foreground color, excluding black & white. */
204                         printf ("\x1B[%dm", 31 + (entries [i].color % 6));
205                 switch (entries [i].type) {
206                 case TYPE_INT:
207                         printf ("%d", *(int*) entries [i].data);
208                         break;
209                 case TYPE_LONGLONG:
210                         printf ("%lld", *(long long*) entries [i].data);
211                         break;
212                 case TYPE_SIZE:
213                         printf ("%"MWORD_FORMAT_SPEC_D, *(mword*) entries [i].data);
214                         break;
215                 case TYPE_POINTER:
216                         printf ("0x%"MWORD_FORMAT_SPEC_P, *(mword*) entries [i].data);
217                         break;
218                 case TYPE_BOOL:
219                         printf ("%s", *(gboolean*) entries [i].data ? "true" : "false");
220                         break;
221                 default:
222                         assert (0);
223                 }
224                 if (color_output && entries [i].color != NO_COLOR)
225                         /* Reset foreground color to default. */
226                         printf ("\x1B[0m");
227         }
228 }
229
230 static int
231 index_color (int index, int num_nums, int *match_indices)
232 {
233         int result;
234         for (result = 0; result < num_nums + 1; ++result)
235                 if (index == match_indices [result])
236                         return result;
237         return NO_COLOR;
238 }
239
240 static void
241 print_entry (int type, void *data, int num_nums, int *match_indices, gboolean color_output)
242 {
243         const char *always_prefix = is_always_match (type) ? "  " : "";
244         printf ("%s%s ", WORKER_PREFIX (type), always_prefix);
245
246         switch (TYPE (type)) {
247
248 #define BEGIN_PROTOCOL_ENTRY0(method) \
249         case PROTOCOL_ID(method): { \
250                 const int pes_size G_GNUC_UNUSED = 0; \
251                 PrintEntry pes [1] G_GNUC_UNUSED; \
252                 printf ("%s", #method + strlen ("binary_protocol_"));
253 #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \
254         case PROTOCOL_ID(method): { \
255                 PROTOCOL_STRUCT (method) *entry = data; \
256                 const int pes_size G_GNUC_UNUSED = 1; \
257                 PrintEntry pes [1] G_GNUC_UNUSED; \
258                 pes [0].type = t1; \
259                 pes [0].name = #f1; \
260                 pes [0].data = &entry->f1; \
261                 pes [0].color = index_color(0, num_nums, match_indices); \
262                 printf ("%s ", #method + strlen ("binary_protocol_"));
263 #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \
264         case PROTOCOL_ID(method): { \
265                 PROTOCOL_STRUCT (method) *entry = data; \
266                 const int pes_size G_GNUC_UNUSED = 2; \
267                 PrintEntry pes [2] G_GNUC_UNUSED; \
268                 pes [0].type = t1; \
269                 pes [0].name = #f1; \
270                 pes [0].data = &entry->f1; \
271                 pes [0].color = index_color(0, num_nums, match_indices); \
272                 pes [1].type = t2; \
273                 pes [1].name = #f2; \
274                 pes [1].data = &entry->f2; \
275                 pes [1].color = index_color(1, num_nums, match_indices); \
276                 printf ("%s ", #method + strlen ("binary_protocol_"));
277 #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \
278         case PROTOCOL_ID(method): { \
279                 PROTOCOL_STRUCT (method) *entry = data; \
280                 const int pes_size G_GNUC_UNUSED = 3; \
281                 PrintEntry pes [3] G_GNUC_UNUSED; \
282                 pes [0].type = t1; \
283                 pes [0].name = #f1; \
284                 pes [0].data = &entry->f1; \
285                 pes [0].color = index_color(0, num_nums, match_indices); \
286                 pes [1].type = t2; \
287                 pes [1].name = #f2; \
288                 pes [1].data = &entry->f2; \
289                 pes [1].color = index_color(1, num_nums, match_indices); \
290                 pes [2].type = t3; \
291                 pes [2].name = #f3; \
292                 pes [2].data = &entry->f3; \
293                 pes [2].color = index_color(2, num_nums, match_indices); \
294                 printf ("%s ", #method + strlen ("binary_protocol_"));
295 #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
296         case PROTOCOL_ID(method): { \
297                 PROTOCOL_STRUCT (method) *entry = data; \
298                 const int pes_size G_GNUC_UNUSED = 4; \
299                 PrintEntry pes [4] G_GNUC_UNUSED; \
300                 pes [0].type = t1; \
301                 pes [0].name = #f1; \
302                 pes [0].data = &entry->f1; \
303                 pes [0].color = index_color(0, num_nums, match_indices); \
304                 pes [1].type = t2; \
305                 pes [1].name = #f2; \
306                 pes [1].data = &entry->f2; \
307                 pes [1].color = index_color(1, num_nums, match_indices); \
308                 pes [2].type = t3; \
309                 pes [2].name = #f3; \
310                 pes [2].data = &entry->f3; \
311                 pes [2].color = index_color(2, num_nums, match_indices); \
312                 pes [3].type = t4; \
313                 pes [3].name = #f4; \
314                 pes [3].data = &entry->f4; \
315                 pes [3].color = index_color(3, num_nums, match_indices); \
316                 printf ("%s ", #method + strlen ("binary_protocol_"));
317 #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
318         case PROTOCOL_ID(method): { \
319                 PROTOCOL_STRUCT (method) *entry = data; \
320                 const int pes_size G_GNUC_UNUSED = 5; \
321                 PrintEntry pes [5] G_GNUC_UNUSED; \
322                 pes [0].type = t1; \
323                 pes [0].name = #f1; \
324                 pes [0].data = &entry->f1; \
325                 pes [0].color = index_color(0, num_nums, match_indices); \
326                 pes [1].type = t2; \
327                 pes [1].name = #f2; \
328                 pes [1].data = &entry->f2; \
329                 pes [1].color = index_color(1, num_nums, match_indices); \
330                 pes [2].type = t3; \
331                 pes [2].name = #f3; \
332                 pes [2].data = &entry->f3; \
333                 pes [2].color = index_color(2, num_nums, match_indices); \
334                 pes [3].type = t4; \
335                 pes [3].name = #f4; \
336                 pes [3].data = &entry->f4; \
337                 pes [3].color = index_color(3, num_nums, match_indices); \
338                 pes [4].type = t5; \
339                 pes [4].name = #f5; \
340                 pes [4].data = &entry->f5; \
341                 pes [4].color = index_color(4, num_nums, match_indices); \
342                 printf ("%s ", #method + strlen ("binary_protocol_"));
343 #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
344         case PROTOCOL_ID(method): { \
345                 PROTOCOL_STRUCT (method) *entry = data; \
346                 const int pes_size G_GNUC_UNUSED = 6; \
347                 PrintEntry pes [6] G_GNUC_UNUSED; \
348                 pes [0].type = t1; \
349                 pes [0].name = #f1; \
350                 pes [0].data = &entry->f1; \
351                 pes [0].color = index_color(0, num_nums, match_indices); \
352                 pes [1].type = t2; \
353                 pes [1].name = #f2; \
354                 pes [1].data = &entry->f2; \
355                 pes [1].color = index_color(1, num_nums, match_indices); \
356                 pes [2].type = t3; \
357                 pes [2].name = #f3; \
358                 pes [2].data = &entry->f3; \
359                 pes [2].color = index_color(2, num_nums, match_indices); \
360                 pes [3].type = t4; \
361                 pes [3].name = #f4; \
362                 pes [3].data = &entry->f4; \
363                 pes [3].color = index_color(3, num_nums, match_indices); \
364                 pes [4].type = t5; \
365                 pes [4].name = #f5; \
366                 pes [4].data = &entry->f5; \
367                 pes [4].color = index_color(4, num_nums, match_indices); \
368                 pes [5].type = t6; \
369                 pes [5].name = #f6; \
370                 pes [5].data = &entry->f6; \
371                 pes [5].color = index_color(5, num_nums, match_indices); \
372                 printf ("%s ", #method + strlen ("binary_protocol_"));
373
374 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
375         BEGIN_PROTOCOL_ENTRY0 (method)
376 #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \
377         BEGIN_PROTOCOL_ENTRY1 (method,t1,f1)
378 #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \
379         BEGIN_PROTOCOL_ENTRY2 (method,t1,f1,t2,f2)
380 #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \
381         BEGIN_PROTOCOL_ENTRY3 (method,t1,f1,t2,f2,t3,f3)
382 #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
383         BEGIN_PROTOCOL_ENTRY4 (method,t1,f1,t2,f2,t3,f3,t4,f4)
384 #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
385         BEGIN_PROTOCOL_ENTRY5 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5)
386 #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
387         BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6)
388
389 #define DEFAULT_PRINT() \
390         print_entry_content (pes_size, pes, color_output);
391 #define CUSTOM_PRINT(print) \
392         print;
393
394 #define IS_ALWAYS_MATCH(_)
395 #define MATCH_INDEX(_)
396 #define IS_VTABLE_MATCH(_)
397
398 #define END_PROTOCOL_ENTRY \
399                 printf ("\n"); \
400                 break; \
401         }
402 #define END_PROTOCOL_ENTRY_FLUSH \
403         END_PROTOCOL_ENTRY
404 #define END_PROTOCOL_ENTRY_HEAVY \
405         END_PROTOCOL_ENTRY
406
407 #include <mono/sgen/sgen-protocol-def.h>
408
409         default: assert (0);
410         }
411 }
412
413 #undef TYPE_INT
414 #undef TYPE_LONGLONG
415 #undef TYPE_SIZE
416 #undef TYPE_POINTER
417
418 #define TYPE_INT int
419 #define TYPE_LONGLONG long long
420 #define TYPE_SIZE mword
421 #define TYPE_POINTER mword
422
423 static gboolean
424 matches_interval (mword ptr, mword start, int size)
425 {
426         return ptr >= start && ptr < start + size;
427 }
428
429 /* Returns the index of the field where a match was found,
430  * BINARY_PROTOCOL_NO_MATCH for no match, or
431  * BINARY_PROTOCOL_MATCH for a match with no index.
432  */
433 static int
434 match_index (mword ptr, int type, void *data)
435 {
436         switch (TYPE (type)) {
437
438 #define BEGIN_PROTOCOL_ENTRY0(method) \
439         case PROTOCOL_ID (method): {
440 #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \
441         case PROTOCOL_ID (method): { \
442                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
443 #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \
444         case PROTOCOL_ID (method): { \
445                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
446 #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \
447         case PROTOCOL_ID (method): { \
448                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
449 #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
450         case PROTOCOL_ID (method): { \
451                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
452 #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
453         case PROTOCOL_ID (method): { \
454                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
455 #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
456         case PROTOCOL_ID (method): { \
457                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
458
459 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
460         BEGIN_PROTOCOL_ENTRY0 (method)
461 #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \
462         BEGIN_PROTOCOL_ENTRY1 (method,t1,f1)
463 #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \
464         BEGIN_PROTOCOL_ENTRY2 (method,t1,f1,t2,f2)
465 #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \
466         BEGIN_PROTOCOL_ENTRY3 (method,t1,f1,t2,f2,t3,f3)
467 #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
468         BEGIN_PROTOCOL_ENTRY4 (method,t1,f1,t2,f2,t3,f3,t4,f4)
469 #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
470         BEGIN_PROTOCOL_ENTRY5 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5)
471 #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
472         BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6)
473
474 #define DEFAULT_PRINT()
475 #define CUSTOM_PRINT(_)
476
477 #define IS_ALWAYS_MATCH(_)
478 #define MATCH_INDEX(block) \
479                 return (block);
480 #define IS_VTABLE_MATCH(_)
481
482 #define END_PROTOCOL_ENTRY \
483                 break; \
484         }
485 #define END_PROTOCOL_ENTRY_FLUSH \
486         END_PROTOCOL_ENTRY
487 #define END_PROTOCOL_ENTRY_HEAVY \
488         END_PROTOCOL_ENTRY
489
490 #include <mono/sgen/sgen-protocol-def.h>
491
492         default: assert (0);
493         }
494 }
495
496 static gboolean
497 is_vtable_match (mword ptr, int type, void *data)
498 {
499         switch (TYPE (type)) {
500
501 #define BEGIN_PROTOCOL_ENTRY0(method) \
502         case PROTOCOL_ID (method): {
503 #define BEGIN_PROTOCOL_ENTRY1(method,t1,f1) \
504         case PROTOCOL_ID (method): { \
505                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
506 #define BEGIN_PROTOCOL_ENTRY2(method,t1,f1,t2,f2) \
507         case PROTOCOL_ID (method): { \
508                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
509 #define BEGIN_PROTOCOL_ENTRY3(method,t1,f1,t2,f2,t3,f3) \
510         case PROTOCOL_ID (method): { \
511                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
512 #define BEGIN_PROTOCOL_ENTRY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
513         case PROTOCOL_ID (method): { \
514                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
515 #define BEGIN_PROTOCOL_ENTRY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
516         case PROTOCOL_ID (method): { \
517                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
518 #define BEGIN_PROTOCOL_ENTRY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
519         case PROTOCOL_ID (method): { \
520                 PROTOCOL_STRUCT (method) *entry G_GNUC_UNUSED = data;
521
522 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
523         BEGIN_PROTOCOL_ENTRY0 (method)
524 #define BEGIN_PROTOCOL_ENTRY_HEAVY1(method,t1,f1) \
525         BEGIN_PROTOCOL_ENTRY1 (method,t1,f1)
526 #define BEGIN_PROTOCOL_ENTRY_HEAVY2(method,t1,f1,t2,f2) \
527         BEGIN_PROTOCOL_ENTRY2 (method,t1,f1,t2,f2)
528 #define BEGIN_PROTOCOL_ENTRY_HEAVY3(method,t1,f1,t2,f2,t3,f3) \
529         BEGIN_PROTOCOL_ENTRY3 (method,t1,f1,t2,f2,t3,f3)
530 #define BEGIN_PROTOCOL_ENTRY_HEAVY4(method,t1,f1,t2,f2,t3,f3,t4,f4) \
531         BEGIN_PROTOCOL_ENTRY4 (method,t1,f1,t2,f2,t3,f3,t4,f4)
532 #define BEGIN_PROTOCOL_ENTRY_HEAVY5(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5) \
533         BEGIN_PROTOCOL_ENTRY5 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5)
534 #define BEGIN_PROTOCOL_ENTRY_HEAVY6(method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6) \
535         BEGIN_PROTOCOL_ENTRY6 (method,t1,f1,t2,f2,t3,f3,t4,f4,t5,f5,t6,f6)
536
537 #define DEFAULT_PRINT()
538 #define CUSTOM_PRINT(_)
539
540 #define IS_ALWAYS_MATCH(_)
541 #define MATCH_INDEX(block) \
542                 return (block);
543 #define IS_VTABLE_MATCH(_)
544
545 #define END_PROTOCOL_ENTRY \
546                 break; \
547         }
548 #define END_PROTOCOL_ENTRY_FLUSH \
549         END_PROTOCOL_ENTRY
550 #define END_PROTOCOL_ENTRY_HEAVY \
551         END_PROTOCOL_ENTRY
552
553 #include <mono/sgen/sgen-protocol-def.h>
554
555         default: assert (0);
556         }
557 }
558
559 #undef TYPE_INT
560 #undef TYPE_LONGLONG
561 #undef TYPE_SIZE
562 #undef TYPE_POINTER
563
564 static gboolean
565 sgen_binary_protocol_read_header (EntryStream *stream)
566 {
567 #ifdef BINPROT_HAS_HEADER
568         char data [MAX_ENTRY_SIZE];
569         int type = read_entry (stream, data);
570         if (type == SGEN_PROTOCOL_EOF)
571                 return FALSE;
572         if (type == PROTOCOL_ID (binary_protocol_header)) {
573                 PROTOCOL_STRUCT (binary_protocol_header) * str = (PROTOCOL_STRUCT (binary_protocol_header) *) data;
574                 if (str->check == PROTOCOL_HEADER_CHECK && str->ptr_size == BINPROT_SIZEOF_VOID_P) {
575                         if (str->version > PROTOCOL_HEADER_VERSION) {
576                                 fprintf (stderr, "The file contains a newer version %d. We support up to %d. Please update.\n", str->version, PROTOCOL_HEADER_VERSION);
577                                 exit (1);
578                         }
579                         return TRUE;
580                 }
581         }
582         return FALSE;
583 #else
584         /*
585          * This implementation doesn't account for the presence of a header,
586          * reading all the entries with the default configuration of the host
587          * machine. It has to be used only after all other implementations
588          * fail to identify a header, for backward compatibility.
589          */
590         return TRUE;
591 #endif
592 }
593
594 #define CONC(A, B) CONC_(A, B)
595 #define CONC_(A, B) A##B
596 #define GREP_ENTRIES_FUNCTION_NAME CONC(sgen_binary_protocol_grep_entries, CONC(ARCH_SUFFIX,PACKED_SUFFIX))
597
598 gboolean
599 GREP_ENTRIES_FUNCTION_NAME (EntryStream *stream, int num_nums, long nums [], int num_vtables, long vtables [],
600                         gboolean dump_all, gboolean pause_times, gboolean color_output, unsigned long long first_entry_to_consider)
601 {
602         int type;
603         void *data = g_malloc0 (MAX_ENTRY_SIZE);
604         int i;
605         gboolean pause_times_stopped = FALSE;
606         gboolean pause_times_concurrent = FALSE;
607         gboolean pause_times_finish = FALSE;
608         long long pause_times_ts = 0;
609         unsigned long long entry_index;
610
611         if (!sgen_binary_protocol_read_header (stream))
612                 return FALSE;
613
614         entry_index = 0;
615         while ((type = read_entry (stream, data)) != SGEN_PROTOCOL_EOF) {
616                 if (entry_index < first_entry_to_consider)
617                         goto next_entry;
618                 if (pause_times) {
619                         switch (type) {
620                         case PROTOCOL_ID (binary_protocol_world_stopping): {
621                                 PROTOCOL_STRUCT (binary_protocol_world_stopping) *entry = data;
622                                 assert (!pause_times_stopped);
623                                 pause_times_concurrent = FALSE;
624                                 pause_times_finish = FALSE;
625                                 pause_times_ts = entry->timestamp;
626                                 pause_times_stopped = TRUE;
627                                 break;
628                         }
629                         case PROTOCOL_ID (binary_protocol_concurrent_finish):
630                                 pause_times_finish = TRUE;
631                         case PROTOCOL_ID (binary_protocol_concurrent_start):
632                         case PROTOCOL_ID (binary_protocol_concurrent_update):
633                                 pause_times_concurrent = TRUE;
634                                 break;
635                         case PROTOCOL_ID (binary_protocol_world_restarted): {
636                                 PROTOCOL_STRUCT (binary_protocol_world_restarted) *entry = data;
637                                 assert (pause_times_stopped);
638                                 printf ("pause-time %d %d %d %lld %lld\n",
639                                                 entry->generation,
640                                                 pause_times_concurrent,
641                                                 pause_times_finish,
642                                                 entry->timestamp - pause_times_ts,
643                                                 pause_times_ts);
644                                 pause_times_stopped = FALSE;
645                                 break;
646                         }
647                         }
648                 } else {
649                         int match_indices [num_nums + 1];
650                         gboolean match = is_always_match (type);
651                         match_indices [num_nums] = num_nums == 0 ? match_index (0, type, data) : BINARY_PROTOCOL_NO_MATCH;
652                         match = match_indices [num_nums] != BINARY_PROTOCOL_NO_MATCH;
653                         for (i = 0; i < num_nums; ++i) {
654                                 match_indices [i] = match_index ((mword) nums [i], type, data);
655                                 match = match || match_indices [i] != BINARY_PROTOCOL_NO_MATCH;
656                         }
657                         if (!match) {
658                                 for (i = 0; i < num_vtables; ++i) {
659                                         if (is_vtable_match ((mword) vtables [i], type, data)) {
660                                                 match = TRUE;
661                                                 break;
662                                         }
663                                 }
664                         }
665                         if (match || dump_all)
666                                 printf ("%12lld ", entry_index);
667                         if (dump_all)
668                                 printf (match ? "* " : "  ");
669                         if (match || dump_all)
670                                 print_entry (type, data, num_nums, match_indices, color_output);
671                 }
672         next_entry:
673                 ++entry_index;
674         }
675         g_free (data);
676         return TRUE;
677 }