2009-04-28 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
index 8b959659c6d7b25a4fc5b5f640fc278d55def70c..04f13567f7c970e3f2d3c298379917c0a912b16d 100644 (file)
@@ -1,3 +1,12 @@
+/*
+ * metadata-verify.c: Metadata verfication support
+ *
+ * Author:
+ *     Mono Project (http://www.mono-project.com)
+ *
+ * Copyright (C) 2005-2008 Novell, Inc. (http://www.novell.com)
+ */
+
 #include <mono/metadata/object-internals.h>
 #include <mono/metadata/verify.h>
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/tokentype.h>
+#include <mono/metadata/security-manager.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/cil-coff.h>
+#include <mono/utils/strenc.h>
 #include <string.h>
 #include <signal.h>
 #include <ctype.h>
 
+/*
+ TODO add fail fast mode
+ TODO add PE32+ support
+ TODO verify the entry point RVA and content.
+ TODO load_section_table and load_data_directories must take PE32+ into account
+ TODO add section relocation support
+ TODO verify the relocation table, since we really don't use, no need so far.
+ TODO do full PECOFF resources verification 
+ TODO verify in the CLI header entry point and resources
+ TODO implement null token typeref validation  
+ TODO verify table wide invariants for typedef (sorting and uniqueness)
+ TODO implement proper authenticode data directory validation
+ TODO verify properties that require multiple tables to be valid 
+ FIXME use subtraction based bounds checking to avoid overflows
+ FIXME get rid of metadata_streams and other fields from VerifyContext
+*/
+
+#ifdef MONO_VERIFIER_DEBUG
+#define VERIFIER_DEBUG(code) do { code; } while (0)
+#else
+#define VERIFIER_DEBUG(code)
+#endif
+
+#define INVALID_OFFSET ((guint32)-1)
+#define INVALID_ADDRESS 0xffffffff
+
+enum {
+       STAGE_PE,
+       STAGE_CLI,
+       STAGE_TABLES
+};
+
+enum {
+       IMPORT_TABLE_IDX = 1, 
+       RESOURCE_TABLE_IDX = 2,
+       CERTIFICATE_TABLE_IDX = 4,
+       RELOCATION_TABLE_IDX = 5,
+       IAT_IDX = 12,
+       CLI_HEADER_IDX = 14,
+};
+
+enum {
+       STRINGS_STREAM,
+       USER_STRINGS_STREAM,
+       BLOB_STREAM,
+       GUID_STREAM,
+       TILDE_STREAM
+};
+
+
+#define INVALID_TABLE (0xFF)
+/*format: number of bits, number of tables, tables{n. tables} */
+const static unsigned char coded_index_desc[] = {
+#define TYPEDEF_OR_REF_DESC (0)
+       2, /*bits*/
+       3, /*tables*/
+       MONO_TABLE_TYPEDEF,
+       MONO_TABLE_TYPEREF,
+       MONO_TABLE_TYPESPEC,
+
+#define HAS_CONSTANT_DESC (TYPEDEF_OR_REF_DESC + 5)
+       2, /*bits*/
+       3, /*tables*/
+       MONO_TABLE_FIELD,
+       MONO_TABLE_PARAM,
+       MONO_TABLE_PROPERTY,
+
+#define HAS_CATTR_DESC (HAS_CONSTANT_DESC + 5)
+       5, /*bits*/
+       19, /*tables*/
+       MONO_TABLE_METHOD,
+       MONO_TABLE_FIELD,
+       MONO_TABLE_TYPEREF,
+       MONO_TABLE_TYPEDEF,
+       MONO_TABLE_PARAM,
+       MONO_TABLE_INTERFACEIMPL,
+       MONO_TABLE_MEMBERREF,
+       MONO_TABLE_MODULE,
+       MONO_TABLE_DECLSECURITY,
+       MONO_TABLE_PROPERTY, 
+       MONO_TABLE_EVENT,
+       MONO_TABLE_STANDALONESIG,
+       MONO_TABLE_MODULEREF,
+       MONO_TABLE_TYPESPEC,
+       MONO_TABLE_ASSEMBLY,
+       MONO_TABLE_ASSEMBLYREF,
+       MONO_TABLE_FILE,
+       MONO_TABLE_EXPORTEDTYPE,
+       MONO_TABLE_MANIFESTRESOURCE,
+
+#define HAS_FIELD_MARSHAL_DESC (HAS_CATTR_DESC + 21)
+       1, /*bits*/
+       2, /*tables*/
+       MONO_TABLE_FIELD,
+       MONO_TABLE_PARAM,
+
+#define HAS_DECL_SECURITY_DESC (HAS_FIELD_MARSHAL_DESC + 4)
+       2, /*bits*/
+       3, /*tables*/
+       MONO_TABLE_TYPEDEF,
+       MONO_TABLE_METHOD,
+       MONO_TABLE_ASSEMBLY,
+
+#define MEMBERREF_PARENT_DESC (HAS_DECL_SECURITY_DESC + 5)
+       3, /*bits*/
+       5, /*tables*/
+       MONO_TABLE_TYPEDEF,
+       MONO_TABLE_TYPEREF,
+       MONO_TABLE_MODULE,
+       MONO_TABLE_METHOD,
+       MONO_TABLE_TYPESPEC,
+
+#define HAS_SEMANTICS_DESC (MEMBERREF_PARENT_DESC + 7)
+       1, /*bits*/
+       2, /*tables*/
+       MONO_TABLE_EVENT,
+       MONO_TABLE_PROPERTY,
+
+#define METHODDEF_OR_REF_DESC (HAS_SEMANTICS_DESC + 4)
+       1, /*bits*/
+       2, /*tables*/
+       MONO_TABLE_METHOD,
+       MONO_TABLE_MEMBERREF,
+
+#define MEMBER_FORWARDED_DESC (METHODDEF_OR_REF_DESC + 4)
+       1, /*bits*/
+       2, /*tables*/
+       MONO_TABLE_FIELD,
+       MONO_TABLE_METHOD,
+
+#define IMPLEMENTATION_DESC (MEMBER_FORWARDED_DESC + 4)
+       2, /*bits*/
+       3, /*tables*/
+       MONO_TABLE_FILE,
+       MONO_TABLE_ASSEMBLYREF,
+       MONO_TABLE_EXPORTEDTYPE,
+
+#define CATTR_TYPE_DESC (IMPLEMENTATION_DESC + 5)
+       3, /*bits*/
+       5, /*tables*/
+       INVALID_TABLE,
+       INVALID_TABLE,
+       MONO_TABLE_METHOD,
+       MONO_TABLE_MEMBERREF,
+       INVALID_TABLE,
+
+#define RES_SCOPE_DESC (CATTR_TYPE_DESC + 7)
+       2, /*bits*/
+       4, /*tables*/
+       MONO_TABLE_MODULE,
+       MONO_TABLE_MODULEREF,
+       MONO_TABLE_ASSEMBLYREF,
+       MONO_TABLE_TYPEREF,
+
+#define TYPE_OR_METHODDEF_DESC (RES_SCOPE_DESC + 6)
+       1, /*bits*/
+       2, /*tables*/
+       MONO_TABLE_TYPEDEF,
+       MONO_TABLE_METHOD
+};
+
+typedef struct {
+       guint32 rva;
+       guint32 size;
+       guint32 translated_offset;
+} DataDirectory;
+
+typedef struct {
+       guint32 offset;
+       guint32 size;
+} OffsetAndSize;
+
+typedef struct {
+       guint32 baseRVA;
+       guint32 baseOffset;
+       guint32 size;
+       guint32 rellocationsRVA;
+       guint16 numberOfRelocations;
+} SectionHeader;
+
+typedef struct {
+       guint32 row_count;
+       guint32 row_size;
+       guint32 offset;
+} TableInfo;
+
 typedef struct {
        const char *data;
        guint32 size;
        GSList *errors;
        int valid;
+       gboolean is_corlib;
+       MonoImage *image;
+       gboolean report_error;
+       int stage;
+
+       DataDirectory data_directories [16];
+       guint32 section_count;
+       SectionHeader *sections;
+
+       OffsetAndSize metadata_streams [5]; //offset from begin of the image
 } VerifyContext;
 
 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)   \
