verify_field_table (MonoImage *image, GSList *list, int level)
{
	MonoTableInfo *t = &image->tables [MONO_TABLE_FIELD];
	guint32 cols [MONO_FIELD_SIZE];
	const char *p;
	guint32 i, flags;

	for (i = 0; i < t->rows; ++i) {
		mono_metadata_decode_row (t, i, cols, MONO_FIELD_SIZE);
		/*
		 * Check this field has only one owner and that the owner is not
		 * an interface (done in verify_typedef_table() )
		 */
		flags = cols [MONO_FIELD_FLAGS];
		switch (flags & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK) {
		case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
		case FIELD_ATTRIBUTE_PRIVATE:
		case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
		case FIELD_ATTRIBUTE_ASSEMBLY:
		case FIELD_ATTRIBUTE_FAMILY:
		case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
		case FIELD_ATTRIBUTE_PUBLIC:
			break;
		default:
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid access mask in Field row %d", i + 1));
			break;
		}
		if (level & MONO_VERIFY_ERROR) {
			if ((flags & FIELD_ATTRIBUTE_LITERAL) && (flags & FIELD_ATTRIBUTE_INIT_ONLY))
				ADD_ERROR (list, g_strdup_printf ("Literal and InitOnly cannot be both set in Field row %d", i + 1));
			if ((flags & FIELD_ATTRIBUTE_LITERAL) && !(flags & FIELD_ATTRIBUTE_STATIC))
				ADD_ERROR (list, g_strdup_printf ("Literal needs also Static set in Field row %d", i + 1));
			if ((flags & FIELD_ATTRIBUTE_RT_SPECIAL_NAME) && !(flags & FIELD_ATTRIBUTE_SPECIAL_NAME))
				ADD_ERROR (list, g_strdup_printf ("RTSpecialName needs also SpecialName set in Field row %d", i + 1));
			/*
			 * FIXME: check there is only one owner in the respective table.
			 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
			 * if (flags & FIELD_ATTRIBUTE_HAS_DEFAULT)
			 * if (flags & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
			 */
		}
		if (!(p = is_valid_string (image, cols [MONO_FIELD_NAME], TRUE))) {
			if (level & MONO_VERIFY_ERROR)
				ADD_ERROR (list, g_strdup_printf ("Invalid name in Field row %d", i + 1));
		} else {
			if (level & MONO_VERIFY_CLS) {
				if (!is_valid_cls_ident (p))
					ADD_WARN (list, MONO_VERIFY_CLS, g_strdup_printf ("Invalid CLS name '%s` in Field row %d", p, i + 1));
			}
		}
		/*
		 * check signature.
		 * if owner is module needs to be static, access mask needs to be compilercontrolled,
		 * public or private (not allowed in cls mode).
		 * if owner is an enum ...
		 */

	}
	return list;
}


MonoReflectionMarshal*
mono_reflection_marshal_from_marshal_spec (MonoDomain *domain, MonoClass *klass,
										   MonoMarshalSpec *spec)
{
	static MonoClass *System_Reflection_Emit_UnmanagedMarshalClass;
	MonoReflectionMarshal *minfo;
	MonoType *mtype;

	if (!System_Reflection_Emit_UnmanagedMarshalClass) {
		System_Reflection_Emit_UnmanagedMarshalClass = mono_class_from_name (
		   mono_defaults.corlib, "System.Reflection.Emit", "UnmanagedMarshal");
		g_assert (System_Reflection_Emit_UnmanagedMarshalClass);
	}

	minfo = (MonoReflectionMarshal*)mono_object_new (domain, System_Reflection_Emit_UnmanagedMarshalClass);
	minfo->type = spec->native;

	switch (minfo->type) {
	case MONO_NATIVE_LPARRAY:
		minfo->eltype = spec->data.array_data.elem_type;
		minfo->count = spec->data.array_data.num_elem;
		minfo->param_num = spec->data.array_data.param_num;
		break;

	case MONO_NATIVE_BYVALTSTR:
	case MONO_NATIVE_BYVALARRAY:
		minfo->count = spec->data.array_data.num_elem;
		break;

	case MONO_NATIVE_CUSTOM:
		if (spec->data.custom_data.custom_name) {
			mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, klass->image);
			if (mtype)
				MONO_OBJECT_SETREF (minfo, marshaltyperef, mono_type_get_object (domain, mtype));

			MONO_OBJECT_SETREF (minfo, marshaltype, mono_string_new (domain, spec->data.custom_data.custom_name));
		}
		if (spec->data.custom_data.cookie)
			MONO_OBJECT_SETREF (minfo, mcookie, mono_string_new (domain, spec->data.custom_data.cookie));
		break;

	default:
		break;
	}

	return minfo;


token_bounds_check (MonoImage *image, guint32 token)
{
	if (image->dynamic)
		return mono_reflection_is_valid_dynamic_token ((MonoDynamicImage*)image, token);
	return image->tables [mono_metadata_token_table (token)].rows >= mono_metadata_token_index (token);
}


gboolean
mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass)
{
	MonoObject *res, *exc;
	void *params [1];
	static MonoClass *System_Reflection_Emit_TypeBuilder = NULL;
	static MonoMethod *method = NULL;

	if (!System_Reflection_Emit_TypeBuilder) {
		System_Reflection_Emit_TypeBuilder = mono_class_from_name (mono_defaults.corlib, "System.Reflection.Emit", "TypeBuilder");
		g_assert (System_Reflection_Emit_TypeBuilder);
	}
	if (method == NULL) {
		method = mono_class_get_method_from_name (System_Reflection_Emit_TypeBuilder, "IsAssignableTo", 1);
		g_assert (method);
	}

	/*
	 * The result of mono_type_get_object () might be a System.MonoType but we
	 * need a TypeBuilder so use klass->reflection_info.
	 */
	g_assert (klass->reflection_info);
	g_assert (!strcmp (((MonoObject*)(klass->reflection_info))->vtable->klass->name, "TypeBuilder"));

	params [0] = mono_type_get_object (mono_domain_get (), &oklass->byval_arg);

	res = mono_runtime_invoke (method, (MonoObject*)(klass->reflection_info), params, &exc);
	if (exc)
		return FALSE;
	else
		return *(MonoBoolean*)mono_object_unbox (res);


type_get_fully_qualified_name (MonoType *type)
{
	return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
}


load_cattr_value (MonoImage *image, MonoType *t, const char *p, const char **end)
{
	int slen, type = t->type;
	MonoClass *tklass = t->data.klass;

handle_enum:
	switch (type) {
	case MONO_TYPE_U1:
	case MONO_TYPE_I1:
	case MONO_TYPE_BOOLEAN: {
		MonoBoolean *bval = g_malloc (sizeof (MonoBoolean));
		*bval = *p;
		*end = p + 1;
		return bval;
	}
	case MONO_TYPE_CHAR:
	case MONO_TYPE_U2:
	case MONO_TYPE_I2: {
		guint16 *val = g_malloc (sizeof (guint16));
		*val = read16 (p);
		*end = p + 2;
		return val;
	}
#if SIZEOF_VOID_P == 4
	case MONO_TYPE_U:
	case MONO_TYPE_I:
#endif
	case MONO_TYPE_R4:
	case MONO_TYPE_U4:
	case MONO_TYPE_I4: {
		guint32 *val = g_malloc (sizeof (guint32));
		*val = read32 (p);
		*end = p + 4;
		return val;
	}
#if SIZEOF_VOID_P == 8
	case MONO_TYPE_U: /* error out instead? this should probably not happen */
	case MONO_TYPE_I:
#endif
	case MONO_TYPE_U8:
	case MONO_TYPE_I8: {
		guint64 *val = g_malloc (sizeof (guint64));
		*val = read64 (p);
		*end = p + 8;
		return val;
	}
	case MONO_TYPE_R8: {
		double *val = g_malloc (sizeof (double));
		readr8 (p, val);
		*end = p + 8;
		return val;
	}
	case MONO_TYPE_VALUETYPE:
		if (t->data.klass->enumtype) {
			type = mono_class_enum_basetype (t->data.klass)->type;
			goto handle_enum;
		} else {
			g_error ("generic valutype %s not handled in custom attr value decoding", t->data.klass->name);
		}
		break;
	case MONO_TYPE_STRING:
		if (*p == (char)0xFF) {
			*end = p + 1;
			return NULL;
		}
		slen = mono_metadata_decode_value (p, &p);
		*end = p + slen;
		return mono_string_new_len (mono_domain_get (), p, slen);
	case MONO_TYPE_CLASS: {
		char *n;
		MonoType *t;
		if (*p == (char)0xFF) {
			*end = p + 1;
			return NULL;
		}
handle_type:
		slen = mono_metadata_decode_value (p, &p);
		n = g_memdup (p, slen + 1);
		n [slen] = 0;
		t = mono_reflection_type_from_name (n, image);
		if (!t)
			g_warning ("Cannot load type '%s'", n);
		g_free (n);
		*end = p + slen;
		if (t)
			return mono_type_get_object (mono_domain_get (), t);
		else
			return NULL;
	}
	case MONO_TYPE_OBJECT: {
		char subt = *p++;
		MonoObject *obj;
		MonoClass *subc = NULL;
		void *val;

		if (subt == 0x50) {
			goto handle_type;
		} else if (subt == 0x0E) {
			type = MONO_TYPE_STRING;
			goto handle_enum;
		} else if (subt == 0x1D) {
			MonoType simple_type = {{0}};
			int etype = *p;
			p ++;

			if (etype == 0x51)
				/* See Partition II, Appendix B3 */
				etype = MONO_TYPE_OBJECT;
			type = MONO_TYPE_SZARRAY;
			simple_type.type = etype;
			tklass = mono_class_from_mono_type (&simple_type);
			goto handle_enum;
		} else if (subt == 0x55) {
			char *n;
			MonoType *t;
			slen = mono_metadata_decode_value (p, &p);
			n = g_memdup (p, slen + 1);
			n [slen] = 0;
			t = mono_reflection_type_from_name (n, image);
			if (!t)
				g_error ("Cannot load type '%s'", n);
			g_free (n);
			p += slen;
			subc = mono_class_from_mono_type (t);
		} else if (subt >= MONO_TYPE_BOOLEAN && subt <= MONO_TYPE_R8) {
			MonoType simple_type = {{0}};
			simple_type.type = subt;
			subc = mono_class_from_mono_type (&simple_type);
		} else {
			g_error ("Unknown type 0x%02x for object type encoding in custom attr", subt);
		}
		val = load_cattr_value (image, &subc->byval_arg, p, end);
		obj = mono_object_new (mono_domain_get (), subc);
		memcpy ((char*)obj + sizeof (MonoObject), val, mono_class_value_size (subc, NULL));
		g_free (val);
		return obj;
	}
	case MONO_TYPE_SZARRAY: {
		MonoArray *arr;
		guint32 i, alen, basetype;
		alen = read32 (p);
		p += 4;
		if (alen == 0xffffffff) {
			*end = p;
			return NULL;
		}
		arr = mono_array_new (mono_domain_get(), tklass, alen);
		basetype = tklass->byval_arg.type;
		if (basetype == MONO_TYPE_VALUETYPE && tklass->enumtype)
			basetype = mono_class_enum_basetype (tklass)->type;
		switch (basetype)
		{
			case MONO_TYPE_U1:
			case MONO_TYPE_I1:
			case MONO_TYPE_BOOLEAN:
				for (i = 0; i < alen; i++) {
					MonoBoolean val = *p++;
					mono_array_set (arr, MonoBoolean, i, val);
				}
				break;
			case MONO_TYPE_CHAR:
			case MONO_TYPE_U2:
			case MONO_TYPE_I2:
				for (i = 0; i < alen; i++) {
					guint16 val = read16 (p);
					mono_array_set (arr, guint16, i, val);
					p += 2;
				}
				break;
			case MONO_TYPE_R4:
			case MONO_TYPE_U4:
			case MONO_TYPE_I4:
				for (i = 0; i < alen; i++) {
					guint32 val = read32 (p);
					mono_array_set (arr, guint32, i, val);
					p += 4;
				}
				break;
			case MONO_TYPE_R8:
				for (i = 0; i < alen; i++) {
					double val;
					readr8 (p, &val);
					mono_array_set (arr, double, i, val);
					p += 8;
				}
				break;
			case MONO_TYPE_U8:
			case MONO_TYPE_I8:
				for (i = 0; i < alen; i++) {
					guint64 val = read64 (p);
					mono_array_set (arr, guint64, i, val);
					p += 8;
				}
				break;
			case MONO_TYPE_CLASS:
			case MONO_TYPE_OBJECT:
			case MONO_TYPE_STRING:
				for (i = 0; i < alen; i++) {
					MonoObject *item = load_cattr_value (image, &tklass->byval_arg, p, &p);
					mono_array_setref (arr, i, item);
				}
				break;
			default:
				g_error ("Type 0x%02x not handled in custom attr array decoding", basetype);
		}
		*end=p;
		return arr;
	}
	default:
		g_error ("Type 0x%02x not handled in custom attr value decoding", type);
	}
	return NULL;
}


is_array_type_compatible (MonoType *target, MonoType *candidate)
{
	MonoArrayType *left = target->data.array;
	MonoArrayType *right = candidate->data.array;

	g_assert (target->type == MONO_TYPE_ARRAY);
	g_assert (candidate->type == MONO_TYPE_ARRAY);

	if (left->rank != right->rank)
		return FALSE;

	return mono_class_is_assignable_from (left->eklass, right->eklass);
}


check_unverifiable_type (VerifyContext *ctx, MonoType *type)
{
	if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Unmanaged pointer is not a verifiable type at 0x%04x", ctx->ip_offset));
		return 0;
	}
	return 1;
}


