2009-04-28 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / metadata-verify.c
index 2ca06aaaebe5ec16de86ce55b3ffcd407655df95..04f13567f7c970e3f2d3c298379917c0a912b16d 100644 (file)
 #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 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 
- FIXME has_cattr coded index / 8 -> Permission table? -- it's decl security
+ 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,
@@ -54,301 +76,118 @@ enum {
        TILDE_STREAM
 };
 
-enum {
-       COL_UINT8,
-       COL_UINT16,
-       COL_UINT32,
-
-       COL_STRING,
-       COL_GUID,
-       COL_BLOB,
-
-       COL_TYPE_DEF_OR_REF, /*includes typespec*/
-       COL_HAS_CONSTANT,
-       COL_HAS_CATTR,
-       COL_HAS_FIELD_MARSHAL,
-       COL_HAS_DECL_SECURITY,
-       COL_MEMBER_REF_PARENT,
-       COL_HAS_SEMANTICS,
-       COL_METHOD_DEF_OR_REF,
-       COL_MEMBER_FORWARDED,
-       COL_IMPLEMENTATION,
-       COL_CATTR_TYPE,
-       COL_RES_SCOPE,
-       COL_TYPE_OR_METHOD_DEF,
-
-       COL_TYPE_DEF,
-       COL_METHOD_DEF,
-       COL_FIELD,
-       COL_PARAM,
-       COL_PROPERTY,
-       COL_EVENT,
-       COL_GENERIC_PARAM,
-       COL_ASSEMBLY_REF,
-       COL_MODULE_REF,
-
-       COL_LAST
-};
 