@@ -33,23 +242,126 @@ typedef struct {
 
 #define ADD_ERROR(__ctx, __msg)        \
        do {    \
-               ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
+               if ((__ctx)->report_error) \
+                       ADD_VERIFY_INFO(__ctx, __msg, MONO_VERIFY_ERROR, MONO_EXCEPTION_INVALID_PROGRAM); \
                (__ctx)->valid = 0; \
+               return; \
        } while (0)
 
 #define CHECK_STATE() do { if (!ctx.valid) goto cleanup; } while (0)
 
+#define CHECK_ERROR() do { if (!ctx->valid) return; } while (0)
+
+static guint32
+pe_signature_offset (VerifyContext *ctx)
+{
+       return read32 (ctx->data + 0x3c);
+}
+
+static guint32
+pe_header_offset (VerifyContext *ctx)
+{
+       return read32 (ctx->data + 0x3c) + 4;
+}
+
+static gboolean
+bounds_check_virtual_address (VerifyContext *ctx, guint32 rva, guint32 size)
+{
+       int i;
+
+       if (rva + size < rva) //overflow
+               return FALSE;
+
+       if (ctx->stage > STAGE_PE) {
+               MonoCLIImageInfo *iinfo = ctx->image->image_info;
+               const int top = iinfo->cli_section_count;
+               MonoSectionTable *tables = iinfo->cli_section_tables;
+               int i;
+               
+               for (i = 0; i < top; i++) {
+                       guint32 base = tables->st_virtual_address;
+                       guint32 end = base + tables->st_raw_data_size;
+
+                       if (rva >= base && rva + size <= end)
+                               return TRUE;
+
+                       /*if ((addr >= tables->st_virtual_address) &&
+                           (addr < tables->st_virtual_address + tables->st_raw_data_size)){
+
+                               return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
+                       }*/
+                       tables++;
+               }
+               return FALSE;
+       }
+
+       if (!ctx->sections)
+               return FALSE;
+
+       for (i = 0; i < ctx->section_count; ++i) {
+               guint32 base = ctx->sections [i].baseRVA;
+               guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
+               if (rva >= base && rva + size <= end)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static gboolean
+bounds_check_datadir (DataDirectory *dir, guint32 offset, guint32 size)
+{
+       if (dir->translated_offset > offset)
+               return FALSE;
+       if (dir->size < size)
+               return FALSE;
+       return offset + size <= dir->translated_offset + dir->size;
+}
+
+static gboolean
+bounds_check_offset (OffsetAndSize *off, guint32 offset, guint32 size)
+{
+       if (off->offset > offset)
+               return FALSE;
+       
+       if (off->size < size)
+               return FALSE;
+
+       return offset + size <= off->offset + off->size;
+}
+
+static guint32
+translate_rva (VerifyContext *ctx, guint32 rva)
+{
+       int i;
+
+       if (ctx->stage > STAGE_PE)
+               return mono_cli_rva_image_map (ctx->image, rva);
+               
+       if (!ctx->sections)
+               return FALSE;
+
+       for (i = 0; i < ctx->section_count; ++i) {
+               guint32 base = ctx->sections [i].baseRVA;
+               guint32 end = ctx->sections [i].baseRVA + ctx->sections [i].size;
+               if (rva >= base && rva <= end) {
+                       guint32 res = (rva - base) + ctx->sections [i].baseOffset;
+                       /* double check */
+                       return res >= ctx->size ? INVALID_OFFSET : res;
+               }
+       }
+
+       return INVALID_OFFSET;
+}
+
 static void
 verify_msdos_header (VerifyContext *ctx)
 {
        guint32 lfanew;
-       if (ctx->size < 128) {
+       if (ctx->size < 128)
                ADD_ERROR (ctx, g_strdup ("Not enough space for the MS-DOS header"));
-               return;
-       }
        if (ctx->data [0] != 0x4d || ctx->data [1] != 0x5a)
                ADD_ERROR (ctx,  g_strdup ("Invalid MS-DOS watermark"));
-       lfanew = read32 (ctx->data + 0x3c);
+       lfanew = pe_signature_offset (ctx);
        if (lfanew > ctx->size - 4)
                ADD_ERROR (ctx, g_strdup ("MS-DOS lfanew offset points to outside of the file"));
 }
@@ -57,7 +369,7 @@ verify_msdos_header (VerifyContext *ctx)
 static void
 verify_pe_header (VerifyContext *ctx)
 {
-       guint32 offset = read32 (ctx->data + 0x3c);
+       guint32 offset = pe_signature_offset (ctx);
        const char *pe_header = ctx->data + offset;
        if (pe_header [0] != 'P' || pe_header [1] != 'E' ||pe_header [2] != 0 ||pe_header [3] != 0)
                ADD_ERROR (ctx,  g_strdup ("Invalid PE header watermark"));
@@ -68,24 +380,1193 @@ verify_pe_header (VerifyContext *ctx)
                ADD_ERROR (ctx, g_strdup ("File with truncated pe header"));
        if (read16 (pe_header) != 0x14c)
                ADD_ERROR (ctx, g_strdup ("Invalid PE header Machine value"));
+}
+
+static void
+verify_pe_optional_header (VerifyContext *ctx)
+{
+       guint32 offset = pe_header_offset (ctx);
+       guint32 header_size, file_alignment;
+       const char *pe_header = ctx->data + offset;
+       const char *pe_optional_header = pe_header + 20;
+
+       header_size = read16 (pe_header + 16);
+       offset += 20;
+
+       if (header_size < 2) /*must be at least 2 or we won't be able to read magic*/
+               ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+       if (offset > ctx->size - header_size || header_size > ctx->size)
+               ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+       if (read16 (pe_optional_header) == 0x10b) {
+               if (header_size != 224)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
+
+               /* LAMESPEC MS plays around this value and ignore it during validation
+               if (read32 (pe_optional_header + 28) != 0x400000)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid Image base %x", read32 (pe_optional_header + 28)));*/
+               if (read32 (pe_optional_header + 32) != 0x2000)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid Section Aligmnent %x", read32 (pe_optional_header + 32)));
+               file_alignment = read32 (pe_optional_header + 36);
+               if (file_alignment != 0x200 && file_alignment != 0x1000)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid file Aligmnent %x", file_alignment));
+               /* All the junk in the middle is irrelevant, specially for mono. */
+               if (read32 (pe_optional_header + 92) > 0x10)
+                       ADD_ERROR (ctx, g_strdup_printf ("Too many data directories %x", read32 (pe_optional_header + 92)));
+       } else {
+               if (read16 (pe_optional_header) == 0x20B)
+                       ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle PE32+"));
+               else
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header magic %d", read16 (pe_optional_header)));
+       }
+}
+
+static void
+load_section_table (VerifyContext *ctx)
+{
+       int i;
+       SectionHeader *sections;
+       guint32 offset =  pe_header_offset (ctx);
+       const char *ptr = ctx->data + offset;
+       guint16 num_sections = ctx->section_count = read16 (ptr + 2);
+
+       offset += 244;/*FIXME, this constant is different under PE32+*/
+       ptr += 244;
+
+       if (num_sections * 40 > ctx->size - offset)
+               ADD_ERROR (ctx, g_strdup ("Invalid PE optional header size"));
+
+       sections = ctx->sections = g_new0 (SectionHeader, num_sections);
+       for (i = 0; i < num_sections; ++i) {
+               sections [i].size = read32 (ptr + 8);
+               sections [i].baseRVA = read32 (ptr + 12);
+               sections [i].baseOffset = read32 (ptr + 20);
+               sections [i].rellocationsRVA = read32 (ptr + 24);
+               sections [i].numberOfRelocations = read16 (ptr + 32);
+               ptr += 40;
+       }
+
+       ptr = ctx->data + offset; /*reset it to the beggining*/
+       for (i = 0; i < num_sections; ++i) {
+               guint32 raw_size, flags;
+               if (sections [i].baseOffset == 0)
+                       ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with intialized data only"));
+               if (sections [i].baseOffset >= ctx->size)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid PointerToRawData %x points beyond EOF", sections [i].baseOffset));
+               if (sections [i].size > ctx->size - sections [i].baseOffset)
+                       ADD_ERROR (ctx, g_strdup ("Invalid VirtualSize points beyond EOF"));
+
+               raw_size = read32 (ptr + 16);
+               if (raw_size < sections [i].size)
+                       ADD_ERROR (ctx, g_strdup ("Metadata verifier doesn't handle sections with SizeOfRawData < VirtualSize"));
+
+               if (raw_size > ctx->size - sections [i].baseOffset)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid SizeOfRawData %x points beyond EOF", raw_size));
+
+               if (sections [i].rellocationsRVA || sections [i].numberOfRelocations)
+                       ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't handle section relocation"));
+
+               flags = read32 (ptr + 36);
+               /*TODO 0xFE0000E0 is all flags from cil-coff.h OR'd. Make it a less magical number*/
+               if (flags == 0 || (flags & ~0xFE0000E0) != 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid section flags %x", flags));
+
+               ptr += 40;
+       }
+}
+
+static gboolean
+is_valid_data_directory (int i)
+{
+       /*LAMESPEC 4 == certificate 6 == debug, MS uses both*/
+       return i == 1 || i == 2 || i == 5 || i == 12 || i == 14 || i == 4 || i == 6; 
+}
+
+static void
+load_data_directories (VerifyContext *ctx)
+{
+       guint32 offset =  pe_header_offset (ctx) + 116; /*FIXME, this constant is different under PE32+*/
+       const char *ptr = ctx->data + offset;
+       int i;
+
+       for (i = 0; i < 16; ++i) {
+               guint32 rva = read32 (ptr);
+               guint32 size = read32 (ptr + 4);
+
+               /*LAMESPEC the authenticode data directory format is different. We don't support CAS, so lets ignore for now.*/
+               if (i == CERTIFICATE_TABLE_IDX) {
+                       ptr += 8;
+                       continue;
+               }
+               if ((rva != 0 || size != 0) && !is_valid_data_directory (i))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d", i));
+
+               if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid data directory %d rva/size pair %x/%x", i, rva, size));
+
+               ctx->data_directories [i].rva = rva;
+               ctx->data_directories [i].size = size;
+               ctx->data_directories [i].translated_offset = translate_rva (ctx, rva);
+
+               ptr += 8;
+       }
+}
+
+#define SIZE_OF_MSCOREE (sizeof ("mscoree.dll"))
+
+#define SIZE_OF_CORMAIN (sizeof ("_CorExeMain"))
+
+static void
+verify_hint_name_table (VerifyContext *ctx, guint32 import_rva, const char *table_name)
+{
+       const char *ptr;
+       guint32 hint_table_rva;
+
+       import_rva = translate_rva (ctx, import_rva);
+       g_assert (import_rva != INVALID_OFFSET);
+
+       hint_table_rva = read32 (ctx->data + import_rva);
+       if (!bounds_check_virtual_address (ctx, hint_table_rva, SIZE_OF_CORMAIN + 2))
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint/Name rva %d for %s", hint_table_rva, table_name));
+
+       hint_table_rva = translate_rva (ctx, hint_table_rva);
+       g_assert (hint_table_rva != INVALID_OFFSET);
+       ptr = ctx->data + hint_table_rva + 2;
+
+       if (memcmp ("_CorExeMain", ptr, SIZE_OF_CORMAIN) && memcmp ("_CorDllMain", ptr, SIZE_OF_CORMAIN)) {
+               char name[SIZE_OF_CORMAIN];
+               memcpy (name, ptr, SIZE_OF_CORMAIN);
+               name [SIZE_OF_CORMAIN - 1] = 0;
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Hint / Name: '%s'", name));
+       }
+}
+
+static void
+verify_import_table (VerifyContext *ctx)
+{
+       DataDirectory it = ctx->data_directories [IMPORT_TABLE_IDX];
+       guint32 offset = it.translated_offset;
+       const char *ptr = ctx->data + offset;
+       guint32 name_rva, ilt_rva, iat_rva;
+
+       g_assert (offset != INVALID_OFFSET);
+
+       if (it.size < 40)
+               ADD_ERROR (ctx, g_strdup_printf ("Import table size %d is smaller than 40", it.size));
+
+       ilt_rva = read32 (ptr);
+       if (!bounds_check_virtual_address (ctx, ilt_rva, 8))
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Lookup Table rva %x", ilt_rva));
+
+       name_rva = read32 (ptr + 12);
+       if (!bounds_check_virtual_address (ctx, name_rva, SIZE_OF_MSCOREE))
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name rva %x", name_rva));
+
+       iat_rva = read32 (ptr + 16);
+       if (!bounds_check_virtual_address (ctx, iat_rva, 8))
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Address Table rva %x", iat_rva));
+
+       if (iat_rva != ctx->data_directories [IAT_IDX].rva)
+               ADD_ERROR (ctx, g_strdup_printf ("Import Address Table rva %x different from data directory entry %x", read32 (ptr + 16), ctx->data_directories [IAT_IDX].rva));
+
+       name_rva = translate_rva (ctx, name_rva);
+       g_assert (name_rva != INVALID_OFFSET);
+       ptr = ctx->data + name_rva;
+
+       if (memcmp ("mscoree.dll", ptr, SIZE_OF_MSCOREE)) {
+               char name[SIZE_OF_MSCOREE];
+               memcpy (name, ptr, SIZE_OF_MSCOREE);
+               name [SIZE_OF_MSCOREE - 1] = 0;
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid Import Table Name: '%s'", name));
+       }
+       
+       verify_hint_name_table (ctx, ilt_rva, "Import Lookup Table");
+       CHECK_ERROR ();
+       verify_hint_name_table (ctx, iat_rva, "Import Address Table");
+}
+
+static void
+verify_resources_table (VerifyContext *ctx)
+{
+       DataDirectory it = ctx->data_directories [RESOURCE_TABLE_IDX];
+       guint32 offset;
+       guint16 named_entries, id_entries;
+       const char *ptr, *root, *end;
+
+       if (it.rva == 0)
+               return;
+
+       if (it.size < 16)
+               ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, must be at least 16 bytes long but it's %d long", it.size));
+
+       offset = it.translated_offset;
+       root = ptr = ctx->data + offset;
+       end = root + it.size;
+
+       g_assert (offset != INVALID_OFFSET);
+
+       named_entries = read16 (ptr + 12);
+       id_entries = read16 (ptr + 14);
+
+       if ((named_entries + id_entries) * 8 + 16 > it.size)
+               ADD_ERROR (ctx, g_strdup_printf ("Resource section is too small, the number of entries (%d) doesn't fit on it's size %d", named_entries + id_entries, it.size));
+
+       /* XXX at least one unmanaged resource is added due to a call to AssemblyBuilder::DefineVersionInfoResource () 
+       if (named_entries || id_entries)
+               ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support full verification of PECOFF resources"));
+       */
+}
+
+/*----------nothing from here on can use data_directory---*/
+
+static DataDirectory
+get_data_dir (VerifyContext *ctx, int idx)
+{
+       MonoCLIImageInfo *iinfo = ctx->image->image_info;
+       MonoPEDirEntry *entry= &iinfo->cli_header.datadir.pe_export_table;
+       DataDirectory res;
+
+       entry += idx;
+       res.rva = entry->rva;
+       res.size = entry->size;
+       res.translated_offset = translate_rva (ctx, res.rva);
+       return res;
+
+}
+static void
+verify_cli_header (VerifyContext *ctx)
+{
+       DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
+       guint32 offset;
+       const char *ptr;
+       int i;
+
+       if (it.rva == 0)
+               ADD_ERROR (ctx, g_strdup_printf ("CLI header missing"));
+
+       if (it.size != 72)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size in data directory %d must be 72", it.size));
+
+       offset = it.translated_offset;
+       ptr = ctx->data + offset;
+
+       g_assert (offset != INVALID_OFFSET);
+
+       if (read16 (ptr) != 72)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid cli header size %d must be 72", read16 (ptr)));
+
+       if (!bounds_check_virtual_address (ctx, read32 (ptr + 8), read32 (ptr + 12)))
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid medatata section rva/size pair %x/%x", read32 (ptr + 8), read32 (ptr + 12)));
+
+
+       if (!read32 (ptr + 8) || !read32 (ptr + 12))
+               ADD_ERROR (ctx, g_strdup_printf ("Missing medatata section in the CLI header"));
+
+       if ((read32 (ptr + 16) & ~0x0001000B) != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid CLI header flags"));
+
+       ptr += 24;
+       for (i = 0; i < 6; ++i) {
+               guint32 rva = read32 (ptr);
+               guint32 size = read32 (ptr + 4);
+
+               if (rva != 0 && !bounds_check_virtual_address (ctx, rva, size))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid cli section %i rva/size pair %x/%x", i, rva, size));
+
+               ptr += 8;
+
+               if (rva && i > 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Metadata verifier doesn't support cli header section %d", i));
+       }
+}
+
+static guint32
+pad4 (guint32 offset)
+{
+       if (offset & 0x3) //pad to the next 4 byte boundary
+               offset = (offset & ~0x3) + 4;
+       return offset;
+}
+
+static void
+verify_metadata_header (VerifyContext *ctx)
+{
+       int i;
+       DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
+       guint32 offset;
+       const char *ptr;
+
+       offset = it.translated_offset;
+       ptr = ctx->data + offset;
+       g_assert (offset != INVALID_OFFSET);
+
+       //build a directory entry for the metadata root
+       ptr += 8;
+       it.rva = read32 (ptr);
+       ptr += 4;
+       it.size = read32 (ptr);
+       it.translated_offset = offset = translate_rva (ctx, it.rva);
+
+       ptr = ctx->data + offset;
+       g_assert (offset != INVALID_OFFSET);
+
+       if (it.size < 20)
+               ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least 20 bytes required for initial decoding)", it.size));
+
+       if (read32 (ptr) != 0x424A5342)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid metadata signature, expected 0x424A5342 but got %08x", read32 (ptr)));
+
+       offset = pad4 (offset + 16 + read32 (ptr + 12));
+
+       if (!bounds_check_datadir (&it, offset, 4))
+               ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small %d (at least %d bytes required for flags decoding)", it.size, offset + 4 - it.translated_offset));
+
+       ptr = ctx->data + offset; //move to streams header 
+
+       if (read16 (ptr + 2) != 5)
+               ADD_ERROR (ctx, g_strdup_printf ("Metadata root section have %d streams (it must have exactly 5)", read16 (ptr + 2)));
+
+       ptr += 4;
+       offset += 4;
+
+       for (i = 0; i < 5; ++i) {
+               guint32 stream_off, stream_size;
+               int string_size, stream_idx;
+
+               if (!bounds_check_datadir (&it, offset, 8))
+                       ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small for initial decode of stream header %d, missing %d bytes", i, offset + 9 - it.translated_offset));
+
+               stream_off = it.translated_offset + read32 (ptr);
+               stream_size = read32 (ptr + 4);
+
+               if (!bounds_check_datadir (&it,  stream_off, stream_size))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid stream header %d offset/size pair %x/%x", 0, stream_off, stream_size));
+
+               ptr += 8;
+               offset += 8;
+
+               for (string_size = 0; string_size < 32; ++string_size) {
+                       if (!bounds_check_datadir (&it, offset++, 1))
+                               ADD_ERROR (ctx, g_strdup_printf ("Metadata root section is too small to decode stream header %d name", i));
+                       if (!ptr [string_size])
+                               break;
+               }
+
+               if (ptr [string_size])
+                       ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d name larger than 32 bytes", i));
+
+               if (!strncmp ("#Strings", ptr, 9))
+                       stream_idx = STRINGS_STREAM;
+               else if (!strncmp ("#US", ptr, 4))
+                       stream_idx = USER_STRINGS_STREAM;
+               else if (!strncmp ("#Blob", ptr, 6))
+                       stream_idx = BLOB_STREAM;
+               else if (!strncmp ("#GUID", ptr, 6))
+                       stream_idx = GUID_STREAM;
+               else if (!strncmp ("#~", ptr, 3))
+                       stream_idx = TILDE_STREAM;
+               else
+                       ADD_ERROR (ctx, g_strdup_printf ("Metadata stream header %d invalid name %s", i, ptr));
+
+               if (ctx->metadata_streams [stream_idx].offset != 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Duplicated metadata stream header %s", ptr));
+
+               ctx->metadata_streams [stream_idx].offset = stream_off;
+               ctx->metadata_streams [stream_idx].size = stream_size;
+
+               offset = pad4 (offset);
+               ptr = ctx->data + offset;
+       }
+}
+
+static void
+verify_tables_schema (VerifyContext *ctx)
+{
+       OffsetAndSize tables_area = ctx->metadata_streams [TILDE_STREAM];
+       unsigned offset = tables_area.offset;
+       const char *ptr = ctx->data + offset;
+       guint64 valid_tables;
+       guint32 count;
+       int i;
+
+       //printf ("tables_area size %d offset %x %s\n", tables_area.size, tables_area.offset, ctx->image->name);
+       if (tables_area.size < 24)
+               ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for initial decoding (requires 24 bytes)", tables_area.size));
+
+       //printf ("ptr %x %x\n", ptr[4], ptr[5]);
+       if (ptr [4] != 2 && ptr [4] != 1)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata major version %d, expected 2", ptr [4]));
+       if (ptr [5] != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata minor version %d, expected 0", ptr [5]));
+
+       if ((ptr [6] & ~0x7) != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Invalid table schemata heap sizes 0x%02x, only bits 0, 1 and 2 can be set", ((unsigned char *) ptr) [6]));
+
+       valid_tables = read64 (ptr + 8);
+       count = 0;
+       for (i = 0; i < 64; ++i) {
+               if (!(valid_tables & ((guint64)1 << i)))
+                       continue;
+
+               /*MS Extensions: 0x3 0x5 0x7 0x13 0x16
+                 Unused: 0x1E 0x1F 0x2D-0x3F
+                 We don't care about the MS extensions.*/
+               if (i == 0x3 || i == 0x5 || i == 0x7 || i == 0x13 || i == 0x16)
+                       ADD_ERROR (ctx, g_strdup_printf ("The metadata verifies doesn't support MS specific table %x", i));
+               if (i == 0x1E || i == 0x1F || i >= 0x2D)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid table %x", i));
+               ++count;
+       }
+
+       if (tables_area.size < 24 + count * 4)
+               ADD_ERROR (ctx, g_strdup_printf ("Table schemata size (%d) too small to for decoding row counts (requires %d bytes)", tables_area.size, 24 + count * 4));
+       ptr += 24;
+
+       for (i = 0; i < 64; ++i) {
+               if (valid_tables & ((guint64)1 << i)) {
+                       guint32 row_count = read32 (ptr);
+                       if (row_count > (1 << 25) - 1)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid Table %d row count, mono only supports ", i));
+                       ptr += 4;
+               }
+       }
+}
+
+/*----------nothing from here on can use data_directory or metadata_streams ---*/
+
+static guint32
+get_col_offset (VerifyContext *ctx, int table, int column)
+{
+       guint32 bitfield = ctx->image->tables [table].size_bitfield;
+       guint32 offset = 0;
+
+       while (column-- > 0)
+               offset += mono_metadata_table_size (bitfield, column);
+
+       return offset;
+}
+
+static guint32
+get_col_size (VerifyContext *ctx, int table, int column)
+{
+       return mono_metadata_table_size (ctx->image->tables [table].size_bitfield, column);
+}
+
+static OffsetAndSize
+get_metadata_stream (VerifyContext *ctx, MonoStreamHeader *header)
+{
+       OffsetAndSize res;
+       res.offset = header->data - ctx->data;
+       res.size = header->size;
 
+       return res;
 }
 
+static gboolean
+is_valid_string_full (VerifyContext *ctx, guint32 offset, gboolean allow_empty)
+{
+       OffsetAndSize strings = get_metadata_stream (ctx, &ctx->image->heap_strings);
+       glong length;
+       const char *data = ctx->data + strings.offset;
+
+       if (offset >= strings.size)
+               return FALSE;
+       if (data + offset < data) //FIXME, use a generalized and smart unsigned add with overflow check and fix the whole thing  
+               return FALSE;
+
+       if (!mono_utf8_validate_and_len_with_bounds (data + offset, strings.size - offset, &length, NULL))
+               return FALSE;
+       return allow_empty || length > 0;
+}
+
+static gboolean
+is_valid_string (VerifyContext *ctx, guint32 offset)
+{
+       return is_valid_string_full (ctx, offset, TRUE);
+}
+
+static gboolean
+is_valid_non_empty_string (VerifyContext *ctx, guint32 offset)
+{
+       return is_valid_string_full (ctx, offset, FALSE);
+}
+
+static gboolean
+is_valid_guid (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize guids = get_metadata_stream (ctx, &ctx->image->heap_guid);
+       return guids.size >= 8 && guids.size - 8 >= offset;
+}
+
+static guint32
+get_coded_index_token (int token_kind, guint32 coded_token)
+{
+       guint32 bits = coded_index_desc [token_kind];
+       return coded_token >> bits;
+}
+
+static guint32
+make_coded_token (int kind, guint32 table, guint32 table_idx)
+{
+       guint32 bits = coded_index_desc [kind++];
+       guint32 tables = coded_index_desc [kind++];
+       guint32 i;
+       for (i = 0; i < tables; ++i) {
+               if (coded_index_desc [kind++] == table)
+                       return ((table_idx + 1) << bits) | i; 
+       }
+       g_assert_not_reached ();
+       return -1;
+}
+
+static gboolean
+is_valid_coded_index (VerifyContext *ctx, int token_kind, guint32 coded_token)
+{
+       guint32 bits = coded_index_desc [token_kind++];
+       guint32 table_count = coded_index_desc [token_kind++];
+       guint32 table = coded_token & ((1 << bits) - 1);
+       guint32 token = coded_token >> bits;
+
+       if (table >= table_count)
+               return FALSE;
+
+       /*token_kind points to the first table idx*/
+       table = coded_index_desc [token_kind + table];
+
+       if (table == INVALID_TABLE)
+               return FALSE;
+       return token <= ctx->image->tables [table].rows;
+}
+
+typedef struct {
+       guint32 token;
+       guint32 col_size;
+       guint32 col_offset;
+} RowLocator;
+
+static int
+token_locator (const void *a, const void *b)
+{
+       RowLocator *loc = (RowLocator *)a;
+       unsigned const char *row = (unsigned const char *)b;
+       guint32 token = loc->col_size == 2 ? read16 (row + loc->col_offset) : read32 (row + loc->col_offset);
+
+       VERIFIER_DEBUG ( printf ("\tfound token %x\n", token) );
+       return (int)loc->token - (int)token;
+}
+
+static int
+search_sorted_table (VerifyContext *ctx, int table, int column, guint32 coded_token)
+{
+       MonoTableInfo *tinfo = &ctx->image->tables [table];
+       RowLocator locator;
+       const char *res, *base;
+       locator.token = coded_token;
+       locator.col_offset = get_col_offset (ctx, table, column);
+       locator.col_size = get_col_size (ctx, table, column);
+       base = tinfo->base;
+
+       VERIFIER_DEBUG ( printf ("looking token %x table %d col %d rsize %d roff %d\n", coded_token, table, column, locator.col_size, locator.col_offset) );
+       res = bsearch (&locator, base, tinfo->rows, tinfo->row_size, token_locator);
+       if (!res)
+               return -1;
+
+       return (res - base) / tinfo->rows;
+}
+
+/*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
+static const char*
+get_string_ptr (VerifyContext *ctx, guint offset)
+{
+       return ctx->image->heap_strings.data + offset;
+}
+
+/*WARNING: This function doesn't verify if the strings @offset points to a valid string*/
+static int
+string_cmp (VerifyContext *ctx, const char *str, guint offset)
+{
+       if (offset == 0)
+               return strcmp (str, "");
+
+       return strcmp (str, get_string_ptr (ctx, offset));
+}
+
+static gboolean
+typedef_is_system_object (VerifyContext *ctx, guint32 *data)
+{
+       return ctx->is_corlib && !string_cmp (ctx, "System", data [MONO_TYPEDEF_NAME]) && !string_cmp (ctx, "Object", data [MONO_TYPEDEF_NAMESPACE]);
+}
+
+static gboolean
+is_valid_field_signature (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 2 && blob.size - 2 >= offset;
+}
+
+static gboolean
+is_valid_method_signature (VerifyContext *ctx, guint32 offset)
+{
+       OffsetAndSize blob = get_metadata_stream (ctx, &ctx->image->heap_blob);
+       //TODO do proper verification
+       return blob.size >= 2 && blob.size - 2 >= offset;
+}
+
+static gboolean
+is_valid_method_header (VerifyContext *ctx, guint32 rva)
+{
+       //TODO do proper method header validation
+       return mono_cli_rva_image_map (ctx->image, rva) != INVALID_ADDRESS;
+}
+
+static void
+verify_module_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_MODULE];
+       guint32 data [MONO_MODULE_SIZE];
+
+       if (table->rows != 1)
+               ADD_ERROR (ctx, g_strdup_printf ("Module table must have exactly one row, but have %d", table->rows));
+
+       mono_metadata_decode_row (table, 0, data, MONO_MODULE_SIZE);
+
+       if (!is_valid_non_empty_string (ctx, data [MONO_MODULE_NAME]))
+               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid name, string index 0x%08x", data [MONO_MODULE_NAME]));
+
+       if (!is_valid_guid (ctx, data [MONO_MODULE_MVID]))
+               ADD_ERROR (ctx, g_strdup_printf ("Module has an invalid Mvid, guid index %x", data [MONO_MODULE_MVID]));
+
+       if (data [MONO_MODULE_ENC] != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero Enc field %x", data [MONO_MODULE_ENC]));
+
+       if (data [MONO_MODULE_ENCBASE] != 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Module has a non zero EncBase field %x", data [MONO_MODULE_ENCBASE]));
+}
+
+static void
+verify_typeref_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEREF];
+       guint32 data [MONO_TYPEREF_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_TYPEREF_SIZE);
+               if (!is_valid_coded_index (ctx, RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d coded index 0x%08x", i, data [MONO_TYPEREF_SCOPE]));
+               
+               if (!get_coded_index_token (RES_SCOPE_DESC, data [MONO_TYPEREF_SCOPE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("The metadata verifier doesn't support null ResolutionScope tokens for typeref row %d", i));
+
+               if (!data [MONO_TYPEREF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d name token 0x%08x", i, data [MONO_TYPEREF_NAME]));
+
+               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typeref row %d namespace token 0x%08x", i, data [MONO_TYPEREF_NAMESPACE]));
+       }
+}
+
+/*bits 9,11,14,15,19,21,24-31 */
+#define INVALID_TYPEDEF_FLAG_BITS ((1 << 9) | (1 << 11) | (1 << 14) | (1 << 15) | (1 << 19) | (1 << 21) | 0xFF000000)
+static void
+verify_typedef_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+       guint32 data [MONO_TYPEDEF_SIZE];
+       guint32 fieldlist = 1, methodlist = 1;
+       int i;
+
+       if (table->rows == 0)
+               ADD_ERROR (ctx, g_strdup_printf ("Typedef table must have exactly at least one row"));
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_TYPEDEF_SIZE);
+               if (data [MONO_TYPEDEF_FLAGS] & INVALID_TYPEDEF_FLAG_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid flags field 0x%08x", i, data [MONO_TYPEDEF_FLAGS]));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_LAYOUT_MASK) == 0x18)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid class layout 0x18", i));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == 0x30000)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+               if ((data [MONO_TYPEDEF_FLAGS] & 0xC00000) != 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d mono doesn't support custom string format", i));
+
+               if (!data [MONO_TYPEDEF_NAME] || !is_valid_non_empty_string (ctx, data [MONO_TYPEDEF_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid name token %08x", i, data [MONO_TYPEDEF_NAME]));
+
+               if (data [MONO_TYPEREF_NAMESPACE] && !is_valid_non_empty_string (ctx, data [MONO_TYPEREF_NAMESPACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d invalid namespace token %08x", i, data [MONO_TYPEREF_NAMESPACE]));
+
+               if (i == 0) {
+                       if (data [MONO_TYPEDEF_EXTENDS] != 0)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row 0 for the special <module> type must have a null extend field"));
+               } else {
+                       if (typedef_is_system_object (ctx, data) && data [MONO_TYPEDEF_EXTENDS] != 0)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for System.Object must have a null extend field", i));
+       
+                       if (data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_INTERFACE) {
+                               if (data [MONO_TYPEDEF_EXTENDS])
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must have a null extend field", i));
+                               if ((data [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_ABSTRACT) == 0)
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for interface type must be abstract", i));
+                       } else {
+                               if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS]))
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d extend field coded index 0x%08x", i, data [MONO_TYPEDEF_EXTENDS]));
+       
+                               if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_TYPEDEF_EXTENDS])) 
+                                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d for non-interface type must have a non-null extend field", i));
+                       }
+               }
+
+               if (data [MONO_TYPEDEF_FIELD_LIST] == 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList be be >= 1", i));
+
+               if (data [MONO_TYPEDEF_FIELD_LIST] > ctx->image->tables [MONO_TABLE_FIELD].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_FIELD_LIST]));
+
+               if (data [MONO_TYPEDEF_FIELD_LIST] < fieldlist)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d FieldList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_FIELD_LIST], fieldlist));
+
+               if (data [MONO_TYPEDEF_METHOD_LIST] == 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList be be >= 1", i));
+
+               if (data [MONO_TYPEDEF_METHOD_LIST] > ctx->image->tables [MONO_TABLE_METHOD].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x is out of range", i, data [MONO_TYPEDEF_METHOD_LIST]));
+
+               if (data [MONO_TYPEDEF_METHOD_LIST] < methodlist)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid typedef row %d MethodList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_TYPEDEF_METHOD_LIST], methodlist));
+
+
+               fieldlist = data [MONO_TYPEDEF_FIELD_LIST];
+               methodlist = data [MONO_TYPEDEF_METHOD_LIST];
+       }
+}
+
+/*bits 3,11,14 */
+#define INVALID_FIELD_FLAG_BITS ((1 << 3) | (1 << 11) | (1 << 14))
+static void
+verify_field_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
+       guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
+       int i;
+
+       module_field_list = (guint32)-1;
+       if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
+               MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+               module_field_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_FIELD_LIST);
+       }
+       
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_FIELD_SIZE);
+               flags = data [MONO_FIELD_FLAGS];
+
+               if (flags & INVALID_FIELD_FLAG_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid flags field 0x%08x", i, flags));
+
+               if ((flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) == 0x7)         
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid field visibility 0x7", i));
+
+               if ((flags & (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY)) == (FIELD_ATTRIBUTE_LITERAL | FIELD_ATTRIBUTE_INIT_ONLY))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d cannot be InitOnly and Literal at the same time", i));
+
+               if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is RTSpecialName but not SpecialName", i));
+
+               if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but not Static", i));
+
+               if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) &&
+                               search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_FIELD, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has FieldMarshal but there is no corresponding row in the FieldMarshal table", i));
+
+               if ((flags & FIELD_ATTRIBUTE_HAS_DEFAULT) &&
+                               search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
+
+               if ((flags & FIELD_ATTRIBUTE_LITERAL) &&
+                               search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_FIELD, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is Literal but there is no corresponding row in the Constant table", i));
+
+               if ((flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA) &&
+                               search_sorted_table (ctx, MONO_TABLE_FIELDRVA, MONO_FIELD_RVA_FIELD, i + 1) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d has Default but there is no corresponding row in the Constant table", i));
+
+               if (!data [MONO_FIELD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_FIELD_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid name token %08x", i, data [MONO_FIELD_NAME]));
+
+               //TODO verify contant flag
+               if (!data [MONO_FIELD_SIGNATURE] || !is_valid_field_signature (ctx, data [MONO_FIELD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d invalid signature token %08x", i, data [MONO_FIELD_SIGNATURE]));
 
-GSList*
-mono_image_verify (const char *data, guint32 size)
+               if (i + 1 < module_field_list) {
+                       guint32 access = flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
+                       if (!(flags & FIELD_ATTRIBUTE_STATIC))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but is not static", i));
+                       if (access != FIELD_ATTRIBUTE_COMPILER_CONTROLLED && access != FIELD_ATTRIBUTE_PRIVATE && access != FIELD_ATTRIBUTE_PUBLIC)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid field row %d is a global variable but have wrong visibility %x", i, access));
+               }
+       }
+}
+
+/*bits 6,8,9,10,11,13,14,15*/
+#define INVALID_METHOD_IMPLFLAG_BITS ((1 << 6) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 13) | (1 << 14) | (1 << 15))
+static void
+verify_method_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 data [MONO_METHOD_SIZE], flags, implflags, rva, module_method_list, access, code_type;
+       guint32 paramlist = 1;
+       gboolean is_ctor, is_cctor;
+       const char *name;
+       int i;
+
+       module_method_list = (guint32)-1;
+       if (ctx->image->tables [MONO_TABLE_TYPEDEF].rows > 1) {
+               MonoTableInfo *type = &ctx->image->tables [MONO_TABLE_TYPEDEF];
+               module_method_list = mono_metadata_decode_row_col (type, 1, MONO_TYPEDEF_METHOD_LIST);
+       }
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_METHOD_SIZE);
+               rva = data [MONO_METHOD_RVA];
+               implflags = data [MONO_METHOD_IMPLFLAGS];
+               flags = data [MONO_METHOD_FLAGS];
+               access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
+               code_type = implflags & METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK;
+               
+
+               if (implflags & INVALID_METHOD_IMPLFLAG_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid implflags field 0x%08x", i, implflags));
+
+               if (access == 0x7)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid MemberAccessMask 0x7", i));
+
+               if (!data [MONO_METHOD_NAME] || !is_valid_non_empty_string (ctx, data [MONO_METHOD_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid name field 0x%08x", i, data [MONO_METHOD_NAME]));
+
+               name = get_string_ptr (ctx, data [MONO_METHOD_NAME]);
+               is_ctor = !strcmp (".ctor", name);
+               is_cctor = !strcmp (".cctor", name);
+
+               if ((is_ctor || is_cctor) &&
+                       search_sorted_table (ctx, MONO_TABLE_GENERICPARAM, MONO_GENERICPARAM_OWNER, make_coded_token (TYPE_OR_METHODDEF_DESC, MONO_TABLE_METHOD, i)) != -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d .ctor or .cctor has generic param", i));
+
+               if ((flags & METHOD_ATTRIBUTE_STATIC) && (flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_NEW_SLOT)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is static and (final, virtual or new slot)", i));
+               
+               if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
+                       if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract and PinvokeImpl", i));
+                       if (!(flags & METHOD_ATTRIBUTE_VIRTUAL))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is Abstract but not Virtual", i));
+               }
+
+               if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && (flags & (METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompileControlled and SpecialName or RtSpecialName", i));
+
+               if ((flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RTSpecialName but not SpecialName", i));
+
+               //XXX no checks against cas stuff 10,11,12,13)
+
+               //TODO check iface with .ctor (15,16)
+
+               if (!data [MONO_METHOD_SIGNATURE] || !is_valid_method_signature (ctx, data [MONO_METHOD_SIGNATURE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d invalid signature token %08x", i, data [MONO_METHOD_SIGNATURE]));
+
+               if (i + 1 < module_method_list) {
+                       if (!(flags & METHOD_ATTRIBUTE_STATIC))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not Static", i));
+                       if (flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_VIRTUAL))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but is Abstract or Virtual", i));
+                       if (!(access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED || access == METHOD_ATTRIBUTE_PUBLIC || access == METHOD_ATTRIBUTE_PRIVATE))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is a global method but not CompilerControled, Public or Private", i));
+               }
+
+               //TODO check valuetype for synchronized
+
+               if ((flags & (METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_STRICT)) && !(flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is (Final, NewSlot or Strict) but not Virtual", i));
+
+               if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && (flags & METHOD_ATTRIBUTE_VIRTUAL))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl and Virtual", i));
+
+               if (!(flags & METHOD_ATTRIBUTE_ABSTRACT) && !rva && !(flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) && 
+                               !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is not Abstract and neither PinvokeImpl, Runtime, InternalCall or with RVA != 0", i));
+
+               if (access == METHOD_ATTRIBUTE_COMPILER_CONTROLLED && !(rva || (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is CompilerControlled but neither RVA != 0 or PinvokeImpl", i));
+
+               //TODO check signature contents
+
+               if (rva) {
+                       if (flags & METHOD_ATTRIBUTE_ABSTRACT)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is Abstract", i));
+                       if (code_type == METHOD_IMPL_ATTRIBUTE_OPTIL)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA != 0 but is CodeTypeMask is neither Native, CIL or Runtime", i));
+                       if (!is_valid_method_header (ctx, rva))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d RVA points to an invalid method header", i));
+               } else {
+                       if (!(flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_PINVOKE_IMPL)) && !(implflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && code_type != METHOD_IMPL_ATTRIBUTE_RUNTIME)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d has RVA = 0 but neither Abstract, InternalCall, Runtime or PinvokeImpl", i));
+               }
+
+               if ((flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                       if (rva)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has RVA != 0", i));
+                       if (search_sorted_table (ctx, MONO_TABLE_IMPLMAP, MONO_IMPLMAP_MEMBER, make_coded_token (MEMBER_FORWARDED_DESC, MONO_TABLE_METHOD, i)) == -1)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is PinvokeImpl but has no row in the ImplMap table", i));
+               }
+               if (flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME && !is_ctor && !is_cctor)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is RtSpecialName but not named .ctor or .cctor", i));
+
+               if ((is_ctor || is_cctor) && !(flags & METHOD_ATTRIBUTE_RT_SPECIAL_NAME))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d is named .ctor or .cctor but is not RtSpecialName", i));
+
+               if (data [MONO_METHOD_PARAMLIST] == 0)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList be be >= 1", i));
+
+               if (data [MONO_METHOD_PARAMLIST] < paramlist)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x can't be smaller than of previous row 0x%08x", i, data [MONO_METHOD_PARAMLIST], paramlist));
+
+               if (data [MONO_METHOD_PARAMLIST] > ctx->image->tables [MONO_TABLE_PARAM].rows + 1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid method row %d ParamList rowid 0x%08x is out of range", i, data [MONO_METHOD_PARAMLIST]));
+
+               paramlist = data [MONO_METHOD_PARAMLIST];
+
+       }
+}
+
+static guint32
+get_next_param_count (VerifyContext *ctx, guint32 *current_method)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 row = *current_method;
+       guint32 paramlist, tmp;
+
+
+       paramlist = mono_metadata_decode_row_col (table, row++, MONO_METHOD_PARAMLIST);
+       while (row < table->rows) {
+               tmp = mono_metadata_decode_row_col (table, row, MONO_METHOD_PARAMLIST);
+               if (tmp > paramlist) {
+                       *current_method = row;
+                       return tmp - paramlist;
+               }
+               ++row;
+       }
+
+       /*no more methods, all params apply to the last one*/
+       *current_method = table->rows;
+       return (guint32)-1;
+}
+
+
+#define INVALID_PARAM_FLAGS_BITS ((1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15))
+static void
+verify_param_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_PARAM];
+       guint32 data [MONO_PARAM_SIZE], flags, sequence = 0, remaining_params, current_method = 0;
+       gboolean first_param = TRUE;
+       int i;
+
+       remaining_params = get_next_param_count (ctx, &current_method);
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_PARAM_SIZE);
+               flags = data [MONO_PARAM_FLAGS];
+
+               if (flags & INVALID_PARAM_FLAGS_BITS)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d bad Flags value 0x%08x", i, flags));
+
+               if (search_sorted_table (ctx, MONO_TABLE_CONSTANT, MONO_CONSTANT_PARENT, make_coded_token (HAS_CONSTANT_DESC, MONO_TABLE_PARAM, i)) == -1) {
+                       if (flags & PARAM_ATTRIBUTE_HAS_DEFAULT)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 1 but no owned row in Contant table", i));
+               } else {
+                       if (!(flags & PARAM_ATTRIBUTE_HAS_DEFAULT))
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasDefault = 0 but has owned row in Contant table", i));
+               }
+
+               if ((flags & PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) && search_sorted_table (ctx, MONO_TABLE_FIELDMARSHAL, MONO_FIELD_MARSHAL_PARENT, make_coded_token (HAS_FIELD_MARSHAL_DESC, MONO_TABLE_PARAM, i)) == -1)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d HasFieldMarshal = 1 but no owned row in FieldMarshal table", i));
+
+               if (!is_valid_string (ctx, data [MONO_PARAM_NAME]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d Name = 1 bad token 0x%08x", i, data [MONO_PARAM_NAME]));
+
+               if (!first_param && data [MONO_PARAM_SEQUENCE] <= sequence)
+                               ADD_ERROR (ctx, g_strdup_printf ("Invalid param row %d sequece = %d previus param has %d", i, data [MONO_PARAM_SEQUENCE], sequence));
+
+               first_param = FALSE;
+               sequence = data [MONO_PARAM_SEQUENCE];
+               if (--remaining_params == 0) {
+                       remaining_params = get_next_param_count (ctx, &current_method);
+                       first_param = TRUE;
+               }
+       }
+}
+
+static void
+verify_interfaceimpl_table (VerifyContext *ctx)
+{
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_INTERFACEIMPL];
+       guint32 data [MONO_INTERFACEIMPL_SIZE];
+       int i;
+
+       for (i = 0; i < table->rows; ++i) {
+               mono_metadata_decode_row (table, i, data, MONO_INTERFACEIMPL_SIZE);
+               if (data [MONO_INTERFACEIMPL_CLASS] && data [MONO_INTERFACEIMPL_CLASS] > ctx->image->tables [MONO_TABLE_TYPEDEF].rows)
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Class field 0x%08x", i, data [MONO_TABLE_TYPEDEF]));
+
+               if (!is_valid_coded_index (ctx, TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field coded index 0x%08x", i, data [MONO_INTERFACEIMPL_INTERFACE]));
+
+               if (!get_coded_index_token (TYPEDEF_OR_REF_DESC, data [MONO_INTERFACEIMPL_INTERFACE]))
+                       ADD_ERROR (ctx, g_strdup_printf ("Invalid InterfaceImpl row %d Inteface field is null", i));
+       }
+}
+
+static void
+verify_tables_data (VerifyContext *ctx)
+{
+       OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
+       guint32 size = 0, tables_offset;
+       int i;
+
+       for (i = 0; i < 0x2D; ++i) {
+               MonoTableInfo *table = &ctx->image->tables [i];
+               guint32 tmp_size;
+               tmp_size = size + (guint32)table->row_size * (guint32)table->rows;
+               if (tmp_size < size) {
+                       size = 0;
+                       break;
+               }
+               size = tmp_size;                        
+       }
+
+       if (size == 0)
+               ADD_ERROR (ctx, g_strdup_printf ("table space is either empty or overflowed"));
+
+       tables_offset = ctx->image->tables_base - ctx->data;
+       if (!bounds_check_offset (&tables_area, tables_offset, size))
+               ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", size, tables_area.size - (tables_offset - tables_area.offset)));
+
+       verify_module_table (ctx);
+       CHECK_ERROR ();
+       verify_typeref_table (ctx);
+       CHECK_ERROR ();
+       verify_typedef_table (ctx);
+       CHECK_ERROR ();
+       verify_field_table (ctx);
+       CHECK_ERROR ();
+       verify_method_table (ctx);
+       CHECK_ERROR ();
+       verify_param_table (ctx);
+       CHECK_ERROR ();
+       verify_interfaceimpl_table (ctx);
+}
+
+static gboolean
+mono_verifier_is_corlib (MonoImage *image)
+{
+       gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ? 
+                       TRUE : mono_security_core_clr_is_platform_image (image);
+
+       return trusted_location && !strcmp ("mscorlib.dll", image->name);
+}
+
+static void
+init_verify_context (VerifyContext *ctx, MonoImage *image, GSList **error_list)
+{
+       memset (ctx, 0, sizeof (VerifyContext));
+       ctx->image = image;
+       ctx->report_error = error_list != NULL;
+       ctx->valid = 1;
+       ctx->size = image->raw_data_len;
+       ctx->data = image->raw_data;
+       ctx->is_corlib = mono_verifier_is_corlib (image);       
+}
+
+static gboolean
+cleanup_context (VerifyContext *ctx, GSList **error_list)
+{
+       g_free (ctx->sections);
+       if (error_list)
+               *error_list = ctx->errors;
+       else
+               mono_free_verify_list (ctx->errors);
+       return ctx->valid;      
+}
+
+gboolean
+mono_verifier_verify_pe_data (MonoImage *image, GSList **error_list)
 {
        VerifyContext ctx;
-       memset (&ctx, 0, sizeof (VerifyContext));
-       ctx.data = data;
-       ctx.size = size;
-       ctx.valid = 1;
+
+       if (!mono_verifier_is_enabled_for_image (image))
+               return TRUE;
+
+       init_verify_context (&ctx, image, error_list);
+       ctx.stage = STAGE_PE;
 
        verify_msdos_header (&ctx);
        CHECK_STATE();
        verify_pe_header (&ctx);
        CHECK_STATE();
+       verify_pe_optional_header (&ctx);
+       CHECK_STATE();
+       load_section_table (&ctx);
+       CHECK_STATE();
+       load_data_directories (&ctx);
+       CHECK_STATE();
+       verify_import_table (&ctx);
+       CHECK_STATE();
+       /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
+       verify_resources_table (&ctx);
 
 cleanup:
-       return ctx.errors;
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_cli_data (MonoImage *image, GSList **error_list)
+{
+       VerifyContext ctx;
+
+       if (!mono_verifier_is_enabled_for_image (image))
+               return TRUE;
+
+       init_verify_context (&ctx, image, error_list);
+       ctx.stage = STAGE_CLI;
+
+       verify_cli_header (&ctx);
+       CHECK_STATE();
+       verify_metadata_header (&ctx);
+       CHECK_STATE();
+       verify_tables_schema (&ctx);
+
+cleanup:
+       return cleanup_context (&ctx, error_list);
+}
+
+gboolean
+mono_verifier_verify_table_data (MonoImage *image, GSList **error_list)
+{
+       VerifyContext ctx;
+
+       if (!mono_verifier_is_enabled_for_image (image))
+               return TRUE;
+
+       init_verify_context (&ctx, image, error_list);
+       ctx.stage = STAGE_TABLES;
+
+       verify_tables_data (&ctx);
+
+       return cleanup_context (&ctx, error_list);
 }