reflection_methodbuilder_from_ctor_builder (ReflectionMethodBuilder *rmb, MonoReflectionCtorBuilder *mb)
{
	const char *name = mb->attrs & METHOD_ATTRIBUTE_STATIC ? ".cctor": ".ctor";

	memset (rmb, 0, sizeof (ReflectionMethodBuilder));

	rmb->ilgen = mb->ilgen;
	rmb->rtype = mono_type_get_object (mono_domain_get (), &mono_defaults.void_class->byval_arg);
	rmb->parameters = mb->parameters;
	rmb->generic_params = NULL;
	rmb->generic_container = NULL;
	rmb->opt_types = NULL;
	rmb->pinfo = mb->pinfo;
	rmb->attrs = mb->attrs;
	rmb->iattrs = mb->iattrs;
	rmb->call_conv = mb->call_conv;
	rmb->code = NULL;
	rmb->type = mb->type;
	rmb->name = mono_string_new (mono_domain_get (), name);
	rmb->table_idx = &mb->table_idx;
	rmb->init_locals = mb->init_locals;
	rmb->skip_visibility = FALSE;
	rmb->return_modreq = NULL;
	rmb->return_modopt = NULL;
	rmb->param_modreq = mb->param_modreq;
	rmb->param_modopt = mb->param_modopt;
	rmb->permissions = mb->permissions;
	rmb->mhandle = mb->mhandle;
	rmb->nrefs = 0;
	rmb->refs = NULL;
}


void
mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
{
	*overrides = NULL;
	*num_overrides = 0;


static MonoMethod*
ctorbuilder_to_mono_method (MonoClass *klass, MonoReflectionCtorBuilder* mb)
{
	ReflectionMethodBuilder rmb;
	MonoMethodSignature *sig;

	mono_loader_lock ();
	sig = ctor_builder_to_signature (klass->image, mb);
	mono_loader_unlock ();

	reflection_methodbuilder_from_ctor_builder (&rmb, mb);

	mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig);
	mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);

	/* If we are in a generic class, we might be called multiple times from inflate_method */
	if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save && !klass->generic_container) {
		/* ilgen is no longer needed */
		mb->ilgen = NULL;
	}

	return mb->mhandle;


mono_custom_attrs_from_class (MonoClass *klass)
{
	guint32 idx;

	if (klass->generic_class)
		klass = klass->generic_class->container_class;

	if (klass->image->dynamic)
		return lookup_custom_attr (klass->image, klass);

	if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR) {
		idx = mono_metadata_token_index (klass->sizes.generic_param_token);
		idx <<= MONO_CUSTOM_ATTR_BITS;
		idx |= MONO_CUSTOM_ATTR_GENERICPAR;
	} else {
		idx = mono_metadata_token_index (klass->type_token);
		idx <<= MONO_CUSTOM_ATTR_BITS;
		idx |= MONO_CUSTOM_ATTR_TYPEDEF;
	}
	return mono_custom_attrs_from_index (klass->image, idx);
}


stack_slot_get_type (ILStackDesc *value)
{
	return value->stype & RAW_TYPE_MASK;
}


do_push_static_field (VerifyContext *ctx, int token, gboolean take_addr)
{
	MonoClassField *field;
	MonoClass *klass;
	if (!check_overflow (ctx))
		return;
	if (!take_addr)
		CLEAR_PREFIX (ctx, PREFIX_VOLATILE);

	if (!(field = verifier_load_field (ctx, token, &klass, take_addr ? "ldsflda" : "ldsfld")))
		return;

	if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot load non static field at 0x%04x", ctx->ip_offset));
		return;
	}
	/*taking the address of initonly field only works from the static constructor */
	if (take_addr && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY) &&
		!(field->parent == ctx->method->klass && (ctx->method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_STATIC)) && !strcmp (".cctor", ctx->method->name)))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot take the address of a init-only field at 0x%04x", ctx->ip_offset));

	if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
		CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);

	set_stack_value (ctx, stack_push (ctx), field->type, take_addr);
}


create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, guint32 len)
{
	const char *p = (const char*)data;
	const char *named;
	guint32 i, j, num_named;
	MonoObject *attr;
	void *params_buf [32];
	void **params;
	MonoMethodSignature *sig;

	mono_class_init (method->klass);

	if (len == 0) {
		attr = mono_object_new (mono_domain_get (), method->klass);
		mono_runtime_invoke (method, attr, NULL, NULL);
		return attr;
	}

	if (len < 2 || read16 (p) != 0x0001) /* Prolog */
		return NULL;

	/*g_print ("got attr %s\n", method->klass->name);*/

	sig = mono_method_signature (method);
	if (sig->param_count < 32)
		params = params_buf;
	else
		/* Allocate using GC so it gets GC tracking */
		params = mono_gc_alloc_fixed (sig->param_count * sizeof (void*), NULL);

	/* skip prolog */
	p += 2;
	for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
		params [i] = load_cattr_value (image, mono_method_signature (method)->params [i], p, &p);
	}

	named = p;
	attr = mono_object_new (mono_domain_get (), method->klass);
	mono_runtime_invoke (method, attr, params, NULL);
	free_param_data (method->signature, params);
	num_named = read16 (named);
	named += 2;
	for (j = 0; j < num_named; j++) {
		gint name_len;
		char *name, named_type, data_type;
		named_type = *named++;
		data_type = *named++; /* type of data */
		if (data_type == MONO_TYPE_SZARRAY)
			data_type = *named++;
		if (data_type == MONO_TYPE_ENUM) {
			gint type_len;
			char *type_name;
			type_len = mono_metadata_decode_blob_size (named, &named);
			type_name = g_malloc (type_len + 1);
			memcpy (type_name, named, type_len);
			type_name [type_len] = 0;
			named += type_len;
			/* FIXME: lookup the type and check type consistency */
			g_free (type_name);
		}
		name_len = mono_metadata_decode_blob_size (named, &named);
		name = g_malloc (name_len + 1);
		memcpy (name, named, name_len);
		name [name_len] = 0;
		named += name_len;
		if (named_type == 0x53) {
			MonoClassField *field = mono_class_get_field_from_name (mono_object_class (attr), name);
			void *val = load_cattr_value (image, field->type, named, &named);
			mono_field_set_value (attr, field, val);
			if (!type_is_reference (field->type))
				g_free (val);
		} else if (named_type == 0x54) {
			MonoProperty *prop;
			void *pparams [1];
			MonoType *prop_type;

			prop = mono_class_get_property_from_name (mono_object_class (attr), name);
			/* can we have more that 1 arg in a custom attr named property? */
			prop_type = prop->get? mono_method_signature (prop->get)->ret :
			     mono_method_signature (prop->set)->params [mono_method_signature (prop->set)->param_count - 1];
			pparams [0] = load_cattr_value (image, prop_type, named, &named);
			mono_property_set_value (prop, attr, pparams, NULL);
			if (!type_is_reference (prop_type))
				g_free (pparams [0]);
		}
		g_free (name);
	}

	if (params != params_buf)
		mono_gc_free_fixed (params);

	return attr;
}


compare_field_marshal (const void *a, const void *b)
{
	const guint32 *a_values = a;
	const guint32 *b_values = b;

	return a_values [MONO_FIELD_MARSHAL_PARENT] - b_values [MONO_FIELD_MARSHAL_PARENT];
}


type_add_cattrs (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb) {
	int i;

	mono_image_add_cattrs (assembly, tb->table_idx, MONO_CUSTOM_ATTR_TYPEDEF, tb->cattrs);
	if (tb->fields) {
		for (i = 0; i < tb->num_fields; ++i) {
			MonoReflectionFieldBuilder* fb;
			fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, i);
			mono_image_add_cattrs (assembly, fb->table_idx, MONO_CUSTOM_ATTR_FIELDDEF, fb->cattrs);
		}
	}
	if (tb->events) {
		for (i = 0; i < mono_array_length (tb->events); ++i) {
			MonoReflectionEventBuilder* eb;
			eb = mono_array_get (tb->events, MonoReflectionEventBuilder*, i);
			mono_image_add_cattrs (assembly, eb->table_idx, MONO_CUSTOM_ATTR_EVENT, eb->cattrs);
		}
	}
	if (tb->properties) {
		for (i = 0; i < mono_array_length (tb->properties); ++i) {
			MonoReflectionPropertyBuilder* pb;
			pb = mono_array_get (tb->properties, MonoReflectionPropertyBuilder*, i);
			mono_image_add_cattrs (assembly, pb->table_idx, MONO_CUSTOM_ATTR_PROPERTY, pb->cattrs);
		}
	}
	if (tb->ctors) {
		for (i = 0; i < mono_array_length (tb->ctors); ++i) {
			MonoReflectionCtorBuilder* cb;
			cb = mono_array_get (tb->ctors, MonoReflectionCtorBuilder*, i);
			mono_image_add_cattrs (assembly, cb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, cb->cattrs);
			params_add_cattrs (assembly, cb->pinfo);
		}
	}

	if (tb->methods) {
		for (i = 0; i < tb->num_methods; ++i) {
			MonoReflectionMethodBuilder* mb;
			mb = mono_array_get (tb->methods, MonoReflectionMethodBuilder*, i);
			mono_image_add_cattrs (assembly, mb->table_idx, MONO_CUSTOM_ATTR_METHODDEF, mb->cattrs);
			params_add_cattrs (assembly, mb->pinfo);
		}
	}

	if (tb->subtypes) {
		for (i = 0; i < mono_array_length (tb->subtypes); ++i)
			type_add_cattrs (assembly, mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i));
	}
}


verifier_get_generic_param_from_type (VerifyContext *ctx, MonoType *type)
{
	MonoGenericContainer *gc;
	MonoMethod *method = ctx->method;
	int num;

	num = mono_type_get_generic_param_num (type);

	if (type->type == MONO_TYPE_VAR) {
		MonoClass *gtd = method->klass;
		if (gtd->generic_class)
			gtd = gtd->generic_class->container_class;
		gc = gtd->generic_container;
	} else { //MVAR
		MonoMethod *gmd = method;
		if (method->is_inflated)
			gmd = ((MonoMethodInflated*)method)->declaring;
		gc = mono_method_get_generic_container (gmd);
	}
	if (!gc)
		return FALSE;
	return mono_generic_container_get_param (gc, num);
}


_mono_reflection_parse_type (char *name, char **endptr, gboolean is_recursed,
			     MonoTypeNameParse *info)
{
	char *start, *p, *w, *temp, *last_point, *startn;
	int in_modifiers = 0;
	int isbyref = 0, rank, arity = 0, i;

	start = p = w = name;

	//FIXME could we just zero the whole struct? memset (&info, 0, sizeof (MonoTypeNameParse))
	memset (&info->assembly, 0, sizeof (MonoAssemblyName));
	info->name = info->name_space = NULL;
	info->nested = NULL;
	info->modifiers = NULL;
	info->type_arguments = NULL;

	/* last_point separates the namespace from the name */
	last_point = NULL;
	/* Skips spaces */
	while (*p == ' ') p++, start++, w++, name++;

	while (*p) {
		switch (*p) {
		case '+':
			*p = 0; /* NULL terminate the name */
			startn = p + 1;
			info->nested = g_list_append (info->nested, startn);
			/* we have parsed the nesting namespace + name */
			if (info->name)
				break;
			if (last_point) {
				info->name_space = start;
				*last_point = 0;
				info->name = last_point + 1;
			} else {
				info->name_space = (char *)"";
				info->name = start;
			}
			break;
		case '.':
			last_point = p;
			break;
		case '\\':
			++p;
			break;
		case '&':
		case '*':
		case '[':
		case ',':
		case ']':
			in_modifiers = 1;
			break;
		case '`':
			++p;
			i = strtol (p, &temp, 10);
			arity += i;
			if (p == temp)
				return 0;
			p = temp-1;
			break;
		default:
			break;
		}
		if (in_modifiers)
			break;
		// *w++ = *p++;
		p++;
	}

	if (!info->name) {
		if (last_point) {
			info->name_space = start;
			*last_point = 0;
			info->name = last_point + 1;
		} else {
			info->name_space = (char *)"";
			info->name = start;
		}
	}
	while (*p) {
		switch (*p) {
		case '&':
			if (isbyref) /* only one level allowed by the spec */
				return 0;
			isbyref = 1;
			info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (0));
			*p++ = 0;
			break;
		case '*':
			info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-1));
			*p++ = 0;
			break;
		case '[':
			if (arity != 0) {
				*p++ = 0;
				info->type_arguments = g_ptr_array_new ();
				for (i = 0; i < arity; i++) {
					MonoTypeNameParse *subinfo = g_new0 (MonoTypeNameParse, 1);
					gboolean fqname = FALSE;

					g_ptr_array_add (info->type_arguments, subinfo);

					if (*p == '[') {
						p++;
						fqname = TRUE;
					}

					if (!_mono_reflection_parse_type (p, &p, TRUE, subinfo))
						return 0;

					/*MS is lenient on [] delimited parameters that aren't fqn - and F# uses them.*/
					if (fqname && (*p != ']')) {
						char *aname;

						if (*p != ',')
							return 0;
						*p++ = 0;

						aname = p;
						while (*p && (*p != ']'))
							p++;

						if (*p != ']')
							return 0;

						*p++ = 0;
						while (*aname) {
							if (g_ascii_isspace (*aname)) {
								++aname;
								continue;
							}
							break;
						}
						if (!*aname ||
						    !assembly_name_to_aname (&subinfo->assembly, aname))
							return 0;
					} else if (fqname && (*p == ']')) {
						*p++ = 0;
					}

					if (i + 1 < arity) {
						if (*p != ',')
							return 0;
					} else {
						if (*p != ']')
							return 0;
					}
					*p++ = 0;
				}

				arity = 0;
				break;
			}
			rank = 1;
			*p++ = 0;
			while (*p) {
				if (*p == ']')
					break;
				if (*p == ',')
					rank++;
				else if (*p == '*') /* '*' means unknown lower bound */
					info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (-2));
				else
					return 0;
				++p;
			}
			if (*p++ != ']')
				return 0;
			info->modifiers = g_list_append (info->modifiers, GUINT_TO_POINTER (rank));
			break;
		case ']':
			if (is_recursed)
				goto end;
			return 0;
		case ',':
			if (is_recursed)
				goto end;
			*p++ = 0;
			while (*p) {
				if (g_ascii_isspace (*p)) {
					++p;
					continue;
				}
				break;
			}
			if (!*p)
				return 0; /* missing assembly name */
			if (!assembly_name_to_aname (&info->assembly, p))
				return 0;
			break;
		default:
			return 0;
		}
		if (info->assembly.name)
			break;
	}
	// *w = 0; /* terminate class name */
 end:
	if (!info->name || !*info->name)
		return 0;
	if (endptr)
		*endptr = p;
	/* add other consistency checks */
	return 1;
}


