* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
+#include "mono/metadata/assembly.h"
#include "mono/metadata/gc-internals.h"
#include "mono/metadata/mono-endian.h"
#include "mono/metadata/object-internals.h"
-#include "mono/metadata/reflection-cache.h"
#include "mono/metadata/custom-attrs-internals.h"
#include "mono/metadata/sre-internals.h"
#include "mono/metadata/reflection-internals.h"
/* FIXME: Need to do more checks */
if (cattr->ctor->method && (cattr->ctor->method->klass->image != image)) {
- int visibility = cattr->ctor->method->klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+ int visibility = mono_class_get_flags (cattr->ctor->method->klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
if ((visibility != TYPE_ATTRIBUTE_PUBLIC) && (visibility != TYPE_ATTRIBUTE_NESTED_PUBLIC))
return FALSE;
find_field_index (MonoClass *klass, MonoClassField *field) {
int i;
- for (i = 0; i < klass->field.count; ++i) {
+ int fcount = mono_class_get_field_count (klass);
+ for (i = 0; i < fcount; ++i) {
if (field == &klass->fields [i])
- return klass->field.first + 1 + i;
+ return mono_class_get_first_field_idx (klass) + 1 + i;
}
return 0;
}
* Find the property index in the metadata Property table.
*/
static guint32
-find_property_index (MonoClass *klass, MonoProperty *property) {
+find_property_index (MonoClass *klass, MonoProperty *property)
+{
int i;
+ MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
- for (i = 0; i < klass->ext->property.count; ++i) {
- if (property == &klass->ext->properties [i])
- return klass->ext->property.first + 1 + i;
+ for (i = 0; i < info->count; ++i) {
+ if (property == &info->properties [i])
+ return info->first + 1 + i;
}
return 0;
}
* Find the event index in the metadata Event table.
*/
static guint32
-find_event_index (MonoClass *klass, MonoEvent *event) {
+find_event_index (MonoClass *klass, MonoEvent *event)
+{
int i;
+ MonoClassEventInfo *info = mono_class_get_event_info (klass);
- for (i = 0; i < klass->ext->event.count; ++i) {
- if (event == &klass->ext->events [i])
- return klass->ext->event.first + 1 + i;
+ for (i = 0; i < info->count; ++i) {
+ if (event == &info->events [i])
+ return info->first + 1 + i;
}
return 0;
}
mono_custom_attrs_from_index (MonoImage *image, guint32 idx)
{
MonoError error;
- MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, &error);
+ MonoCustomAttrInfo *result = mono_custom_attrs_from_index_checked (image, idx, FALSE, &error);
mono_error_cleanup (&error);
return result;
}
* Returns: NULL if no attributes are found. On error returns NULL and sets @error.
*/
MonoCustomAttrInfo*
-mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, MonoError *error)
+mono_custom_attrs_from_index_checked (MonoImage *image, guint32 idx, gboolean ignore_missing, MonoError *error)
{
guint32 mtoken, i, len;
guint32 cols [MONO_CUSTOM_ATTR_SIZE];
attr = &ainfo->attrs [i - 1];
attr->ctor = mono_get_method_checked (image, mtoken, NULL, NULL, error);
if (!attr->ctor) {
- g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to %s", image->name, mtoken, mono_error_get_message (error));
- g_list_free (list);
- g_free (ainfo);
- return NULL;
+ g_warning ("Can't find custom attr constructor image: %s mtoken: 0x%08x due to: %s", image->name, mtoken, mono_error_get_message (error));
+ if (ignore_missing) {
+ mono_error_cleanup (error);
+ mono_error_init (error);
+ } else {
+ g_list_free (list);
+ g_free (ainfo);
+ return NULL;
+ }
}
if (!mono_verifier_verify_cattr_blob (image, cols [MONO_CUSTOM_ATTR_VALUE], NULL)) {
idx = mono_method_get_index (method);
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_METHODDEF;
- return mono_custom_attrs_from_index_checked (method->klass->image, idx, error);
+ return mono_custom_attrs_from_index_checked (method->klass->image, idx, FALSE, error);
}
MonoCustomAttrInfo*
mono_error_init (error);
- if (klass->generic_class)
- klass = klass->generic_class->container_class;
+ if (mono_class_is_ginst (klass))
+ klass = mono_class_get_generic_class (klass)->container_class;
if (image_is_dynamic (klass->image))
return lookup_custom_attr (klass->image, klass);
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_TYPEDEF;
}
- return mono_custom_attrs_from_index_checked (klass->image, idx, error);
+ return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
}
MonoCustomAttrInfo*
mono_custom_attrs_from_assembly (MonoAssembly *assembly)
{
MonoError error;
- MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, &error);
+ MonoCustomAttrInfo *result = mono_custom_attrs_from_assembly_checked (assembly, FALSE, &error);
mono_error_cleanup (&error);
return result;
}
MonoCustomAttrInfo*
-mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, MonoError *error)
+mono_custom_attrs_from_assembly_checked (MonoAssembly *assembly, gboolean ignore_missing, MonoError *error)
{
guint32 idx;
idx = 1; /* there is only one assembly */
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
- return mono_custom_attrs_from_index_checked (assembly->image, idx, error);
+ return mono_custom_attrs_from_index_checked (assembly->image, idx, ignore_missing, error);
}
static MonoCustomAttrInfo*
idx = 1; /* there is only one module */
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_MODULE;
- return mono_custom_attrs_from_index_checked (image, idx, error);
+ return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
}
MonoCustomAttrInfo*
idx = find_property_index (klass, property);
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_PROPERTY;
- return mono_custom_attrs_from_index_checked (klass->image, idx, error);
+ return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
}
MonoCustomAttrInfo*
idx = find_event_index (klass, event);
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_EVENT;
- return mono_custom_attrs_from_index_checked (klass->image, idx, error);
+ return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
}
MonoCustomAttrInfo*
idx = find_field_index (klass, field);
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_FIELDDEF;
- return mono_custom_attrs_from_index_checked (klass->image, idx, error);
+ return mono_custom_attrs_from_index_checked (klass->image, idx, FALSE, error);
}
/**
idx = i;
idx <<= MONO_CUSTOM_ATTR_BITS;
idx |= MONO_CUSTOM_ATTR_PARAMDEF;
- return mono_custom_attrs_from_index_checked (image, idx, error);
+ return mono_custom_attrs_from_index_checked (image, idx, FALSE, error);
}
gboolean
{
int i;
for (i = 0; i < ainfo->num_attrs; ++i) {
- MonoClass *klass = ainfo->attrs [i].ctor->klass;
- if (mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
+ MonoCustomAttrEntry *centry = &ainfo->attrs[i];
+ if (centry->ctor == NULL)
+ continue;
+ MonoClass *klass = centry->ctor->klass;
+ if (klass == attr_klass || mono_class_has_parent (klass, attr_klass) || (MONO_CLASS_IS_INTERFACE (attr_klass) && mono_class_is_assignable_from (attr_klass, klass)))
return TRUE;
}
return FALSE;
if (centry->ctor == NULL)
continue;
MonoClass *klass = centry->ctor->klass;
- if (mono_class_is_assignable_from (attr_klass, klass))
+ if (attr_klass == klass || mono_class_is_assignable_from (attr_klass, klass))
break;
}
if (centry == NULL)
return_val_if_nok (error, NULL);
} else if (strcmp ("Assembly", klass->name) == 0 || strcmp ("MonoAssembly", klass->name) == 0) {
MonoReflectionAssembly *rassembly = (MonoReflectionAssembly*)obj;
- cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, error);
+ cinfo = mono_custom_attrs_from_assembly_checked (rassembly->assembly, FALSE, error);
return_val_if_nok (error, NULL);
} else if (strcmp ("Module", klass->name) == 0 || strcmp ("MonoModule", klass->name) == 0) {
MonoReflectionModule *module = (MonoReflectionModule*)obj;
return result;
}
+
+static gboolean
+custom_attr_class_name_from_methoddef (MonoImage *image, guint32 method_token, const gchar **nspace, const gchar **class_name)
+{
+ /* mono_get_method_from_token () */
+ g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD);
+ guint32 type_token = mono_metadata_typedef_from_method (image, method_token);
+ if (!type_token) {
+ /* Bad method token (could not find corresponding typedef) */
+ return FALSE;
+ }
+ type_token |= MONO_TOKEN_TYPE_DEF;
+ {
+ /* mono_class_create_from_typedef () */
+ MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
+ guint32 cols [MONO_TYPEDEF_SIZE];
+ guint tidx = mono_metadata_token_index (type_token);
+
+ if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
+ /* "Invalid typedef token %x", type_token */
+ return FALSE;
+ }
+
+ mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
+
+ if (class_name)
+ *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
+ if (nspace)
+ *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
+ return TRUE;
+ }
+}
+
+
+/**
+ * custom_attr_class_name_from_method_token:
+ * @image: The MonoImage
+ * @method_token: a token for a custom attr constructor in @image
+ * @assembly_token: out argment set to the assembly ref token of the custom attr
+ * @nspace: out argument set to namespace (a string in the string heap of @image) of the custom attr
+ * @class_name: out argument set to the class name of the custom attr.
+ *
+ * Given an @image and a @method_token (which is assumed to be a
+ * constructor), fills in the out arguments with the assembly ref (if
+ * a methodref) and the namespace and class name of the custom
+ * attribute.
+ *
+ * Returns: TRUE on success, FALSE otherwise.
+ *
+ * LOCKING: does not take locks
+ */
+static gboolean
+custom_attr_class_name_from_method_token (MonoImage *image, guint32 method_token, guint32 *assembly_token, const gchar **nspace, const gchar **class_name)
+{
+ /* This only works with method tokens constructed from a
+ * custom attr token, which can only be methoddef or
+ * memberref */
+ g_assert (mono_metadata_token_table (method_token) == MONO_TABLE_METHOD
+ || mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF);
+
+ if (mono_metadata_token_table (method_token) == MONO_TABLE_MEMBERREF) {
+ /* method_from_memberref () */
+ guint32 cols[6];
+ guint32 nindex, class_index;
+
+ int idx = mono_metadata_token_index (method_token);
+
+ mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], idx-1, cols, 3);
+ nindex = cols [MONO_MEMBERREF_CLASS] >> MONO_MEMBERREF_PARENT_BITS;
+ class_index = cols [MONO_MEMBERREF_CLASS] & MONO_MEMBERREF_PARENT_MASK;
+ if (class_index == MONO_MEMBERREF_PARENT_TYPEREF) {
+ guint32 type_token = MONO_TOKEN_TYPE_REF | nindex;
+ /* mono_class_from_typeref_checked () */
+ {
+ guint32 cols [MONO_TYPEREF_SIZE];
+ MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
+
+ mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
+
+ if (class_name)
+ *class_name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
+ if (nspace)
+ *nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
+ if (assembly_token)
+ *assembly_token = cols [MONO_TYPEREF_SCOPE];
+ return TRUE;
+ }
+ } else if (class_index == MONO_MEMBERREF_PARENT_METHODDEF) {
+ guint32 methoddef_token = MONO_TOKEN_METHOD_DEF | nindex;
+ if (assembly_token)
+ *assembly_token = 0;
+ return custom_attr_class_name_from_methoddef (image, methoddef_token, nspace, class_name);
+ } else {
+ /* Attributes can't be generic, so it won't be
+ * a typespec, and they're always
+ * constructors, so it won't be a moduleref */
+ g_assert_not_reached ();
+ }
+ } else {
+ /* must be MONO_TABLE_METHOD */
+ if (assembly_token)
+ *assembly_token = 0;
+ return custom_attr_class_name_from_methoddef (image, method_token, nspace, class_name);
+ }
+}
+
+/**
+ * mono_assembly_metadata_foreach_custom_attr:
+ * @assembly: the assembly to iterate over
+ * @func: the function to call for each custom attribute
+ * @user_data: passed to @func
+ *
+ * Calls @func for each custom attribute type on the given assembly until @func returns TRUE.
+ * Everything is done using low-level metadata APIs, so it is safe to use during assembly loading.
+ *
+ */
+void
+mono_assembly_metadata_foreach_custom_attr (MonoAssembly *assembly, MonoAssemblyMetadataCustomAttrIterFunc func, gpointer user_data)
+{
+ MonoImage *image;
+ guint32 mtoken, i;
+ guint32 cols [MONO_CUSTOM_ATTR_SIZE];
+ MonoTableInfo *ca;
+ guint32 idx;
+
+ /*
+ * This might be called during assembly loading, so do everything using the low-level
+ * metadata APIs.
+ */
+
+ image = assembly->image;
+ g_assert (!image_is_dynamic (image));
+ idx = 1; /* there is only one assembly */
+ idx <<= MONO_CUSTOM_ATTR_BITS;
+ idx |= MONO_CUSTOM_ATTR_ASSEMBLY;
+
+ /* Inlined from mono_custom_attrs_from_index_checked () */
+ ca = &image->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+ i = mono_metadata_custom_attrs_from_index (image, idx);
+ if (!i)
+ return;
+ i --;
+ gboolean stop_iterating = FALSE;
+ while (!stop_iterating && i < ca->rows) {
+ if (mono_metadata_decode_row_col (ca, i, MONO_CUSTOM_ATTR_PARENT) != idx)
+ break;
+ mono_metadata_decode_row (ca, i, cols, MONO_CUSTOM_ATTR_SIZE);
+ i ++;
+ mtoken = cols [MONO_CUSTOM_ATTR_TYPE] >> MONO_CUSTOM_ATTR_TYPE_BITS;
+ switch (cols [MONO_CUSTOM_ATTR_TYPE] & MONO_CUSTOM_ATTR_TYPE_MASK) {
+ case MONO_CUSTOM_ATTR_TYPE_METHODDEF:
+ mtoken |= MONO_TOKEN_METHOD_DEF;
+ break;
+ case MONO_CUSTOM_ATTR_TYPE_MEMBERREF:
+ mtoken |= MONO_TOKEN_MEMBER_REF;
+ break;
+ default:
+ g_warning ("Unknown table for custom attr type %08x", cols [MONO_CUSTOM_ATTR_TYPE]);
+ continue;
+ }
+
+ const char *nspace = NULL;
+ const char *name = NULL;
+ guint32 assembly_token = 0;
+
+ if (!custom_attr_class_name_from_method_token (image, mtoken, &assembly_token, &nspace, &name))
+ continue;
+
+ stop_iterating = func (image, assembly_token, nspace, name, mtoken, user_data);
+ }
+}