2004-05-29 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / verify.c
1
2 #include <mono/metadata/object.h>
3 #include <mono/metadata/verify.h>
4 #include <mono/metadata/opcodes.h>
5 #include <mono/metadata/tabledefs.h>
6 #include <mono/metadata/reflection.h>
7 #include <mono/metadata/debug-helpers.h>
8 #include <mono/metadata/mono-endian.h>
9 #include <mono/metadata/metadata.h>
10 #include <mono/metadata/tokentype.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <ctype.h>
14
15 /*
16  * Pull the list of opcodes
17  */
18 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
19         a = i,
20
21 enum {
22 #include "mono/cil/opcode.def"
23         LAST = 0xff
24 };
25 #undef OPDEF
26
27 void
28 mono_free_verify_list (GSList *list)
29 {
30         MonoVerifyInfo* info;
31         GSList *tmp;
32
33         for (tmp = list; tmp; tmp = tmp->next) {
34                 info = tmp->data;
35                 g_free (info->message);
36                 g_free (info);
37         }
38         g_slist_free (list);
39 }
40
41 #define ADD_ERROR(list,msg)     \
42         do {    \
43                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
44                 vinfo->status = MONO_VERIFY_ERROR;      \
45                 vinfo->message = (msg); \
46                 (list) = g_slist_prepend ((list), vinfo);       \
47         } while (0)
48
49 #define ADD_WARN(list,code,msg) \
50         do {    \
51                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
52                 vinfo->status = (code); \
53                 vinfo->message = (msg); \
54                 (list) = g_slist_prepend ((list), vinfo);       \
55         } while (0)
56
57 static const char* const
58 valid_cultures[] = {
59         "ar-SA", "ar-IQ", "ar-EG", "ar-LY",
60         "ar-DZ", "ar-MA", "ar-TN", "ar-OM",
61         "ar-YE", "ar-SY", "ar-JO", "ar-LB",
62         "ar-KW", "ar-AE", "ar-BH", "ar-QA",
63         "bg-BG", "ca-ES", "zh-TW", "zh-CN",
64         "zh-HK", "zh-SG", "zh-MO", "cs-CZ",
65         "da-DK", "de-DE", "de-CH", "de-AT",
66         "de-LU", "de-LI", "el-GR", "en-US",
67         "en-GB", "en-AU", "en-CA", "en-NZ",
68         "en-IE", "en-ZA", "en-JM", "en-CB",
69         "en-BZ", "en-TT", "en-ZW", "en-PH",
70         "es-ES-Ts", "es-MX", "es-ES-Is", "es-GT",
71         "es-CR", "es-PA", "es-DO", "es-VE",
72         "es-CO", "es-PE", "es-AR", "es-EC",
73         "es-CL", "es-UY", "es-PY", "es-BO",
74         "es-SV", "es-HN", "es-NI", "es-PR",
75         "Fi-FI", "fr-FR", "fr-BE", "fr-CA",
76         "Fr-CH", "fr-LU", "fr-MC", "he-IL",
77         "hu-HU", "is-IS", "it-IT", "it-CH",
78         "Ja-JP", "ko-KR", "nl-NL", "nl-BE",
79         "nb-NO", "nn-NO", "pl-PL", "pt-BR",
80         "pt-PT", "ro-RO", "ru-RU", "hr-HR",
81         "Lt-sr-SP", "Cy-sr-SP", "sk-SK", "sq-AL",
82         "sv-SE", "sv-FI", "th-TH", "tr-TR",
83         "ur-PK", "id-ID", "uk-UA", "be-BY",
84         "sl-SI", "et-EE", "lv-LV", "lt-LT",
85         "fa-IR", "vi-VN", "hy-AM", "Lt-az-AZ",
86         "Cy-az-AZ",
87         "eu-ES", "mk-MK", "af-ZA",
88         "ka-GE", "fo-FO", "hi-IN", "ms-MY",
89         "ms-BN", "kk-KZ", "ky-KZ", "sw-KE",
90         "Lt-uz-UZ", "Cy-uz-UZ", "tt-TA", "pa-IN",
91         "gu-IN", "ta-IN", "te-IN", "kn-IN",
92         "mr-IN", "sa-IN", "mn-MN", "gl-ES",
93         "kok-IN", "syr-SY", "div-MV",
94         NULL
95 };
96
97 static int
98 is_valid_culture (const char *cname)
99 {
100         int i;
101         int found;
102                         
103         found = *cname == 0;
104         for (i = 0; !found && valid_cultures [i]; ++i) {
105                 if (g_strcasecmp (valid_cultures [i], cname))
106                         found = 1;
107         }
108         return found;
109 }
110
111 static int
112 is_valid_assembly_flags (guint32 flags) {
113         /* Metadata: 22.1.2 */
114         flags &= ~(0x8000 | 0x4000); /* ignore reserved bits 0x0030? */
115         return ((flags == 1) || (flags == 0));
116 }
117
118 static int
119 is_valid_blob (MonoImage *image, guint32 blob_index, int notnull)
120 {
121         guint32 size;
122         const char *p, *blob_end;
123         
124         if (blob_index >= image->heap_blob.size)
125                 return 0;
126         p = mono_metadata_blob_heap (image, blob_index);
127         size = mono_metadata_decode_blob_size (p, &blob_end);
128         if (blob_index + size + (blob_end-p) > image->heap_blob.size)
129                 return 0;
130         if (notnull && !size)
131                 return 0;
132         return 1;
133 }
134
135 static const char*
136 is_valid_string (MonoImage *image, guint32 str_index, int notnull)
137 {
138         const char *p, *blob_end, *res;
139         
140         if (str_index >= image->heap_strings.size)
141                 return NULL;
142         res = p = mono_metadata_string_heap (image, str_index);
143         blob_end = mono_metadata_string_heap (image, image->heap_strings.size - 1);
144         if (notnull && !*p)
145                 return 0;
146         /* 
147          * FIXME: should check it's a valid utf8 string, too.
148          */
149         while (p <= blob_end) {
150                 if (!*p)
151                         return res;
152                 ++p;
153         }
154         return *p? NULL: res;
155 }
156
157 static int
158 is_valid_cls_ident (const char *p)
159 {
160         /*
161          * FIXME: we need the full unicode glib support for this.
162          * Check: http://www.unicode.org/unicode/reports/tr15/Identifier.java
163          * We do the lame thing for now.
164          */
165         if (!isalpha (*p))
166                 return 0;
167         ++p;
168         while (*p) {
169                 if (!isalnum (*p) && *p != '_')
170                         return 0;
171                 ++p;
172         }
173         return 1;
174 }
175
176 static int
177 is_valid_filename (const char *p)
178 {
179         if (!*p)
180                 return 0;
181         return strpbrk (p, "\\//:")? 0: 1;
182 }
183
184 static GSList*
185 verify_assembly_table (MonoImage *image, GSList *list, int level)
186 {
187         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLY];
188         guint32 cols [MONO_ASSEMBLY_SIZE];
189         const char *p;
190
191         if (level & MONO_VERIFY_ERROR) {
192                 if (t->rows > 1)
193                         ADD_ERROR (list, g_strdup ("Assembly table may only have 0 or 1 rows"));
194                 mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
195                 
196                 switch (cols [MONO_ASSEMBLY_HASH_ALG]) {
197                 case ASSEMBLY_HASH_NONE:
198                 case ASSEMBLY_HASH_MD5:
199                 case ASSEMBLY_HASH_SHA1:
200                         break;
201                 default:
202                         ADD_ERROR (list, g_strdup_printf ("Hash algorithm 0x%x unknown", cols [MONO_ASSEMBLY_HASH_ALG]));
203                 }
204                 
205                 if (!is_valid_assembly_flags (cols [MONO_ASSEMBLY_FLAGS]))
206                         ADD_ERROR (list, g_strdup_printf ("Invalid flags in assembly: 0x%x", cols [MONO_ASSEMBLY_FLAGS]));
207                 
208                 if (!is_valid_blob (image, cols [MONO_ASSEMBLY_PUBLIC_KEY], FALSE))
209                         ADD_ERROR (list, g_strdup ("Assembly public key is an invalid index"));
210                 
211                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_NAME], TRUE))) {
212                         ADD_ERROR (list, g_strdup ("Assembly name is invalid"));
213                 } else {
214                         if (strpbrk (p, ":\\/."))
215                                 ADD_ERROR (list, g_strdup_printf ("Assembly name `%s' contains invalid chars", p));
216                 }
217
218                 if (!(p = is_valid_string (image, cols [MONO_ASSEMBLY_CULTURE], FALSE))) {
219                         ADD_ERROR (list, g_strdup ("Assembly culture is an invalid index"));
220                 } else {
221                         if (!is_valid_culture (p))
222                                 ADD_ERROR (list, g_strdup_printf ("Assembly culture `%s' is invalid", p));
223                 }
224         }
225         return list;
226 }
227
228 static GSList*
229 verify_assemblyref_table (MonoImage *image, GSList *list, int level)
230 {
231         MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
232         guint32 cols [MONO_ASSEMBLYREF_SIZE];
233         const char *p;
234         int i;
235
236         if (level & MONO_VERIFY_ERROR) {
237                 for (i = 0; i < t->rows; ++i) {
238                         mono_metadata_decode_row (t, i, cols, MONO_ASSEMBLYREF_SIZE);
239                         if (!is_valid_assembly_flags (cols [MONO_ASSEMBLYREF_FLAGS]))
240                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in assemblyref row %d: 0x%x", i + 1, cols [MONO_ASSEMBLY_FLAGS]));
241                 
242                         if (!is_valid_blob (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], FALSE))
243                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef public key in row %d is an invalid index", i + 1));
244                 
245                         if (!(p = is_valid_string (image, cols [MONO_ASSEMBLYREF_CULTURE], FALSE))) {
246                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture in row %d is invalid", i + 1));
247                         } else {
248                                 if (!is_valid_culture (p))
249                                         ADD_ERROR (list, g_strdup_printf ("AssemblyRef culture `%s' in row %d is invalid", p, i + 1));
250                         }
251
252                         if (cols [MONO_ASSEMBLYREF_HASH_VALUE] && !is_valid_blob (image, cols [MONO_ASSEMBLYREF_HASH_VALUE], TRUE))
253                                 ADD_ERROR (list, g_strdup_printf ("AssemblyRef hash value in row %d is invalid or not null and empty", i + 1));
254                 }
255         }
256         if (level & MONO_VERIFY_WARNING) {
257                 /* check for duplicated rows */
258                 for (i = 0; i < t->rows; ++i) {
259                 }
260         }
261         return list;
262 }
263
264 static GSList*
265 verify_class_layout_table (MonoImage *image, GSList *list, int level)
266 {
267         MonoTableInfo *t = &image->tables [MONO_TABLE_CLASSLAYOUT];
268         MonoTableInfo *tdef = &image->tables [MONO_TABLE_TYPEDEF];
269         guint32 cols [MONO_CLASS_LAYOUT_SIZE];
270         guint32 value, i;
271         
272         if (level & MONO_VERIFY_ERROR) {
273                 for (i = 0; i < t->rows; ++i) {
274                         mono_metadata_decode_row (t, i, cols, MONO_CLASS_LAYOUT_SIZE);
275
276                         if (cols [MONO_CLASS_LAYOUT_PARENT] > tdef->rows || !cols [MONO_CLASS_LAYOUT_PARENT]) {
277                                 ADD_ERROR (list, g_strdup_printf ("Parent in class layout is invalid in row %d", i + 1));
278                         } else {
279                                 value = mono_metadata_decode_row_col (tdef, cols [MONO_CLASS_LAYOUT_PARENT] - 1, MONO_TYPEDEF_FLAGS);
280                                 if (value & TYPE_ATTRIBUTE_INTERFACE)
281                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is an interface", i + 1));
282                                 if (value & TYPE_ATTRIBUTE_AUTO_LAYOUT)
283                                         ADD_ERROR (list, g_strdup_printf ("Parent in class layout row %d is AutoLayout", i + 1));
284                                 if (value & TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) {
285                                         switch (cols [MONO_CLASS_LAYOUT_PACKING_SIZE]) {
286                                         case 0: case 1: case 2: case 4: case 8: case 16:
287                                         case 32: case 64: case 128: break;
288                                         default:
289                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
290                                         }
291                                 } else if (value & TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
292                                         /*
293                                          * FIXME: LAMESPEC: it claims it must be 0 (it's 1, instead).
294                                         if (cols [MONO_CLASS_LAYOUT_PACKING_SIZE])
295                                                 ADD_ERROR (list, g_strdup_printf ("Packing size %d in class layout row %d is invalid with explicit layout", cols [MONO_CLASS_LAYOUT_PACKING_SIZE], i + 1));
296                                         */
297                                 }
298                                 /*
299                                  * FIXME: we need to check that if class size != 0, 
300                                  * it needs to be greater than the class calculated size.
301                                  * If parent is a valuetype it also needs to be smaller than
302                                  * 1 MByte (0x100000 bytes).
303                                  * To do both these checks we need to load the referenced 
304                                  * assemblies, though (the spec claims we didn't have to, bah).
305                                  */
306                                 /* 
307                                  * We need to check that the parent types have the samme layout 
308                                  * type as well.
309                                  */
310                         }
311                 }
312         }
313         
314         return list;
315 }
316
317 static GSList*
318 verify_constant_table (MonoImage *image, GSList *list, int level)
319 {
320         MonoTableInfo *t = &image->tables [MONO_TABLE_CONSTANT];
321         guint32 cols [MONO_CONSTANT_SIZE];
322         guint32 value, i;
323         GHashTable *dups = g_hash_table_new (NULL, NULL);
324         
325         for (i = 0; i < t->rows; ++i) {
326                 mono_metadata_decode_row (t, i, cols, MONO_CONSTANT_SIZE);
327
328                 if (level & MONO_VERIFY_ERROR)
329                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT])))
330                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Constant row %d", cols [MONO_CONSTANT_PARENT], i + 1));
331                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]),
332                                 GUINT_TO_POINTER (cols [MONO_CONSTANT_PARENT]));
333
334                 switch (cols [MONO_CONSTANT_TYPE]) {
335                 case MONO_TYPE_U1: /* LAMESPEC: it says I1...*/
336                 case MONO_TYPE_U2:
337                 case MONO_TYPE_U4:
338                 case MONO_TYPE_U8:
339                         if (level & MONO_VERIFY_CLS)
340                                 ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Type 0x%x not CLS compliant in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
341                 case MONO_TYPE_BOOLEAN:
342                 case MONO_TYPE_CHAR:
343                 case MONO_TYPE_I1:
344                 case MONO_TYPE_I2:
345                 case MONO_TYPE_I4:
346                 case MONO_TYPE_I8:
347                 case MONO_TYPE_R4:
348                 case MONO_TYPE_R8:
349                 case MONO_TYPE_STRING:
350                 case MONO_TYPE_CLASS:
351                         break;
352                 default:
353                         if (level & MONO_VERIFY_ERROR)
354                                 ADD_ERROR (list, g_strdup_printf ("Type 0x%x is invalid in Constant row %d", cols [MONO_CONSTANT_TYPE], i + 1));
355                 }
356                 if (level & MONO_VERIFY_ERROR) {
357                         value = cols [MONO_CONSTANT_PARENT] >> HASCONSTANT_BITS;
358                         switch (cols [MONO_CONSTANT_PARENT] & HASCONSTANT_MASK) {
359                         case HASCONSTANT_FIEDDEF:
360                                 if (value > image->tables [MONO_TABLE_FIELD].rows)
361                                         ADD_ERROR (list, g_strdup_printf ("Parent (field) is invalid in Constant row %d", i + 1));
362                                 break;
363                         case HASCONSTANT_PARAM:
364                                 if (value > image->tables [MONO_TABLE_PARAM].rows)
365                                         ADD_ERROR (list, g_strdup_printf ("Parent (param) is invalid in Constant row %d", i + 1));
366                                 break;
367                         case HASCONSTANT_PROPERTY:
368                                 if (value > image->tables [MONO_TABLE_PROPERTY].rows)
369                                         ADD_ERROR (list, g_strdup_printf ("Parent (property) is invalid in Constant row %d", i + 1));
370                                 break;
371                         default:
372                                 ADD_ERROR (list, g_strdup_printf ("Parent is invalid in Constant row %d", i + 1));
373                                 break;
374                         }
375                 }
376                 if (level & MONO_VERIFY_CLS) {
377                         /* 
378                          * FIXME: verify types is consistent with the enum type
379                          * is parent is an enum.
380                          */
381                 }
382         }
383         g_hash_table_destroy (dups);
384         return list;
385 }
386
387 static GSList*
388 verify_event_map_table (MonoImage *image, GSList *list, int level)
389 {
390         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENTMAP];
391         guint32 cols [MONO_EVENT_MAP_SIZE];
392         guint32 i, last_event;
393         GHashTable *dups = g_hash_table_new (NULL, NULL);
394
395         last_event = 0;
396
397         for (i = 0; i < t->rows; ++i) {
398                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_MAP_SIZE);
399                 if (level & MONO_VERIFY_ERROR)
400                         if (g_hash_table_lookup (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT])))
401                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is duplicated in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
402                 g_hash_table_insert (dups, GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]),
403                                 GUINT_TO_POINTER (cols [MONO_EVENT_MAP_PARENT]));
404                 if (level & MONO_VERIFY_ERROR) {
405                         if (cols [MONO_EVENT_MAP_PARENT] > image->tables [MONO_TABLE_TYPEDEF].rows)
406                                 ADD_ERROR (list, g_strdup_printf ("Parent 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_PARENT], i + 1));
407                         if (cols [MONO_EVENT_MAP_EVENTLIST] > image->tables [MONO_TABLE_EVENT].rows)
408                                 ADD_ERROR (list, g_strdup_printf ("EventList 0x%08x is invalid in Event Map row %d", cols [MONO_EVENT_MAP_EVENTLIST], i + 1));
409
410                         if (cols [MONO_EVENT_MAP_EVENTLIST] <= last_event)
411                                 ADD_ERROR (list, g_strdup_printf ("EventList overlap in Event Map row %d", i + 1));
412                         last_event = cols [MONO_EVENT_MAP_EVENTLIST];
413                 }
414         }
415
416         g_hash_table_destroy (dups);
417         return list;
418 }
419
420 static GSList*
421 verify_event_table (MonoImage *image, GSList *list, int level)
422 {
423         MonoTableInfo *t = &image->tables [MONO_TABLE_EVENT];
424         guint32 cols [MONO_EVENT_SIZE];
425         const char *p;
426         guint32 value, i;
427         
428         for (i = 0; i < t->rows; ++i) {
429                 mono_metadata_decode_row (t, i, cols, MONO_EVENT_SIZE);
430
431                 if (cols [MONO_EVENT_FLAGS] & ~(EVENT_SPECIALNAME|EVENT_RTSPECIALNAME)) {
432                         if (level & MONO_VERIFY_ERROR)
433                                 ADD_ERROR (list, g_strdup_printf ("Flags 0x%04x invalid in Event row %d", cols [MONO_EVENT_FLAGS], i + 1));
434                 }
435                 if (!(p = is_valid_string (image, cols [MONO_EVENT_NAME], TRUE))) {
436                         if (level & MONO_VERIFY_ERROR)
437                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Event row %d", i + 1));
438                 } else {
439                         if (level & MONO_VERIFY_CLS) {
440                                 if (!is_valid_cls_ident (p))
441                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Event row %d", p, i + 1));
442                         }
443                 }
444                 
445                 if (level & MONO_VERIFY_ERROR && cols [MONO_EVENT_TYPE]) {
446                         value = cols [MONO_EVENT_TYPE] >> TYPEDEFORREF_BITS;
447                         switch (cols [MONO_EVENT_TYPE] & TYPEDEFORREF_MASK) {
448                         case TYPEDEFORREF_TYPEDEF:
449                                 if (!value || value > image->tables [MONO_TABLE_TYPEDEF].rows)
450                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
451                                 break;
452                         case TYPEDEFORREF_TYPEREF:
453                                 if (!value || value > image->tables [MONO_TABLE_TYPEREF].rows)
454                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
455                                 break;
456                         case TYPEDEFORREF_TYPESPEC:
457                                 if (!value || value > image->tables [MONO_TABLE_TYPESPEC].rows)
458                                         ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
459                                 break;
460                         default:
461                                 ADD_ERROR (list, g_strdup_printf ("Type invalid in Event row %d", i + 1));
462                         }
463                 }
464                 /*
465                  * FIXME: check that there is 1 add and remove row in methodsemantics
466                  * and 0 or 1 raise and 0 or more other (maybe it's better to check for 
467                  * these while checking methodsemantics).
468                  * check for duplicated names for the same type [ERROR]
469                  * check for CLS duplicate names for the same type [CLS]
470                  */
471         }
472         return list;
473 }
474
475 static GSList*
476 verify_field_table (MonoImage *image, GSList *list, int level)
477 {
478         MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
479         guint32 cols [MONO_FIELD_SIZE];
480         const char *p;
481         guint32 i, flags;
482         
483         for (i = 0; i < t->rows; ++i) {
484                 mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
485                 /*
486                  * Check this field has only one owner and that the owner is not 
487                  * an interface (done in verify_typedef_table() )
488                  */
489                 flags = cols [MONO_FIELD_FLAGS];
490                 switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
491                 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
492                 case FIELD_ATTRIBUTE_PRIVATE:
493                 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
494                 case FIELD_ATTRIBUTE_ASSEMBLY:
495                 case FIELD_ATTRIBUTE_FAMILY:
496                 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
497                 case FIELD_ATTRIBUTE_PUBLIC:
498                         break;
499                 default:
500                         if (level & MONO_VERIFY_ERROR)
501                                 ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
502                         break;
503                 }
504                 if (level & MONO_VERIFY_ERROR) {
505                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
506                                 ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
507                         if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
508                                 ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
509                         if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
510                                 ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
511                         /*
512                          * FIXME: check there is only ono owner in the respective table.
513                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
514                          * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
515                          * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
516                          */
517                 }
518                 if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
519                         if (level & MONO_VERIFY_ERROR)
520                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
521                 } else {
522                         if (level & MONO_VERIFY_CLS) {
523                                 if (!is_valid_cls_ident (p))
524                                         ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
525                         }
526                 }
527                 /*
528                  * check signature.
529                  * if owner is module needs to be static, access mask needs to be compilercontrolled,
530                  * public or private (not allowed in cls mode).
531                  * if owner is an enum ...
532                  */
533                 
534                 
535         }
536         return list;
537 }
538
539 static GSList*
540 verify_file_table (MonoImage *image, GSList *list, int level)
541 {
542         MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
543         guint32 cols [MONO_FILE_SIZE];
544         const char *p;
545         guint32 i;
546         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
547         
548         for (i = 0; i < t->rows; ++i) {
549                 mono_metadata_decode_row (t, i, cols, MONO_FILE_SIZE);
550                 if (level & MONO_VERIFY_ERROR) {
551                         if (cols [MONO_FILE_FLAGS] != FILE_CONTAINS_METADATA && cols [MONO_FILE_FLAGS] != FILE_CONTAINS_NO_METADATA)
552                                 ADD_ERROR (list, g_strdup_printf ("Invalid flags in File row %d", i + 1));
553                         if (!is_valid_blob (image, cols [MONO_FILE_HASH_VALUE], TRUE))
554                                 ADD_ERROR (list, g_strdup_printf ("File hash value in row %d is invalid or not null and empty", i + 1));
555                 }
556                 if (!(p = is_valid_string (image, cols [MONO_FILE_NAME], TRUE))) {
557                         if (level & MONO_VERIFY_ERROR)
558                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in File row %d", i + 1));
559                 } else {
560                         if (level & MONO_VERIFY_ERROR) {
561                                 if (!is_valid_filename (p))
562                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in File row %d", p, i + 1));
563                                 else if (g_hash_table_lookup (dups, p)) {
564                                         ADD_ERROR (list, g_strdup_printf ("Duplicate name '%s` in File row %d", p, i + 1));
565                                 }
566                                 g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
567                         }
568                 }
569                 /*
570                  * FIXME: I don't understand what this means:
571                  * If this module contains a row in the Assembly table (that is, if this module "holds the manifest") 
572                  * then there shall not be any row in the File table for this module - i.e., no self-reference  [ERROR]
573                  */
574
575         }
576         if (level & MONO_VERIFY_WARNING) {
577                 if (!t->rows && image->tables [MONO_TABLE_EXPORTEDTYPE].rows)
578                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup ("ExportedType table should be empty if File table is empty"));
579         }
580         g_hash_table_destroy (dups);
581         return list;
582 }
583
584 static GSList*
585 verify_moduleref_table (MonoImage *image, GSList *list, int level)
586 {
587         MonoTableInfo *t = &image->tables [MONO_TABLE_MODULEREF];
588         MonoTableInfo *tfile = &image->tables [MONO_TABLE_FILE];
589         guint32 cols [MONO_MODULEREF_SIZE];
590         const char *p, *pf;
591         guint32 found, i, j, value;
592         GHashTable *dups = g_hash_table_new (g_str_hash, g_str_equal);
593         
594         for (i = 0; i < t->rows; ++i) {
595                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
596                 if (!(p = is_valid_string (image, cols [MONO_MODULEREF_NAME], TRUE))) {
597                         if (level & MONO_VERIFY_ERROR)
598                                 ADD_ERROR (list, g_strdup_printf ("Invalid name in ModuleRef row %d", i + 1));
599                 } else {
600                         if (level & MONO_VERIFY_ERROR) {
601                                 if (!is_valid_filename (p))
602                                         ADD_ERROR (list, g_strdup_printf ("Invalid name '%s` in ModuleRef row %d", p, i + 1));
603                                 else if (g_hash_table_lookup (dups, p)) {
604                                         ADD_WARN (list, MONO_VERIFY_WARNING, g_strdup_printf ("Duplicate name '%s` in ModuleRef row %d", p, i + 1));
605                                         g_hash_table_insert (dups, (gpointer)p, (gpointer)p);
606                                         found = 0;
607                                         for (j = 0; j < tfile->rows; ++j) {
608                                                 value = mono_metadata_decode_row_col (tfile, j, MONO_FILE_NAME);
609                                                 if ((pf = is_valid_string (image, value, TRUE)))
610                                                         if (strcmp (p, pf) == 0) {
611                                                                 found = 1;
612                                                                 break;
613                                                         }
614                                         }
615                                         if (!found)
616                                                 ADD_ERROR (list, g_strdup_printf ("Name '%s` in ModuleRef row %d doesn't have a match in File table", p, i + 1));
617                                 }
618                         }
619                 }
620         }
621         g_hash_table_destroy (dups);
622         return list;
623 }
624
625 static GSList*
626 verify_standalonesig_table (MonoImage *image, GSList *list, int level)
627 {
628         MonoTableInfo *t = &image->tables [MONO_TABLE_STANDALONESIG];
629         guint32 cols [MONO_STAND_ALONE_SIGNATURE_SIZE];
630         const char *p;
631         guint32 i;
632
633         for (i = 0; i < t->rows; ++i) {
634                 mono_metadata_decode_row (t, i, cols, MONO_STAND_ALONE_SIGNATURE_SIZE);
635                 if (level & MONO_VERIFY_ERROR) {
636                         if (!is_valid_blob (image, cols [MONO_STAND_ALONE_SIGNATURE], TRUE)) {
637                                 ADD_ERROR (list, g_strdup_printf ("Signature is invalid in StandAloneSig row %d", i + 1));
638                         } else {
639                                 p = mono_metadata_blob_heap (image, cols [MONO_STAND_ALONE_SIGNATURE]);
640                                 /* FIXME: check it's a valid locals or method sig.*/
641                         }
642                 }
643         }
644         return list;
645 }
646
647 GSList*
648 mono_image_verify_tables (MonoImage *image, int level)
649 {
650         GSList *error_list = NULL;
651
652         error_list = verify_assembly_table (image, error_list, level);
653         /* 
654          * AssemblyOS, AssemblyProcessor, AssemblyRefOs and
655          * AssemblyRefProcessor should be ignored, 
656          * though we may want to emit a warning, since it should not 
657          * be present in a PE file.
658          */
659         error_list = verify_assemblyref_table (image, error_list, level);
660         error_list = verify_class_layout_table (image, error_list, level);
661         error_list = verify_constant_table (image, error_list, level);
662         /*
663          * cutom attribute, declsecurity 
664          */
665         error_list = verify_event_map_table (image, error_list, level);
666         error_list = verify_event_table (image, error_list, level);
667         error_list = verify_field_table (image, error_list, level);
668         error_list = verify_file_table (image, error_list, level);
669         error_list = verify_moduleref_table (image, error_list, level);
670         error_list = verify_standalonesig_table (image, error_list, level);
671
672         return g_slist_reverse (error_list);
673 }
674
675 enum {
676         TYPE_INV = 0, /* leave at 0. */
677         TYPE_I4  = 1,
678         TYPE_I8  = 2,
679         TYPE_PTR = 3,
680         TYPE_R8  = 4,
681         TYPE_MP  = 5,
682         TYPE_OBJ = 6,
683         TYPE_VT  = 7,
684         TYPE_MAX = 8
685 };
686
687 static const char* 
688 arg_name [TYPE_MAX] = {
689         "Invalid",
690         "Int32",
691         "Int64",
692         "IntPtr",
693         "Double",
694         "Managed Pointer",
695         "ObjRef",
696         "ValueType"
697 };
698
699 static const char
700 bin_num_table [TYPE_MAX] [TYPE_MAX] = {
701         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
702         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_INV},
703         {TYPE_INV, TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
704         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_INV},
705         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_R8,  TYPE_INV, TYPE_INV, TYPE_INV},
706         {TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_MP,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV},
707         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
708         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
709 };
710
711 static const char 
712 neg_table [] = {
713         TYPE_INV, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_INV, TYPE_INV, TYPE_INV
714 };
715
716 /* reduce the size of this table */
717 static const char
718 bin_int_table [TYPE_MAX] [TYPE_MAX] = {
719         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
720         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
721         {TYPE_INV, TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
722         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
723         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
724         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
725         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
726         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
727 };
728
729 static const char
730 bin_comp_table [TYPE_MAX] [TYPE_MAX] = {
731         {0},
732         {0, 1, 0, 1, 0, 0, 0, 0},
733         {0, 0, 1, 0, 0, 0, 0, 0},
734         {0, 1, 0, 1, 0, 2, 0, 0},
735         {0, 0, 0, 0, 1, 0, 0, 0},
736         {0, 0, 0, 2, 0, 1, 0, 0},
737         {0, 0, 0, 0, 0, 0, 3, 0},
738         {0, 0, 0, 0, 0, 0, 0, 0},
739 };
740
741 /* reduce the size of this table */
742 static const char
743 shift_table [TYPE_MAX] [TYPE_MAX] = {
744         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
745         {TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_I4,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
746         {TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_I8,  TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
747         {TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_PTR, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
748         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
749         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
750         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV},
751         {TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV, TYPE_INV}
752 };
753
754 static const char 
755 ldind_type [] = {
756         TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_OBJ
757 };
758
759 static const char
760 ldelem_type [] = {
761         TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I4, TYPE_I8, TYPE_PTR, TYPE_R8, TYPE_R8, TYPE_OBJ
762 };
763
764 #define ADD_INVALID(list,msg)   \
765         do {    \
766                 MonoVerifyInfo *vinfo = g_new (MonoVerifyInfo, 1);      \
767                 vinfo->status = MONO_VERIFY_ERROR;      \
768                 vinfo->message = (msg); \
769                 (list) = g_slist_prepend ((list), vinfo);       \
770                 /*G_BREAKPOINT ();*/    \
771                 goto invalid_cil;       \
772         } while (0)
773
774 #define CHECK_STACK_UNDERFLOW(num)      \
775         do {    \
776                 if (cur_stack < (num))  \
777                         ADD_INVALID (list, g_strdup_printf ("Stack underflow at 0x%04x (%d items instead of %d)", ip_offset, cur_stack, (num)));        \
778         } while (0)
779
780 #define CHECK_STACK_OVERFLOW()  \
781         do {    \
782                 if (cur_stack >= max_stack)     \
783                         ADD_INVALID (list, g_strdup_printf ("Maxstack exceeded at 0x%04x", ip_offset)); \
784         } while (0)
785
786 enum {
787         PREFIX_UNALIGNED = 1,
788         PREFIX_VOLATILE  = 2,
789         PREFIX_TAIL      = 4,
790         PREFIX_ADDR_MASK = 3,
791         PREFIX_FUNC_MASK = 4
792 };
793
794 enum {
795         CODE_SEEN = 1
796 };
797
798 typedef struct {
799         MonoType *type;
800         int stype;
801 } ILStackDesc;
802
803 typedef struct {
804         ILStackDesc *stack;
805         guint16 stack_count;
806         guint16 flags;
807 } ILCodeDesc;
808
809 static void
810 type_to_eval_stack_type (MonoType *type, ILStackDesc *stack, int take_addr) {
811         int t = type->type;
812
813         stack->type = type;
814         if (type->byref || take_addr) { /* fix double addr issue */
815                 stack->stype = TYPE_MP;
816                 return;
817         }
818
819 handle_enum:
820         switch (t) {
821         case MONO_TYPE_I1:
822         case MONO_TYPE_U1:
823         case MONO_TYPE_BOOLEAN:
824         case MONO_TYPE_I2:
825         case MONO_TYPE_U2:
826         case MONO_TYPE_CHAR:
827         case MONO_TYPE_I4:
828         case MONO_TYPE_U4:
829                 stack->stype = TYPE_I4;
830                 return;
831         case MONO_TYPE_I:
832         case MONO_TYPE_U:
833         case MONO_TYPE_PTR:
834                 stack->stype = TYPE_PTR;
835                 return;
836         case MONO_TYPE_CLASS:
837         case MONO_TYPE_STRING:
838         case MONO_TYPE_OBJECT:
839         case MONO_TYPE_SZARRAY:
840         case MONO_TYPE_ARRAY:    
841                 stack->stype = TYPE_OBJ;
842                 return;
843         case MONO_TYPE_I8:
844         case MONO_TYPE_U8:
845                 stack->stype = TYPE_I8;
846                 return;
847         case MONO_TYPE_R4:
848         case MONO_TYPE_R8:
849                 stack->stype = TYPE_R8;
850                 return;
851         case MONO_TYPE_VALUETYPE:
852                 if (type->data.klass->enumtype) {
853                         t = type->data.klass->enum_basetype->type;
854                         goto handle_enum;
855                 } else {
856                         stack->stype = TYPE_VT;
857                         return;
858                 }
859         default:
860                 g_error ("unknown type %02x in eval stack type", type->type);
861         }
862         return;
863 }
864
865 static int
866 type_from_op (int ins, ILStackDesc *arg) {
867         switch (ins) {
868         /* binops */
869         case CEE_ADD:
870         case CEE_SUB:
871         case CEE_MUL:
872         case CEE_DIV:
873         case CEE_REM:
874                 /* FIXME: check unverifiable args for TYPE_MP */
875                 return arg->stype = bin_num_table [arg->stype] [arg [1].stype];
876         case CEE_DIV_UN:
877         case CEE_REM_UN:
878         case CEE_AND:
879         case CEE_OR:
880         case CEE_XOR:
881                 return arg->stype = bin_int_table [arg->stype] [arg [1].stype];
882         case CEE_SHL:
883         case CEE_SHR:
884         case CEE_SHR_UN:
885                 return arg->stype = shift_table [arg->stype] [arg [1].stype];
886         case CEE_BEQ_S:
887         case CEE_BGE_S:
888         case CEE_BGT_S:
889         case CEE_BLE_S:
890         case CEE_BLT_S:
891         case CEE_BNE_UN_S:
892         case CEE_BGE_UN_S:
893         case CEE_BGT_UN_S:
894         case CEE_BLE_UN_S:
895         case CEE_BLT_UN_S:
896         case CEE_BEQ:
897         case CEE_BGE:
898         case CEE_BGT:
899         case CEE_BLE:
900         case CEE_BLT:
901         case CEE_BNE_UN:
902         case CEE_BGE_UN:
903         case CEE_BGT_UN:
904         case CEE_BLE_UN:
905         case CEE_BLT_UN:
906                 /* FIXME: handle some specifics with ins->next->type */
907                 return bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
908         case 256+CEE_CEQ:
909         case 256+CEE_CGT:
910         case 256+CEE_CGT_UN:
911         case 256+CEE_CLT:
912         case 256+CEE_CLT_UN:
913                 return arg->stype = bin_comp_table [arg->stype] [arg [1].stype] ? TYPE_I4: TYPE_INV;
914         /* unops */
915         case CEE_NEG:
916                 return arg->stype = neg_table [arg->stype];
917         case CEE_NOT:
918                 if (arg->stype >= TYPE_I4 && arg->stype <= TYPE_PTR)
919                         return arg->stype;
920                 else
921                         return arg->stype = TYPE_INV;
922         case CEE_CONV_I1:
923         case CEE_CONV_U1:
924         case CEE_CONV_I2:
925         case CEE_CONV_U2:
926         case CEE_CONV_I4:
927         case CEE_CONV_U4:
928         case CEE_CONV_OVF_I1:
929         case CEE_CONV_OVF_U1:
930         case CEE_CONV_OVF_I2:
931         case CEE_CONV_OVF_U2:
932         case CEE_CONV_OVF_I4:
933         case CEE_CONV_OVF_U4:
934         case CEE_CONV_OVF_I1_UN:
935         case CEE_CONV_OVF_U1_UN:
936         case CEE_CONV_OVF_I2_UN:
937         case CEE_CONV_OVF_U2_UN:
938         case CEE_CONV_OVF_I4_UN:
939         case CEE_CONV_OVF_U4_UN:
940                 if (arg->stype == TYPE_INV || arg->stype >= TYPE_MP)
941                         return arg->stype = TYPE_INV;
942                 return arg->stype = TYPE_I4;
943         case CEE_CONV_I:
944         case CEE_CONV_U:
945         case CEE_CONV_OVF_I:
946         case CEE_CONV_OVF_U:
947         case CEE_CONV_OVF_I_UN:
948         case CEE_CONV_OVF_U_UN:
949                 if (arg->stype == TYPE_INV || arg->stype == TYPE_VT)
950                         return arg->stype = TYPE_INV;
951                 return arg->stype = TYPE_PTR;
952         case CEE_CONV_I8:
953         case CEE_CONV_U8:
954         case CEE_CONV_OVF_I8:
955         case CEE_CONV_OVF_U8:
956         case CEE_CONV_OVF_I8_UN:
957         case CEE_CONV_OVF_U8_UN:
958                 return arg->stype = TYPE_I8;
959         case CEE_CONV_R4:
960         case CEE_CONV_R8:
961                 return arg->stype = TYPE_R8;
962         default:
963                 g_error ("opcode 0x%04x not handled in type from op", ins);
964                 break;
965         }
966         return FALSE;
967 }
968
969 static int
970 in_any_block (MonoMethodHeader *header, guint offset)
971 {
972         int i;
973         MonoExceptionClause *clause;
974
975         for (i = 0; i < header->num_clauses; ++i) {
976                 clause = &header->clauses [i];
977                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
978                         return 1;
979                 if (MONO_OFFSET_IN_HANDLER (clause, offset))
980                         return 1;
981                 /* need to check filter ... */
982         }
983         return 0;
984 }
985
986 static int
987 in_same_block (MonoMethodHeader *header, guint offset, guint target)
988 {
989         int i;
990         MonoExceptionClause *clause;
991
992         for (i = 0; i < header->num_clauses; ++i) {
993                 clause = &header->clauses [i];
994                 if (MONO_OFFSET_IN_CLAUSE (clause, offset) && !MONO_OFFSET_IN_CLAUSE (clause, target))
995                         return 0;
996                 if (MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
997                         return 0;
998                 /* need to check filter ... */
999         }
1000         return 1;
1001 }
1002
1003 /*
1004  * A leave can't escape a finally block 
1005  */
1006 static int
1007 is_correct_leave (MonoMethodHeader *header, guint offset, guint target)
1008 {
1009         int i;
1010         MonoExceptionClause *clause;
1011
1012         for (i = 0; i < header->num_clauses; ++i) {
1013                 clause = &header->clauses [i];
1014                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY && MONO_OFFSET_IN_HANDLER (clause, offset) && !MONO_OFFSET_IN_HANDLER (clause, target))
1015                         return 0;
1016                 /* need to check filter ... */
1017         }
1018         return 1;
1019 }
1020
1021 static int
1022 can_merge_stack (ILCodeDesc *a, ILCodeDesc *b)
1023 {
1024         if (!b->flags & CODE_SEEN) {
1025                 b->flags |= CODE_SEEN;
1026                 b->stack_count = a->stack_count;
1027                 /* merge types */
1028                 return 1;
1029         }
1030         if (a->stack_count != b->stack_count)
1031                 return 0;
1032         /* merge types */
1033         return 1;
1034 }
1035
1036 static int
1037 is_valid_bool_arg (ILStackDesc *arg)
1038 {
1039         switch (arg->stype) {
1040         case TYPE_I4:
1041         case TYPE_I8:
1042         case TYPE_PTR:
1043         case TYPE_MP:
1044         case TYPE_OBJ:
1045                 return TRUE;
1046         default:
1047                 return FALSE;
1048         }
1049 }
1050
1051 static int
1052 can_store_type (ILStackDesc *arg, MonoType *type)
1053 {
1054         int t = type->type;
1055         if (type->byref && arg->stype != TYPE_MP)
1056                 return FALSE;
1057 handle_enum:
1058         switch (t) {
1059         case MONO_TYPE_VOID:
1060                 return FALSE;
1061         case MONO_TYPE_I1:
1062         case MONO_TYPE_U1:
1063         case MONO_TYPE_BOOLEAN:
1064         case MONO_TYPE_I2:
1065         case MONO_TYPE_U2:
1066         case MONO_TYPE_CHAR:
1067         case MONO_TYPE_I4:
1068         case MONO_TYPE_U4:
1069                 if (arg->stype == TYPE_I4 || arg->stype == TYPE_PTR)
1070                         return TRUE;
1071                 return FALSE;
1072         case MONO_TYPE_I:
1073         case MONO_TYPE_U:
1074         case MONO_TYPE_PTR:
1075                 return TRUE;
1076         case MONO_TYPE_CLASS:
1077         case MONO_TYPE_STRING:
1078         case MONO_TYPE_OBJECT:
1079         case MONO_TYPE_SZARRAY:
1080         case MONO_TYPE_ARRAY:    
1081                 return TRUE; /* FIXME */
1082         case MONO_TYPE_I8:
1083         case MONO_TYPE_U8:
1084                 if (arg->stype == TYPE_I8)
1085                         return TRUE;
1086                 return FALSE;
1087         case MONO_TYPE_R4:
1088         case MONO_TYPE_R8:
1089                 if (arg->stype == TYPE_R8)
1090                         return TRUE;
1091                 return FALSE;
1092         case MONO_TYPE_VALUETYPE:
1093                 if (type->data.klass->enumtype) {
1094                         t = type->data.klass->enum_basetype->type;
1095                         goto handle_enum;
1096                 } else {
1097                         if (arg->type->data.klass != type->data.klass)
1098                                 return FALSE;
1099                         return TRUE;
1100                 }
1101         default:
1102                 g_error ("unknown type %02x in store type", type->type);
1103         }
1104         return FALSE;
1105 }
1106
1107 static int
1108 stind_type (int op, int type) {
1109         switch (op) {
1110         case CEE_STIND_REF:
1111                 return type == TYPE_OBJ;
1112         case CEE_STIND_I1:
1113         case CEE_STIND_I2:
1114         case CEE_STIND_I4:
1115                 return type == TYPE_I4;
1116         case CEE_STIND_I8:
1117                 return type == TYPE_I8;
1118         case CEE_STIND_R4:
1119         case CEE_STIND_R8:
1120                 return type == TYPE_R8;
1121         default:
1122                 g_assert_not_reached ();
1123         }
1124         return FALSE;
1125 }
1126
1127 /*
1128  * FIXME: need to distinguish between valid and verifiable.
1129  * Need to keep track of types on the stack.
1130  * Verify types for opcodes.
1131  */
1132 GSList*
1133 mono_method_verify (MonoMethod *method, int level)
1134 {
1135         MonoMethodHeader *header;
1136         MonoMethodSignature *signature, *csig;
1137         MonoGenericContext *generic_context = NULL;
1138         MonoMethod *cmethod;
1139         MonoClassField *field;
1140         MonoClass *klass;
1141         MonoImage *image;
1142         MonoType **params;
1143         ILStackDesc *stack;
1144         register const unsigned char *ip;
1145         register const unsigned char *end;
1146         const unsigned char *target; /* branch target */
1147         int max_args, max_stack, cur_stack, i, n, need_merge, start;
1148         guint32 token, ip_offset;
1149         char *local_state = NULL;
1150         GSList *list = NULL;
1151         guint prefix = 0;
1152         ILCodeDesc *code;
1153
1154         if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1155                         (method->flags & (METHOD_ATTRIBUTE_PINVOKE_IMPL | METHOD_ATTRIBUTE_ABSTRACT))) {
1156                 return NULL;
1157         }
1158         signature = method->signature;
1159         header = ((MonoMethodNormal *)method)->header;
1160         ip = header->code;
1161         end = ip + header->code_size;
1162         max_args = signature->param_count + signature->hasthis;
1163         max_stack = header->max_stack;
1164         need_merge = cur_stack = 0;
1165         start = 1;
1166         image = method->klass->image;
1167         code = g_new0 (ILCodeDesc, header->code_size);
1168         stack = g_new0 (ILStackDesc, max_stack);
1169         if (signature->hasthis) {
1170                 params = g_new0 (MonoType*, max_args);
1171                 params [0] = &method->klass->this_arg;
1172                 memcpy (params + 1, signature->params, sizeof (MonoType*) * signature->param_count);
1173         } else {
1174                 params = signature->params;
1175         }
1176
1177         if (method->signature->is_inflated)
1178                 generic_context = ((MonoMethodInflated *) method)->context;
1179
1180         if (header->num_locals) {
1181                 local_state = g_new (char, header->num_locals);
1182                 memset (local_state, header->init_locals, header->num_locals);
1183         }
1184         /*g_print ("Method %s.%s::%s\n", method->klass->name_space, method->klass->name, method->name);*/
1185
1186         for (i = 0; i < header->num_clauses; ++i) {
1187                 MonoExceptionClause *clause = &header->clauses [i];
1188                 /* catch blocks have the exception on the stack. */
1189                 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
1190                         code [clause->handler_offset].stack_count = 1;
1191                         code [clause->handler_offset].flags |= CODE_SEEN;
1192                 }
1193         }
1194
1195         while (ip < end) {
1196                 ip_offset = ip - header->code;
1197                 if (start || !(code [ip_offset].flags & CODE_SEEN)) {
1198                         if (start) {
1199                                 /* g_print ("setting stack of IL_%04x to %d\n", ip_offset, 0); */
1200                                 cur_stack = code [ip_offset].stack_count;
1201                         } else {
1202                                 code [ip_offset].stack_count = cur_stack;
1203                         }
1204                         code [ip_offset].flags |= CODE_SEEN;
1205                 } else {
1206                         /* stack merge */
1207                         if (code [ip_offset].stack_count != cur_stack)
1208                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
1209                 }
1210                 start = 0;
1211                 if (need_merge) {
1212                         if (!can_merge_stack (&code [ip_offset], &code [target - header->code]))
1213                                 ADD_INVALID (list, g_strdup_printf ("Cannot merge stack states at 0x%04x", ip_offset));
1214                         need_merge = 0;
1215                 }
1216 #if 0
1217                 {
1218                         char *discode;
1219                         discode = mono_disasm_code_one (NULL, method, ip, NULL);
1220                         discode [strlen (discode) - 1] = 0; /* no \n */
1221                         g_print ("%-29s (%d)\n", discode, cur_stack);
1222                         g_free (discode);
1223                 }
1224 #endif
1225
1226                 switch (*ip) {
1227                 case CEE_NOP:
1228                 case CEE_BREAK: 
1229                         ++ip;
1230                         break;
1231                 case CEE_LDARG_0:
1232                 case CEE_LDARG_1:
1233                 case CEE_LDARG_2:
1234                 case CEE_LDARG_3:
1235                         if (*ip - CEE_LDARG_0 >= max_args)
1236                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", *ip - CEE_LDARG_0, ip_offset));
1237                         CHECK_STACK_OVERFLOW ();
1238                         type_to_eval_stack_type (params [*ip - CEE_LDARG_0], stack + cur_stack, FALSE);
1239                         ++cur_stack;
1240                         ++ip;
1241                         break;
1242                 case CEE_LDLOC_0:
1243                 case CEE_LDLOC_1:
1244                 case CEE_LDLOC_2:
1245                 case CEE_LDLOC_3:
1246                         if (*ip - CEE_LDLOC_0 >= header->num_locals)
1247                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
1248                         if (0 && !local_state [*ip - CEE_LDLOC_0])
1249                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", *ip - CEE_LDLOC_0, ip_offset));
1250                         CHECK_STACK_OVERFLOW ();
1251                         type_to_eval_stack_type (header->locals [*ip - CEE_LDLOC_0], stack + cur_stack, FALSE);
1252                         ++cur_stack;
1253                         ++ip;
1254                         break;
1255                 case CEE_STLOC_0:
1256                 case CEE_STLOC_1:
1257                 case CEE_STLOC_2:
1258                 case CEE_STLOC_3:
1259                         if (*ip - CEE_STLOC_0 >= header->num_locals)
1260                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", *ip - CEE_STLOC_0, ip_offset));
1261                         local_state [*ip - CEE_STLOC_0] = 1;
1262                         CHECK_STACK_UNDERFLOW (1);
1263                         --cur_stack;
1264                         if (!can_store_type (stack + cur_stack, header->locals [*ip - CEE_STLOC_0]))
1265                                 ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1266                         ++ip;
1267                         break;
1268                 case CEE_LDARG_S:
1269                 case CEE_LDARGA_S:
1270                         if (ip [1] >= max_args)
1271                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
1272                         CHECK_STACK_OVERFLOW ();
1273                         type_to_eval_stack_type (params [ip [1]], stack + cur_stack, *ip == CEE_LDARGA_S);
1274                         ++cur_stack;
1275                         ip += 2;
1276                         break;
1277                 case CEE_STARG_S:
1278                         if (ip [1] >= max_args)
1279                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", ip [1], ip_offset));
1280                         CHECK_STACK_UNDERFLOW (1);
1281                         --cur_stack;
1282                         ip += 2;
1283                         break;
1284                 case CEE_LDLOC_S:
1285                 case CEE_LDLOCA_S:
1286                         if (ip [1] >= header->num_locals)
1287                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
1288                         /* no need to check if the var is initialized if the address is taken */
1289                         if (0 && *ip == CEE_LDLOC_S && !local_state [ip [1]])
1290                                 ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", ip [1], ip_offset));
1291                         CHECK_STACK_OVERFLOW ();
1292                         type_to_eval_stack_type (header->locals [ip [1]], stack + cur_stack, *ip == CEE_LDLOCA_S);
1293                         ++cur_stack;
1294                         ip += 2;
1295                         break;
1296                 case CEE_STLOC_S:
1297                         if (ip [1] >= header->num_locals)
1298                                 ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", ip [1], ip_offset));
1299                         local_state [ip [1]] = 1;
1300                         CHECK_STACK_UNDERFLOW (1);
1301                         --cur_stack;
1302                         if (!can_store_type (stack + cur_stack, header->locals [ip [1]]))
1303                                 ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1304                         ip += 2;
1305                         break;
1306                 case CEE_LDNULL:
1307                         CHECK_STACK_OVERFLOW ();
1308                         stack [cur_stack].type = &mono_defaults.object_class->byval_arg;
1309                         stack [cur_stack].stype = TYPE_OBJ;
1310                         ++cur_stack;
1311                         ++ip;
1312                         break;
1313                 case CEE_LDC_I4_M1:
1314                 case CEE_LDC_I4_0:
1315                 case CEE_LDC_I4_1:
1316                 case CEE_LDC_I4_2:
1317                 case CEE_LDC_I4_3:
1318                 case CEE_LDC_I4_4:
1319                 case CEE_LDC_I4_5:
1320                 case CEE_LDC_I4_6:
1321                 case CEE_LDC_I4_7:
1322                 case CEE_LDC_I4_8:
1323                         CHECK_STACK_OVERFLOW ();
1324                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1325                         stack [cur_stack].stype = TYPE_I4;
1326                         ++cur_stack;
1327                         ++ip;
1328                         break;
1329                 case CEE_LDC_I4_S:
1330                         CHECK_STACK_OVERFLOW ();
1331                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1332                         stack [cur_stack].stype = TYPE_I4;
1333                         ++cur_stack;
1334                         ip += 2;
1335                         break;
1336                 case CEE_LDC_I4:
1337                         CHECK_STACK_OVERFLOW ();
1338                         stack [cur_stack].type = &mono_defaults.int_class->byval_arg;
1339                         stack [cur_stack].stype = TYPE_I4;
1340                         ++cur_stack;
1341                         ip += 5;
1342                         break;
1343                 case CEE_LDC_I8:
1344                         CHECK_STACK_OVERFLOW ();
1345                         stack [cur_stack].type = &mono_defaults.int64_class->byval_arg;
1346                         stack [cur_stack].stype = TYPE_I8;
1347                         ++cur_stack;
1348                         ip += 9;
1349                         break;
1350                 case CEE_LDC_R4:
1351                         CHECK_STACK_OVERFLOW ();
1352                         stack [cur_stack].type = &mono_defaults.double_class->byval_arg;
1353                         stack [cur_stack].stype = TYPE_R8;
1354                         ++cur_stack;
1355                         ip += 5;
1356                         break;
1357                 case CEE_LDC_R8:
1358                         CHECK_STACK_OVERFLOW ();
1359                         stack [cur_stack].type = &mono_defaults.double_class->byval_arg;
1360                         stack [cur_stack].stype = TYPE_R8;
1361                         ++cur_stack;
1362                         ip += 9;
1363                         break;
1364                 case CEE_UNUSED99: ++ip; break; /* warn/error instead? */
1365                 case CEE_DUP:
1366                         CHECK_STACK_UNDERFLOW (1);
1367                         CHECK_STACK_OVERFLOW ();
1368                         stack [cur_stack] = stack [cur_stack - 1];
1369                         ++cur_stack;
1370                         ++ip;
1371                         break;
1372                 case CEE_POP:
1373                         CHECK_STACK_UNDERFLOW (1);
1374                         --cur_stack;
1375                         ++ip;
1376                         break;
1377                 case CEE_JMP:
1378                         if (cur_stack)
1379                                 ADD_INVALID (list, g_strdup_printf ("Eval stack must be empty in jmp at 0x%04x", ip_offset));
1380                         token = read32 (ip + 1);
1381                         if (in_any_block (header, ip_offset))
1382                                 ADD_INVALID (list, g_strdup_printf ("jmp cannot escape exception blocks at 0x%04x", ip_offset));
1383                         /*
1384                          * FIXME: check signature, retval, arguments etc.
1385                          */
1386                         ip += 5;
1387                         break;
1388                 case CEE_CALL:
1389                 case CEE_CALLVIRT:
1390                         token = read32 (ip + 1);
1391                         /*
1392                          * FIXME: we could just load the signature ...
1393                          */
1394                         cmethod = mono_get_method_full (image, token, NULL, generic_context);
1395                         if (!cmethod)
1396                                 ADD_INVALID (list, g_strdup_printf ("Method 0x%08x not found at 0x%04x", token, ip_offset));
1397                         csig = cmethod->signature;
1398                         CHECK_STACK_UNDERFLOW (csig->param_count + csig->hasthis);
1399                         cur_stack -= csig->param_count + csig->hasthis;
1400                         if (csig->ret->type != MONO_TYPE_VOID) {
1401                                 CHECK_STACK_OVERFLOW ();
1402                                 type_to_eval_stack_type (csig->ret, stack + cur_stack, FALSE);
1403                                 ++cur_stack;
1404                         }
1405                         ip += 5;
1406                         break;
1407                 case CEE_CALLI:
1408                         token = read32 (ip + 1);
1409                         /*
1410                          * FIXME: check signature, retval, arguments etc.
1411                          */
1412                         ip += 5;
1413                         break;
1414                 case CEE_RET:
1415                         if (signature->ret->type != MONO_TYPE_VOID) {
1416                                 CHECK_STACK_UNDERFLOW (1);
1417                                 --cur_stack;
1418                                 if (!can_store_type (stack + cur_stack, signature->ret))
1419                                         ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in ret at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1420                         }
1421                         if (cur_stack)
1422                                 ADD_INVALID (list, g_strdup_printf ("Stack not empty (%d) after ret at 0x%04x", cur_stack, ip_offset));
1423                         cur_stack = 0;
1424                         if (in_any_block (header, ip_offset))
1425                                 ADD_INVALID (list, g_strdup_printf ("ret cannot escape exception blocks at 0x%04x", ip_offset));
1426                         ++ip;
1427                         start = 1;
1428                         break;
1429                 case CEE_BR_S:
1430                         target = ip + (signed char)ip [1] + 2;
1431                         if (target >= end || target < header->code)
1432                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1433                         if (!in_same_block (header, ip_offset, target - header->code))
1434                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1435                         ip += 2;
1436                         start = 1;
1437                         break;
1438                 case CEE_BRFALSE_S:
1439                 case CEE_BRTRUE_S:
1440                         target = ip + (signed char)ip [1] + 2;
1441                         if (target >= end || target < header->code)
1442                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1443                         if (!in_same_block (header, ip_offset, target - header->code))
1444                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1445                         CHECK_STACK_UNDERFLOW (1);
1446                         --cur_stack;
1447                         if (!is_valid_bool_arg (stack + cur_stack))
1448                                 ADD_INVALID (list, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1449                         ip += 2;
1450                         need_merge = 1;
1451                         break;
1452                 case CEE_BEQ_S:
1453                 case CEE_BGE_S:
1454                 case CEE_BGT_S:
1455                 case CEE_BLE_S:
1456                 case CEE_BLT_S:
1457                 case CEE_BNE_UN_S:
1458                 case CEE_BGE_UN_S:
1459                 case CEE_BGT_UN_S:
1460                 case CEE_BLE_UN_S:
1461                 case CEE_BLT_UN_S:
1462                         target = ip + (signed char)ip [1] + 2;
1463                         if (target >= end || target < header->code)
1464                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1465                         if (!in_same_block (header, ip_offset, target - header->code))
1466                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1467                         CHECK_STACK_UNDERFLOW (2);
1468                         cur_stack -= 2;
1469                         if (type_from_op (*ip, stack + cur_stack) == TYPE_INV)
1470                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1471                         ip += 2;
1472                         need_merge = 1;
1473                         break;
1474                 case CEE_BR:
1475                         target = ip + (gint32)read32 (ip + 1) + 5;
1476                         if (target >= end || target < header->code)
1477                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1478                         if (!in_same_block (header, ip_offset, target - header->code))
1479                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1480                         ip += 5;
1481                         start = 1;
1482                         break;
1483                 case CEE_BRFALSE:
1484                 case CEE_BRTRUE:
1485                         target = ip + (gint32)read32 (ip + 1) + 5;
1486                         if (target >= end || target < header->code)
1487                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1488                         if (!in_same_block (header, ip_offset, target - header->code))
1489                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1490                         CHECK_STACK_UNDERFLOW (1);
1491                         --cur_stack;
1492                         if (!is_valid_bool_arg (stack + cur_stack))
1493                                 ADD_INVALID (list, g_strdup_printf ("Argument type %s not valid for brtrue/brfalse at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1494                         ip += 5;
1495                         need_merge = 1;
1496                         break;
1497                 case CEE_BEQ:
1498                 case CEE_BGE:
1499                 case CEE_BGT:
1500                 case CEE_BLE:
1501                 case CEE_BLT:
1502                 case CEE_BNE_UN:
1503                 case CEE_BGE_UN:
1504                 case CEE_BGT_UN:
1505                 case CEE_BLE_UN:
1506                 case CEE_BLT_UN:
1507                         target = ip + (gint32)read32 (ip + 1) + 5;
1508                         if (target >= end || target < header->code)
1509                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1510                         if (!in_same_block (header, ip_offset, target - header->code))
1511                                 ADD_INVALID (list, g_strdup_printf ("Branch target escapes out of exception block at 0x%04x", ip_offset));
1512                         CHECK_STACK_UNDERFLOW (2);
1513                         cur_stack -= 2;
1514                         if (type_from_op (*ip, stack + cur_stack) == TYPE_INV)
1515                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1516                         ip += 5;
1517                         need_merge = 1;
1518                         break;
1519                 case CEE_SWITCH:
1520                         n = read32 (ip + 1);
1521                         target = ip + sizeof (guint32) * n;
1522                         /* FIXME: check that ip is in range (and within the same exception block) */
1523                         for (i = 0; i < n; ++i)
1524                                 if (target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) >= end || target + (gint32) read32 (ip + 5 + i * sizeof (gint32)) < header->code)
1525                                         ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1526                         CHECK_STACK_UNDERFLOW (1);
1527                         --cur_stack;
1528                         if (stack [cur_stack].stype != TYPE_I4)
1529                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to switch at 0x%04x", ip_offset));
1530                         ip += 5 + sizeof (guint32) * n;
1531                         break;
1532                 case CEE_LDIND_I1:
1533                 case CEE_LDIND_U1:
1534                 case CEE_LDIND_I2:
1535                 case CEE_LDIND_U2:
1536                 case CEE_LDIND_I4:
1537                 case CEE_LDIND_U4:
1538                 case CEE_LDIND_I8:
1539                 case CEE_LDIND_I:
1540                 case CEE_LDIND_R4:
1541                 case CEE_LDIND_R8:
1542                 case CEE_LDIND_REF:
1543                         CHECK_STACK_UNDERFLOW (1);
1544                         if (stack [cur_stack - 1].stype != TYPE_PTR && stack [cur_stack - 1].stype != TYPE_MP)
1545                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldind at 0x%04x", ip_offset));
1546                         stack [cur_stack - 1].stype = ldind_type [*ip - CEE_LDIND_I1];
1547                         ++ip;
1548                         break;
1549                 case CEE_STIND_REF:
1550                 case CEE_STIND_I1:
1551                 case CEE_STIND_I2:
1552                 case CEE_STIND_I4:
1553                 case CEE_STIND_I8:
1554                 case CEE_STIND_R4:
1555                 case CEE_STIND_R8:
1556                         CHECK_STACK_UNDERFLOW (2);
1557                         cur_stack -= 2;
1558                         if (stack [cur_stack].stype != TYPE_PTR && stack [cur_stack].stype != TYPE_MP)
1559                                 ADD_INVALID (list, g_strdup_printf ("Invalid pointer argument to stind at 0x%04x", ip_offset));
1560                         if (!stind_type (*ip, stack [cur_stack + 1].stype))
1561                                 ADD_INVALID (list, g_strdup_printf ("Incompatible value argument to stind at 0x%04x", ip_offset));
1562                         ++ip;
1563                         break;
1564                 case CEE_ADD:
1565                 case CEE_SUB:
1566                 case CEE_MUL:
1567                 case CEE_DIV:
1568                 case CEE_DIV_UN:
1569                 case CEE_REM:
1570                 case CEE_REM_UN:
1571                 case CEE_AND:
1572                 case CEE_OR:
1573                 case CEE_XOR:
1574                 case CEE_SHL:
1575                 case CEE_SHR:
1576                 case CEE_SHR_UN:
1577                         CHECK_STACK_UNDERFLOW (2);
1578                         --cur_stack;
1579                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1580                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1581                         ++ip;
1582                         break;
1583                 case CEE_NEG:
1584                 case CEE_NOT:
1585                 case CEE_CONV_I1:
1586                 case CEE_CONV_I2:
1587                 case CEE_CONV_I4:
1588                 case CEE_CONV_I8:
1589                 case CEE_CONV_R4:
1590                 case CEE_CONV_R8:
1591                 case CEE_CONV_U4:
1592                 case CEE_CONV_U8:
1593                         CHECK_STACK_UNDERFLOW (1);
1594                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1595                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1596                         ++ip;
1597                         break;
1598                 case CEE_CPOBJ:
1599                         token = read32 (ip + 1);
1600                         CHECK_STACK_UNDERFLOW (2);
1601                         cur_stack -= 2;
1602                         ip += 5;
1603                         break;
1604                 case CEE_LDOBJ:
1605                         token = read32 (ip + 1);
1606                         CHECK_STACK_UNDERFLOW (1);
1607                         if (stack [cur_stack - 1].stype != TYPE_MP)
1608                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldobj at 0x%04x", ip_offset));
1609                         klass = mono_class_get_full (image, token, generic_context);
1610                         if (!klass)
1611                                 ADD_INVALID (list, g_strdup_printf ("Cannot load class from token 0x%08x at 0x%04x", token, ip_offset));
1612                         if (!klass->valuetype)
1613                                 ADD_INVALID (list, g_strdup_printf ("Class is not a valuetype at 0x%04x", ip_offset));
1614                         stack [cur_stack - 1].stype = TYPE_VT;
1615                         stack [cur_stack - 1].type = &klass->byval_arg;
1616                         ip += 5;
1617                         break;
1618                 case CEE_LDSTR:
1619                         token = read32 (ip + 1);
1620                         CHECK_STACK_OVERFLOW ();
1621                         stack [cur_stack].type = &mono_defaults.string_class->byval_arg;
1622                         stack [cur_stack].stype = TYPE_OBJ;
1623                         ++cur_stack;
1624                         ip += 5;
1625                         break;
1626                 case CEE_NEWOBJ:
1627                         token = read32 (ip + 1);
1628                         /*
1629                          * FIXME: we could just load the signature ...
1630                          */
1631                         cmethod = mono_get_method_full (image, token, NULL, generic_context);
1632                         if (!cmethod)
1633                                 ADD_INVALID (list, g_strdup_printf ("Constructor 0x%08x not found at 0x%04x", token, ip_offset));
1634                         csig = cmethod->signature;
1635                         CHECK_STACK_UNDERFLOW (csig->param_count);
1636                         cur_stack -= csig->param_count;
1637                         CHECK_STACK_OVERFLOW ();
1638                         stack [cur_stack].type = &cmethod->klass->byval_arg;
1639                         stack [cur_stack].stype = cmethod->klass->valuetype? TYPE_VT: TYPE_OBJ;
1640                         ++cur_stack;
1641                         ip += 5;
1642                         break;
1643                 case CEE_CASTCLASS:
1644                 case CEE_ISINST:
1645                         token = read32 (ip + 1);
1646                         CHECK_STACK_UNDERFLOW (1);
1647                         ip += 5;
1648                         break;
1649                 case CEE_CONV_R_UN:
1650                         CHECK_STACK_UNDERFLOW (1);
1651                         ++ip;
1652                         break;
1653                 case CEE_UNUSED58:
1654                 case CEE_UNUSED1:
1655                         ++ip; /* warn, error ? */
1656                         break;
1657                 case CEE_UNBOX:
1658                         token = read32 (ip + 1);
1659                         CHECK_STACK_UNDERFLOW (1);
1660                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1661                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to unbox at 0x%04x", arg_name [stack [cur_stack - 1].stype], ip_offset));
1662                         stack [cur_stack - 1].stype = TYPE_MP;
1663                         stack [cur_stack - 1].type = NULL;
1664                         ip += 5;
1665                         break;
1666                 case CEE_THROW:
1667                         CHECK_STACK_UNDERFLOW (1);
1668                         --cur_stack;
1669                         ++ip;
1670                         start = 1;
1671                         break;
1672                 case CEE_LDFLD:
1673                         CHECK_STACK_UNDERFLOW (1);
1674                         if (stack [cur_stack - 1].stype != TYPE_OBJ && stack [cur_stack - 1].stype != TYPE_MP)
1675                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to ldfld at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
1676                         token = read32 (ip + 1);
1677                         field = mono_field_from_token (image, token, &klass, generic_context);
1678                         if (!field)
1679                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1680                         type_to_eval_stack_type (field->type, stack + cur_stack - 1, FALSE);
1681                         ip += 5;
1682                         break;
1683                 case CEE_LDFLDA:
1684                         CHECK_STACK_UNDERFLOW (1);
1685                         if (stack [cur_stack - 1].stype != TYPE_OBJ && stack [cur_stack - 1].stype != TYPE_MP)
1686                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldflda at 0x%04x", ip_offset));
1687                         token = read32 (ip + 1);
1688                         field = mono_field_from_token (image, token, &klass, generic_context);
1689                         if (!field)
1690                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1691                         type_to_eval_stack_type (field->type, stack + cur_stack - 1, TRUE);
1692                         ip += 5;
1693                         break;
1694                 case CEE_STFLD:
1695                         CHECK_STACK_UNDERFLOW (2);
1696                         cur_stack -= 2;
1697                         if (stack [cur_stack].stype != TYPE_OBJ && stack [cur_stack].stype != TYPE_MP)
1698                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to stfld at 0x%04x", ip_offset));
1699                         token = read32 (ip + 1);
1700                         field = mono_field_from_token (image, token, &klass, generic_context);
1701                         if (!field)
1702                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1703                         /* can_store */
1704                         ip += 5;
1705                         break;
1706                 case CEE_LDSFLD:
1707                         CHECK_STACK_OVERFLOW ();
1708                         token = read32 (ip + 1);
1709                         field = mono_field_from_token (image, token, &klass, generic_context);
1710                         if (!field)
1711                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1712                         type_to_eval_stack_type (field->type, stack + cur_stack, FALSE);
1713                         ++cur_stack;
1714                         ip += 5;
1715                         break;
1716                 case CEE_LDSFLDA:
1717                         CHECK_STACK_OVERFLOW ();
1718                         token = read32 (ip + 1);
1719                         field = mono_field_from_token (image, token, &klass, generic_context);
1720                         if (!field)
1721                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1722                         type_to_eval_stack_type (field->type, stack + cur_stack, TRUE);
1723                         ++cur_stack;
1724                         ip += 5;
1725                         break;
1726                 case CEE_STSFLD:
1727                         CHECK_STACK_UNDERFLOW (1);
1728                         --cur_stack;
1729                         token = read32 (ip + 1);
1730                         field = mono_field_from_token (image, token, &klass, generic_context);
1731                         if (!field)
1732                                 ADD_INVALID (list, g_strdup_printf ("Cannot load field from token 0x%08x at 0x%04x", token, ip_offset));
1733                         /* can store */
1734                         ip += 5;
1735                         break;
1736                 case CEE_STOBJ:
1737                         CHECK_STACK_UNDERFLOW (2);
1738                         cur_stack -= 2;
1739                         token = read32 (ip + 1);
1740                         ip += 5;
1741                         break;
1742                 case CEE_CONV_OVF_I1_UN:
1743                 case CEE_CONV_OVF_I2_UN:
1744                 case CEE_CONV_OVF_I4_UN:
1745                 case CEE_CONV_OVF_I8_UN:
1746                 case CEE_CONV_OVF_U1_UN:
1747                 case CEE_CONV_OVF_U2_UN:
1748                 case CEE_CONV_OVF_U4_UN:
1749                 case CEE_CONV_OVF_U8_UN:
1750                 case CEE_CONV_OVF_I_UN:
1751                 case CEE_CONV_OVF_U_UN:
1752                         CHECK_STACK_UNDERFLOW (1);
1753                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1754                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1755                         ++ip;
1756                         break;
1757                 case CEE_BOX:
1758                         CHECK_STACK_UNDERFLOW (1);
1759                         token = read32 (ip + 1);
1760                         if (stack [cur_stack - 1].stype == TYPE_OBJ)
1761                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument %s to box at 0x%04x", arg_name [stack [cur_stack - 1].stype], ip_offset));
1762                         stack [cur_stack - 1].stype = TYPE_OBJ;
1763                         ip += 5;
1764                         break;
1765                 case CEE_NEWARR:
1766                         CHECK_STACK_UNDERFLOW (1);
1767                         token = read32 (ip + 1);
1768                         stack [cur_stack - 1].stype = TYPE_OBJ;
1769                         ip += 5;
1770                         break;
1771                 case CEE_LDLEN:
1772                         CHECK_STACK_UNDERFLOW (1);
1773                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1774                                 ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldlen at 0x%04x", ip_offset));
1775                         stack [cur_stack - 1].type = &mono_defaults.int_class->byval_arg; /* FIXME: use a native int type */
1776                         stack [cur_stack - 1].stype = TYPE_PTR;
1777                         ++ip;
1778                         break;
1779                 case CEE_LDELEMA:
1780                         CHECK_STACK_UNDERFLOW (2);
1781                         --cur_stack;
1782                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1783                                 ADD_INVALID (list, g_strdup_printf ("Invalid array argument to ldelema at 0x%04x", ip_offset));
1784                         if (stack [cur_stack].stype != TYPE_I4 && stack [cur_stack].stype != TYPE_PTR)
1785                                 ADD_INVALID (list, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
1786                         stack [cur_stack - 1].stype = TYPE_MP;
1787                         token = read32 (ip + 1);
1788                         ip += 5;
1789                         break;
1790                 case CEE_LDELEM_I1:
1791                 case CEE_LDELEM_U1:
1792                 case CEE_LDELEM_I2:
1793                 case CEE_LDELEM_U2:
1794                 case CEE_LDELEM_I4:
1795                 case CEE_LDELEM_U4:
1796                 case CEE_LDELEM_I8:
1797                 case CEE_LDELEM_I:
1798                 case CEE_LDELEM_R4:
1799                 case CEE_LDELEM_R8:
1800                 case CEE_LDELEM_REF:
1801                         CHECK_STACK_UNDERFLOW (2);
1802                         --cur_stack;
1803                         if (stack [cur_stack - 1].stype != TYPE_OBJ)
1804                                 ADD_INVALID (list, g_strdup_printf ("Invalid array argument to ldelem at 0x%04x", ip_offset));
1805                         if (stack [cur_stack].stype != TYPE_I4 && stack [cur_stack].stype != TYPE_PTR)
1806                                 ADD_INVALID (list, g_strdup_printf ("Array index needs to be Int32 or IntPtr at 0x%04x", ip_offset));
1807                         stack [cur_stack - 1].stype = ldelem_type [*ip - CEE_LDELEM_I1];
1808                         ++ip;
1809                         break;
1810                 case CEE_STELEM_I:
1811                 case CEE_STELEM_I1:
1812                 case CEE_STELEM_I2:
1813                 case CEE_STELEM_I4:
1814                 case CEE_STELEM_I8:
1815                 case CEE_STELEM_R4:
1816                 case CEE_STELEM_R8:
1817                 case CEE_STELEM_REF:
1818                         CHECK_STACK_UNDERFLOW (3);
1819                         cur_stack -= 3;
1820                         ++ip;
1821                         break;
1822                 case CEE_LDELEM:
1823                 case CEE_STELEM:
1824                 case CEE_UNBOX_ANY:
1825                 case CEE_UNUSED5:
1826                 case CEE_UNUSED6:
1827                 case CEE_UNUSED7:
1828                 case CEE_UNUSED8:
1829                 case CEE_UNUSED9:
1830                 case CEE_UNUSED10:
1831                 case CEE_UNUSED11:
1832                 case CEE_UNUSED12:
1833                 case CEE_UNUSED13:
1834                 case CEE_UNUSED14:
1835                 case CEE_UNUSED15:
1836                 case CEE_UNUSED16:
1837                 case CEE_UNUSED17:
1838                         ++ip; /* warn, error ? */
1839                         break;
1840                 case CEE_CONV_OVF_I1:
1841                 case CEE_CONV_OVF_U1:
1842                 case CEE_CONV_OVF_I2:
1843                 case CEE_CONV_OVF_U2:
1844                 case CEE_CONV_OVF_I4:
1845                 case CEE_CONV_OVF_U4:
1846                 case CEE_CONV_OVF_I8:
1847                 case CEE_CONV_OVF_U8:
1848                         CHECK_STACK_UNDERFLOW (1);
1849                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1850                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1851                         ++ip;
1852                         break;
1853                 case CEE_UNUSED50:
1854                 case CEE_UNUSED18:
1855                 case CEE_UNUSED19:
1856                 case CEE_UNUSED20:
1857                 case CEE_UNUSED21:
1858                 case CEE_UNUSED22:
1859                 case CEE_UNUSED23:
1860                         ++ip; /* warn, error ? */
1861                         break;
1862                 case CEE_REFANYVAL:
1863                         CHECK_STACK_UNDERFLOW (1);
1864                         ++ip;
1865                         break;
1866                 case CEE_CKFINITE:
1867                         CHECK_STACK_UNDERFLOW (1);
1868                         ++ip;
1869                         break;
1870                 case CEE_UNUSED24:
1871                 case CEE_UNUSED25:
1872                         ++ip; /* warn, error ? */
1873                         break;
1874                 case CEE_MKREFANY:
1875                         CHECK_STACK_UNDERFLOW (1);
1876                         token = read32 (ip + 1);
1877                         ip += 5;
1878                         break;
1879                 case CEE_UNUSED59:
1880                 case CEE_UNUSED60:
1881                 case CEE_UNUSED61:
1882                 case CEE_UNUSED62:
1883                 case CEE_UNUSED63:
1884                 case CEE_UNUSED64:
1885                 case CEE_UNUSED65:
1886                 case CEE_UNUSED66:
1887                 case CEE_UNUSED67:
1888                         ++ip; /* warn, error ? */
1889                         break;
1890                 case CEE_LDTOKEN:
1891                         CHECK_STACK_OVERFLOW ();
1892                         token = read32 (ip + 1);
1893                         ++cur_stack;
1894                         ip += 5;
1895                         break;
1896                 case CEE_CONV_U2:
1897                 case CEE_CONV_U1:
1898                 case CEE_CONV_I:
1899                 case CEE_CONV_OVF_I:
1900                 case CEE_CONV_OVF_U:
1901                         CHECK_STACK_UNDERFLOW (1);
1902                         if (type_from_op (*ip, stack + cur_stack - 1) == TYPE_INV)
1903                                 ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0x%02x at 0x%04x", *ip, ip_offset));
1904                         ++ip;
1905                         break;
1906                 case CEE_ADD_OVF:
1907                 case CEE_ADD_OVF_UN:
1908                 case CEE_MUL_OVF:
1909                 case CEE_MUL_OVF_UN:
1910                 case CEE_SUB_OVF:
1911                 case CEE_SUB_OVF_UN:
1912                         CHECK_STACK_UNDERFLOW (2);
1913                         --cur_stack;
1914                         ++ip;
1915                         break;
1916                 case CEE_ENDFINALLY:
1917                         ++ip;
1918                         start = 1;
1919                         break;
1920                 case CEE_LEAVE:
1921                         target = ip + (gint32)read32(ip + 1) + 5;
1922                         if (target >= end || target < header->code)
1923                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1924                         if (!is_correct_leave (header, ip_offset, target - header->code))
1925                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1926                         ip += 5;
1927                         start = 1;
1928                         break;
1929                 case CEE_LEAVE_S:
1930                         target = ip + (signed char)ip [1] + 2;
1931                         if (target >= end || target < header->code)
1932                                 ADD_INVALID (list, g_strdup_printf ("Branch target out of code at 0x%04x", ip_offset));
1933                         if (!is_correct_leave (header, ip_offset, target - header->code))
1934                                 ADD_INVALID (list, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ip_offset));
1935                         ip += 2;
1936                         start = 1;
1937                         break;
1938                 case CEE_STIND_I:
1939                         CHECK_STACK_UNDERFLOW (2);
1940                         cur_stack -= 2;
1941                         ++ip;
1942                         break;
1943                 case CEE_CONV_U:
1944                         CHECK_STACK_UNDERFLOW (1);
1945                         ++ip;
1946                         break;
1947                 case CEE_UNUSED26:
1948                 case CEE_UNUSED27:
1949                 case CEE_UNUSED28:
1950                 case CEE_UNUSED29:
1951                 case CEE_UNUSED30:
1952                 case CEE_UNUSED31:
1953                 case CEE_UNUSED32:
1954                 case CEE_UNUSED33:
1955                 case CEE_UNUSED34:
1956                 case CEE_UNUSED35:
1957                 case CEE_UNUSED36:
1958                 case CEE_UNUSED37:
1959                 case CEE_UNUSED38:
1960                 case CEE_UNUSED39:
1961                 case CEE_UNUSED40:
1962                 case CEE_UNUSED41:
1963                 case CEE_UNUSED42:
1964                 case CEE_UNUSED43:
1965                 case CEE_UNUSED44:
1966                 case CEE_UNUSED45:
1967                 case CEE_UNUSED46:
1968                 case CEE_UNUSED47:
1969                 case CEE_UNUSED48:
1970                         ++ip;
1971                         break;
1972                 case CEE_PREFIX7:
1973                 case CEE_PREFIX6:
1974                 case CEE_PREFIX5:
1975                 case CEE_PREFIX4:
1976                 case CEE_PREFIX3:
1977                 case CEE_PREFIX2:
1978                 case CEE_PREFIXREF:
1979                         ++ip;
1980                         break;
1981                 case CEE_PREFIX1:
1982                         ++ip;
1983                         switch (*ip) {
1984                         case CEE_ARGLIST:
1985                                 CHECK_STACK_OVERFLOW ();
1986                                 ++ip;
1987                                 break;
1988                         case CEE_CEQ:
1989                         case CEE_CGT:
1990                         case CEE_CGT_UN:
1991                         case CEE_CLT:
1992                         case CEE_CLT_UN:
1993                                 CHECK_STACK_UNDERFLOW (2);
1994                                 --cur_stack;
1995                                 if (type_from_op (256 + *ip, stack + cur_stack - 1) == TYPE_INV)
1996                                         ADD_INVALID (list, g_strdup_printf ("Invalid arguments to opcode 0xFE 0x%02x at 0x%04x", *ip, ip_offset));
1997                                 ++ip;
1998                                 break;
1999                         case CEE_LDFTN:
2000                                 CHECK_STACK_OVERFLOW ();
2001                                 token = read32 (ip + 1);
2002                                 ip += 5;
2003                                 stack [cur_stack].stype = TYPE_PTR;
2004                                 cur_stack++;
2005                                 break;
2006                         case CEE_LDVIRTFTN:
2007                                 CHECK_STACK_UNDERFLOW (1);
2008                                 token = read32 (ip + 1);
2009                                 ip += 5;
2010                                 if (stack [cur_stack - 1].stype != TYPE_OBJ)
2011                                         ADD_INVALID (list, g_strdup_printf ("Invalid argument to ldvirtftn at 0x%04x", ip_offset));
2012                                 stack [cur_stack - 1].stype = TYPE_PTR;
2013                                 break;
2014                         case CEE_UNUSED56:
2015                                 ++ip;
2016                                 break;
2017                         case CEE_LDARG:
2018                         case CEE_LDARGA:
2019                                 if (read16 (ip + 1) >= max_args)
2020                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16 (ip + 1), ip_offset));
2021                                 CHECK_STACK_OVERFLOW ();
2022                                 ++cur_stack;
2023                                 ip += 3;
2024                                 break;
2025                         case CEE_STARG:
2026                                 if (read16 (ip + 1) >= max_args)
2027                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have argument %d at 0x%04x", read16(ip + 1), ip_offset));
2028                                 CHECK_STACK_UNDERFLOW (1);
2029                                 --cur_stack;
2030                                 ip += 3;
2031                                 break;
2032                         case CEE_LDLOC:
2033                         case CEE_LDLOCA:
2034                                 n = read16 (ip + 1);
2035                                 if (n >= header->num_locals)
2036                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", n, ip_offset));
2037                                 /* no need to check if the var is initialized if the address is taken */
2038                                 if (0 && *ip == CEE_LDLOC && !local_state [n])
2039                                         ADD_INVALID (list, g_strdup_printf ("Local var %d is initialized at 0x%04x", n, ip_offset));
2040                                 CHECK_STACK_OVERFLOW ();
2041                                 type_to_eval_stack_type (header->locals [n], stack + cur_stack, *ip == CEE_LDLOCA);
2042                                 ++cur_stack;
2043                                 ip += 3;
2044                                 break;
2045                         case CEE_STLOC:
2046                                 n = read16 (ip + 1);
2047                                 if (n >= header->num_locals)
2048                                         ADD_INVALID (list, g_strdup_printf ("Method doesn't have local var %d at 0x%04x", n, ip_offset));
2049                                 local_state [n] = 1;
2050                                 CHECK_STACK_UNDERFLOW (1);
2051                                 --cur_stack;
2052                                 if (!can_store_type (stack + cur_stack, header->locals [n]))
2053                                         ADD_INVALID (list, g_strdup_printf ("Incompatible type %s in store at 0x%04x", arg_name [stack [cur_stack].stype], ip_offset));
2054                                 ip += 3;
2055                                 break;
2056                         case CEE_LOCALLOC:
2057                                 if (cur_stack != 1)
2058                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only size item in localloc at 0x%04x", ip_offset));
2059                                 if (stack [cur_stack -1].stype != TYPE_I4 && stack [cur_stack -1].stype != TYPE_PTR)
2060                                         ADD_INVALID (list, g_strdup_printf ("Invalid argument to localloc at 0x%04x", ip_offset));
2061                                 stack [cur_stack -1].stype = TYPE_MP;
2062                                 ++ip;
2063                                 break;
2064                         case CEE_UNUSED57:
2065                                 ++ip;
2066                                 break;
2067                         case CEE_ENDFILTER:
2068                                 if (cur_stack != 1)
2069                                         ADD_INVALID (list, g_strdup_printf ("Stack must have only filter result in endfilter at 0x%04x", ip_offset));
2070                                 ++ip;
2071                                 break;
2072                         case CEE_UNALIGNED_:
2073                                 prefix |= PREFIX_UNALIGNED;
2074                                 ++ip;
2075                                 break;
2076                         case CEE_VOLATILE_:
2077                                 prefix |= PREFIX_VOLATILE;
2078                                 ++ip;
2079                                 break;
2080                         case CEE_TAIL_:
2081                                 prefix |= PREFIX_TAIL;
2082                                 ++ip;
2083                                 if (ip < end && (*ip != CEE_CALL && *ip != CEE_CALLI && *ip != CEE_CALLVIRT))
2084                                         ADD_INVALID (list, g_strdup_printf ("tail prefix must be used only with call opcodes at 0x%04x", ip_offset));
2085                                 break;
2086                         case CEE_INITOBJ:
2087                                 CHECK_STACK_UNDERFLOW (1);
2088                                 token = read32 (ip + 1);
2089                                 ip += 5;
2090                                 --cur_stack;
2091                                 break;
2092                         case CEE_CONSTRAINED_:
2093                                 token = read32 (ip + 1);
2094                                 ip += 5;
2095                                 break;
2096                         case CEE_CPBLK:
2097                                 CHECK_STACK_UNDERFLOW (3);
2098                                 ip++;
2099                                 break;
2100                         case CEE_INITBLK:
2101                                 CHECK_STACK_UNDERFLOW (3);
2102                                 ip++;
2103                                 break;
2104                         case CEE_NO_:
2105                                 ip += 2;
2106                                 break;
2107                         case CEE_RETHROW:
2108                                 ++ip;
2109                                 break;
2110                         case CEE_UNUSED:
2111                                 ++ip;
2112                                 break;
2113                         case CEE_SIZEOF:
2114                                 CHECK_STACK_OVERFLOW ();
2115                                 token = read32 (ip + 1);
2116                                 ip += 5;
2117                                 stack [cur_stack].type = &mono_defaults.uint_class->byval_arg;
2118                                 stack [cur_stack].stype = TYPE_I4;
2119                                 cur_stack++;
2120                                 break;
2121                         case CEE_REFANYTYPE:
2122                                 CHECK_STACK_UNDERFLOW (1);
2123                                 ++ip;
2124                                 break;
2125                         case CEE_UNUSED53:
2126                         case CEE_UNUSED54:
2127                         case CEE_UNUSED55:
2128                         case CEE_UNUSED70:
2129                                 ++ip;
2130                                 break;
2131                         }
2132                 }
2133         }
2134         /*
2135          * if ip != end we overflowed: mark as error.
2136          */
2137         if (ip != end || !start) {
2138                 ADD_INVALID (list, g_strdup_printf ("Run ahead of method code at 0x%04x", ip_offset));
2139         }
2140 invalid_cil:
2141
2142         g_free (local_state);
2143         g_free (code);
2144         g_free (stack);
2145         if (signature->hasthis)
2146                 g_free (params);
2147         return list;
2148 }
2149
2150 typedef struct {
2151         const char *name;
2152         guint64 offset;
2153 } FieldDesc;
2154
2155 typedef struct {
2156         const char *name;
2157         const FieldDesc *fields;
2158 } ClassDesc;
2159
2160 static const FieldDesc 
2161 typebuilder_fields[] = {
2162         {"tname", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, name)},
2163         {"nspace", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, nspace)},
2164         {"parent", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, parent)},
2165         {"interfaces", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, interfaces)},
2166         {"methods", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, methods)},
2167         {"properties", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, properties)},
2168         {"fields", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, fields)},
2169         {"attrs", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, attrs)},
2170         {"table_idx", G_STRUCT_OFFSET (MonoReflectionTypeBuilder, table_idx)},
2171         {NULL, 0}
2172 };
2173
2174 static const FieldDesc 
2175 modulebuilder_fields[] = {
2176         {"types", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, types)},
2177         {"cattrs", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, cattrs)},
2178         {"guid", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, guid)},
2179         {"table_idx", G_STRUCT_OFFSET (MonoReflectionModuleBuilder, table_idx)},
2180         {NULL, 0}
2181 };
2182
2183 static const FieldDesc 
2184 assemblybuilder_fields[] = {
2185         {"entry_point", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, entry_point)},
2186         {"modules", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, modules)},
2187         {"name", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, name)},
2188         {"resources", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, resources)},
2189         {"version", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, version)},
2190         {"culture", G_STRUCT_OFFSET (MonoReflectionAssemblyBuilder, culture)},
2191         {NULL, 0}
2192 };
2193
2194 static const FieldDesc 
2195 ctorbuilder_fields[] = {
2196         {"ilgen", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, ilgen)},
2197         {"parameters", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, parameters)},
2198         {"attrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, attrs)},
2199         {"iattrs", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, iattrs)},
2200         {"table_idx", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, table_idx)},
2201         {"call_conv", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, call_conv)},
2202         {"type", G_STRUCT_OFFSET (MonoReflectionCtorBuilder, type)},
2203         {NULL, 0}
2204 };
2205
2206 static const FieldDesc 
2207 methodbuilder_fields[] = {
2208         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, mhandle)},
2209         {"rtype", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, rtype)},
2210         {"parameters", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, parameters)},
2211         {"attrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, attrs)},
2212         {"iattrs", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, iattrs)},
2213         {"name", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, name)},
2214         {"table_idx", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, table_idx)},
2215         {"code", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, code)},
2216         {"ilgen", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, ilgen)},
2217         {"type", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, type)},
2218         {"pinfo", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, pinfo)},
2219         {"pi_dll", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dll)},
2220         {"pi_entry", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, dllentry)},
2221         {"ncharset", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, charset)},
2222         {"native_cc", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, native_cc)},
2223         {"call_conv", G_STRUCT_OFFSET (MonoReflectionMethodBuilder, call_conv)},
2224         {NULL, 0}
2225 };
2226
2227 static const FieldDesc 
2228 fieldbuilder_fields[] = {
2229         {"attrs", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, attrs)},
2230         {"type", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, type)},
2231         {"name", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, name)},
2232         {"def_value", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, def_value)},
2233         {"offset", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, offset)},
2234         {"table_idx", G_STRUCT_OFFSET (MonoReflectionFieldBuilder, table_idx)},
2235         {NULL, 0}
2236 };
2237
2238 static const FieldDesc 
2239 propertybuilder_fields[] = {
2240         {"attrs", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, attrs)},
2241         {"name", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, name)},
2242         {"type", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, type)},
2243         {"parameters", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, parameters)},
2244         {"def_value", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, def_value)},
2245         {"set_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, set_method)},
2246         {"get_method", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, get_method)},
2247         {"table_idx", G_STRUCT_OFFSET (MonoReflectionPropertyBuilder, table_idx)},
2248         {NULL, 0}
2249 };
2250
2251 static const FieldDesc 
2252 ilgenerator_fields[] = {
2253         {"code", G_STRUCT_OFFSET (MonoReflectionILGen, code)},
2254         {"code_len", G_STRUCT_OFFSET (MonoReflectionILGen, code_len)},
2255         {"max_stack", G_STRUCT_OFFSET (MonoReflectionILGen, max_stack)},
2256         {"cur_stack", G_STRUCT_OFFSET (MonoReflectionILGen, cur_stack)},
2257         {"locals", G_STRUCT_OFFSET (MonoReflectionILGen, locals)},
2258         {"ex_handlers", G_STRUCT_OFFSET (MonoReflectionILGen, ex_handlers)},
2259         {NULL, 0}
2260 };
2261
2262 static const FieldDesc 
2263 ilexinfo_fields[] = {
2264         {"handlers", G_STRUCT_OFFSET (MonoILExceptionInfo, handlers)},
2265         {"start", G_STRUCT_OFFSET (MonoILExceptionInfo, start)},
2266         {"len", G_STRUCT_OFFSET (MonoILExceptionInfo, len)},
2267         {"end", G_STRUCT_OFFSET (MonoILExceptionInfo, label)},
2268         {NULL, 0}
2269 };
2270
2271 static const FieldDesc 
2272 ilexblock_fields[] = {
2273         {"extype", G_STRUCT_OFFSET (MonoILExceptionBlock, extype)},
2274         {"type", G_STRUCT_OFFSET (MonoILExceptionBlock, type)},
2275         {"start", G_STRUCT_OFFSET (MonoILExceptionBlock, start)},
2276         {"len", G_STRUCT_OFFSET (MonoILExceptionBlock, len)},
2277         {"filter_offset", G_STRUCT_OFFSET (MonoILExceptionBlock, filter_offset)},
2278         {NULL, 0}
2279 };
2280
2281 static const ClassDesc
2282 emit_classes_to_check [] = {
2283         {"TypeBuilder", typebuilder_fields},
2284         {"ModuleBuilder", modulebuilder_fields},
2285         {"AssemblyBuilder", assemblybuilder_fields},
2286         {"ConstructorBuilder", ctorbuilder_fields},
2287         {"MethodBuilder", methodbuilder_fields},
2288         {"FieldBuilder", fieldbuilder_fields},
2289         {"PropertyBuilder", propertybuilder_fields},
2290         {"ILGenerator", ilgenerator_fields},
2291         {"ILExceptionBlock", ilexblock_fields},
2292         {"ILExceptionInfo", ilexinfo_fields},
2293         {NULL, NULL}
2294 };
2295
2296 static const FieldDesc 
2297 monoevent_fields[] = {
2298         {"klass", G_STRUCT_OFFSET (MonoReflectionEvent, klass)},
2299         {"handle", G_STRUCT_OFFSET (MonoReflectionEvent, event)},
2300         {NULL, 0}
2301 };
2302
2303 static const FieldDesc 
2304 monoproperty_fields[] = {
2305         {"klass", G_STRUCT_OFFSET (MonoReflectionProperty, klass)},
2306         {"prop", G_STRUCT_OFFSET (MonoReflectionProperty, property)},
2307         {NULL, 0}
2308 };
2309
2310 static const FieldDesc 
2311 monofield_fields[] = {
2312         {"klass", G_STRUCT_OFFSET (MonoReflectionField, klass)},
2313         {"fhandle", G_STRUCT_OFFSET (MonoReflectionField, field)},
2314         {NULL, 0}
2315 };
2316
2317 static const FieldDesc 
2318 monomethodinfo_fields[] = {
2319         {"parent", G_STRUCT_OFFSET (MonoMethodInfo, parent)},
2320         {"ret", G_STRUCT_OFFSET (MonoMethodInfo, ret)},
2321         {"attrs", G_STRUCT_OFFSET (MonoMethodInfo, attrs)},
2322         {"iattrs", G_STRUCT_OFFSET (MonoMethodInfo, implattrs)},
2323         {NULL, 0}
2324 };
2325
2326 static const FieldDesc 
2327 monopropertyinfo_fields[] = {
2328         {"parent", G_STRUCT_OFFSET (MonoPropertyInfo, parent)},
2329         {"name", G_STRUCT_OFFSET (MonoPropertyInfo, name)},
2330         {"get_method", G_STRUCT_OFFSET (MonoPropertyInfo, get)},
2331         {"set_method", G_STRUCT_OFFSET (MonoPropertyInfo, set)},
2332         {"attrs", G_STRUCT_OFFSET (MonoPropertyInfo, attrs)},
2333         {NULL, 0}
2334 };
2335
2336 static const FieldDesc 
2337 monomethod_fields[] = {
2338         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
2339         {NULL, 0}
2340 };
2341
2342 static const FieldDesc 
2343 monocmethod_fields[] = {
2344         {"mhandle", G_STRUCT_OFFSET (MonoReflectionMethod, method)},
2345         {NULL, 0}
2346 };
2347
2348 static const FieldDesc 
2349 pinfo_fields[] = {
2350         {"ClassImpl", G_STRUCT_OFFSET (MonoReflectionParameter, ClassImpl)},
2351         {"DefaultValueImpl", G_STRUCT_OFFSET (MonoReflectionParameter, DefaultValueImpl)},
2352         {"MemberImpl", G_STRUCT_OFFSET (MonoReflectionParameter, MemberImpl)},
2353         {"NameImpl", G_STRUCT_OFFSET (MonoReflectionParameter, NameImpl)},
2354         {"PositionImpl", G_STRUCT_OFFSET (MonoReflectionParameter, PositionImpl)},
2355         {"AttrsImpl", G_STRUCT_OFFSET (MonoReflectionParameter, AttrsImpl)},
2356         {NULL, 0}
2357 };
2358
2359 static const ClassDesc
2360 reflection_classes_to_check [] = {
2361         {"MonoEvent", monoevent_fields},
2362         {"MonoProperty", monoproperty_fields},
2363         {"MonoField", monofield_fields},
2364         {"MonoMethodInfo", monomethodinfo_fields},
2365         {"MonoPropertyInfo", monopropertyinfo_fields},
2366         {"MonoMethod", monomethod_fields},
2367         {"MonoCMethod", monocmethod_fields},
2368         {"ParameterInfo", pinfo_fields},
2369         {NULL, NULL}
2370 };
2371
2372 static FieldDesc 
2373 enuminfo_fields[] = {
2374         {"utype", G_STRUCT_OFFSET (MonoEnumInfo, utype)},
2375         {"values", G_STRUCT_OFFSET (MonoEnumInfo, values)},
2376         {"names", G_STRUCT_OFFSET (MonoEnumInfo, names)},
2377         {NULL, 0}
2378 };
2379
2380 static FieldDesc 
2381 delegate_fields[] = {
2382         {"target_type", G_STRUCT_OFFSET (MonoDelegate, target_type)},
2383         {"m_target", G_STRUCT_OFFSET (MonoDelegate, target)},
2384         {"method_name", G_STRUCT_OFFSET (MonoDelegate, method_name)},
2385         {"method_ptr", G_STRUCT_OFFSET (MonoDelegate, method_ptr)},
2386         {"delegate_trampoline", G_STRUCT_OFFSET (MonoDelegate, delegate_trampoline)},
2387         {"method_info", G_STRUCT_OFFSET (MonoDelegate, method_info)},
2388         {NULL, 0}
2389 };
2390
2391 static FieldDesc 
2392 multicast_delegate_fields[] = {
2393         {"prev", G_STRUCT_OFFSET (MonoMulticastDelegate, prev)},
2394         {NULL, 0}
2395 };
2396
2397 static FieldDesc 
2398 async_result_fields[] = {
2399         {"async_state", G_STRUCT_OFFSET (MonoAsyncResult, async_state)},
2400         {"handle", G_STRUCT_OFFSET (MonoAsyncResult, handle)},
2401         {"async_delegate", G_STRUCT_OFFSET (MonoAsyncResult, async_delegate)},
2402         {"data", G_STRUCT_OFFSET (MonoAsyncResult, data)},
2403         {"sync_completed", G_STRUCT_OFFSET (MonoAsyncResult, sync_completed)},
2404         {"completed", G_STRUCT_OFFSET (MonoAsyncResult, completed)},
2405         {"endinvoke_called", G_STRUCT_OFFSET (MonoAsyncResult, endinvoke_called)},
2406         {"async_callback", G_STRUCT_OFFSET (MonoAsyncResult, async_callback)},
2407         {NULL, 0}
2408 };
2409
2410 static FieldDesc 
2411 exception_fields[] = {
2412         {"trace_ips", G_STRUCT_OFFSET (MonoException, trace_ips)},
2413         {"inner_exception", G_STRUCT_OFFSET (MonoException, inner_ex)},
2414         {"message", G_STRUCT_OFFSET (MonoException, message)},
2415         {"help_link", G_STRUCT_OFFSET (MonoException, help_link)},
2416         {"class_name", G_STRUCT_OFFSET (MonoException, class_name)},
2417         {"stack_trace", G_STRUCT_OFFSET (MonoException, stack_trace)},
2418         {"remote_stack_trace", G_STRUCT_OFFSET (MonoException, remote_stack_trace)},
2419         {"remote_stack_index", G_STRUCT_OFFSET (MonoException, remote_stack_index)},
2420         {"hresult", G_STRUCT_OFFSET (MonoException, hresult)},
2421         {"source", G_STRUCT_OFFSET (MonoException, source)},
2422         {NULL, 0}
2423 };
2424
2425 static const ClassDesc
2426 system_classes_to_check [] = {
2427         {"Exception", exception_fields},
2428         {"MonoEnumInfo", enuminfo_fields},
2429         {"Delegate", delegate_fields},
2430         {"MulticastDelegate", multicast_delegate_fields},
2431         {NULL, NULL}
2432 };
2433
2434 static FieldDesc 
2435 stack_frame_fields [] = {
2436         {"ilOffset", G_STRUCT_OFFSET (MonoStackFrame, il_offset)},
2437         {"nativeOffset", G_STRUCT_OFFSET (MonoStackFrame, native_offset)},
2438         {"methodBase", G_STRUCT_OFFSET (MonoStackFrame, method)},
2439         {"fileName", G_STRUCT_OFFSET (MonoStackFrame, filename)},
2440         {"lineNumber", G_STRUCT_OFFSET (MonoStackFrame, line)},
2441         {"columnNumber", G_STRUCT_OFFSET (MonoStackFrame, column)},
2442         {NULL, 0}
2443 };
2444
2445 static const ClassDesc
2446 system_diagnostics_classes_to_check [] = {
2447         {"StackFrame", stack_frame_fields},
2448         {NULL, NULL}
2449 };
2450
2451 static FieldDesc 
2452 mono_method_message_fields[] = {
2453         {"method", G_STRUCT_OFFSET (MonoMethodMessage, method)},
2454         {"args", G_STRUCT_OFFSET (MonoMethodMessage, args)},
2455         {"names", G_STRUCT_OFFSET (MonoMethodMessage, names)},
2456         {"arg_types", G_STRUCT_OFFSET (MonoMethodMessage, arg_types)},
2457         {"ctx", G_STRUCT_OFFSET (MonoMethodMessage, ctx)},
2458         {"rval", G_STRUCT_OFFSET (MonoMethodMessage, rval)},
2459         {"exc", G_STRUCT_OFFSET (MonoMethodMessage, exc)},
2460         {NULL, 0}
2461 };
2462
2463 static const ClassDesc
2464 messaging_classes_to_check [] = {
2465         {"AsyncResult", async_result_fields},
2466         {"MonoMethodMessage", mono_method_message_fields},
2467         {NULL, NULL}
2468 };
2469
2470 static FieldDesc 
2471 transparent_proxy_fields[] = {
2472         {"_rp", G_STRUCT_OFFSET (MonoTransparentProxy, rp)},
2473         {"_class", G_STRUCT_OFFSET (MonoTransparentProxy, remote_class)},
2474         {NULL, 0}
2475 };
2476
2477 static FieldDesc 
2478 real_proxy_fields[] = {
2479         {"class_to_proxy", G_STRUCT_OFFSET (MonoRealProxy, class_to_proxy)},
2480         {NULL, 0}
2481 };
2482
2483 static const ClassDesc
2484 proxy_classes_to_check [] = {
2485         {"TransparentProxy", transparent_proxy_fields},
2486         {"RealProxy", real_proxy_fields},
2487         {NULL, NULL}
2488 };
2489
2490 static FieldDesc 
2491 wait_handle_fields[] = {
2492         {"os_handle", G_STRUCT_OFFSET (MonoWaitHandle, handle)},
2493         {"disposed", G_STRUCT_OFFSET (MonoWaitHandle, disposed)},
2494         {NULL, 0}
2495 };
2496
2497 static FieldDesc 
2498 thread_fields[] = {
2499         {"system_thread_handle", G_STRUCT_OFFSET (MonoThread, handle)},
2500         {"current_culture", G_STRUCT_OFFSET (MonoThread, culture_info)},
2501         {"threadpool_thread", G_STRUCT_OFFSET (MonoThread, threadpool_thread)},
2502         {"state", G_STRUCT_OFFSET (MonoThread, state)},
2503         {"abort_exc", G_STRUCT_OFFSET (MonoThread, abort_exc)},
2504         {"abort_state", G_STRUCT_OFFSET (MonoThread, abort_state)},
2505         {"thread_id", G_STRUCT_OFFSET (MonoThread, tid)},
2506         {NULL, 0}
2507 };
2508
2509 static const ClassDesc
2510 threading_classes_to_check [] = {
2511         {"Thread", thread_fields},
2512         {"WaitHandle", wait_handle_fields},
2513         {NULL, NULL}
2514 };
2515
2516 static const FieldDesc
2517 cinfo_fields[] = {
2518         {"datetime_format", G_STRUCT_OFFSET (MonoCultureInfo, datetime_format)},
2519         {"number_format", G_STRUCT_OFFSET (MonoCultureInfo, number_format)},
2520         {"textinfo", G_STRUCT_OFFSET (MonoCultureInfo, textinfo)},
2521         {"name", G_STRUCT_OFFSET (MonoCultureInfo, name)},
2522         {"displayname", G_STRUCT_OFFSET (MonoCultureInfo, displayname)},
2523         {"englishname", G_STRUCT_OFFSET (MonoCultureInfo, englishname)},
2524         {"nativename", G_STRUCT_OFFSET (MonoCultureInfo, nativename)},
2525         {"iso3lang", G_STRUCT_OFFSET (MonoCultureInfo, iso3lang)},
2526         {"iso2lang", G_STRUCT_OFFSET (MonoCultureInfo, iso2lang)},
2527         {"icu_name", G_STRUCT_OFFSET (MonoCultureInfo, icu_name)},
2528         {"win3lang", G_STRUCT_OFFSET (MonoCultureInfo, win3lang)},
2529         {"compareinfo", G_STRUCT_OFFSET (MonoCultureInfo, compareinfo)},
2530         {NULL, 0}
2531 };
2532
2533 static const FieldDesc
2534 dtfinfo_fields[] = {
2535         {"_AMDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, AMDesignator)},
2536         {"_PMDesignator", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, PMDesignator)},
2537         {"_DayNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, DayNames)},
2538         {"_MonthNames", G_STRUCT_OFFSET (MonoDateTimeFormatInfo, MonthNames)},
2539         {NULL, 0}
2540 };
2541
2542 static const FieldDesc
2543 nfinfo_fields[] = {
2544         {"decimalFormats", G_STRUCT_OFFSET (MonoNumberFormatInfo, decimalFormats)},
2545         {"currencySymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, currencySymbol)},
2546         {"percentSymbol", G_STRUCT_OFFSET (MonoNumberFormatInfo, percentSymbol)},
2547         {"positiveSign", G_STRUCT_OFFSET (MonoNumberFormatInfo, positiveSign)},
2548         {NULL, 0}
2549 };
2550
2551 static const FieldDesc
2552 compinfo_fields[] = {
2553         {"lcid", G_STRUCT_OFFSET (MonoCompareInfo, lcid)},
2554         {"ICU_collator", G_STRUCT_OFFSET (MonoCompareInfo, ICU_collator)},
2555         {NULL, 0}
2556 };
2557
2558 static const FieldDesc
2559 sortkey_fields[] = {
2560         {"str", G_STRUCT_OFFSET (MonoSortKey, str)},
2561         {"options", G_STRUCT_OFFSET (MonoSortKey, options)},
2562         {"key", G_STRUCT_OFFSET (MonoSortKey, key)},
2563         {"lcid", G_STRUCT_OFFSET (MonoSortKey, lcid)},
2564         {NULL, 0}
2565 };
2566
2567 static const ClassDesc
2568 globalization_classes_to_check [] = {
2569         {"CultureInfo", cinfo_fields},
2570         {"DateTimeFormatInfo", dtfinfo_fields},
2571         {"NumberFormatInfo", nfinfo_fields},
2572         {"CompareInfo", compinfo_fields},
2573         {"SortKey", sortkey_fields},
2574         {NULL, NULL}
2575 };
2576
2577 typedef struct {
2578         const char *name;
2579         const ClassDesc *types;
2580 } NameSpaceDesc;
2581
2582 static const NameSpaceDesc
2583 namespaces_to_check[] = {
2584         {"System.Runtime.Remoting.Proxies", proxy_classes_to_check},
2585         {"System.Runtime.Remoting.Messaging", messaging_classes_to_check},
2586         {"System.Reflection.Emit", emit_classes_to_check},
2587         {"System.Reflection", reflection_classes_to_check},
2588         {"System.Threading", threading_classes_to_check},
2589         {"System.Diagnostics", system_diagnostics_classes_to_check},
2590         {"System", system_classes_to_check},
2591         {"System.Globalization", globalization_classes_to_check},
2592         {NULL, NULL}
2593 };
2594
2595 static char*
2596 check_corlib (MonoImage *corlib)
2597 {
2598         MonoClass *klass;
2599         MonoClassField *field;
2600         const FieldDesc *fdesc;
2601         const ClassDesc *cdesc;
2602         const NameSpaceDesc *ndesc;
2603         gint struct_offset;
2604         GString *result = NULL;
2605
2606         for (ndesc = namespaces_to_check; ndesc->name; ++ndesc) {
2607                 for (cdesc = ndesc->types; cdesc->name; ++cdesc) {
2608                         klass = mono_class_from_name (corlib, ndesc->name, cdesc->name);
2609                         if (!klass) {
2610                                 if (!result)
2611                                         result = g_string_new ("");
2612                                 g_string_append_printf (result, "Cannot find class %s\n", cdesc->name);
2613                                 continue;
2614                         }
2615                         mono_class_init (klass);
2616                         /*
2617                          * FIXME: we should also check the size of valuetypes, or
2618                          * we're going to have trouble when we access them in arrays.
2619                          */
2620                         if (klass->valuetype)
2621                                 struct_offset = sizeof (MonoObject);
2622                         else
2623                                 struct_offset = 0;
2624                         for (fdesc = cdesc->fields; fdesc->name; ++fdesc) {
2625                                 field = mono_class_get_field_from_name (klass, fdesc->name);
2626                                 if (!field || (field->offset != (fdesc->offset + struct_offset))) {
2627                                         if (!result)
2628                                                 result = g_string_new ("");
2629                                         g_string_append_printf (result, "field `%s' mismatch in class %s (%ld + %ld != %ld)\n", fdesc->name, cdesc->name, (long) fdesc->offset, (long)struct_offset, (long) (field?field->offset:-1));
2630                                 }
2631                         }
2632                 }
2633         }
2634         if (result)
2635                 return g_string_free (result, FALSE);
2636         return NULL;
2637 }
2638
2639 char*
2640 mono_verify_corlib () {
2641         return check_corlib (mono_defaults.corlib);
2642 }
2643
2644