mono_type_is_generic_argument (MonoType *type)
{
	return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
}


mono_blob_entry_hash (const char* str)
{
	guint len, h;
	const char *end;
	len = mono_metadata_decode_blob_size (str, &str);
	if (len > 0) {
		end = str + len;
		h = *str;
		for (str += 1; str < end; str++)
			h = (h << 5) - h + *str;
		return h;
	} else {
		return 0;
	}
}


verifier_load_method (VerifyContext *ctx, int token, const char *opcode) {
	MonoMethod* method;

	if (!IS_METHOD_DEF_OR_REF_OR_SPEC (token) || !token_bounds_check (ctx->image, token)) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Invalid method token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	method = mono_get_method_full (ctx->image, token, NULL, ctx->generic_context);

	if (!method) {
		ADD_VERIFY_ERROR2 (ctx, g_strdup_printf ("Cannot load method from token 0x%08x for %s at 0x%04x", token, opcode, ctx->ip_offset), MONO_EXCEPTION_BAD_IMAGE);
		return NULL;
	}

	if (mono_method_is_valid_in_context (ctx, method) == RESULT_INVALID)
		return NULL;

	return method;
}


collect_types (GPtrArray *types, MonoReflectionTypeBuilder *type)
{
	int i;

	g_ptr_array_add (types, type); /* FIXME: GC object added to unmanaged memory */

	if (!type->subtypes)
		return;

	for (i = 0; i < mono_array_length (type->subtypes); ++i) {
		MonoReflectionTypeBuilder *subtype = mono_array_get (type->subtypes, MonoReflectionTypeBuilder*, i);
		collect_types (types, subtype);
	}
}


is_usertype (MonoReflectionType *ref)
{
	MonoClass *class = mono_object_class (ref);
	return class->image != mono_defaults.corlib || strcmp ("TypeDelegator", class->name) == 0;
}


gboolean
mono_verifier_verify_class (MonoClass *class)
{
	/* The verifier was disabled at compile time */
	return TRUE;


MonoType*
mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types)
{
	MonoClass *klass;
	MonoReflectionTypeBuilder *tb = NULL;
	gboolean is_dynamic = FALSE;
	MonoDomain *domain;
	MonoClass *geninst;

	mono_loader_lock ();

	domain = mono_object_domain (type);

	if (!strcmp (((MonoObject *) type)->vtable->klass->name, "TypeBuilder")) {
		tb = (MonoReflectionTypeBuilder *) type;

		is_dynamic = TRUE;
	} else if (!strcmp (((MonoObject *) type)->vtable->klass->name, "MonoGenericClass")) {
		MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;

		tb = rgi->generic_type;
		is_dynamic = TRUE;
	}

	/* FIXME: fix the CreateGenericParameters protocol to avoid the two stage setup of TypeBuilders */
	if (tb && tb->generic_container)
		mono_reflection_create_generic_class (tb);

	klass = mono_class_from_mono_type (mono_reflection_type_get_handle (type));
	if (!klass->generic_container) {
		mono_loader_unlock ();
		return NULL;
	}

	if (klass->wastypebuilder) {
		tb = (MonoReflectionTypeBuilder *) klass->reflection_info;

		is_dynamic = TRUE;
	}

	mono_loader_unlock ();

	geninst = mono_class_bind_generic_parameters (klass, type_argc, types, is_dynamic);

	return &geninst->byval_arg;


encode_constraints (MonoReflectionGenericParam *gparam, guint32 owner, MonoDynamicImage *assembly)
{
	MonoDynamicTable *table;
	guint32 num_constraints, i;
	guint32 *values;
	guint32 table_idx;

	table = &assembly->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
	num_constraints = gparam->iface_constraints ?
		mono_array_length (gparam->iface_constraints) : 0;
	table->rows += num_constraints;
	if (gparam->base_type)
		table->rows++;
	alloc_table (table, table->rows);

	if (gparam->base_type) {
		table_idx = table->next_idx ++;
		values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;

		values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
		values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (
			assembly, mono_reflection_type_get_handle (gparam->base_type));
	}

	for (i = 0; i < num_constraints; i++) {
		MonoReflectionType *constraint = mono_array_get (
			gparam->iface_constraints, gpointer, i);

		table_idx = table->next_idx ++;
		values = table->values + table_idx * MONO_GENPARCONSTRAINT_SIZE;

		values [MONO_GENPARCONSTRAINT_GENERICPAR] = owner;
		values [MONO_GENPARCONSTRAINT_CONSTRAINT] = mono_image_typedef_or_ref (
			assembly, mono_reflection_type_get_handle (constraint));
	}
}


MonoReflectionEvent *
mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
{
	g_assert_not_reached ();
	return NULL;


mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 original,
				     const gchar *name, guint32 sig)
{
	MonoDynamicTable *table;
	guint32 token;
	guint32 *values;

	table = &assembly->tables [MONO_TABLE_MEMBERREF];

	if (assembly->save) {
		alloc_table (table, table->rows + 1);
		values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
		values [MONO_MEMBERREF_CLASS] = original;
		values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
		values [MONO_MEMBERREF_SIGNATURE] = sig;
	}

	token = MONO_TOKEN_MEMBER_REF | table->next_idx;
	table->next_idx ++;

	return token;
}


stack_slot_stack_type_full_name (ILStackDesc *value)
{
	GString *str = g_string_new ("");
	char *result;
	gboolean has_pred = FALSE, first = TRUE;

	if ((value->stype & TYPE_MASK) != value->stype) {
		g_string_append(str, "[");
		APPEND_WITH_PREDICATE (stack_slot_is_this_pointer, "this");
		APPEND_WITH_PREDICATE (stack_slot_is_boxed_value, "boxed");
		APPEND_WITH_PREDICATE (stack_slot_is_null_literal, "null");
		APPEND_WITH_PREDICATE (stack_slot_is_managed_mutability_pointer, "cmmp");
		APPEND_WITH_PREDICATE (stack_slot_is_managed_pointer, "mp");
		has_pred = TRUE;
	}

	if (mono_type_is_generic_argument (value->type) && !stack_slot_is_boxed_value (value)) {
		if (!has_pred)
			g_string_append(str, "[");
		if (!first)
			g_string_append (str, ", ");
		g_string_append (str, "unboxed");
		has_pred = TRUE;
	}

	if (has_pred)
		g_string_append(str, "] ");

	g_string_append (str, stack_slot_get_name (value));
	result = str->str;
	g_string_free (str, FALSE);
	return result;
}


reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb, MonoReflectionMethodBuilder *mb)
{
	memset (rmb, 0, sizeof (ReflectionMethodBuilder));

	rmb->ilgen = mb->ilgen;
	rmb->rtype = mono_reflection_type_resolve_user_types ((MonoReflectionType*)mb->rtype);
	rmb->parameters = mb->parameters;
	rmb->generic_params = mb->generic_params;
	rmb->generic_container = mb->generic_container;
	rmb->opt_types = NULL;
	rmb->pinfo = mb->pinfo;
	rmb->attrs = mb->attrs;
	rmb->iattrs = mb->iattrs;
	rmb->call_conv = mb->call_conv;
	rmb->code = mb->code;
	rmb->type = mb->type;
	rmb->name = mb->name;
	rmb->table_idx = &mb->table_idx;
	rmb->init_locals = mb->init_locals;
	rmb->skip_visibility = FALSE;
	rmb->return_modreq = mb->return_modreq;
	rmb->return_modopt = mb->return_modopt;
	rmb->param_modreq = mb->param_modreq;
	rmb->param_modopt = mb->param_modopt;
	rmb->permissions = mb->permissions;
	rmb->mhandle = mb->mhandle;
	rmb->nrefs = 0;
	rmb->refs = NULL;

	if (mb->dll) {
		rmb->charset = mb->charset;
		rmb->extra_flags = mb->extra_flags;
		rmb->native_cc = mb->native_cc;
		rmb->dllentry = mb->dllentry;
		rmb->dll = mb->dll;
	}
}


mono_generic_class_get_object (MonoDomain *domain, MonoType *geninst)
{
	static MonoClass *System_Reflection_MonoGenericClass;
	MonoReflectionGenericClass *res;
	MonoClass *klass, *gklass;
	MonoGenericInst *ginst;
	MonoArray *type_args;
	int i;

	if (!System_Reflection_MonoGenericClass) {
		System_Reflection_MonoGenericClass = mono_class_from_name (
			mono_defaults.corlib, "System.Reflection", "MonoGenericClass");
		g_assert (System_Reflection_MonoGenericClass);
	}

	klass = mono_class_from_mono_type (geninst);
	gklass = klass->generic_class->container_class;

	mono_class_init (klass);

#ifdef HAVE_SGEN_GC
	res = (MonoReflectionGenericClass *) mono_gc_alloc_pinned_obj (mono_class_vtable (domain, System_Reflection_MonoGenericClass), mono_class_instance_size (System_Reflection_MonoGenericClass));
#else
	res = (MonoReflectionGenericClass *) mono_object_new (domain, System_Reflection_MonoGenericClass);
#endif

	res->type.type = geninst;
	g_assert (gklass->reflection_info);
	g_assert (!strcmp (((MonoObject*)gklass->reflection_info)->vtable->klass->name, "TypeBuilder"));
	MONO_OBJECT_SETREF (res, generic_type, gklass->reflection_info);

	ginst = klass->generic_class->context.class_inst;
	type_args = mono_array_new (domain, mono_defaults.systemtype_class, ginst->type_argc);
	for (i = 0; i < ginst->type_argc; ++i)
		mono_array_setref (type_args, i, mono_type_get_object (domain, ginst->type_argv [i]));
	MONO_OBJECT_SETREF (res, type_arguments, type_args);

	return res;
}


do_load_indirect (VerifyContext *ctx, int opcode)
{
	ILStackDesc *value;
	CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);

	if (!check_underflow (ctx, 1))
		return;

	value = stack_pop (ctx);
	if (!stack_slot_is_managed_pointer (value)) {
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Load indirect not using a manager pointer at 0x%04x", ctx->ip_offset));
		set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
		return;
	}

	if (opcode == CEE_LDIND_REF) {
		if (stack_slot_get_underlying_type (value) != TYPE_COMPLEX || mono_class_from_mono_type (value->type)->valuetype)
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind_ref expected object byref operation at 0x%04x", ctx->ip_offset));
		set_stack_value (ctx, stack_push (ctx), mono_type_get_type_byval (value->type), FALSE);
	} else {
		if (!verify_type_compatibility_full (ctx, mono_type_from_opcode (opcode), mono_type_get_type_byval (value->type), TRUE))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid type at stack for ldind 0x%x operation at 0x%04x", opcode, ctx->ip_offset));
		set_stack_value (ctx, stack_push (ctx), mono_type_from_opcode (opcode), FALSE);
	}
}


encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf)
{
	if (!type) {
		g_assert_not_reached ();
		return;
	}

	if (type->byref)
		sigbuffer_add_value (buf, MONO_TYPE_BYREF);

	switch (type->type){
	case MONO_TYPE_VOID:
	case MONO_TYPE_BOOLEAN:
	case MONO_TYPE_CHAR:
	case MONO_TYPE_I1:
	case MONO_TYPE_U1:
	case MONO_TYPE_I2:
	case MONO_TYPE_U2:
	case MONO_TYPE_I4:
	case MONO_TYPE_U4:
	case MONO_TYPE_I8:
	case MONO_TYPE_U8:
	case MONO_TYPE_R4:
	case MONO_TYPE_R8:
	case MONO_TYPE_I:
	case MONO_TYPE_U:
	case MONO_TYPE_STRING:
	case MONO_TYPE_OBJECT:
	case MONO_TYPE_TYPEDBYREF:
		sigbuffer_add_value (buf, type->type);
		break;
	case MONO_TYPE_PTR:
		sigbuffer_add_value (buf, type->type);
		encode_type (assembly, type->data.type, buf);
		break;
	case MONO_TYPE_SZARRAY:
		sigbuffer_add_value (buf, type->type);
		encode_type (assembly, &type->data.klass->byval_arg, buf);
		break;
	case MONO_TYPE_VALUETYPE:
	case MONO_TYPE_CLASS: {
		MonoClass *k = mono_class_from_mono_type (type);

		if (k->generic_container) {
			MonoGenericClass *gclass = mono_metadata_lookup_generic_class (k, k->generic_container->context.class_inst, TRUE);
			encode_generic_class (assembly, gclass, buf);
		} else {
			/*
			 * Make sure we use the correct type.
			 */
			sigbuffer_add_value (buf, k->byval_arg.type);
			/*
			 * ensure only non-byref gets passed to mono_image_typedef_or_ref(),
			 * otherwise two typerefs could point to the same type, leading to
			 * verification errors.
			 */
			sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, &k->byval_arg));
		}
		break;
	}
	case MONO_TYPE_ARRAY:
		sigbuffer_add_value (buf, type->type);
		encode_type (assembly, &type->data.array->eklass->byval_arg, buf);
		sigbuffer_add_value (buf, type->data.array->rank);
		sigbuffer_add_value (buf, 0); /* FIXME: set to 0 for now */
		sigbuffer_add_value (buf, 0);
		break;
	case MONO_TYPE_GENERICINST:
		encode_generic_class (assembly, type->data.generic_class, buf);
		break;
	case MONO_TYPE_VAR:
	case MONO_TYPE_MVAR:
		sigbuffer_add_value (buf, type->type);
		sigbuffer_add_value (buf, mono_type_get_generic_param_num (type));
		break;
	default:
		g_error ("need to encode type %x", type->type);
	}
}


