1 #include <mono/metadata/profiler.h>
2 #include <mono/metadata/tokentype.h>
3 #include <mono/metadata/tabledefs.h>
4 #include <mono/metadata/debug-helpers.h>
5 #include <mono/metadata/assembly.h>
9 * Coverage profiler. Compile with:
10 * gcc -Wall -shared -o mono-profiler-cov.so mono-cov.c `pkg-config --cflags --libs mono`
11 * Install the binary where the dynamic loader can find it (/usr/local/lib, for example,
12 * or set the env var LD_LIBRARY_PATH to the directory where the file is).
14 * mono --profile=cov:yourassembly test_suite.exe
15 * mono --profile=cov:yourassembly/namespace test_suite.exe
18 struct _MonoProfiler {
22 MonoAssembly *assembly;
27 get_assembly (MonoAssembly* ass, MonoProfiler *prof)
29 if (strcmp (prof->assembly_name, ass->aname.name) == 0)
34 coverage_callback (MonoProfiler *prof, const MonoProfileCoverageEntry *entry)
41 if (entry->filename) {
42 cmsg = g_strdup_printf ("offset 0x%04x (%s: line: %d, col: %d)",
43 entry->iloffset, entry->filename, entry->line, entry->col);
45 cmsg = g_strdup_printf ("offset 0x%04x", entry->iloffset);
47 prof->bb_coverage = g_list_append (prof->bb_coverage, cmsg);
51 check_partial_coverage (MonoProfiler *prof, MonoMethod *method)
55 mono_profiler_coverage_get (prof, method, coverage_callback);
56 if (prof->bb_coverage) {
57 char *name = mono_method_full_name (method, TRUE);
58 g_print ("Partial coverage: %s\n", name + 3);
60 for (tmp = prof->bb_coverage; tmp; tmp = tmp->next) {
61 g_print ("\t%s\n", (char*)tmp->data);
64 g_list_free (prof->bb_coverage);
65 prof->bb_coverage = NULL;
69 /* called at the end of the program */
71 cov_shutdown (MonoProfiler *prof)
78 mono_assembly_foreach ((GFunc)get_assembly, prof);
79 if (!prof->assembly) {
80 g_print ("Assembly '%s' was not loaded\n", prof->assembly_name);
83 image = prof->assembly->image;
84 for (i = 1; i <= image->tables [MONO_TABLE_METHOD].rows; ++i) {
85 method = mono_get_method (image, i | MONO_TOKEN_METHOD_DEF, NULL);
88 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT))
90 /* FIXME: handle icalls, runtime calls and synchronized methods */
91 if (prof->class_name && *prof->class_name) {
92 if (!strstr (method->klass->name, prof->class_name) && !strstr (method->klass->name_space, prof->class_name))
95 /*g_print ("check %s::%s, %p\n", method->klass->name, method->name, method);*/
96 if (g_hash_table_lookup (prof->hash, method)) {
97 /* the method was executed: check it was fully covered */
98 check_partial_coverage (prof, method);
101 name = mono_method_full_name (method, TRUE);
102 g_print ("Not covered: %s\n", name + 3);
108 cov_method_enter (MonoProfiler *prof, MonoMethod *method)
110 /*g_print ("enter %s::%s, %p\n", method->klass->name, method->name, method);*/
111 g_hash_table_insert (prof->hash, method, GINT_TO_POINTER (1));
115 cov_method_leave (MonoProfiler *prof, MonoMethod *method)
119 /* the entry point */
121 mono_profiler_startup (const char *desc)
125 prof = g_new0 (MonoProfiler, 1);
126 prof->hash = g_hash_table_new (NULL, NULL);
127 if (strncmp ("cov:", desc, 4) == 0 && desc [4]) {
129 prof->assembly_name = g_strdup (desc + 4);
130 cname = strchr (prof->assembly_name, '/');
133 prof->class_name = cname + 1;
136 prof->assembly_name = g_strdup ("mscorlib");
139 mono_profiler_install (prof, cov_shutdown);
141 mono_profiler_install_enter_leave (cov_method_enter, cov_method_leave);
143 mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_COVERAGE);