Пример #1
0
/*监控需要hook的函数*/
static void profile_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) {
    if (result == MONO_PROFILE_FAILED) return;
    if (mono_method_get_token (method) == 0) return;                /*一般是动态生成的marshall*/
    uint32_t iflags;
    int flag = mono_method_get_flags (method, &iflags);
    if (iflags != 0) return;                                        /*iflags非0 一般是一些native和特殊的method实现*/
    if (mono_jit_info_get_code_size (jinfo) < 4) return;            /*代码段太小, 无法hook*/

    void *p = mono_jit_info_get_code_start (jinfo);
    if (p == 0) {
        LOGD ("function code size is null");
        return;
    }

        /*测试jit函数是否是mov r12, sp*/
    if (*(uint32_t*)p != 0xE1A0C00D)
         LOGD ("exception func : %s , %p", mono_method_get_name (method), p);

    /*TODO : 增加可配置的image和函数列表*/
    if (strcmp (get_method_image_name (method), "Assembly-CSharp") != 0) return;
    if (strcmp (mono_method_get_name (method), ".ctor") == 0) return;
    if (strcmp (mono_method_get_name (method), ".cctor") == 0) return;
    if (strcmp (mono_method_get_name (method), "set") == 0) return;
    if (strcmp (mono_method_get_name (method), "get") == 0) return;
    if (strcmp (mono_method_get_name (method), "Update") == 0) return;
    if (strcmp (mono_method_get_name (method), "LateUpdate") == 0) return;
    if (strcmp (mono_method_get_name (method), "OnGUI") == 0) return;

    /*TODO : 需要一个容器来存储还未编译, 但又想hook的函数*/

    bool donthook = false;
    pthread_mutex_lock (&replace_mutex);
    if (replace_method_dict.find (method) != replace_method_dict.end ())
        donthook = true;
    pthread_mutex_unlock (&replace_mutex);
    if (donthook) return;

    char *hook = specific_hook (p, method, (void*)func_trace);
    if (hook == 0) {
        /*将失败的hook也放到一个表里面*/
        LOGD ("hook err : %s", mono_method_get_name (method));
        return;
    }
    pthread_mutex_lock (&hooked_mutex);
    hooked_method_dict[method] = new HookInfo(jinfo, hook);
    pthread_mutex_unlock (&hooked_mutex);
    LOGD ("hook func : %s , %p", mono_method_get_name (method), p);
    return;
}
Пример #2
0
GDMonoClassMember::Visibility GDMonoMethod::get_visibility() {
	switch (mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
		case MONO_METHOD_ATTR_PRIVATE:
			return GDMonoClassMember::PRIVATE;
		case MONO_METHOD_ATTR_FAM_AND_ASSEM:
			return GDMonoClassMember::PROTECTED_AND_INTERNAL;
		case MONO_METHOD_ATTR_ASSEM:
			return GDMonoClassMember::INTERNAL;
		case MONO_METHOD_ATTR_FAMILY:
			return GDMonoClassMember::PROTECTED;
		case MONO_METHOD_ATTR_PUBLIC:
			return GDMonoClassMember::PUBLIC;
		default:
			ERR_FAIL_V(GDMonoClassMember::PRIVATE);
	}
}
Пример #3
0
	MonoMemberVisibility MonoMethod::getVisibility()
	{
		uint32_t flags = mono_method_get_flags(mMethod, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK;

		if (flags == MONO_METHOD_ATTR_PRIVATE)
			return MonoMemberVisibility::Private;
		else if (flags == MONO_METHOD_ATTR_FAM_AND_ASSEM)
			return MonoMemberVisibility::ProtectedInternal;
		else if (flags == MONO_METHOD_ATTR_ASSEM)
			return MonoMemberVisibility::Internal;
		else if (flags == MONO_METHOD_ATTR_FAMILY)
			return MonoMemberVisibility::Protected;
		else if (flags == MONO_METHOD_ATTR_PUBLIC)
			return MonoMemberVisibility::Public;

		assert(false);
		return MonoMemberVisibility::Private;
	}
Пример #4
0
GDMonoClassMember::Visibility GDMonoProperty::get_visibility() {
	MonoMethod *prop_method = mono_property_get_get_method(mono_property);
	if (prop_method == NULL)
		prop_method = mono_property_get_set_method(mono_property);

	switch (mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_ACCESS_MASK) {
		case MONO_METHOD_ATTR_PRIVATE:
			return GDMonoClassMember::PRIVATE;
		case MONO_METHOD_ATTR_FAM_AND_ASSEM:
			return GDMonoClassMember::PROTECTED_AND_INTERNAL;
		case MONO_METHOD_ATTR_ASSEM:
			return GDMonoClassMember::INTERNAL;
		case MONO_METHOD_ATTR_FAMILY:
			return GDMonoClassMember::PROTECTED;
		case MONO_METHOD_ATTR_PUBLIC:
			return GDMonoClassMember::PUBLIC;
		default:
			ERR_FAIL_V(GDMonoClassMember::PRIVATE);
	}
}
Пример #5
0
bool GDMonoMethod::is_static() {
	return mono_method_get_flags(mono_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
Пример #6
0
bool GDMonoProperty::is_static() {
	MonoMethod *prop_method = mono_property_get_get_method(mono_property);
	if (prop_method == NULL)
		prop_method = mono_property_get_set_method(mono_property);
	return mono_method_get_flags(prop_method, NULL) & MONO_METHOD_ATTR_STATIC;
}
Пример #7
0
void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {

	CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));

	if (methods_fetched)
		return;

	void *iter = NULL;
	MonoMethod *raw_method = NULL;
	while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != NULL) {
		StringName name = mono_method_get_name(raw_method);

		// get_method implicitly fetches methods and adds them to this->methods
		GDMonoMethod *method = get_method(raw_method, name);
		ERR_CONTINUE(!method);

		if (method->get_name() != name) {

#ifdef DEBUG_ENABLED
			String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
			WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" +
						method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`.");
#endif
			continue;
		}

#ifdef DEBUG_ENABLED
		// For debug builds, we also fetched from native base classes as well before if this is not a native base class.
		// This allows us to warn the user here if he is using snake_case by mistake.

		if (p_native_base != this) {

			GDMonoClass *native_top = p_native_base;
			while (native_top) {
				GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count());

				if (m && m->get_name() != name) {
					// found
					String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
					WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() +
								"`. In class `" + namespace_name + "." + class_name + "`.");
					break;
				}

				if (native_top == CACHED_CLASS(GodotObject))
					break;

				native_top = native_top->get_parent_class();
			}
		}