do_initobj (VerifyContext *ctx, int token)
{
	ILStackDesc *obj;
	MonoType *stack, *type = get_boxable_mono_type (ctx, token, "initobj");
	if (!type)
		return;

	if (!check_underflow (ctx, 1))
		return;

	obj = stack_pop (ctx);

	if (!stack_slot_is_managed_pointer (obj))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid object address for initobj at 0x%04x", ctx->ip_offset));

	if (stack_slot_is_managed_mutability_pointer (obj))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with initobj at 0x%04x", ctx->ip_offset));

	stack = mono_type_get_type_byval (obj->type);
	if (MONO_TYPE_IS_REFERENCE (stack)) {
		if (!verify_type_compatibility (ctx, stack, type))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
		else if (IS_STRICT_MODE (ctx) && !mono_metadata_type_equal (type, stack))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Type token of initobj not compatible with value on stack at 0x%04x", ctx->ip_offset));
	} else if (!verify_type_compatibility (ctx, stack, type)) {
		char *expected_name = mono_type_full_name (type);
		char *stack_name = mono_type_full_name (stack);

		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Initobj %s not compatible with value on stack %s at 0x%04x", expected_name, stack_name, ctx->ip_offset));
		g_free (expected_name);
		g_free (stack_name);
	}
}


reflected_hash (gconstpointer a) {
	const ReflectedEntry *ea = a;
	return mono_aligned_addr_hash (ea->item);
}


static gboolean
is_usertype (MonoReflectionType *ref)
{
	MonoClass *class = mono_object_class (ref);
	return class->image != mono_defaults.corlib || strcmp ("TypeDelegator", class->name) == 0;


mono_image_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
{
	MonoDynamicAssembly *assembly;
	MonoDynamicImage *image;
	MonoDomain *domain = mono_object_domain (assemblyb);

	MONO_ARCH_SAVE_REGS;

	if (assemblyb->dynamic_assembly)
		return;

#if HAVE_BOEHM_GC
	/* assembly->assembly.image might be GC allocated */
	assembly = assemblyb->dynamic_assembly = GC_MALLOC (sizeof (MonoDynamicAssembly));
#else
	assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1);
#endif

	mono_profiler_assembly_event (&assembly->assembly, MONO_PROFILE_START_LOAD);

	assembly->assembly.ref_count = 1;
	assembly->assembly.dynamic = TRUE;
	assembly->assembly.corlib_internal = assemblyb->corlib_internal;
	assemblyb->assembly.assembly = (MonoAssembly*)assembly;
	assembly->assembly.basedir = mono_string_to_utf8 (assemblyb->dir);
	if (assemblyb->culture)
		assembly->assembly.aname.culture = mono_string_to_utf8 (assemblyb->culture);
	else
		assembly->assembly.aname.culture = g_strdup ("");

        if (assemblyb->version) {
			char *vstr = mono_string_to_utf8 (assemblyb->version);
			char **version = g_strsplit (vstr, ".", 4);
			char **parts = version;
			assembly->assembly.aname.major = atoi (*parts++);
			assembly->assembly.aname.minor = atoi (*parts++);
			assembly->assembly.aname.build = *parts != NULL ? atoi (*parts++) : 0;
			assembly->assembly.aname.revision = *parts != NULL ? atoi (*parts) : 0;

			g_strfreev (version);
			g_free (vstr);
        } else {
			assembly->assembly.aname.major = 0;
			assembly->assembly.aname.minor = 0;
			assembly->assembly.aname.build = 0;
			assembly->assembly.aname.revision = 0;
        }

	assembly->run = assemblyb->access != 2;
	assembly->save = assemblyb->access != 1;
	assembly->domain = domain;

	image = create_dynamic_mono_image (assembly, mono_string_to_utf8 (assemblyb->name), g_strdup ("RefEmit_YouForgotToDefineAModule"));
	image->initial_image = TRUE;
	assembly->assembly.aname.name = image->image.name;
	assembly->assembly.image = &image->image;
	if (assemblyb->pktoken && assemblyb->pktoken->max_length) {
		/* -1 to correct for the trailing NULL byte */
		if (assemblyb->pktoken->max_length != MONO_PUBLIC_KEY_TOKEN_LENGTH - 1) {
			g_error ("Public key token length invalid for assembly %s: %i", assembly->assembly.aname.name, assemblyb->pktoken->max_length);
		}
		memcpy (&assembly->assembly.aname.public_key_token, mono_array_addr (assemblyb->pktoken, guint8, 0), assemblyb->pktoken->max_length);
	}

	mono_domain_assemblies_lock (domain);
	domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, assembly);
	mono_domain_assemblies_unlock (domain);

	register_assembly (mono_object_domain (assemblyb), &assemblyb->assembly, &assembly->assembly);

	mono_profiler_assembly_loaded (&assembly->assembly, MONO_PROFILE_OK);

	mono_assembly_invoke_load_hook ((MonoAssembly*)assembly);
}


mono_reflection_resolve_custom_attribute_data (MonoReflectionMethod *ref_method, MonoReflectionAssembly *assembly, gpointer data, guint32 len, MonoArray **ctor_args, MonoArray **named_args)
{
	MonoDomain *domain;
	MonoArray *typedargs, *namedargs;
	MonoImage *image;
	MonoMethod *method;
	CattrNamedArg *arginfo;
	int i;

	*ctor_args = NULL;
	*named_args = NULL;

	if (len == 0)
		return;

	image = assembly->assembly->image;
	method = ref_method->method;
	domain = mono_object_domain (ref_method);

	if (!mono_class_init (method->klass))
		mono_raise_exception (mono_class_get_exception_for_failure (method->klass));

	mono_reflection_create_custom_attr_data_args (image, method, data, len, &typedargs, &namedargs, &arginfo);
	if (mono_loader_get_last_error ())
		mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));

	if (!typedargs || !namedargs)
		return;

	for (i = 0; i < mono_method_signature (method)->param_count; ++i) {
		MonoObject *obj = mono_array_get (typedargs, MonoObject*, i);
		MonoObject *typedarg;

		typedarg = create_cattr_typed_arg (mono_method_signature (method)->params [i], obj);
		mono_array_setref (typedargs, i, typedarg);
	}

	for (i = 0; i < mono_array_length (namedargs); ++i) {
		MonoObject *obj = mono_array_get (namedargs, MonoObject*, i);
		MonoObject *typedarg, *namedarg, *minfo;

		if (arginfo [i].prop)
			minfo = (MonoObject*)mono_property_get_object (domain, NULL, arginfo [i].prop);
		else
			minfo = (MonoObject*)mono_field_get_object (domain, NULL, arginfo [i].field);

		typedarg = create_cattr_typed_arg (arginfo [i].type, obj);
		namedarg = create_cattr_named_arg (minfo, typedarg);

		mono_array_setref (namedargs, i, namedarg);
	}

	*ctor_args = typedargs;
	*named_args = namedargs;
}


mono_custom_attrs_data_construct (MonoCustomAttrInfo *cinfo)
{
	MonoArray *result;
	MonoObject *attr;
	int i;

	result = mono_array_new (mono_domain_get (), mono_defaults.customattribute_data_class, cinfo->num_attrs);
	for (i = 0; i < cinfo->num_attrs; ++i) {
		attr = create_custom_attr_data (cinfo->image, &cinfo->attrs [i]);
		mono_array_setref (result, i, attr);
	}
	return result;
}


mono_reflection_get_type_internal (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, gboolean ignorecase)
{
	MonoClass *klass;
	GList *mod;
	int modval;
	gboolean bounded = FALSE;

	if (!image)
		image = mono_defaults.corlib;

	if (ignorecase)
		klass = mono_class_from_name_case (image, info->name_space, info->name);
	else
		klass = mono_class_from_name (image, info->name_space, info->name);
	if (!klass)
		return NULL;
	for (mod = info->nested; mod; mod = mod->next) {
		gpointer iter = NULL;
		MonoClass *parent;

		parent = klass;
		mono_class_init (parent);

		while ((klass = mono_class_get_nested_types (parent, &iter))) {
			if (ignorecase) {
				if (mono_utf8_strcasecmp (klass->name, mod->data) == 0)
					break;
			} else {
				if (strcmp (klass->name, mod->data) == 0)
					break;
			}
		}
		if (!klass)
			break;
	}
	if (!klass)
		return NULL;

	if (info->type_arguments) {
		MonoType **type_args = g_new0 (MonoType *, info->type_arguments->len);
		MonoReflectionType *the_type;
		MonoType *instance;
		int i;

		for (i = 0; i < info->type_arguments->len; i++) {
			MonoTypeNameParse *subinfo = g_ptr_array_index (info->type_arguments, i);

			type_args [i] = _mono_reflection_get_type_from_info (subinfo, rootimage, ignorecase);
			if (!type_args [i]) {
				g_free (type_args);
				return NULL;
			}
		}

		the_type = mono_type_get_object (mono_domain_get (), &klass->byval_arg);

		instance = mono_reflection_bind_generic_parameters (
			the_type, info->type_arguments->len, type_args);

		g_free (type_args);
		if (!instance)
			return NULL;

		klass = mono_class_from_mono_type (instance);
	}

	for (mod = info->modifiers; mod; mod = mod->next) {
		modval = GPOINTER_TO_UINT (mod->data);
		if (!modval) { /* byref: must be last modifier */
			return &klass->this_arg;
		} else if (modval == -1) {
			klass = mono_ptr_class_get (&klass->byval_arg);
		} else if (modval == -2) {
			bounded = TRUE;
		} else { /* array rank */
			klass = mono_bounded_array_class_get (klass, modval, bounded);
		}
	}

	return &klass->byval_arg;
}


gboolean
mono_verifier_is_class_full_trust (MonoClass *klass)
{
	/* under CoreCLR code is trusted if it is part of the "platform" otherwise all code inside the GAC is trusted */
	gboolean trusted_location = (mono_security_get_mode () != MONO_SECURITY_MODE_CORE_CLR) ?
		(klass->image->assembly && klass->image->assembly->in_gac) : mono_security_core_clr_is_platform_image (klass->image);

	if (verify_all && verifier_mode == MONO_VERIFIER_MODE_OFF)
		return trusted_location || klass->image == mono_defaults.corlib;
	return verifier_mode < MONO_VERIFIER_MODE_VERIFIABLE || trusted_location || klass->image == mono_defaults.corlib;


do_store_static_field (VerifyContext *ctx, int token) {
	MonoClassField *field;
	MonoClass *klass;
	ILStackDesc *value;
	CLEAR_PREFIX (ctx, PREFIX_VOLATILE);

	if (!check_underflow (ctx, 1))
		return;

	value = stack_pop (ctx);

	if (!(field = verifier_load_field (ctx, token, &klass, "stsfld")))
		return;

	if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot store non static field at 0x%04x", ctx->ip_offset));
		return;
	}

	if (field->type->type == MONO_TYPE_TYPEDBYREF) {
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Typedbyref field is an unverfiable type in store static field at 0x%04x", ctx->ip_offset));
		return;
	}

	if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_field_full (ctx->method, field, NULL))
		CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Type at stack is not accessible at 0x%04x", ctx->ip_offset), MONO_EXCEPTION_FIELD_ACCESS);

	if (!verify_stack_type_compatibility (ctx, field->type, value)) {
		char *stack_name = stack_slot_full_name (value);
		char *field_name = mono_type_full_name (field->type);
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible type in static field store expected '%s' but found '%s' at 0x%04x",
				field_name, stack_name, ctx->ip_offset));
		g_free (field_name);
		g_free (stack_name);
	}
}


do_stobj (VerifyContext *ctx, int token)
{
	ILStackDesc *dest, *src;
	MonoType *type = get_boxable_mono_type (ctx, token, "stobj");
	CLEAR_PREFIX (ctx, PREFIX_UNALIGNED | PREFIX_VOLATILE);

	if (!type)
		return;

	if (!check_underflow (ctx, 2))
		return;

	src = stack_pop (ctx);
	dest = stack_pop (ctx);

	if (stack_slot_is_managed_mutability_pointer (dest))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer with stobj at 0x%04x", ctx->ip_offset));

	if (!stack_slot_is_managed_pointer (dest))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid destination of stobj operation at 0x%04x", ctx->ip_offset));

	if (stack_slot_is_boxed_value (src) && !MONO_TYPE_IS_REFERENCE (src->type) && !MONO_TYPE_IS_REFERENCE (type))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use stobj with a boxed source value that is not a reference type at 0x%04x", ctx->ip_offset));

	if (!verify_stack_type_compatibility (ctx, type, src)) {
		char *type_name = mono_type_full_name (type);
		char *src_name = stack_slot_full_name (src);
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Token '%s' and source '%s' of stobj don't match ' at 0x%04x", type_name, src_name, ctx->ip_offset));
		g_free (type_name);
		g_free (src_name);
	}

	if (!verify_type_compatibility (ctx, mono_type_get_type_byval (dest->type), type))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Destination and token types of stobj don't match at 0x%04x", ctx->ip_offset));
}


