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