#endif

		uint32_t flags = mono_method_get_flags(method->mono_method, NULL);

		if (!(flags & MONO_METHOD_ATTR_VIRTUAL))
			continue;

		// Virtual method of Godot Object derived type, let's try to find GodotMethod attribute

		GDMonoClass *top = p_native_base;

		while (top) {
			GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count());

			if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) {
				// Found base method with GodotMethod attribute.
				// We get the original API method name from this attribute.
				// This name must point to the virtual method.

				MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute));

				StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr);
#ifdef DEBUG_ENABLED
				CRASH_COND(godot_method_name == StringName());
#endif
				MethodKey key = MethodKey(godot_method_name, method->get_parameters_count());
				GDMonoMethod **existing_method = methods.getptr(key);
				if (existing_method)
					memdelete(*existing_method); // Must delete old one
				methods.set(key, method);

				break;
			}

			if (top == CACHED_CLASS(GodotObject))
				break;

			top = top->get_parent_class();
		}
	}

	methods_fetched = true;
}
Пример #8
0
void
virt_mono_throw_unhandled_exception (MonoObject *exc)
{
  caddr_t err;
  char *message = (char *) "";
  const char *name = (const char *) "";
  MonoString *str;
  MonoMethod *method;
  MonoClass *klass;
  gboolean free_message = FALSE;
  gint i;

  if (mono_object_isinst (exc, mono_get_exception_class ()))
    {
      klass = mono_object_get_class (exc);
      method = NULL;
      while (klass && method == NULL)
	{
	  gpointer m_iter = NULL;
	  for (method = mono_class_get_methods (klass, &m_iter); method != NULL;
	      method = mono_class_get_methods (klass, &m_iter))
	    {
	      MonoMethodSignature *sig = mono_method_signature (method);
	      guint32 flags = 0;
	      const char *name = mono_method_get_name (method);

	      mono_method_get_flags (method, &flags);
	      if (!strcmp ("ToString", name) &&
		  sig->param_count == 0
#ifdef OLD_KIT_1_1_5
		  && (flags & METHOD_ATTRIBUTE_VIRTUAL)
		  && (flags & METHOD_ATTRIBUTE_PUBLIC)
#endif
		  )
		{
		  break;
		}
	      method = NULL;
	    }

	  if (method == NULL)
	    klass = mono_class_get_parent (klass);
	}

      g_assert (method);

      str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
      if (str) {
	message = mono_string_to_utf8 (str);
	free_message = TRUE;
	name = mono_class_get_name (klass);
      }
    }

  /*
   * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
   *	   exc->vtable->klass->name, message);
   */
  g_printerr ("\nUnhandled Exception: %s\n", message);


  err = srv_make_new_error ("42000", "MN001", "Unhandled Mono Exception [%.200s]: %.200s",
      name, message);
  if (free_message)
    g_free (message);
  sqlr_resignal (err);
}
Пример #9
0
static gboolean
collect_coverage_for (MonoProfiler *prof, MonoMethod *method)
{
	int i;
	char *classname;
	char *fqn;
	MonoMethodHeader *header;
	gboolean has_positive, found;
	guint32 iflags, flags, code_size;
	MonoClass *klass;
	MonoImage *image;

	flags = mono_method_get_flags (method, &iflags);
	if ((iflags & 0x1000 /*METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL*/) ||
	    (flags & 0x2000 /*METHOD_ATTRIBUTE_PINVOKE_IMPL*/))
		return FALSE;

	//if (method->wrapper_type != MONO_WRAPPER_NONE)
	//	return FALSE;

	klass = mono_method_get_class (method);
	image = mono_class_get_image (klass);
	/* Hacky way of determining the executing assembly */
	if (! prof->outfile_name && (strcmp (mono_method_get_name (method), "Main") == 0)) {
		prof->outfile_name = g_strdup_printf ("%s.cov", mono_image_get_filename (image));
	}

	/* Check filters */
	if (prof->filters) {
		/* Check already filtered classes first */
		if (g_hash_table_lookup (prof->filtered_classes, klass))
			return FALSE;

		classname = mono_type_get_name (mono_class_get_type (klass));

		fqn = g_strdup_printf ("[%s]%s", mono_image_get_name (image), classname);

		// Check positive filters first
		has_positive = FALSE;
		found = FALSE;
		for (i = 0; i < prof->filters->len; ++i) {
			char *filter = g_ptr_array_index (prof->filters_as_str, i);
			if (filter [0] == '+') {
				filter = &filter [1];
				if (strstr (fqn, filter) != NULL)
					found = TRUE;
				has_positive = TRUE;
			}
		}
		if (has_positive && !found)
			return FALSE;

		for (i = 0; i < prof->filters->len; ++i) {
			// Is substring search suffices ???
//			GPatternSpec *spec = g_ptr_array_index (filters, i);
//			if (g_pattern_match_string (spec, classname)) {
			char *filter = g_ptr_array_index (prof->filters_as_str, i);
			if (filter [0] == '+')
				continue;

			// Skip '-'
			filter = &filter [1];
			if (strstr (fqn, filter) != NULL) {
				g_hash_table_insert (prof->filtered_classes, klass, klass);
				return FALSE;
			}
		}
		g_free (fqn);
		g_free (classname);
	}

	header = mono_method_get_header (method);

	mono_method_header_get_code (header, &code_size, NULL);
	if (code_size > 20000) {
		exit (1);
		g_warning ("Unable to instrument method %s:%s since it is too complex.", mono_class_get_name (klass), mono_method_get_name (method));
		return FALSE;
	}

	g_hash_table_insert (prof->methods, method, method);

	g_hash_table_insert (prof->classes, klass, klass);

	g_hash_table_insert (prof->assemblies, mono_image_get_assembly (image), mono_image_get_assembly (image));

	return TRUE;
}