do_invoke_method (VerifyContext *ctx, int method_token, gboolean virtual)
{
	int param_count, i;
	MonoMethodSignature *sig;
	ILStackDesc *value;
	MonoMethod *method;
	gboolean virt_check_this = FALSE;
	gboolean constrained = ctx->prefix_set & PREFIX_CONSTRAINED;

	if (!(method = verifier_load_method (ctx, method_token, virtual ? "callvirt" : "call")))
		return;

	if (virtual) {
		CLEAR_PREFIX (ctx, PREFIX_CONSTRAINED);

		if (method->klass->valuetype) // && !constrained ???
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with valuetype method at 0x%04x", ctx->ip_offset));

		if ((method->flags & METHOD_ATTRIBUTE_STATIC))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use callvirtual with static method at 0x%04x", ctx->ip_offset));

	} else {
		if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use call with an abstract method at 0x%04x", ctx->ip_offset));

		if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !(method->flags & METHOD_ATTRIBUTE_FINAL) && !(method->klass->flags & TYPE_ATTRIBUTE_SEALED)) {
			virt_check_this = TRUE;
			ctx->code [ctx->ip_offset].flags |= IL_CODE_CALL_NONFINAL_VIRTUAL;
		}
	}

	if (!(sig = mono_method_get_signature_full (method, ctx->image, method_token, ctx->generic_context)))
		sig = mono_method_get_signature (method, ctx->image, method_token);

	if (!sig) {
		char *name = mono_type_get_full_name (method->klass);
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Could not resolve signature of %s:%s at 0x%04x", name, method->name, ctx->ip_offset));
		g_free (name);
		return;
	}

	param_count = sig->param_count + sig->hasthis;
	if (!check_underflow (ctx, param_count))
		return;

	for (i = sig->param_count - 1; i >= 0; --i) {
		VERIFIER_DEBUG ( printf ("verifying argument %d\n", i); );
		value = stack_pop (ctx);
		if (!verify_stack_type_compatibility (ctx, sig->params[i], value)) {
			char *stack_name = stack_slot_full_name (value);
			char *sig_name = mono_type_full_name (sig->params [i]);
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible parameter with function signature: Calling method with signature (%s) but for argument %d there is a (%s) on stack at 0x%04x", sig_name, i, stack_name, ctx->ip_offset));
			g_free (stack_name);
			g_free (sig_name);
		}

		if (stack_slot_is_managed_mutability_pointer (value))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a readonly pointer as argument of %s at 0x%04x", virtual ? "callvirt" : "call",  ctx->ip_offset));

		if ((ctx->prefix_set & PREFIX_TAIL) && stack_slot_is_managed_pointer (value)) {
			ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Cannot  pass a byref argument to a tail %s at 0x%04x", virtual ? "callvirt" : "call",  ctx->ip_offset));
			return;
		}
	}

	if (sig->hasthis) {
		MonoType *type = &method->klass->byval_arg;
		ILStackDesc copy;

		if (mono_method_is_constructor (method) && !method->klass->valuetype) {
			if (!mono_method_is_constructor (ctx->method))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor outside one at 0x%04x", ctx->ip_offset));
			if (method->klass != ctx->method->klass->parent && method->klass != ctx->method->klass)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a constructor to a type diferent that this or super at 0x%04x", ctx->ip_offset));

			ctx->super_ctor_called = TRUE;
			value = stack_pop_safe (ctx);
			if ((value->stype & THIS_POINTER_MASK) != THIS_POINTER_MASK)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Invalid 'this ptr' argument for constructor at 0x%04x", ctx->ip_offset));
		} else {
			value = stack_pop (ctx);
		}

		copy_stack_value (&copy, value);
		//TODO we should extract this to a 'drop_byref_argument' and use everywhere
		//Other parts of the code suffer from the same issue of
		copy.type = mono_type_get_type_byval (copy.type);
		copy.stype &= ~POINTER_MASK;

		if (virt_check_this && !stack_slot_is_this_pointer (value) && !(method->klass->valuetype || stack_slot_is_boxed_value (value)))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use the call opcode with a non-final virtual method on an object diferent thant the this pointer at 0x%04x", ctx->ip_offset));

		if (constrained && virtual) {
			if (!stack_slot_is_managed_pointer (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object is not a managed pointer for a constrained call at 0x%04x", ctx->ip_offset));
			if (!mono_metadata_type_equal_full (mono_type_get_type_byval (value->type), ctx->constrained_type, TRUE))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Object not compatible with constrained type at 0x%04x", ctx->ip_offset));
			copy.stype |= BOXED_MASK;
		} else {
			if (stack_slot_is_managed_pointer (value) && !mono_class_from_mono_type (value->type)->valuetype)
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a reference type using a managed pointer to the this arg at 0x%04x", ctx->ip_offset));

			if (!virtual && mono_class_from_mono_type (value->type)->valuetype && !method->klass->valuetype && !stack_slot_is_boxed_value (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot call a valuetype baseclass at 0x%04x", ctx->ip_offset));

			if (virtual && mono_class_from_mono_type (value->type)->valuetype && !stack_slot_is_boxed_value (value))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a valuetype with callvirt at 0x%04x", ctx->ip_offset));

			if (method->klass->valuetype && (stack_slot_is_boxed_value (value) || !stack_slot_is_managed_pointer (value)))
				CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Cannot use a boxed or literal valuetype to call a valuetype method at 0x%04x", ctx->ip_offset));
		}
		if (!verify_stack_type_compatibility (ctx, type, &copy)) {
			char *expected = mono_type_full_name (type);
			char *effective = stack_slot_full_name (&copy);
			char *method_name = mono_method_full_name (method, TRUE);
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Incompatible this argument on stack with method signature expected '%s' but got '%s' for a call to '%s' at 0x%04x",
					expected, effective, method_name, ctx->ip_offset));
			g_free (method_name);
			g_free (effective);
			g_free (expected);
		}

		if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, mono_class_from_mono_type (value->type))) {
			char *name = mono_method_full_name (method, TRUE);
			CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
			g_free (name);
		}

	} else if (!IS_SKIP_VISIBILITY (ctx) && !mono_method_can_access_method_full (ctx->method, method, NULL)) {
		char *name = mono_method_full_name (method, TRUE);
		CODE_NOT_VERIFIABLE2 (ctx, g_strdup_printf ("Method %s is not accessible at 0x%04x", name, ctx->ip_offset), MONO_EXCEPTION_METHOD_ACCESS);
		g_free (name);
	}

	if (sig->ret->type != MONO_TYPE_VOID) {
		if (check_overflow (ctx)) {
			value = stack_push (ctx);
			set_stack_value (ctx, value, sig->ret, FALSE);
			if ((ctx->prefix_set & PREFIX_READONLY) && method->klass->rank && !strcmp (method->name, "Address")) {
				ctx->prefix_set &= ~PREFIX_READONLY;
				value->stype |= CMMP_MASK;
			}
		}
	}

	if ((ctx->prefix_set & PREFIX_TAIL)) {
		if (!mono_delegate_ret_equal (mono_method_signature (ctx->method)->ret, sig->ret))
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call with incompatible return type at 0x%04x", ctx->ip_offset));
		if (ctx->header->code [ctx->ip_offset + 5] != CEE_RET)
			CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Tail call not followed by ret at 0x%04x", ctx->ip_offset));
	}

}


do_leave (VerifyContext *ctx, int delta)
{
	int target = ((gint32)ctx->ip_offset) + delta;
	if (target >= ctx->code_size || target < 0)
		ADD_VERIFY_ERROR (ctx, g_strdup_printf ("Branch target out of code at 0x%04x", ctx->ip_offset));

	if (!is_correct_leave (ctx->header, ctx->ip_offset, target))
		CODE_NOT_VERIFIABLE (ctx, g_strdup_printf ("Leave not allowed in finally block at 0x%04x", ctx->ip_offset));
	ctx->eval.size = 0;
}


mono_image_get_field_on_inst_token (MonoDynamicImage *assembly, MonoReflectionFieldOnTypeBuilderInst *f)
{
	guint32 token;
	MonoClass *klass;
	MonoGenericClass *gclass;
	MonoDynamicGenericClass *dgclass;
	MonoType *type;
	char *name;

	token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, f));
	if (token)
		return token;
	if (is_sre_field_builder (mono_object_class (f->fb))) {
		MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)f->fb;
		type = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst);
		klass = mono_class_from_mono_type (type);
		gclass = type->data.generic_class;
		g_assert (gclass->is_dynamic);
		dgclass = (MonoDynamicGenericClass *) gclass;

		name = mono_string_to_utf8 (fb->name);
		token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name,
												field_encode_signature (assembly, fb));
		g_free (name);
	} else if (is_sr_mono_field (mono_object_class (f->fb))) {
		guint32 sig;
		MonoClassField *field = ((MonoReflectionField *)f->fb)->field;

		type = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst);
		klass = mono_class_from_mono_type (type);

		sig = fieldref_encode_signature (assembly, field->parent->image, field->type);
		token = mono_image_get_memberref_token (assembly, &klass->byval_arg, field->name, sig);
	} else {
		char *name = mono_type_get_full_name (mono_object_class (f->fb));
		g_error ("mono_image_get_field_on_inst_token: don't know how to handle %s", name);
	}

	mono_g_hash_table_insert (assembly->handleref_managed, f, GUINT_TO_POINTER (token));
	return token;
}


init_type_builder_generics (MonoObject *type)
{
	MonoReflectionTypeBuilder *tb;

	if (!is_sre_type_builder(mono_object_class (type)))
		return;
	tb = (MonoReflectionTypeBuilder *)type;

	if (tb && tb->generic_container)
		mono_reflection_create_generic_class (tb);
}


mono_param_get_objects_internal (MonoDomain *domain, MonoMethod *method, MonoClass *refclass)
{
	static MonoClass *System_Reflection_ParameterInfo;
	static MonoClass *System_Reflection_ParameterInfo_array;
	MonoError error;
	MonoArray *res = NULL;
	MonoReflectionMethod *member = NULL;
	MonoReflectionParameter *param = NULL;
	char **names, **blobs = NULL;
	guint32 *types = NULL;
	MonoType *type = NULL;
	MonoObject *dbnull = NULL;
	MonoObject *missing = NULL;
	MonoMarshalSpec **mspecs;
	MonoMethodSignature *sig;
	MonoVTable *pinfo_vtable;
	int i;

	if (!System_Reflection_ParameterInfo_array) {
		MonoClass *klass;

		klass = mono_class_from_name (mono_defaults.corlib, "System.Reflection", "ParameterInfo");
		mono_memory_barrier ();
		System_Reflection_ParameterInfo = klass;

		klass = mono_array_class_get (klass, 1);
		mono_memory_barrier ();
		System_Reflection_ParameterInfo_array = klass;
	}

	sig = mono_method_signature_checked (method, &error);
	if (!mono_error_ok (&error))
		mono_error_raise_exception (&error);

	if (!sig->param_count)
		return mono_array_new_specific (mono_class_vtable (domain, System_Reflection_ParameterInfo_array), 0);

	/* Note: the cache is based on the address of the signature into the method
	 * since we already cache MethodInfos with the method as keys.
	 */
	CHECK_OBJECT (MonoArray*, &(method->signature), refclass);

	member = mono_method_get_object (domain, method, refclass);
	names = g_new (char *, sig->param_count);
	mono_method_get_param_names (method, (const char **) names);

	mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
	mono_method_get_marshal_info (method, mspecs);

	res = mono_array_new_specific (mono_class_vtable (domain, System_Reflection_ParameterInfo_array), sig->param_count);
	pinfo_vtable = mono_class_vtable (domain, System_Reflection_ParameterInfo);
	for (i = 0; i < sig->param_count; ++i) {
		param = (MonoReflectionParameter *)mono_object_new_specific (pinfo_vtable);
		MONO_OBJECT_SETREF (param, ClassImpl, mono_type_get_object (domain, sig->params [i]));
		MONO_OBJECT_SETREF (param, MemberImpl, (MonoObject*)member);
		MONO_OBJECT_SETREF (param, NameImpl, mono_string_new (domain, names [i]));
		param->PositionImpl = i;
		param->AttrsImpl = sig->params [i]->attrs;

		if (!(param->AttrsImpl & PARAM_ATTRIBUTE_HAS_DEFAULT)) {
			if (param->AttrsImpl & PARAM_ATTRIBUTE_OPTIONAL)
				MONO_OBJECT_SETREF (param, DefaultValueImpl, get_reflection_missing (domain, &missing));
			else
				MONO_OBJECT_SETREF (param, DefaultValueImpl, get_dbnull (domain, &dbnull));
		} else {

			if (!blobs) {
				blobs = g_new0 (char *, sig->param_count);
				types = g_new0 (guint32, sig->param_count);
				get_default_param_value_blobs (method, blobs, types);
			}

			/* Build MonoType for the type from the Constant Table */
			if (!type)
				type = g_new0 (MonoType, 1);
			type->type = types [i];
			type->data.klass = NULL;
			if (types [i] == MONO_TYPE_CLASS)
				type->data.klass = mono_defaults.object_class;
			else if ((sig->params [i]->type == MONO_TYPE_VALUETYPE) && sig->params [i]->data.klass->enumtype) {
				/* For enums, types [i] contains the base type */

					type->type = MONO_TYPE_VALUETYPE;
					type->data.klass = mono_class_from_mono_type (sig->params [i]);
			} else
				type->data.klass = mono_class_from_mono_type (type);

			MONO_OBJECT_SETREF (param, DefaultValueImpl, mono_get_object_from_blob (domain, type, blobs [i]));

			/* Type in the Constant table is MONO_TYPE_CLASS for nulls */
			if (types [i] != MONO_TYPE_CLASS && !param->DefaultValueImpl) {
				if (param->AttrsImpl & PARAM_ATTRIBUTE_OPTIONAL)
					MONO_OBJECT_SETREF (param, DefaultValueImpl, get_reflection_missing (domain, &missing));
				else
					MONO_OBJECT_SETREF (param, DefaultValueImpl, get_dbnull (domain, &dbnull));
			}

		}

		if (mspecs [i + 1])
			MONO_OBJECT_SETREF (param, MarshalAsImpl, (MonoObject*)mono_reflection_marshal_from_marshal_spec (domain, method->klass, mspecs [i + 1]));

		mono_array_setref (res, i, param);
	}
	g_free (names);
	g_free (blobs);
	g_free (types);
	g_free (type);

	for (i = mono_method_signature (method)->param_count; i >= 0; i--)
		if (mspecs [i])
			mono_metadata_free_marshal_spec (mspecs [i]);
	g_free (mspecs);

	CACHE_OBJECT (MonoArray *, &(method->signature), res, refclass);
}