-const static unsigned char table_desc [] = {
-       /* 0x00 Module */
-       COL_UINT16, /*Generation*/
-       COL_STRING, /*Name*/
-       COL_GUID, /*Mvid*/
-       COL_GUID, /*EncId*/
-       COL_GUID, /*EncBaseId*/
-       COL_LAST,
-
-       /* 0x01 TypeRef */
-       COL_RES_SCOPE, /*ResolutionScope*/
-       COL_STRING, /*TypeName*/
-       COL_STRING, /*TypeNameSpace*/
-       COL_LAST,
-
-       /* 0x02 TypeDef */
-       COL_UINT32, /*Flags*/
-       COL_STRING, /*TypeName*/
-       COL_STRING, /*TypeNameSpace*/
-       COL_TYPE_DEF_OR_REF, /*Extends*/
-       COL_FIELD, /*FieldList*/
-       COL_METHOD_DEF, /*FieldList*/
-       COL_LAST,
-
-       /* 0x03 non documented extension */
-       COL_LAST,
-
-       /* 0x04 Field */
-       COL_UINT16, /*FieldAttributes*/
-       COL_STRING, /*Name*/
-       COL_BLOB, /*Signature*/
-       COL_LAST,
-
-       /* 0x05 non documented extension */
-       COL_LAST,
-
-       /* 0x06 MethodDef */
-       COL_UINT32, /*RVA*/
-       COL_UINT16, /*ImplFlags*/
-       COL_UINT16, /*Flags*/
-       COL_STRING, /*Name*/
-       COL_BLOB, /*Signature*/
-       COL_PARAM, /*ParamList*/
-       COL_LAST,
-
-       /* 0x07 non documented extension */
-       COL_LAST,
-
-       /* 0x08 Param */
-       COL_UINT16, /*Flags*/
-       COL_UINT16, /*Sequence*/
-       COL_STRING, /*Name*/
-       COL_LAST,
-
-       /* 0x09 InterfaceImpl */
-       COL_TYPE_DEF, /*Class*/
-       COL_TYPE_DEF_OR_REF, /*Interface*/
-       COL_LAST,
-       
-       /* 0x0A MemberRef */
-       COL_MEMBER_REF_PARENT, /*Class*/
-       COL_STRING, /*Name*/
-       COL_BLOB, /*Signature*/
-       COL_LAST,
-
-       /* 0x0B Constant */
-       COL_HAS_CONSTANT, /*Parent*/
-       COL_BLOB, /*Value*/
-       COL_LAST,
-
-       /* 0x0C CustomAttribute */
-       COL_HAS_CATTR, /*Parent*/
-       COL_CATTR_TYPE, /*Type*/
-       COL_BLOB, /*Value*/
-       COL_LAST,
-
-       /* 0x0D FieldMarshal */
-       COL_HAS_FIELD_MARSHAL, /*Parent*/
-       COL_BLOB, /*NativeType*/
-       COL_LAST,
-
-       /* 0x0E DeclSecurity */
-       COL_UINT16, /*Action*/
-       COL_HAS_DECL_SECURITY, /*Parent*/ 
-       COL_BLOB, /*PermissionSet*/
-       COL_LAST,
-
-       /* 0x0F ClassLayout */
-       COL_UINT16, /*Packingsize*/
-       COL_UINT32, /*ClassSize*/
-       COL_TYPE_DEF, /*Parent*/
-       COL_LAST,
-
-       /* 0x10 FieldLayout */
-       COL_UINT32, /*Offset*/
-       COL_FIELD, /*Field*/
-       COL_LAST,
-
-       /* 0x11 StandAloneSig */
-       COL_BLOB, /*Signature*/
-       COL_LAST,
-
-       /* 0x12 EventMap */
-       COL_TYPE_DEF, /*Parent*/
-       COL_EVENT, /*EventList*/
-       COL_LAST,
-
-       /* 0x13 non documented extension */
-       COL_LAST,
-
-       /* 0x14 Event */
-       COL_UINT16, /*EventFlags*/
-       COL_STRING, /*Name*/
-       COL_TYPE_DEF_OR_REF, /*EventType*/
-       COL_LAST,
-
-       /* 0x15 PropertyMap */
-       COL_TYPE_DEF, /*Parent*/
-       COL_PROPERTY, /*PropertyList*/
-       COL_LAST,
-
-       /* 0x16 non documented extension */
-       COL_LAST,
-
-       /* 0x17 Property */
-       COL_UINT16, /*Flags*/
-       COL_STRING, /*Name*/
-       COL_BLOB, /*Signature*/
-       COL_LAST,
-
-       /* 0x18 MethodSemantics */
-       COL_UINT16, /*Semantics*/
-       COL_METHOD_DEF, /*Method*/
-       COL_HAS_SEMANTICS, /*Association*/
-       COL_LAST,
-
-       /* 0x19 MethodImpl */
-       COL_TYPE_DEF, /*Class*/
-       COL_METHOD_DEF_OR_REF, /*MethodBody*/
-       COL_METHOD_DEF_OR_REF, /*MethodDeclaration*/
-       COL_LAST,
-
-       /* 0x1A ModuleRef */
-       COL_STRING, /*Name*/
-       COL_LAST,
-
-       /* 0x1B TypeSpec */
-       COL_BLOB, /*Signature*/
-       COL_LAST,
-
-       /* 0x1C ImplMap */
-       COL_UINT16, /*MappingFlags*/
-       COL_MEMBER_FORWARDED, /*MappingFlags*/
-       COL_STRING, /*ImportName*/
-       COL_MODULE_REF, /*ImportScope*/
-       COL_LAST,
-
-       /* 0x1D FieldRVA */
-       COL_UINT32, /*RVA*/
-       COL_FIELD, /*Field*/
-       COL_LAST,
-
-       /* 0x1E Unused */
-       COL_LAST,
-
-       /* 0x1F Unused */
-       COL_LAST,
-
-       /* 0x20 Assembly */
-       COL_UINT32, /*HashAlgId*/
-       COL_UINT16, /*Major*/
-       COL_UINT16, /*Minor*/
-       COL_UINT16, /*Build*/
-       COL_UINT16, /*Revision*/
-       COL_UINT32, /*Flags*/
-       COL_BLOB, /*PublicKey*/
-       COL_STRING, /*Name*/
-       COL_STRING, /*Culture*/
-       COL_LAST,
-
-       /* 0x21 AssemblyProcessor */
-       COL_UINT32, /*Processor*/
-       COL_LAST,
-
-       /* 0x22 AssemblyOS */
-       COL_UINT32, /*OSPlatformID*/
-       COL_UINT32, /*OSMajorVersion*/
-       COL_UINT32, /*OSMinorVersion*/
-       COL_LAST,
-
-       /* 0x23 AssemblyRef */
-       COL_UINT16, /*Major*/
-       COL_UINT16, /*Minor*/
-       COL_UINT16, /*Build*/
-       COL_UINT16, /*Revision*/
-       COL_UINT32, /*Flags*/
-       COL_BLOB, /*PublicKeyOrToken*/
-       COL_STRING, /*Name*/
-       COL_STRING, /*Culture*/
-       COL_BLOB, /*HashValue*/
-       COL_LAST,
-
-       /* 0x24 AssemblyRefProcessor */
-       COL_UINT32, /*Processor*/
-       COL_ASSEMBLY_REF, /*AssemblyRef*/
-       COL_LAST,
-
-       /* 0x25 AssemblyRefOS */
-       COL_UINT32, /*OSPlatformID*/
-       COL_UINT32, /*OSMajorVersion*/
-       COL_UINT32, /*OSMinorVersion*/
-       COL_ASSEMBLY_REF, /*AssemblyRef*/
-       COL_LAST,
-
-       /* 0x26 Unused */
-       COL_UINT32, /*Flags*/
-       COL_STRING, /*Name*/
-       COL_BLOB, /*HashValue*/
-       COL_LAST,
-
-       /* 0x27 ExportedType */
-       COL_UINT32, /*Flags*/
-       COL_UINT32, /*TypeDefId*/
-       COL_STRING, /*TypeName*/
-       COL_STRING, /*TypeNamespace*/
-       COL_IMPLEMENTATION, /*Implementation*/
-       COL_LAST,
-
-       /* 0x28 ManifestResource  */
-       COL_UINT32, /*Offset*/
-       COL_UINT32, /*Flags*/
-       COL_STRING, /*Name*/
-       COL_IMPLEMENTATION, /*Implementation*/
-       COL_LAST,
-
-       /* 0x29 NestedClass  */
-       COL_TYPE_DEF, /*NestedClass*/
-       COL_TYPE_DEF, /*EnclosingClass*/
-       COL_LAST,
-
-       /* 0x2A GenericParam  */
-       COL_UINT16, /*Number*/
-       COL_UINT16, /*Flags*/
-       COL_TYPE_OR_METHOD_DEF, /*Owner*/
-       COL_STRING, /*Name*/
-       COL_LAST,
-
-       /* 0x2B MethodSpec  */
-       COL_METHOD_DEF_OR_REF, /*Method*/
-       COL_BLOB, /*Instantiation*/
-       COL_LAST,
-
-       /* 0x2C GenericParamConstraint  */
-       COL_GENERIC_PARAM, /*Owner*/
-       COL_TYPE_DEF_OR_REF, /*Constraint*/
-       COL_LAST,
+#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;
@@ -371,6 +210,7 @@ typedef struct {
 typedef struct {
        guint32 row_count;
        guint32 row_size;
+       guint32 offset;
 } TableInfo;
 
 typedef struct {
@@ -378,14 +218,16 @@ typedef struct {
        guint32 size;
        GSList *errors;
        int valid;
-       guint32 section_count, tables_offset;
-       SectionHeader *sections;
-       gboolean wide_strings, wide_guid, wide_blob;
+       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
-       TableInfo tables [MONO_TABLE_NUM];
-       guint32 field_sizes [COL_LAST];
 } VerifyContext;
 
 #define ADD_VERIFY_INFO(__ctx, __msg, __status, __exception)   \
@@ -400,7 +242,8 @@ 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)
@@ -426,6 +269,32 @@ 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;
 
@@ -465,6 +334,9 @@ 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;
 
@@ -531,7 +403,8 @@ verify_pe_optional_header (VerifyContext *ctx)
                if (header_size != 224)
                        ADD_ERROR (ctx, g_strdup_printf ("Invalid optional header size %d", header_size));
 
-               /*if (read32 (pe_optional_header + 28) != 0x400000)
+               /* 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)));
@@ -621,6 +494,11 @@ load_data_directories (VerifyContext *ctx)
                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));
 
@@ -731,18 +609,35 @@ verify_resources_table (VerifyContext *ctx)
        named_entries = read16 (ptr + 12);
        id_entries = read16 (ptr + 14);
 
-       printf ("named %d id_entries %d\n", named_entries, id_entries);
        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 = ctx->data_directories [CLI_HEADER_IDX];
+       DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
        guint32 offset;
        const char *ptr;
        int i;
@@ -764,6 +659,7 @@ verify_cli_header (VerifyContext *ctx)
        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"));
 
@@ -797,7 +693,7 @@ static void
 verify_metadata_header (VerifyContext *ctx)
 {
        int i;
-       DataDirectory it = ctx->data_directories [CLI_HEADER_IDX];
+       DataDirectory it = get_data_dir (ctx, CLI_HEADER_IDX);
        guint32 offset;
        const char *ptr;
 
@@ -894,10 +790,12 @@ verify_tables_schema (VerifyContext *ctx)
        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));
 
-       if (ptr [4] != 2)
+       //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]));
@@ -905,10 +803,6 @@ verify_tables_schema (VerifyContext *ctx)
        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]));
 
-       ctx->wide_strings = ptr [6] & 0x1;
-       ctx->wide_guid = ptr [6] & 0x2;
-       ctx->wide_blob = ptr [6] & 04;
-
        valid_tables = read64 (ptr + 8);
        count = 0;
        for (i = 0; i < 64; ++i) {
@@ -927,129 +821,699 @@ verify_tables_schema (VerifyContext *ctx)
 
        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)) {
-                       ctx->tables [i].row_count = read32 (ptr);
+                       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;
                }
        }
-       ctx->tables_offset = offset + 24 + count * 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
-enc_index_size (guint32 bits, guint32 max)
+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)
 {
-       guint32 size = 1 << (16 - bits); 
-       return max >= size ? 4 : 2;
+       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
-calc_fields_size (VerifyContext *ctx)
+verify_field_table (VerifyContext *ctx)
 {
-#define TS(T) (ctx->tables [T].row_count)
-#define MAX2(TA,TB) MAX (TS (TA), TS (TB))
-#define MAX3(TA,TB,TC) MAX (TS (TA), MAX (TS (TB), TS (TC)))
-#define TB_SIZE(T) (TS (T) >= (1 << 16) ? 4 : 2)
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_FIELD];
+       guint32 data [MONO_FIELD_SIZE], flags, module_field_list;
+       int i;
 
-       int tmp;
-       memset (ctx->field_sizes, 0, sizeof (guint32) * COL_LAST);
+       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);
+       }
        
-       ctx->field_sizes [COL_UINT8] = 1;
-       ctx->field_sizes [COL_UINT16] = 2;
-       ctx->field_sizes [COL_UINT32] = 4;
-
-       ctx->field_sizes [COL_STRING] = ctx->wide_strings ? 4 : 2;
-       ctx->field_sizes [COL_GUID] = ctx->wide_guid ? 4 : 2;
-       ctx->field_sizes [COL_BLOB] = ctx->wide_blob? 4 : 2;
-
-       ctx->field_sizes [COL_TYPE_DEF_OR_REF] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_TYPESPEC));
-       ctx->field_sizes [COL_HAS_CONSTANT] = enc_index_size (2, MAX3 (MONO_TABLE_FIELD, MONO_TABLE_PARAM, MONO_TABLE_PROPERTY));
-
-       tmp = MAX3 (MONO_TABLE_METHOD, MONO_TABLE_FIELD, MONO_TABLE_TYPEREF);
-       tmp = MAX (tmp, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_PARAM, MONO_TABLE_INTERFACEIMPL));
-       tmp = MAX (tmp, MAX3 (MONO_TABLE_MEMBERREF, MONO_TABLE_MODULE, COL_HAS_DECL_SECURITY));
-       tmp = MAX (tmp, MAX3 (MONO_TABLE_PROPERTY, MONO_TABLE_EVENT, MONO_TABLE_STANDALONESIG));
-       tmp = MAX (tmp, MAX3 (MONO_TABLE_MODULEREF, MONO_TABLE_TYPESPEC, MONO_TABLE_ASSEMBLY));
-       tmp = MAX (tmp, MAX3 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_FILE, MONO_TABLE_EXPORTEDTYPE));
-       tmp = MAX (tmp, MONO_TABLE_MANIFESTRESOURCE);
-       ctx->field_sizes [COL_HAS_CATTR] = enc_index_size (5, tmp);
-
-       ctx->field_sizes [COL_HAS_FIELD_MARSHAL] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_PARAM));
-       ctx->field_sizes [COL_HAS_DECL_SECURITY] = enc_index_size (2, MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD, MONO_TABLE_ASSEMBLY));
-
-       tmp = MAX3 (MONO_TABLE_TYPEDEF, MONO_TABLE_TYPEREF, MONO_TABLE_MODULEREF);
-       tmp = MAX (tmp, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_TYPESPEC));
-       ctx->field_sizes [COL_MEMBER_REF_PARENT] = enc_index_size (3, tmp);
-
-       ctx->field_sizes [COL_HAS_SEMANTICS] = enc_index_size (1, MAX2 (MONO_TABLE_EVENT, MONO_TABLE_PROPERTY));
-       ctx->field_sizes [COL_METHOD_DEF_OR_REF] = enc_index_size (1, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
-       ctx->field_sizes [COL_MEMBER_FORWARDED] = enc_index_size (1, MAX2 (MONO_TABLE_FIELD, MONO_TABLE_METHOD));
-       ctx->field_sizes [COL_IMPLEMENTATION] = enc_index_size (2, MAX3 (MONO_TABLE_FILE, MONO_TABLE_ASSEMBLYREF, MONO_TABLE_EXPORTEDTYPE));
-
-       ctx->field_sizes [COL_CATTR_TYPE] = enc_index_size (3, MAX2 (MONO_TABLE_METHOD, MONO_TABLE_MEMBERREF));
-       ctx->field_sizes [COL_RES_SCOPE] = enc_index_size (2, MAX (MAX2 (MONO_TABLE_MODULE, MONO_TABLE_MODULEREF), MAX2 (MONO_TABLE_ASSEMBLYREF, MONO_TABLE_TYPEREF))); 
-       ctx->field_sizes [COL_TYPE_OR_METHOD_DEF] = enc_index_size (1, MAX2 (MONO_TABLE_TYPEDEF, MONO_TABLE_METHOD));
-
-       ctx->field_sizes [COL_TYPE_DEF] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_METHOD_DEF] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_FIELD] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_PARAM] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_PROPERTY] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_EVENT] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_GENERIC_PARAM] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_ASSEMBLY_REF] = TB_SIZE (MONO_TABLE_TYPEDEF);
-       ctx->field_sizes [COL_MODULE_REF] = TB_SIZE (MONO_TABLE_TYPEDEF);
+       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]));
+
+               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
-calc_row_size (VerifyContext *ctx)
+get_next_param_count (VerifyContext *ctx, guint32 *current_method)
 {
-       int i, idx;
-       guint64 total_size = 0;
-       
-       for (idx = 0, i = 0; i < 0x2D; ++i) {
-               int size = 0, type;
+       MonoTableInfo *table = &ctx->image->tables [MONO_TABLE_METHOD];
+       guint32 row = *current_method;
+       guint32 paramlist, tmp;
 
-               while ((type = table_desc [idx++]) != COL_LAST)
-                       size += ctx->field_sizes [type];
 
-               ctx->tables [i].row_size = size;
-               total_size += (guint64)size * ctx->tables [i].row_count;
+       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;
        }
 
-       if (total_size > G_MAXUINT32)
-               return 0;
+       /*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]));
 
-       return (guint32)total_size; 
+               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 = ctx->metadata_streams [TILDE_STREAM];
-       guint table_area_size;
-       calc_fields_size (ctx);
-       table_area_size = calc_row_size (ctx);
+       OffsetAndSize tables_area = get_metadata_stream (ctx, &ctx->image->heap_tables);
+       guint32 size = 0, tables_offset;
+       int i;
 
-       if (table_area_size == 0)
+       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"));
 
-       if (!bounds_check_offset (&tables_area, ctx->tables_offset, table_area_size))
-               ADD_ERROR (ctx, g_strdup_printf ("Tables data require %d bytes but the only %d are available in the #~ stream", table_area_size, tables_area.size - (ctx->tables_offset - tables_area.offset)));
+       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;      
 }
 
-GSList*
-mono_image_verify (const char *data, guint32 size)
+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();
@@ -1065,16 +1529,44 @@ mono_image_verify (const char *data, guint32 size)
        CHECK_STATE();
        /*No need to check the IAT directory entry, it's content is indirectly verified by verify_import_table*/
        verify_resources_table (&ctx);
-       CHECK_STATE();
+
+cleanup:
+       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);
-       CHECK_STATE();
-       verify_tables_data (&ctx);
-       CHECK_STATE();
+
 cleanup:
-       g_free (ctx.sections);
-       return ctx.errors;
+       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);
 }