is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *context, MonoGenericInst *ginst)
{
	MonoError error;
	int i;

	if (ginst->type_argc != gc->type_argc)
		return FALSE;

	for (i = 0; i < gc->type_argc; ++i) {
		MonoGenericParamInfo *param_info = mono_generic_container_get_param_info (gc, i);
		MonoClass *paramClass;
		MonoClass **constraints;
		MonoType *param_type = ginst->type_argv [i];

		/*it's not our job to validate type variables*/
		if (mono_type_is_generic_argument (param_type))
			continue;

		paramClass = mono_class_from_mono_type (param_type);

		if (paramClass->exception_type != MONO_EXCEPTION_NONE)
			return FALSE;

		/* A GTD can't be a generic argument.
		 *
		 * Due to how types are encoded we must check for the case of a genericinst MonoType and GTD MonoClass.
		 * This happens in cases such as: class Foo<T>  { void X() { new Bar<T> (); } }
		 *
		 * Open instantiations can have GTDs as this happens when one type is instantiated with others params
		 * and the former has an expansion into the later. For example:
		 * class B<K> {}
		 * class A<T>: B<K> {}
		 * The type A <K> has a parent B<K>, that is inflated into the GTD B<>.
		 * Since A<K> is open, thus not instantiatable, this is valid.
		 */
		if (paramClass->generic_container && param_type->type != MONO_TYPE_GENERICINST && !ginst->is_open)
			return FALSE;

		/*it's not safe to call mono_class_init from here*/
		if (paramClass->generic_class && !paramClass->inited) {
			if (!mono_class_is_valid_generic_instantiation (NULL, paramClass))
				return FALSE;
		}

		if (!param_info->constraints && !(param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK))
			continue;

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && (!paramClass->valuetype || mono_class_is_nullable (paramClass)))
			return FALSE;

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && paramClass->valuetype)
			return FALSE;

		if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !paramClass->valuetype && !mono_class_has_default_constructor (paramClass))
			return FALSE;

		if (!param_info->constraints)
			continue;

		for (constraints = param_info->constraints; *constraints; ++constraints) {
			MonoClass *ctr = *constraints;
			MonoType *inflated;

			inflated = mono_class_inflate_generic_type_checked (&ctr->byval_arg, context, &error);
			if (!mono_error_ok (&error)) {
				mono_error_cleanup (&error);
				return FALSE;
			}
			ctr = mono_class_from_mono_type (inflated);
			mono_metadata_free_type (inflated);

			if (!mono_class_is_assignable_from_slow (ctr, paramClass))
				return FALSE;
		}
	}
	return TRUE;
}


assembly_name_to_aname (MonoAssemblyName *assembly, char *p) {
	int found_sep;
	char *s;
	gboolean quoted = FALSE;

	memset (assembly, 0, sizeof (MonoAssemblyName));
	assembly->culture = "";
	memset (assembly->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);

	if (*p == '"') {
		quoted = TRUE;
		p++;
	}
	assembly->name = p;
	while (*p && (isalnum (*p) || *p == '.' || *p == '-' || *p == '_' || *p == '$' || *p == '@' || g_ascii_isspace (*p)))
		p++;
	if (quoted) {
		if (*p != '"')
			return 1;
		*p = 0;
		p++;
	}
	if (*p != ',')
		return 1;
	*p = 0;
	/* Remove trailing whitespace */
	s = p - 1;
	while (*s && g_ascii_isspace (*s))
		*s-- = 0;
	p ++;
	while (g_ascii_isspace (*p))
		p++;
	while (*p) {
		if (*p == 'V' && g_ascii_strncasecmp (p, "Version=", 8) == 0) {
			p += 8;
			assembly->major = strtoul (p, &s, 10);
			if (s == p || *s != '.')
				return 1;
			p = ++s;
			assembly->minor = strtoul (p, &s, 10);
			if (s == p || *s != '.')
				return 1;
			p = ++s;
			assembly->build = strtoul (p, &s, 10);
			if (s == p || *s != '.')
				return 1;
			p = ++s;
			assembly->revision = strtoul (p, &s, 10);
			if (s == p)
				return 1;
			p = s;
		} else if (*p == 'C' && g_ascii_strncasecmp (p, "Culture=", 8) == 0) {
			p += 8;
			if (g_ascii_strncasecmp (p, "neutral", 7) == 0) {
				assembly->culture = "";
				p += 7;
			} else {
				assembly->culture = p;
				while (*p && *p != ',') {
					p++;
				}
			}
		} else if (*p == 'P' && g_ascii_strncasecmp (p, "PublicKeyToken=", 15) == 0) {
			p += 15;
			if (strncmp (p, "null", 4) == 0) {
				p += 4;
			} else {
				int len;
				gchar *start = p;
				while (*p && *p != ',') {
					p++;
				}
				len = (p - start + 1);
				if (len > MONO_PUBLIC_KEY_TOKEN_LENGTH)
					len = MONO_PUBLIC_KEY_TOKEN_LENGTH;
				g_strlcpy ((char*)assembly->public_key_token, start, len);
			}
		} else {
			while (*p && *p != ',')
				p++;
		}
		found_sep = 0;
		while (g_ascii_isspace (*p) || *p == ',') {
			*p++ = 0;
			found_sep = 1;
			continue;
		}
		/* failed */
		if (!found_sep)
			return 1;
	}

	return 0;
}


string_format(uschar *buffer, int buflen, char *format, ...)
{
BOOL yield;
va_list ap;
va_start(ap, format);
yield = string_vformat(buffer, buflen, format, ap);
va_end(ap);
return yield;
}


string_split_message(uschar *msg)
{
uschar *s, *ss;

if (msg == NULL || Ustrlen(msg) <= 75) return msg;
s = ss = msg = string_copy(msg);

for (;;)
  {
  int i = 0;
  while (i < 75 && *ss != 0 && *ss != '\n') ss++, i++;
  if (*ss == 0) break;
  if (*ss == '\n')
    s = ++ss;
  else
    {
    uschar *t = ss + 1;
    uschar *tt = NULL;
    while (--t > s + 35)
      {
      if (*t == ' ')
        {
        if (t[-1] == ':') { tt = t; break; }
        if (tt == NULL) tt = t;
        }
      }

    if (tt == NULL)          /* Can't split behind - try ahead */
      {
      t = ss + 1;
      while (*t != 0)
        {
        if (*t == ' ' || *t == '\n')
          { tt = t; break; }
        t++;
        }
      }

    if (tt == NULL) break;   /* Can't find anywhere to split */
    *tt = '\n';
    s = ss = tt+1;
    }
  }

return msg;
}


static int sort_dvi_up(const void *p1, const void *p2)
{
	return ((long *)p1)[0] - ((long *)p2)[0];
}


static int vf_load_font(DviParams *params, DviFont *font)
{
	FILE	*p;
	Uchar	*macros;
	int	msize;
	int	mlen;
	Int32	checksum;
	long	alpha, beta, z;
	int	op;
	int	i;
	int	nchars;
	int	loc, hic;
	DviFontRef *last;

	macros = NULL;
	msize = mlen = 0;
	p = font->in;

	if(fuget1(p) != 247 || fuget1(p) != 202)
		goto badvf;
	mlen = fuget1(p);
	fseek(p, (long)mlen, SEEK_CUR);
	checksum = fuget4(p);
	if(checksum && font->checksum && checksum != font->checksum) {
		mdvi_warning(_("%s: Checksum mismatch (expected %u, got %u)\n"),
			     font->fontname, font->checksum, checksum);
	} else if(!font->checksum)
		font->checksum = checksum;
	font->design = fuget4(p);

	/* read all the fonts in the preamble */
	last = NULL;

	/* initialize alpha, beta and z for TFM width computation */
	TFMPREPARE(font->scale, z, alpha, beta);

	op = fuget1(p);
	while(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4) {
		DviFontRef *ref;
		Int32	scale, design;
		Uint32	checksum;
		int	id;
		int	n;
		int	hdpi;
		int	vdpi;
		char	*name;

		/* process fnt_def commands */

		id = fugetn(p, op - DVI_FNT_DEF1 + 1);
		checksum = fuget4(p);
		scale = fuget4(p);
		design = fuget4(p);

		/* scale this font according to our parent's scale */
		scale = TFMSCALE(scale, z, alpha, beta);
		design = FROUND(params->tfm_conv * design);

		/* compute the resolution */
		hdpi = FROUND(params->mag * params->dpi * scale / design);
		vdpi = FROUND(params->mag * params->vdpi * scale / design);
		n = fuget1(p) + fuget1(p);
		name = mdvi_malloc(n + 1);
		fread(name, 1, n, p);
		name[n] = 0;
		DEBUG((DBG_FONTS, "(vf) %s: defined font `%s' at %.1fpt (%dx%d dpi)\n",
			font->fontname, name,
			(double)scale / (params->tfm_conv * 0x100000), hdpi, vdpi));

		/* get the font */
		ref = font_reference(params, id, name, checksum, hdpi, vdpi, scale);
		if(ref == NULL) {
			mdvi_error(_("(vf) %s: could not load font `%s'\n"),
				   font->fontname, name);
			goto error;
		}
		mdvi_free(name);
		if(last == NULL)
			font->subfonts = last = ref;
		else
			last->next = ref;
		ref->next = NULL;
		op = fuget1(p);
	}

	if(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4)
		goto error;

	/* This function correctly reads both .vf and .ovf files */

	font->chars = xnalloc(DviFontChar, 256);
	for(i = 0; i < 256; i++)
		font->chars[i].offset = 0;
	nchars = 256;
	loc = -1; hic = -1;
	/* now read the characters themselves */
	while(op <= 242) {
		int	pl;
		Int32	cc;
		Int32	tfm;

		if(op == 242) {
			pl = fuget4(p);
			cc = fuget4(p);
			tfm = fuget4(p);
		} else {
			pl = op;
			cc = fuget1(p);
			tfm = fuget3(p);
		}
		if (cc < 0 || cc > 65536) {
			/* TeX engines do not support char codes bigger than 65535 */
			mdvi_error(_("(vf) %s: unexpected character %d\n"),
				   font->fontname, cc);
			goto error;
		}
		if(loc < 0 || cc < loc)
			loc = cc;
		if(hic < 0 || cc > hic)
			hic = cc;
		if(cc >= nchars) {
			font->chars = xresize(font->chars,
				DviFontChar, cc + 16);
			for(i = nchars; i < cc + 16; i++)
				font->chars[i].offset = 0;
			nchars = cc + 16;
		}
		if(font->chars[cc].offset) {
			mdvi_error(_("(vf) %s: character %d redefined\n"),
				   font->fontname, cc);
			goto error;
		}

		DEBUG((DBG_GLYPHS, "(vf) %s: defined character %d (macro length %d)\n",
			font->fontname, cc, pl));
		font->chars[cc].width = pl + 1;
		font->chars[cc].code = cc;
		font->chars[cc].tfmwidth = TFMSCALE(tfm, z, alpha, beta);
		font->chars[cc].offset = mlen;
		font->chars[cc].loaded = 1;
		if(mlen + pl + 1 > msize) {
			msize = mlen + pl + 256;
			macros = xresize(macros, Uchar, msize);
		}
		if(pl && fread(macros + mlen, 1, pl, p) != pl)
			break;
		macros[mlen+pl] = DVI_EOP;
		mlen += pl + 1;
		op = fuget1(p);
	}
	if(op != 248) {
		mdvi_error(_("(vf) %s: no postamble\n"), font->fontname);
		goto error;
	}

	/* make macro memory just big enough */
	if(msize > mlen) {
		macros = xresize(macros, Uchar, mlen);
		msize = mlen;
	}

	DEBUG((DBG_FONTS|DBG_GLYPHS,
		"(vf) %s: macros use %d bytes\n", font->fontname, msize));

	if(loc > 0 || hic < nchars-1) {
		memmove(font->chars, font->chars + loc,
			(hic - loc + 1) * sizeof(DviFontChar));
		font->chars = xresize(font->chars,
			DviFontChar, hic - loc + 1);
	}
	font->loc = loc;
	font->hic = hic;
	font->private = macros;

	return 0;

badvf:
	mdvi_error(_("%s: File corrupted, or not a VF file.\n"), font->fontname);
error:
	if(font->chars)
		mdvi_free(font->chars);
	if(macros)
		mdvi_free(macros);
	return -1;
}


int mdvi_configure(DviContext *dvi, DviParamCode option, ...)
{
	va_list	ap;
	int	reset_all;
	int	reset_font;
	DviParams np;

	va_start(ap, option);

	reset_font = 0;
	reset_all  = 0;
	np = dvi->params; /* structure copy */
	while(option != MDVI_PARAM_LAST) {
		switch(option) {
		case MDVI_SET_DPI:
			np.dpi = np.vdpi = va_arg(ap, Uint);
			reset_all = 1;
			break;
		case MDVI_SET_XDPI:
			np.dpi = va_arg(ap, Uint);
			reset_all = 1;
			break;
		case MDVI_SET_YDPI:
			np.vdpi = va_arg(ap, Uint);
			break;
		case MDVI_SET_SHRINK:
			np.hshrink = np.vshrink = va_arg(ap, Uint);
			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
			break;
		case MDVI_SET_XSHRINK:
			np.hshrink = va_arg(ap, Uint);
			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
			break;
		case MDVI_SET_YSHRINK:
			np.vshrink = va_arg(ap, Uint);
			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
			break;
		case MDVI_SET_ORIENTATION:
			np.orientation = va_arg(ap, DviOrientation);
			reset_font = MDVI_FONTSEL_GLYPH;
			break;
		case MDVI_SET_GAMMA:
			np.gamma = va_arg(ap, double);
			reset_font = MDVI_FONTSEL_GREY;
			break;
		case MDVI_SET_DENSITY:
			np.density = va_arg(ap, Uint);
			reset_font = MDVI_FONTSEL_BITMAP;
			break;
		case MDVI_SET_MAGNIFICATION:
			np.mag = va_arg(ap, double);
			reset_all = 1;
			break;
		case MDVI_SET_DRIFT:
			np.hdrift = np.vdrift = va_arg(ap, int);
			break;
		case MDVI_SET_HDRIFT:
			np.hdrift = va_arg(ap, int);
			break;
		case MDVI_SET_VDRIFT:
			np.vdrift = va_arg(ap, int);
			break;
		case MDVI_SET_FOREGROUND:
			np.fg = va_arg(ap, Ulong);
			reset_font = MDVI_FONTSEL_GREY;
			break;
		case MDVI_SET_BACKGROUND:
			np.bg = va_arg(ap, Ulong);
			reset_font = MDVI_FONTSEL_GREY;
			break;
		default:
			break;
		}
		option = va_arg(ap, DviParamCode);
	}
	va_end(ap);

	/* check that all values make sense */
	if(np.dpi <= 0 || np.vdpi <= 0)
		return -1;
	if(np.mag <= 0.0)
		return -1;
	if(np.density < 0)
		return -1;
	if(np.hshrink < 1 || np.vshrink < 1)
		return -1;
	if(np.hdrift < 0 || np.vdrift < 0)
		return -1;
	if(np.fg == np.bg)
		return -1;

	/*
	 * If the dpi or the magnification change, we basically have to reload
	 * the DVI file again from scratch.
	 */

	if(reset_all)
		return (mdvi_reload(dvi, &np) == 0);

	if(np.hshrink != dvi->params.hshrink) {
		np.conv = dvi->dviconv;
		if(np.hshrink)
			np.conv /= np.hshrink;
	}
	if(np.vshrink != dvi->params.vshrink) {
		np.vconv = dvi->dvivconv;
		if(np.vshrink)
			np.vconv /= np.vshrink;
	}

	if(reset_font) {
		font_reset_chain_glyphs(&dvi->device, dvi->fonts, reset_font);
	}
	dvi->params = np;
	if((reset_font & MDVI_FONTSEL_GLYPH) && dvi->device.refresh) {
		dvi->device.refresh(dvi, dvi->device.device_data);
		return 0;
	}

	return 1;
}


static int dread(DviContext *dvi, char *buffer, size_t len)
{
	if(NEEDBYTES(dvi, len) && get_bytes(dvi, len) == -1)
		return -1;
	memcpy(buffer, dvi->buffer.data + dvi->buffer.pos, len);
	dvi->buffer.pos += len;
	return 0;
}


static void dummy_dev_set_color(void *a, Ulong b, Ulong c)
{
}


void	flush_font_metrics(void)
{
	TFMPool	*ptr;

	for(; (ptr = (TFMPool *)tfmpool.head); ) {
		tfmpool.head = LIST(ptr->next);

		mdvi_free(ptr->short_name);
		mdvi_free(ptr->tfminfo.chars);
		mdvi_free(ptr);
	}
	mdvi_hash_reset(&tfmhash, 0);
}


static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
{
	kpse_glyph_file_type type;
	char *filename;

	if(pk_auto_generate == 0) {
		kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
		pk_auto_generate = 1;
	}
	filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
		kpse_pk_format, &type);
	if(filename && type.source == kpse_glyph_source_fallback) {
		mdvi_free(filename);
		filename = NULL;
	} else if(filename) {
		*hdpi = *vdpi = type.dpi;
	}
	return filename;
}


static enum parseKey recognize(char *ident)
{
    int lower = 0, upper = (int) NOPE, midpoint, cmpvalue;
    BOOL found = FALSE;

    while ((upper >= lower) && !found)
    {
        midpoint = (lower + upper)/2;
        if (keyStrings[midpoint] == NULL) break;
        cmpvalue = strncmp(ident, keyStrings[midpoint], MAX_NAME);
        if (cmpvalue == 0) found = TRUE;
        else if (cmpvalue < 0) upper = midpoint - 1;
        else lower = midpoint + 1;
    } /* while */

    if (found) return (enum parseKey) midpoint;
    else return NOPE;

} /* recognize */


void	free_font_metrics(TFMInfo *info)
{
	TFMPool *tfm;

	if(tfmpool.count == 0)
		return;
	/* get the entry -- can't use the hash table for this, because
	 * we don't have the short name */
	for(tfm = (TFMPool *)tfmpool.head; tfm; tfm = tfm->next)
		if(info == &tfm->tfminfo)
			break;
	if(tfm == NULL)
		return;
	if(--tfm->links > 0) {
		DEBUG((DBG_FONTS, "(mt) %s not removed, still in use\n",
			tfm->short_name));
		return;
	}
	mdvi_hash_remove_ptr(&tfmhash, MDVI_KEY(tfm->short_name));

	DEBUG((DBG_FONTS, "(mt) removing unused TFM data for `%s'\n", tfm->short_name));
	listh_remove(&tfmpool, LIST(tfm));
	mdvi_free(tfm->short_name);
	mdvi_free(tfm->tfminfo.chars);
	mdvi_free(tfm);
}


int	no_op(DviContext *dvi, int opcode)
{
	SHOWCMD((dvi, "noop", -1, ""));
	return 0;
}


AvahiDnsPacket *avahi_recv_dns_packet_ipv4(
        int fd,
        AvahiIPv4Address *ret_src_address,
        uint16_t *ret_src_port,
        AvahiIPv4Address *ret_dst_address,
        AvahiIfIndex *ret_iface,
        uint8_t *ret_ttl) {

    AvahiDnsPacket *p= NULL;
    struct msghdr msg;
    struct iovec io;
    size_t aux[1024 / sizeof(size_t)]; /* for alignment on ia64 ! */
    ssize_t l;
    struct cmsghdr *cmsg;
    int found_addr = 0;
    int ms;
    struct sockaddr_in sa;

    assert(fd >= 0);

    if (ioctl(fd, FIONREAD, &ms) < 0) {
        avahi_log_warn("ioctl(): %s", strerror(errno));
        goto fail;
    }

    if (ms < 0) {
        avahi_log_warn("FIONREAD returned negative value.");
        goto fail;
    }

    p = avahi_dns_packet_new(ms + AVAHI_DNS_PACKET_EXTRA_SIZE);

    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    io.iov_len = p->max_size;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &sa;
    msg.msg_namelen = sizeof(sa);
    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    msg.msg_control = aux;
    msg.msg_controllen = sizeof(aux);
    msg.msg_flags = 0;

    if ((l = recvmsg(fd, &msg, 0)) < 0) {
        /* Linux returns EAGAIN when an invalid IP packet has been
        received. We suppress warnings in this case because this might
        create quite a bit of log traffic on machines with unstable
        links. (See #60) */

        if (errno != EAGAIN)
            avahi_log_warn("recvmsg(): %s", strerror(errno));

        goto fail;
    }

    /* For corrupt packets FIONREAD returns zero size (See rhbz #607297). So
     * fail after having read them. */
    if (!ms)
        goto fail;

    if (sa.sin_addr.s_addr == INADDR_ANY)
        /* Linux 2.4 behaves very strangely sometimes! */
        goto fail;

    assert(!(msg.msg_flags & MSG_CTRUNC));
    assert(!(msg.msg_flags & MSG_TRUNC));

    p->size = (size_t) l;

    if (ret_src_port)
        *ret_src_port = avahi_port_from_sockaddr((struct sockaddr*) &sa);

    if (ret_src_address) {
        AvahiAddress a;
        avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
        *ret_src_address = a.data.ipv4;
    }

    if (ret_ttl)
        *ret_ttl = 255;

    if (ret_iface)
        *ret_iface = AVAHI_IF_UNSPEC;

    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {

        if (cmsg->cmsg_level == IPPROTO_IP) {

            switch (cmsg->cmsg_type) {
#ifdef IP_RECVTTL
                case IP_RECVTTL:
#endif
                case IP_TTL:
                    if (ret_ttl)
                        *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));

                    break;

#ifdef IP_PKTINFO
                case IP_PKTINFO: {
                    struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);

                    if (ret_iface)
                        *ret_iface = (int) i->ipi_ifindex;

                    if (ret_dst_address)
                        ret_dst_address->address = i->ipi_addr.s_addr;

                    found_addr = 1;

                    break;
                }
#endif

#ifdef IP_RECVIF
                case IP_RECVIF: {
                    struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA (cmsg);

                    if (ret_iface)
#ifdef __sun
                        *ret_iface = *(uint_t*) sdl;
#else
                        *ret_iface = (int) sdl->sdl_index;
#endif

                    break;
                }
#endif

#ifdef IP_RECVDSTADDR
                case IP_RECVDSTADDR:
                    if (ret_dst_address)
                        memcpy(&ret_dst_address->address, CMSG_DATA (cmsg), 4);

                    found_addr = 1;
                    break;
#endif

                default:
                    avahi_log_warn("Unhandled cmsg_type : %d", cmsg->cmsg_type);
                    break;
            }
        }
    }

    assert(found_addr);

    return p;

fail:
    if (p)
        avahi_dns_packet_free(p);

    return NULL;
}


int avahi_send_dns_packet_ipv6(
        int fd,
        AvahiIfIndex interface,
        AvahiDnsPacket *p,
        const AvahiIPv6Address *src_address,
        const AvahiIPv6Address *dst_address,
        uint16_t dst_port) {

    struct sockaddr_in6 sa;
    struct msghdr msg;
    struct iovec io;
    struct cmsghdr *cmsg;
    size_t cmsg_data[(CMSG_SPACE(sizeof(struct in6_pktinfo))/sizeof(size_t)) + 1];

    assert(fd >= 0);
    assert(p);
    assert(avahi_dns_packet_check_valid(p) >= 0);
    assert(!dst_address || dst_port > 0);

    if (!dst_address)
        mdns_mcast_group_ipv6(&sa);
    else
        ipv6_address_to_sockaddr(&sa, dst_address, dst_port);

    memset(&io, 0, sizeof(io));
    io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    io.iov_len = p->size;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &sa;
    msg.msg_namelen = sizeof(sa);
    msg.msg_iov = &io;
    msg.msg_iovlen = 1;
    msg.msg_flags = 0;

    if (interface > 0 || src_address) {
        struct in6_pktinfo *pkti;

        memset(cmsg_data, 0, sizeof(cmsg_data));
        msg.msg_control = cmsg_data;
        msg.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));

        cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_len = msg.msg_controllen;
        cmsg->cmsg_level = IPPROTO_IPV6;
        cmsg->cmsg_type = IPV6_PKTINFO;

        pkti = (struct in6_pktinfo*) CMSG_DATA(cmsg);

        if (interface > 0)
            pkti->ipi6_ifindex = interface;

        if (src_address)
            memcpy(&pkti->ipi6_addr, src_address->address, sizeof(src_address->address));
    } else {
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
    }

    return sendmsg_loop(fd, &msg, 0);
}


int avahi_open_unicast_socket_ipv4(void) {
    struct sockaddr_in local;
    int fd = -1;

    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;

    if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
        avahi_log_warn("bind() failed: %s", strerror(errno));
        goto fail;
    }

    if (ipv4_pktinfo(fd) < 0) {
         goto fail;
    }

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}


int avahi_open_socket_ipv6(int no_reuse) {
    struct sockaddr_in6 sa, local;
    int fd = -1, yes, r;
    int ttl;

    mdns_mcast_group_ipv6(&sa);

    if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
        avahi_log_warn("socket() failed: %s", strerror(errno));
        goto fail;
    }

    ttl = 255;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IPV6_MULTICAST_HOPS failed: %s", strerror(errno));
        goto fail;
    }

    ttl = 255;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
        avahi_log_warn("IPV6_UNICAST_HOPS failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
        goto fail;
    }

    yes = 1;
    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
        avahi_log_warn("IPV6_MULTICAST_LOOP failed: %s", strerror(errno));
        goto fail;
    }

    memset(&local, 0, sizeof(local));
    local.sin6_family = AF_INET6;
    local.sin6_port = htons(AVAHI_MDNS_PORT);

    if (no_reuse)
        r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    else
        r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));

    if (r < 0)
        goto fail;

    if (ipv6_pktinfo(fd) < 0)
        goto fail;

    if (avahi_set_cloexec(fd) < 0) {
        avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
        goto fail;
    }

    if (avahi_set_nonblock(fd) < 0) {
        avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
        goto fail;
    }

    return fd;

fail:
    if (fd >= 0)
        close(fd);

    return -1;
}


insert_file (struct stat const *st)
{
   file_id *p;
   static file_id *next_slot;

   if (!next_slot)
     next_slot = xmalloc (sizeof *next_slot);
   next_slot->dev = st->st_dev;
   next_slot->ino = st->st_ino;
   p = hash_insert (file_id_table, next_slot);
   if (!p)
     xalloc_die ();
   if (p == next_slot)
     next_slot = NULL;
}


copy_attr_error (struct error_context *ctx, char const *fmt, ...)
{
  int err = errno;
  va_list ap;

  /* use verror module to print error message */
  va_start (ap, fmt);
  verror (0, err, fmt, ap);
  va_end (ap);
}


systemic (char const *command)
{
  if (debug & 8)
    say ("+ %s\n", command);
  fflush (stdout);
  return system (command);
}


removedirs (char const *name)
{
  char *filename = xstrdup (name);
  size_t i;

  for (i = strlen (filename);  i != 0;  i--)
    if (ISSLASH (filename[i])
	&& ! (ISSLASH (filename[i - 1])
	      || (filename[i - 1] == '.'
		  && (i == 1
		      || ISSLASH (filename[i - 2])
		      || (filename[i - 2] == '.'
			  && (i == 2
			      || ISSLASH (filename[i - 3])))))))
      {
	filename[i] = '\0';
	if (rmdir (filename) == 0 && verbosity == VERBOSE)
	  say ("Removed empty directory %s\n", quotearg (filename));
	filename[i] = '/';
      }
  free (filename);
}


makedirs (char const *name)
{
  char *filename = xstrdup (name);
  char *f;
  char *flim = replace_slashes (filename);

  if (flim)
    {
      /* Create any missing directories, replacing NULs by '/'s.
	 Ignore errors.  We may have to keep going even after an EEXIST,
	 since the path may contain ".."s; and when there is an EEXIST
	 failure the system may return some other error number.
	 Any problems will eventually be reported when we create the file.  */
      for (f = filename;  f <= flim;  f++)
	if (!*f)
	  {
	    mkdir (filename,
		   S_IRUSR|S_IWUSR|S_IXUSR
		   |S_IRGRP|S_IWGRP|S_IXGRP
		   |S_IROTH|S_IWOTH|S_IXOTH);
	    *f = '/';
	  }
    }
  free (filename);
}


copy_attr (char const *src_path, char const *dst_path)
{
  struct error_context ctx =
  {
    .error = copy_attr_error,
    .quote = copy_attr_quote,
    .quote_free = copy_attr_free
  };
  return attr_copy_file (src_path, dst_path, copy_attr_check, &ctx);
}


contains_slash (const char *s)
{
  for (; *s; s++)
    if (ISSLASH(*s))
      return true;
  return false;
}


file_already_seen (struct stat const *st)
{
  file_id f;
  f.dev = st->st_dev;
  f.ino = st->st_ino;
  return hash_lookup (file_id_table, &f) != 0;
}


parse_name (char const *s, int strip_leading, char const **endp)
{
  char *ret;

  while (ISSPACE ((unsigned char) *s))
    s++;
  if (*s == '"')
    ret = parse_c_string (s, endp);
  else
    {
      char const *t;

      for (t = s; *t && ! ISSPACE ((unsigned char) *t); t++)
	/* do nothing*/ ;
      ret = savebuf (s, t - s + 1);
      ret[t - s] = 0;
      if (endp)
	*endp = t;
    }
  if (! strip_leading_slashes (ret, strip_leading))
    {
      free (ret);
      ret = NULL;
    }
  return ret;
}


vsay (char const *format, va_list args)
{
  vfprintf (stdout, format, args);
  fflush (stdout);
}


inline void readit(int f, void *buf, size_t len) {
	ssize_t res;
	while (len > 0) {
		DEBUG("*");
		if ((res = read(f, buf, len)) <= 0)
			err("Read failed: %m");
		len -= res;
		buf += res;
	}
}


ssize_t rawexpwrite(off_t a, char *buf, size_t len, CLIENT *client) {
	int fhandle;
	off_t foffset;
	size_t maxbytes;
	ssize_t retval;

	if(get_filepos(client->export, a, &fhandle, &foffset, &maxbytes))
		return -1;
	if(maxbytes && len > maxbytes)
		len = maxbytes;

	DEBUG4("(WRITE to fd %d offset %llu len %u), ", fhandle, foffset, len);

	myseek(fhandle, foffset);
	retval = write(fhandle, buf, len);
	if(client->server->flags & F_SYNC) {
		fsync(fhandle);
	}
	return retval;
}


CLIENT* negotiate(int net, CLIENT *client, GArray* servers) {
	char zeros[128];
	uint64_t size_host;
	uint32_t flags = NBD_FLAG_HAS_FLAGS;
	uint16_t smallflags = 0;
	uint64_t magic;

	memset(zeros, '\0', sizeof(zeros));
	if(!client || !client->modern) {
		/* common */
		if (write(net, INIT_PASSWD, 8) < 0) {
			err_nonfatal("Negotiation failed: %m");
			if(client)
				exit(EXIT_FAILURE);
		}
		if(!client || client->modern) {
			/* modern */
			magic = htonll(opts_magic);
		} else {
			/* oldstyle */
			magic = htonll(cliserv_magic);
		}
		if (write(net, &magic, sizeof(magic)) < 0) {
			err_nonfatal("Negotiation failed: %m");
			if(client)
				exit(EXIT_FAILURE);
		}
	}
	if(!client) {
		/* modern */
		uint32_t reserved;
		uint32_t opt;
		uint32_t namelen;
		char* name;
		int i;

		if(!servers)
			err("programmer error");
		if (write(net, &smallflags, sizeof(uint16_t)) < 0)
			err("Negotiation failed: %m");
		if (read(net, &reserved, sizeof(reserved)) < 0)
			err("Negotiation failed: %m");
		if (read(net, &magic, sizeof(magic)) < 0)
			err("Negotiation failed: %m");
		magic = ntohll(magic);
		if(magic != opts_magic) {
			close(net);
			return NULL;
		}
		if (read(net, &opt, sizeof(opt)) < 0)
			err("Negotiation failed: %m");
		opt = ntohl(opt);
		if(opt != NBD_OPT_EXPORT_NAME) {
			close(net);
			return NULL;
		}
		if (read(net, &namelen, sizeof(namelen)) < 0)
			err("Negotiation failed: %m");
		namelen = ntohl(namelen);
		name = malloc(namelen+1);
		name[namelen]=0;
		if (read(net, name, namelen) < 0)
			err("Negotiation failed: %m");
		for(i=0; i<servers->len; i++) {
			SERVER* serve = &(g_array_index(servers, SERVER, i));
			if(!strcmp(serve->servename, name)) {
				CLIENT* client = g_new0(CLIENT, 1);
				client->server = serve;
				client->exportsize = OFFT_MAX;
				client->net = net;
				client->modern = TRUE;
				return client;
			}
		}
		return NULL;
	}
	/* common */
	size_host = htonll((u64)(client->exportsize));
	if (write(net, &size_host, 8) < 0)
		err("Negotiation failed: %m");
	if (client->server->flags & F_READONLY)
		flags |= NBD_FLAG_READ_ONLY;
	if (!client->modern) {
		/* oldstyle */
		flags = htonl(flags);
		if (write(client->net, &flags, 4) < 0)
			err("Negotiation failed: %m");
	} else {
		/* modern */
		smallflags = (uint16_t)(flags & ~((uint16_t)0));
		smallflags = htons(smallflags);
		if (write(client->net, &smallflags, sizeof(smallflags)) < 0) {
			err("Negotiation failed: %m");
		}
	}
	/* common */
	if (write(client->net, zeros, 124) < 0)
		err("Negotiation failed: %m");
	return NULL;
}


void usage() {
	printf("This is nbd-server version " VERSION "\n");
	printf("Usage: [ip:|ip6@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name] [-M max connections]\n"
	       "\t-r|--read-only\t\tread only\n"
	       "\t-m|--multi-file\t\tmultiple file\n"
	       "\t-c|--copy-on-write\tcopy on write\n"
	       "\t-C|--config-file\tspecify an alternate configuration file\n"
	       "\t-l|--authorize-file\tfile with list of hosts that are allowed to\n\t\t\t\tconnect.\n"
	       "\t-p|--pid-file\t\tspecify a filename to write our PID to\n"
	       "\t-o|--output-config\toutput a config file section for what you\n\t\t\t\tspecified on the command line, with the\n\t\t\t\tspecified section name\n"
	       "\t-M|--max-connections\tspecify the maximum number of opened connections\n\n"
	       "\tif port is set to 0, stdin is used (for running from inetd)\n"
	       "\tif file_to_export contains '%%s', it is substituted with the IP\n"
	       "\t\taddress of the machine trying to connect\n"
	       "\tif ip is set, it contains the local IP address on which we're listening.\n\tif not, the server will listen on all local IP addresses\n");
	printf("Using configuration file %s\n", CFILE);
}


void serveconnection(CLIENT *client) {
	if(do_run(client->server->prerun, client->exportname)) {
		exit(EXIT_FAILURE);
	}
	setupexport(client);

	if (client->server->flags & F_COPYONWRITE) {
		copyonwrite_prepare(client);
	}

	setmysockopt(client->net);

	mainloop(client);
	do_run(client->server->postrun, client->exportname);
}


int serveloop(GArray* servers) {
	struct sockaddr_storage addrin;
	socklen_t addrinlen=sizeof(addrin);
	int i;
	int max;
	int sock;
	fd_set mset;
	fd_set rset;

	/*
	 * Set up the master fd_set. The set of descriptors we need
	 * to select() for never changes anyway and it buys us a *lot*
	 * of time to only build this once. However, if we ever choose
	 * to not fork() for clients anymore, we may have to revisit
	 * this.
	 */
	max=0;
	FD_ZERO(&mset);
	for(i=0;i<servers->len;i++) {
		if((sock=(g_array_index(servers, SERVER, i)).socket)) {
			FD_SET(sock, &mset);
			max=sock>max?sock:max;
		}
	}
	if(modernsock) {
		FD_SET(modernsock, &mset);
		max=modernsock>max?modernsock:max;
	}
	for(;;) {
		CLIENT *client = NULL;
		pid_t *pid;

		memcpy(&rset, &mset, sizeof(fd_set));
		if(select(max+1, &rset, NULL, NULL, NULL)>0) {
			int net = 0;
			SERVER* serve;

			DEBUG("accept, ");
			if(FD_ISSET(modernsock, &rset)) {
				if((net=accept(modernsock, (struct sockaddr *) &addrin, &addrinlen)) < 0)
					err("accept: %m");
				client = negotiate(net, NULL, servers);
				if(!client) {
					err_nonfatal("negotiation failed");
					close(net);
					net=0;
				}
			}
			for(i=0;i<servers->len && !net;i++) {
				serve=&(g_array_index(servers, SERVER, i));
				if(FD_ISSET(serve->socket, &rset)) {
					if ((net=accept(serve->socket, (struct sockaddr *) &addrin, &addrinlen)) < 0)
						err("accept: %m");
				}
			}
			if(net) {
				int sock_flags;

				if(serve->max_connections > 0 &&
				   g_hash_table_size(children) >= serve->max_connections) {
					msg2(LOG_INFO, "Max connections reached");
					close(net);
					continue;
				}
				if((sock_flags = fcntl(net, F_GETFL, 0))==-1) {
					err("fcntl F_GETFL");
				}
				if(fcntl(net, F_SETFL, sock_flags &~O_NONBLOCK)==-1) {
					err("fcntl F_SETFL ~O_NONBLOCK");
				}
				if(!client) {
					client = g_new0(CLIENT, 1);
					client->server=serve;
					client->exportsize=OFFT_MAX;
					client->net=net;
				}
				set_peername(net, client);
				if (!authorized_client(client)) {
					msg2(LOG_INFO,"Unauthorized client") ;
					close(net);
					continue;
				}
				msg2(LOG_INFO,"Authorized client") ;
				pid=g_malloc(sizeof(pid_t));
#ifndef NOFORK
				if ((*pid=fork())<0) {
					msg3(LOG_INFO,"Could not fork (%s)",strerror(errno)) ;
					close(net);
					continue;
				}
				if (*pid>0) { /* parent */
					close(net);
					g_hash_table_insert(children, pid, pid);
					continue;
				}
				/* child */
				g_hash_table_destroy(children);
				for(i=0;i<servers->len;i++) {
					serve=&g_array_index(servers, SERVER, i);
					close(serve->socket);
				}
				/* FALSE does not free the
				actual data. This is required,
				because the client has a
				direct reference into that
				data, and otherwise we get a
				segfault... */
				g_array_free(servers, FALSE);
#endif // NOFORK
				msg2(LOG_INFO,"Starting to serve");
				serveconnection(client);
				exit(EXIT_SUCCESS);
			}
		}
	}
}


xfs_ioc_setxflags(
	xfs_inode_t		*ip,
	struct file		*filp,
	void			__user *arg)
{
	struct fsxattr		fa;
	unsigned int		flags;
	unsigned int		mask;

	if (copy_from_user(&flags, arg, sizeof(flags)))
		return -EFAULT;

	if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
		      FS_NOATIME_FL | FS_NODUMP_FL | \
		      FS_SYNC_FL))
		return -EOPNOTSUPP;

	mask = FSX_XFLAGS;
	if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
		mask |= FSX_NONBLOCK;
	fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));

	return -xfs_ioctl_setattr(ip, &fa, mask);
}


do_readlink(
	char __user		*buffer,
	int			buflen,
	const char		*link)
{
        int len;

	len = PTR_ERR(link);
	if (IS_ERR(link))
		goto out;

	len = strlen(link);
	if (len > (unsigned) buflen)
		len = buflen;
	if (copy_to_user(buffer, link, len))
		len = -EFAULT;
 out:
	return len;
}


xfs_ioc_getbmap(
	struct xfs_inode	*ip,
	int			ioflags,
	unsigned int		cmd,
	void			__user *arg)
{
	struct getbmapx		bmx;
	int			error;

	if (copy_from_user(&bmx, arg, sizeof(struct getbmapx)))
		return -XFS_ERROR(EFAULT);

	if (bmx.bmv_count < 2)
		return -XFS_ERROR(EINVAL);

	bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0);
	if (ioflags & IO_INVIS)
		bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ;

	error = xfs_getbmap(ip, &bmx, xfs_getbmap_format,
			    (struct getbmap *)arg+1);
	if (error)
		return -error;

	/* copy back header - only size of getbmap */
	if (copy_to_user(arg, &bmx, sizeof(struct getbmap)))
		return -XFS_ERROR(EFAULT);
	return 0;
}