Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[mono.git] / mono / metadata / profiler.c
1 /*
2  * profiler.c: Profiler interface for Mono
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Alex Rønne Petersen (alexrp@xamarin.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
11  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12  */
13
14 #include "config.h"
15 #include "mono/metadata/profiler-private.h"
16 #include "mono/metadata/assembly.h"
17 #include "mono/metadata/debug-helpers.h"
18 #include "mono/metadata/mono-debug.h"
19 #include "mono/metadata/debug-mono-symfile.h"
20 #include "mono/metadata/metadata-internals.h"
21 #include "mono/metadata/class-internals.h"
22 #include "mono/metadata/domain-internals.h"
23 #include "mono/metadata/gc-internals.h"
24 #include "mono/metadata/mono-config-dirs.h"
25 #include "mono/io-layer/io-layer.h"
26 #include "mono/utils/mono-dl.h"
27 #include <mono/utils/mono-logger-internals.h>
28 #include <string.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35 #ifdef HAVE_BACKTRACE_SYMBOLS
36 #include <execinfo.h>
37 #endif
38
39 typedef struct _ProfilerDesc ProfilerDesc;
40 struct _ProfilerDesc {
41         ProfilerDesc *next;
42         MonoProfiler *profiler;
43         MonoProfileFlags events;
44
45         MonoProfileAppDomainFunc   domain_start_load;
46         MonoProfileAppDomainResult domain_end_load;
47         MonoProfileAppDomainFunc   domain_start_unload;
48         MonoProfileAppDomainFunc   domain_end_unload;
49         MonoProfileAppDomainFriendlyNameFunc   domain_name;
50
51         MonoProfileContextFunc context_load;
52         MonoProfileContextFunc context_unload;
53
54         MonoProfileAssemblyFunc   assembly_start_load;
55         MonoProfileAssemblyResult assembly_end_load;
56         MonoProfileAssemblyFunc   assembly_start_unload;
57         MonoProfileAssemblyFunc   assembly_end_unload;
58
59         MonoProfileModuleFunc   module_start_load;
60         MonoProfileModuleResult module_end_load;
61         MonoProfileModuleFunc   module_start_unload;
62         MonoProfileModuleFunc   module_end_unload;
63
64         MonoProfileClassFunc   class_start_load;
65         MonoProfileClassResult class_end_load;
66         MonoProfileClassFunc   class_start_unload;
67         MonoProfileClassFunc   class_end_unload;
68
69         MonoProfileMethodFunc   jit_start;
70         MonoProfileMethodResult jit_end;
71         MonoProfileJitResult    jit_end2;
72         MonoProfileMethodFunc   method_free;
73         MonoProfileMethodFunc   method_start_invoke;
74         MonoProfileMethodFunc   method_end_invoke;
75         MonoProfileMethodResult man_unman_transition;
76         MonoProfileAllocFunc    allocation_cb;
77         MonoProfileMonitorFunc  monitor_event_cb;
78         MonoProfileStatFunc     statistical_cb;
79         MonoProfileStatCallChainFunc statistical_call_chain_cb;
80         int                     statistical_call_chain_depth;
81         MonoProfilerCallChainStrategy  statistical_call_chain_strategy;
82         MonoProfileMethodFunc   method_enter;
83         MonoProfileMethodFunc   method_leave;
84
85         MonoProfileExceptionFunc        exception_throw_cb;
86         MonoProfileMethodFunc exception_method_leave_cb;
87         MonoProfileExceptionClauseFunc exception_clause_cb;
88
89         MonoProfileIomapFunc iomap_cb;
90
91         MonoProfileThreadFunc   thread_start;
92         MonoProfileThreadFunc   thread_end;
93         MonoProfileThreadNameFunc   thread_name;
94
95         MonoProfileCoverageFilterFunc coverage_filter_cb;
96
97         MonoProfileFunc shutdown_callback;
98
99         MonoProfileGCFunc        gc_event;
100         MonoProfileGCResizeFunc  gc_heap_resize;
101         MonoProfileGCMoveFunc    gc_moves;
102         MonoProfileGCHandleFunc  gc_handle;
103         MonoProfileGCRootFunc    gc_roots;
104
105         MonoProfileGCFinalizeFunc gc_finalize_begin;
106         MonoProfileGCFinalizeObjectFunc gc_finalize_object_begin;
107         MonoProfileGCFinalizeObjectFunc gc_finalize_object_end;
108         MonoProfileGCFinalizeFunc gc_finalize_end;
109
110         MonoProfileFunc          runtime_initialized_event;
111
112         MonoProfilerCodeChunkNew code_chunk_new;
113         MonoProfilerCodeChunkDestroy code_chunk_destroy;
114         MonoProfilerCodeBufferNew code_buffer_new;
115 };
116
117 static ProfilerDesc *prof_list = NULL;
118
119 #define mono_profiler_coverage_lock() mono_os_mutex_lock (&profiler_coverage_mutex)
120 #define mono_profiler_coverage_unlock() mono_os_mutex_unlock (&profiler_coverage_mutex)
121 static mono_mutex_t profiler_coverage_mutex;
122
123 /* this is directly accessible to other mono libs.
124  * It is the ORed value of all the profiler's events.
125  */
126 MonoProfileFlags mono_profiler_events;
127
128 /**
129  * mono_profiler_install:
130  * @prof: a MonoProfiler structure pointer, or a pointer to a derived structure.
131  * @callback: the function to invoke at shutdown
132  *
133  * Use mono_profiler_install to activate profiling in the Mono runtime.
134  * Typically developers of new profilers will create a new structure whose
135  * first field is a MonoProfiler and put any extra information that they need
136  * to access from the various profiling callbacks there.
137  *
138  */
139 void
140 mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
141 {
142         ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
143         if (!prof_list)
144                 mono_os_mutex_init_recursive (&profiler_coverage_mutex);
145         desc->profiler = prof;
146         desc->shutdown_callback = callback;
147         desc->next = prof_list;
148         prof_list = desc;
149 }
150
151 /**
152  * mono_profiler_set_events:
153  * @events: an ORed set of values made up of MONO_PROFILER_ flags
154  *
155  * The events descriped in the @events argument is a set of flags
156  * that represent which profiling events must be triggered.  For
157  * example if you have registered a set of methods for tracking
158  * JIT compilation start and end with mono_profiler_install_jit_compile,
159  * you will want to pass the MONO_PROFILE_JIT_COMPILATION flag to
160  * this routine.
161  *
162  * You can call mono_profile_set_events more than once and you can
163  * do this at runtime to modify which methods are invoked.
164  */
165 void
166 mono_profiler_set_events (MonoProfileFlags events)
167 {
168         ProfilerDesc *prof;
169         MonoProfileFlags value = (MonoProfileFlags)0;
170         if (prof_list)
171                 prof_list->events = events;
172         for (prof = prof_list; prof; prof = prof->next)
173                 value = (MonoProfileFlags)(value | prof->events);
174         mono_profiler_events = value;
175 }
176
177 /**
178  * mono_profiler_get_events:
179  *
180  * Returns a list of active events that will be intercepted. 
181  */
182 MonoProfileFlags
183 mono_profiler_get_events (void)
184 {
185         return mono_profiler_events;
186 }
187
188 /**
189  * mono_profiler_install_enter_leave:
190  * @enter: the routine to be called on each method entry
191  * @fleave: the routine to be called each time a method returns
192  *
193  * Use this routine to install routines that will be called everytime
194  * a method enters and leaves.   The routines will receive as an argument
195  * the MonoMethod representing the method that is entering or leaving.
196  */
197 void
198 mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
199 {
200         if (!prof_list)
201                 return;
202         prof_list->method_enter = enter;
203         prof_list->method_leave = fleave;
204 }
205
206 /**
207  * mono_profiler_install_jit_compile:
208  * @start: the routine to be called when the JIT process starts.
209  * @end: the routine to be called when the JIT process ends.
210  *
211  * Use this routine to install routines that will be called when JIT 
212  * compilation of a method starts and completes.
213  */
214 void 
215 mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
216 {
217         if (!prof_list)
218                 return;
219         prof_list->jit_start = start;
220         prof_list->jit_end = end;
221 }
222
223 void 
224 mono_profiler_install_jit_end (MonoProfileJitResult end)
225 {
226         if (!prof_list)
227                 return;
228         prof_list->jit_end2 = end;
229 }
230
231 void 
232 mono_profiler_install_method_free (MonoProfileMethodFunc callback)
233 {
234         if (!prof_list)
235                 return;
236         prof_list->method_free = callback;
237 }
238
239 void
240 mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end)
241 {
242         if (!prof_list)
243                 return;
244         prof_list->method_start_invoke = start;
245         prof_list->method_end_invoke = end;
246 }
247
248 void 
249 mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
250 {
251         if (!prof_list)
252                 return;
253         prof_list->thread_start = start;
254         prof_list->thread_end = end;
255 }
256
257 void 
258 mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb)
259 {
260         if (!prof_list)
261                 return;
262         prof_list->thread_name = thread_name_cb;
263 }
264
265 void 
266 mono_profiler_install_transition (MonoProfileMethodResult callback)
267 {
268         if (!prof_list)
269                 return;
270         prof_list->man_unman_transition = callback;
271 }
272
273 void 
274 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
275 {
276         if (!prof_list)
277                 return;
278         prof_list->allocation_cb = callback;
279 }
280
281 void
282 mono_profiler_install_monitor  (MonoProfileMonitorFunc callback)
283 {
284         if (!prof_list)
285                 return;
286         prof_list->monitor_event_cb = callback;
287 }
288
289 static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
290 static int64_t sampling_frequency = 100; // Hz
291
292 /**
293  * mono_profiler_set_statistical_mode:
294  * @mode the sampling mode used.
295  * @sample_frequency_is_us the sampling frequency in microseconds.
296  *
297  * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness.
298  * The default sampling mode is process mode, which only reports samples when there's activity in the process.
299  *
300  * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms.
301  *
302  * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere.
303  */
304 void
305 mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_hz)
306 {
307         sampling_mode = mode;
308         sampling_frequency = sampling_frequency_hz;
309 }
310
311 void 
312 mono_profiler_install_statistical (MonoProfileStatFunc callback)
313 {
314         if (!prof_list)
315                 return;
316         prof_list->statistical_cb = callback;
317 }
318
319 int64_t
320 mono_profiler_get_sampling_rate (void)
321 {
322         return sampling_frequency;
323 }
324
325 MonoProfileSamplingMode
326 mono_profiler_get_sampling_mode (void)
327 {
328         return sampling_mode;
329 }
330
331 void 
332 mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) {
333         if (!prof_list)
334                 return;
335         if (call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) {
336                 call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH;
337         }
338         if ((call_chain_strategy >= MONO_PROFILER_CALL_CHAIN_INVALID) || (call_chain_strategy < MONO_PROFILER_CALL_CHAIN_NONE)) {
339                 call_chain_strategy = MONO_PROFILER_CALL_CHAIN_NONE;
340         }
341         prof_list->statistical_call_chain_cb = callback;
342         prof_list->statistical_call_chain_depth = call_chain_depth;
343         prof_list->statistical_call_chain_strategy = call_chain_strategy;
344 }
345
346 int
347 mono_profiler_stat_get_call_chain_depth (void) {
348         if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
349                 return prof_list->statistical_call_chain_depth;
350         } else {
351                 return 0;
352         }
353 }
354
355 MonoProfilerCallChainStrategy
356 mono_profiler_stat_get_call_chain_strategy (void) {
357         if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
358                 return prof_list->statistical_call_chain_strategy;
359         } else {
360                 return MONO_PROFILER_CALL_CHAIN_NONE;
361         }
362 }
363
364 void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback)
365 {
366         if (!prof_list)
367                 return;
368         prof_list->exception_throw_cb = throw_callback;
369         prof_list->exception_method_leave_cb = exc_method_leave;
370         prof_list->exception_clause_cb = clause_callback;
371 }
372
373 void 
374 mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
375 {
376         if (!prof_list)
377                 return;
378         prof_list->coverage_filter_cb = callback;
379 }
380
381 void 
382 mono_profiler_install_appdomain   (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
383                                    MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
384
385 {
386         if (!prof_list)
387                 return;
388         prof_list->domain_start_load = start_load;
389         prof_list->domain_end_load = end_load;
390         prof_list->domain_start_unload = start_unload;
391         prof_list->domain_end_unload = end_unload;
392 }
393
394 void
395 mono_profiler_install_appdomain_name (MonoProfileAppDomainFriendlyNameFunc domain_name_cb)
396 {
397         if (!prof_list)
398                 return;
399
400         prof_list->domain_name = domain_name_cb;
401 }
402
403 void
404 mono_profiler_install_context (MonoProfileContextFunc load, MonoProfileContextFunc unload)
405 {
406         if (!prof_list)
407                 return;
408
409         prof_list->context_load = load;
410         prof_list->context_unload = unload;
411 }
412
413 void 
414 mono_profiler_install_assembly    (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
415                                    MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
416 {
417         if (!prof_list)
418                 return;
419         prof_list->assembly_start_load = start_load;
420         prof_list->assembly_end_load = end_load;
421         prof_list->assembly_start_unload = start_unload;
422         prof_list->assembly_end_unload = end_unload;
423 }
424
425 void 
426 mono_profiler_install_module      (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
427                                    MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
428 {
429         if (!prof_list)
430                 return;
431         prof_list->module_start_load = start_load;
432         prof_list->module_end_load = end_load;
433         prof_list->module_start_unload = start_unload;
434         prof_list->module_end_unload = end_unload;
435 }
436
437 void
438 mono_profiler_install_class       (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
439                                    MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
440 {
441         if (!prof_list)
442                 return;
443         prof_list->class_start_load = start_load;
444         prof_list->class_end_load = end_load;
445         prof_list->class_start_unload = start_unload;
446         prof_list->class_end_unload = end_unload;
447 }
448
449 void
450 mono_profiler_method_enter (MonoMethod *method)
451 {
452         ProfilerDesc *prof;
453         for (prof = prof_list; prof; prof = prof->next) {
454                 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_enter)
455                         prof->method_enter (prof->profiler, method);
456         }
457 }
458
459 void
460 mono_profiler_method_leave (MonoMethod *method)
461 {
462         ProfilerDesc *prof;
463         for (prof = prof_list; prof; prof = prof->next) {
464                 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_leave)
465                         prof->method_leave (prof->profiler, method);
466         }
467 }
468
469 void 
470 mono_profiler_method_jit (MonoMethod *method)
471 {
472         ProfilerDesc *prof;
473         for (prof = prof_list; prof; prof = prof->next) {
474                 if ((prof->events & MONO_PROFILE_JIT_COMPILATION) && prof->jit_start)
475                         prof->jit_start (prof->profiler, method);
476         }
477 }
478
479 void 
480 mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result)
481 {
482         ProfilerDesc *prof;
483         for (prof = prof_list; prof; prof = prof->next) {
484                 if ((prof->events & MONO_PROFILE_JIT_COMPILATION)) {
485                         if (prof->jit_end)
486                                 prof->jit_end (prof->profiler, method, result);
487                         if (prof->jit_end2)
488                                 prof->jit_end2 (prof->profiler, method, jinfo, result);
489                 }
490         }
491 }
492
493 void 
494 mono_profiler_method_free (MonoMethod *method)
495 {
496         ProfilerDesc *prof;
497         for (prof = prof_list; prof; prof = prof->next) {
498                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_free)
499                         prof->method_free (prof->profiler, method);
500         }
501 }
502
503 void
504 mono_profiler_method_start_invoke (MonoMethod *method)
505 {
506         ProfilerDesc *prof;
507         for (prof = prof_list; prof; prof = prof->next) {
508                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_start_invoke)
509                         prof->method_start_invoke (prof->profiler, method);
510         }
511 }
512
513 void
514 mono_profiler_method_end_invoke (MonoMethod *method)
515 {
516         ProfilerDesc *prof;
517         for (prof = prof_list; prof; prof = prof->next) {
518                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_end_invoke)
519                         prof->method_end_invoke (prof->profiler, method);
520         }
521 }
522
523 void 
524 mono_profiler_code_transition (MonoMethod *method, int result)
525 {
526         ProfilerDesc *prof;
527         for (prof = prof_list; prof; prof = prof->next) {
528                 if ((prof->events & MONO_PROFILE_TRANSITIONS) && prof->man_unman_transition)
529                         prof->man_unman_transition (prof->profiler, method, result);
530         }
531 }
532
533 void 
534 mono_profiler_allocation (MonoObject *obj)
535 {
536         ProfilerDesc *prof;
537         for (prof = prof_list; prof; prof = prof->next) {
538                 if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb)
539                         prof->allocation_cb (prof->profiler, obj, obj->vtable->klass);
540         }
541 }
542
543 void
544 mono_profiler_monitor_event      (MonoObject *obj, MonoProfilerMonitorEvent event) {
545         ProfilerDesc *prof;
546         for (prof = prof_list; prof; prof = prof->next) {
547                 if ((prof->events & MONO_PROFILE_MONITOR_EVENTS) && prof->monitor_event_cb)
548                         prof->monitor_event_cb (prof->profiler, obj, event);
549         }
550 }
551
552 void
553 mono_profiler_stat_hit (guchar *ip, void *context)
554 {
555         ProfilerDesc *prof;
556         for (prof = prof_list; prof; prof = prof->next) {
557                 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_cb)
558                         prof->statistical_cb (prof->profiler, ip, context);
559         }
560 }
561
562 void
563 mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context)
564 {
565         ProfilerDesc *prof;
566         for (prof = prof_list; prof; prof = prof->next) {
567                 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_call_chain_cb)
568                         prof->statistical_call_chain_cb (prof->profiler, call_chain_depth, ips, context);
569         }
570 }
571
572 void
573 mono_profiler_exception_thrown (MonoObject *exception)
574 {
575         ProfilerDesc *prof;
576         for (prof = prof_list; prof; prof = prof->next) {
577                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_throw_cb)
578                         prof->exception_throw_cb (prof->profiler, exception);
579         }
580 }
581
582 void
583 mono_profiler_exception_method_leave (MonoMethod *method)
584 {
585         ProfilerDesc *prof;
586         for (prof = prof_list; prof; prof = prof->next) {
587                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_method_leave_cb)
588                         prof->exception_method_leave_cb (prof->profiler, method);
589         }
590 }
591
592 void
593 mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num)
594 {
595         ProfilerDesc *prof;
596         for (prof = prof_list; prof; prof = prof->next) {
597                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_clause_cb)
598                         prof->exception_clause_cb (prof->profiler, method, clause_type, clause_num);
599         }
600 }
601
602 void
603 mono_profiler_thread_start (gsize tid)
604 {
605         ProfilerDesc *prof;
606         for (prof = prof_list; prof; prof = prof->next) {
607                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_start)
608                         prof->thread_start (prof->profiler, tid);
609         }
610 }
611
612 void 
613 mono_profiler_thread_end (gsize tid)
614 {
615         ProfilerDesc *prof;
616         for (prof = prof_list; prof; prof = prof->next) {
617                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_end)
618                         prof->thread_end (prof->profiler, tid);
619         }
620 }
621
622 void
623 mono_profiler_thread_name (gsize tid, const char *name)
624 {
625         ProfilerDesc *prof;
626         for (prof = prof_list; prof; prof = prof->next) {
627                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name)
628                         prof->thread_name (prof->profiler, tid, name);
629         }
630 }
631
632 void 
633 mono_profiler_assembly_event  (MonoAssembly *assembly, int code)
634 {
635         ProfilerDesc *prof;
636         for (prof = prof_list; prof; prof = prof->next) {
637                 if (!(prof->events & MONO_PROFILE_ASSEMBLY_EVENTS))
638                         continue;
639
640                 switch (code) {
641                 case MONO_PROFILE_START_LOAD:
642                         if (prof->assembly_start_load)
643                                 prof->assembly_start_load (prof->profiler, assembly);
644                         break;
645                 case MONO_PROFILE_START_UNLOAD:
646                         if (prof->assembly_start_unload)
647                                 prof->assembly_start_unload (prof->profiler, assembly);
648                         break;
649                 case MONO_PROFILE_END_UNLOAD:
650                         if (prof->assembly_end_unload)
651                                 prof->assembly_end_unload (prof->profiler, assembly);
652                         break;
653                 default:
654                         g_assert_not_reached ();
655                 }
656         }
657 }
658
659 void 
660 mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
661 {
662         ProfilerDesc *prof;
663         for (prof = prof_list; prof; prof = prof->next) {
664                 if ((prof->events & MONO_PROFILE_ASSEMBLY_EVENTS) && prof->assembly_end_load)
665                         prof->assembly_end_load (prof->profiler, assembly, result);
666         }
667 }
668
669 void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname)
670 {
671         ProfilerDesc *prof;
672         for (prof = prof_list; prof; prof = prof->next) {
673                 if ((prof->events & MONO_PROFILE_IOMAP_EVENTS) && prof->iomap_cb)
674                         prof->iomap_cb (prof->profiler, report, pathname, new_pathname);
675         }
676 }
677
678 void 
679 mono_profiler_module_event  (MonoImage *module, int code)
680 {
681         ProfilerDesc *prof;
682         for (prof = prof_list; prof; prof = prof->next) {
683                 if (!(prof->events & MONO_PROFILE_MODULE_EVENTS))
684                         continue;
685
686                 switch (code) {
687                 case MONO_PROFILE_START_LOAD:
688                         if (prof->module_start_load)
689                                 prof->module_start_load (prof->profiler, module);
690                         break;
691                 case MONO_PROFILE_START_UNLOAD:
692                         if (prof->module_start_unload)
693                                 prof->module_start_unload (prof->profiler, module);
694                         break;
695                 case MONO_PROFILE_END_UNLOAD:
696                         if (prof->module_end_unload)
697                                 prof->module_end_unload (prof->profiler, module);
698                         break;
699                 default:
700                         g_assert_not_reached ();
701                 }
702         }
703 }
704
705 void 
706 mono_profiler_module_loaded (MonoImage *module, int result)
707 {
708         ProfilerDesc *prof;
709         for (prof = prof_list; prof; prof = prof->next) {
710                 if ((prof->events & MONO_PROFILE_MODULE_EVENTS) && prof->module_end_load)
711                         prof->module_end_load (prof->profiler, module, result);
712         }
713 }
714
715 void 
716 mono_profiler_class_event  (MonoClass *klass, int code)
717 {
718         ProfilerDesc *prof;
719         for (prof = prof_list; prof; prof = prof->next) {
720                 if (!(prof->events & MONO_PROFILE_CLASS_EVENTS))
721                         continue;
722
723                 switch (code) {
724                 case MONO_PROFILE_START_LOAD:
725                         if (prof->class_start_load)
726                                 prof->class_start_load (prof->profiler, klass);
727                         break;
728                 case MONO_PROFILE_START_UNLOAD:
729                         if (prof->class_start_unload)
730                                 prof->class_start_unload (prof->profiler, klass);
731                         break;
732                 case MONO_PROFILE_END_UNLOAD:
733                         if (prof->class_end_unload)
734                                 prof->class_end_unload (prof->profiler, klass);
735                         break;
736                 default:
737                         g_assert_not_reached ();
738                 }
739         }
740 }
741
742 void 
743 mono_profiler_class_loaded (MonoClass *klass, int result)
744 {
745         ProfilerDesc *prof;
746         for (prof = prof_list; prof; prof = prof->next) {
747                 if ((prof->events & MONO_PROFILE_CLASS_EVENTS) && prof->class_end_load)
748                         prof->class_end_load (prof->profiler, klass, result);
749         }
750 }
751
752 void 
753 mono_profiler_appdomain_event  (MonoDomain *domain, int code)
754 {
755         ProfilerDesc *prof;
756         for (prof = prof_list; prof; prof = prof->next) {
757                 if (!(prof->events & MONO_PROFILE_APPDOMAIN_EVENTS))
758                         continue;
759
760                 switch (code) {
761                 case MONO_PROFILE_START_LOAD:
762                         if (prof->domain_start_load)
763                                 prof->domain_start_load (prof->profiler, domain);
764                         break;
765                 case MONO_PROFILE_START_UNLOAD:
766                         if (prof->domain_start_unload)
767                                 prof->domain_start_unload (prof->profiler, domain);
768                         break;
769                 case MONO_PROFILE_END_UNLOAD:
770                         if (prof->domain_end_unload)
771                                 prof->domain_end_unload (prof->profiler, domain);
772                         break;
773                 default:
774                         g_assert_not_reached ();
775                 }
776         }
777 }
778
779 void 
780 mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
781 {
782         ProfilerDesc *prof;
783         for (prof = prof_list; prof; prof = prof->next) {
784                 if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_end_load)
785                         prof->domain_end_load (prof->profiler, domain, result);
786         }
787 }
788
789 void
790 mono_profiler_appdomain_name (MonoDomain *domain, const char *name)
791 {
792         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
793                 if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_name)
794                         prof->domain_name (prof->profiler, domain, name);
795 }
796
797 void
798 mono_profiler_context_loaded (MonoAppContext *context)
799 {
800         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
801                 if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_load)
802                         prof->context_load (prof->profiler, context);
803 }
804
805 void
806 mono_profiler_context_unloaded (MonoAppContext *context)
807 {
808         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
809                 if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_unload)
810                         prof->context_unload (prof->profiler, context);
811 }
812
813 void 
814 mono_profiler_shutdown (void)
815 {
816         ProfilerDesc *prof;
817         for (prof = prof_list; prof; prof = prof->next) {
818                 if (prof->shutdown_callback)
819                         prof->shutdown_callback (prof->profiler);
820         }
821
822         mono_profiler_set_events ((MonoProfileFlags)0);
823 }
824
825 void
826 mono_profiler_gc_heap_resize (gint64 new_size)
827 {
828         ProfilerDesc *prof;
829         for (prof = prof_list; prof; prof = prof->next) {
830                 if ((prof->events & MONO_PROFILE_GC) && prof->gc_heap_resize)
831                         prof->gc_heap_resize (prof->profiler, new_size);
832         }
833 }
834
835 void
836 mono_profiler_gc_event (MonoGCEvent event, int generation)
837 {
838         ProfilerDesc *prof;
839         for (prof = prof_list; prof; prof = prof->next) {
840                 if ((prof->events & MONO_PROFILE_GC) && prof->gc_event)
841                         prof->gc_event (prof->profiler, event, generation);
842         }
843 }
844
845 void
846 mono_profiler_gc_moves (void **objects, int num)
847 {
848         ProfilerDesc *prof;
849         for (prof = prof_list; prof; prof = prof->next) {
850                 if ((prof->events & MONO_PROFILE_GC_MOVES) && prof->gc_moves)
851                         prof->gc_moves (prof->profiler, objects, num);
852         }
853 }
854
855 void
856 mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj)
857 {
858         ProfilerDesc *prof;
859         for (prof = prof_list; prof; prof = prof->next) {
860                 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle)
861                         prof->gc_handle (prof->profiler, op, type, handle, obj);
862         }
863 }
864
865 void
866 mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info)
867 {
868         ProfilerDesc *prof;
869         for (prof = prof_list; prof; prof = prof->next) {
870                 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots)
871                         prof->gc_roots (prof->profiler, num, objects, root_types, extra_info);
872         }
873 }
874
875 void
876 mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
877 {
878         if (!prof_list)
879                 return;
880         prof_list->gc_event = callback;
881         prof_list->gc_heap_resize = heap_resize_callback;
882 }
883
884 /**
885  * mono_profiler_install_gc_moves:
886  * @callback: callback function
887  *
888  * Install the @callback function that the GC will call when moving objects.
889  * The callback receives an array of pointers and the number of elements
890  * in the array. Every even element in the array is the original object location
891  * and the following odd element is the new location of the object in memory.
892  * So the number of elements argument will always be a multiple of 2.
893  * Since this callback happens during the GC, it is a restricted environment:
894  * no locks can be taken and the object pointers can be inspected only once
895  * the GC is finished (of course the original location pointers will not
896  * point to valid objects anymore).
897  */
898 void
899 mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback)
900 {
901         if (!prof_list)
902                 return;
903         prof_list->gc_moves = callback;
904 }
905
906 /**
907  * mono_profiler_install_gc_roots:
908  * @handle_callback: callback function
909  * @roots_callback: callback function
910  *
911  * Install the @handle_callback function that the GC will call when GC
912  * handles are created or destroyed.
913  * The callback receives an operation, which is either #MONO_PROFILER_GC_HANDLE_CREATED
914  * or #MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
915  * object pointer, if present.
916  * Install the @roots_callback function that the GC will call when tracing
917  * the roots for a collection.
918  * The callback receives the number of elements and three arrays: an array
919  * of objects, an array of root types and flags and an array of extra info.
920  * The size of each array is given by the first argument.
921  */
922 void
923 mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback)
924 {
925         if (!prof_list)
926                 return;
927         prof_list->gc_handle = handle_callback;
928         prof_list->gc_roots = roots_callback;
929 }
930
931 void
932 mono_profiler_gc_finalize_begin (void)
933 {
934         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
935                 if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_begin)
936                         prof->gc_finalize_begin (prof->profiler);
937 }
938
939 void
940 mono_profiler_gc_finalize_object_begin (MonoObject *obj)
941 {
942         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
943                 if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_begin)
944                         prof->gc_finalize_object_begin (prof->profiler, obj);
945 }
946
947 void
948 mono_profiler_gc_finalize_object_end (MonoObject *obj)
949 {
950         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
951                 if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_end)
952                         prof->gc_finalize_object_end (prof->profiler, obj);
953 }
954
955 void
956 mono_profiler_gc_finalize_end (void)
957 {
958         for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
959                 if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_end)
960                         prof->gc_finalize_end (prof->profiler);
961 }
962
963 void
964 mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end)
965 {
966         if (!prof_list)
967                 return;
968
969         prof_list->gc_finalize_begin = begin;
970         prof_list->gc_finalize_object_begin = begin_obj;
971         prof_list->gc_finalize_object_end = end_obj;
972         prof_list->gc_finalize_end = end;
973 }
974
975 void
976 mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
977 {
978         if (!prof_list)
979                 return;
980         prof_list->runtime_initialized_event = runtime_initialized_callback;
981 }
982
983 void
984 mono_profiler_runtime_initialized (void) {
985         ProfilerDesc *prof;
986         for (prof = prof_list; prof; prof = prof->next) {
987                 if (prof->runtime_initialized_event)
988                         prof->runtime_initialized_event (prof->profiler);
989         }
990 }
991
992 void
993 mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback) {
994         if (!prof_list)
995                 return;
996         prof_list->code_chunk_new = callback;
997 }
998 void
999 mono_profiler_code_chunk_new (gpointer chunk, int size) {
1000         ProfilerDesc *prof;
1001         for (prof = prof_list; prof; prof = prof->next) {
1002                 if (prof->code_chunk_new)
1003                         prof->code_chunk_new (prof->profiler, chunk, size);
1004         }
1005 }
1006
1007 void
1008 mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback) {
1009         if (!prof_list)
1010                 return;
1011         prof_list->code_chunk_destroy = callback;
1012 }
1013 void
1014 mono_profiler_code_chunk_destroy (gpointer chunk) {
1015         ProfilerDesc *prof;
1016         for (prof = prof_list; prof; prof = prof->next) {
1017                 if (prof->code_chunk_destroy)
1018                         prof->code_chunk_destroy (prof->profiler, chunk);
1019         }
1020 }
1021
1022 void
1023 mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback) {
1024         if (!prof_list)
1025                 return;
1026         prof_list->code_buffer_new = callback;
1027 }
1028
1029 void
1030 mono_profiler_install_iomap (MonoProfileIomapFunc callback)
1031 {
1032         if (!prof_list)
1033                 return;
1034         prof_list->iomap_cb = callback;
1035 }
1036
1037 void
1038 mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data) {
1039         ProfilerDesc *prof;
1040         for (prof = prof_list; prof; prof = prof->next) {
1041                 if (prof->code_buffer_new)
1042                         prof->code_buffer_new (prof->profiler, buffer, size, type, (void*)data);
1043         }
1044 }
1045
1046 static GHashTable *coverage_hash = NULL;
1047
1048 MonoProfileCoverageInfo* 
1049 mono_profiler_coverage_alloc (MonoMethod *method, int entries)
1050 {
1051         MonoProfileCoverageInfo *res;
1052         int instrument = FALSE;
1053         ProfilerDesc *prof;
1054
1055         for (prof = prof_list; prof; prof = prof->next) {
1056                 /* note that we call the filter on all the profilers even if just
1057                  * a single one would be enough to instrument a method
1058                  */
1059                 if (prof->coverage_filter_cb)
1060                         if (prof->coverage_filter_cb (prof->profiler, method))
1061                                 instrument = TRUE;
1062         }
1063         if (!instrument)
1064                 return NULL;
1065
1066         mono_profiler_coverage_lock ();
1067         if (!coverage_hash)
1068                 coverage_hash = g_hash_table_new (NULL, NULL);
1069
1070         res = (MonoProfileCoverageInfo *)g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
1071
1072         res->entries = entries;
1073
1074         g_hash_table_insert (coverage_hash, method, res);
1075         mono_profiler_coverage_unlock ();
1076
1077         return res;
1078 }
1079
1080 /* safe only when the method antive code has been unloaded */
1081 void
1082 mono_profiler_coverage_free (MonoMethod *method)
1083 {
1084         MonoProfileCoverageInfo* info;
1085
1086         mono_profiler_coverage_lock ();
1087         if (!coverage_hash) {
1088                 mono_profiler_coverage_unlock ();
1089                 return;
1090         }
1091
1092         info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
1093         if (info) {
1094                 g_free (info);
1095                 g_hash_table_remove (coverage_hash, method);
1096         }
1097         mono_profiler_coverage_unlock ();
1098 }
1099
1100 /**
1101  * mono_profiler_coverage_get:
1102  * @prof: The profiler handle, installed with mono_profiler_install
1103  * @method: the method to gather information from.
1104  * @func: A routine that will be called back with the results
1105  *
1106  * If the MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation
1107  * it is posisble to obtain coverage information about a give method.
1108  *
1109  * The function @func will be invoked repeatedly with instances of the
1110  * MonoProfileCoverageEntry structure.
1111  */
1112 void 
1113 mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
1114 {
1115         MonoError error;
1116         MonoProfileCoverageInfo* info = NULL;
1117         int i, offset;
1118         guint32 code_size;
1119         const unsigned char *start, *end, *cil_code;
1120         MonoMethodHeader *header;
1121         MonoProfileCoverageEntry entry;
1122         MonoDebugMethodInfo *debug_minfo;
1123
1124         mono_profiler_coverage_lock ();
1125         if (coverage_hash)
1126                 info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
1127         mono_profiler_coverage_unlock ();
1128
1129         if (!info)
1130                 return;
1131
1132         header = mono_method_get_header_checked (method, &error);
1133         mono_error_assert_ok (&error);
1134         start = mono_method_header_get_code (header, &code_size, NULL);
1135         debug_minfo = mono_debug_lookup_method (method);
1136
1137         end = start + code_size;
1138         for (i = 0; i < info->entries; ++i) {
1139                 cil_code = info->data [i].cil_code;
1140                 if (cil_code && cil_code >= start && cil_code < end) {
1141                         char *fname = NULL;
1142                         offset = cil_code - start;
1143                         entry.iloffset = offset;
1144                         entry.method = method;
1145                         entry.counter = info->data [i].count;
1146                         entry.line = entry.col = 1;
1147                         entry.filename = NULL;
1148                         if (debug_minfo) {
1149                                 MonoDebugSourceLocation *location;
1150
1151                                 location = mono_debug_symfile_lookup_location (debug_minfo, offset);
1152                                 if (location) {
1153                                         entry.line = location->row;
1154                                         entry.col = location->column;
1155                                         entry.filename = fname = g_strdup (location->source_file);
1156                                         mono_debug_free_source_location (location);
1157                                 }
1158                         }
1159
1160                         func (prof, &entry);
1161                         g_free (fname);
1162                 }
1163         }
1164         mono_metadata_free_mh (header);
1165 }
1166
1167 typedef void (*ProfilerInitializer) (const char*);
1168 #define INITIALIZER_NAME "mono_profiler_startup"
1169
1170
1171 static gboolean
1172 load_profiler (MonoDl *pmodule, const char *desc, const char *symbol)
1173 {
1174         char *err;
1175         ProfilerInitializer func;
1176
1177         if (!pmodule)
1178                 return FALSE;
1179
1180         if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) {
1181                 g_free (err);
1182                 return FALSE;
1183         } else {
1184                 func (desc);
1185         }
1186         return TRUE;
1187 }
1188
1189 static gboolean
1190 load_embedded_profiler (const char *desc, const char *name)
1191 {
1192         char *err = NULL;
1193         char *symbol;
1194         MonoDl *pmodule = NULL;
1195         gboolean result;
1196
1197         /*
1198          * Some profilers (such as ours) may need to call back into the runtime
1199          * from their sampling callback (which is called in async-signal context).
1200          * They need to be able to know that all references back to the runtime
1201          * have been resolved; otherwise, calling runtime functions may result in
1202          * invoking the dynamic linker which is not async-signal-safe. Passing
1203          * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
1204          */
1205         pmodule = mono_dl_open (NULL, MONO_DL_EAGER, &err);
1206         if (!pmodule) {
1207                 g_warning ("Could not open main executable (%s)", err);
1208                 g_free (err);
1209                 return FALSE;
1210         }
1211
1212         symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name);
1213         result = load_profiler (pmodule, desc, symbol);
1214         g_free (symbol);
1215
1216         return result;
1217 }
1218
1219 // TODO: Much of the library loading code here is custom. It would be better to merge this with mono-dl
1220 static gboolean
1221 load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
1222 {
1223         MonoDl *pmodule = NULL;
1224         char* path;
1225         char *err;
1226         void *iter;
1227
1228         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler %s from %s (desc %s)", libname, directory, desc);
1229
1230         iter = NULL;
1231         err = NULL;
1232         while ((path = mono_dl_build_path (directory, libname, &iter))) {
1233                 pmodule = mono_dl_open (path, MONO_DL_EAGER, &err);
1234                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler: %s, %ssuccessful, err: %s", path, pmodule?"":"not ", err);
1235                 g_free (path);
1236                 g_free (err);
1237                 if (pmodule)
1238                         return load_profiler (pmodule, desc, INITIALIZER_NAME);
1239         }
1240                 
1241         return FALSE;
1242 }
1243
1244 static gboolean
1245 load_profiler_from_mono_installation (const char *libname, const char *desc)
1246 {
1247         char *err = NULL;
1248         MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
1249         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler from runtime libs: %s, %ssuccessful, err: %s", libname, pmodule?"":"not ", err);
1250         g_free (err);
1251         if (pmodule)
1252                 return load_profiler (pmodule, desc, INITIALIZER_NAME);
1253         return FALSE;
1254 }
1255
1256 /**
1257  * mono_profiler_load:
1258  * @desc: arguments to configure the profiler
1259  *
1260  * Invoke this method to initialize the profiler.   This will drive the
1261  * loading of the internal ("default") or any external profilers.
1262  *
1263  * This routine is invoked by Mono's driver, but must be called manually
1264  * if you embed Mono into your application.
1265  */
1266 void 
1267 mono_profiler_load (const char *desc)
1268 {
1269         char *cdesc = NULL;
1270         mono_gc_base_init ();
1271
1272         if (!desc || (strcmp ("default", desc) == 0)) {
1273                 desc = "log:report";
1274         }
1275         /* we keep command-line compat with the old version here */
1276         if (strncmp (desc, "default:", 8) == 0) {
1277                 gchar **args, **ptr;
1278                 GString *str = g_string_new ("log:report");
1279                 args = g_strsplit (desc + 8, ",", -1);
1280                 for (ptr = args; ptr && *ptr; ptr++) {
1281                         const char *arg = *ptr;
1282
1283                         if (!strcmp (arg, "time"))
1284                                 g_string_append (str, ",calls");
1285                         else if (!strcmp (arg, "alloc"))
1286                                 g_string_append (str, ",alloc");
1287                         else if (!strcmp (arg, "stat"))
1288                                 g_string_append (str, ",sample");
1289                         else if (!strcmp (arg, "jit"))
1290                                 continue; /* accept and do nothing */
1291                         else if (strncmp (arg, "file=", 5) == 0) {
1292                                 g_string_append_printf (str, ",output=%s", arg + 5);
1293                         } else {
1294                                 fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
1295                                 return;
1296                         }
1297                 }
1298                 desc = cdesc = g_string_free (str, FALSE);
1299         }
1300         {
1301                 const char* col = strchr (desc, ':');
1302                 char* libname;
1303                 char *mname;
1304                 gboolean res = FALSE;
1305
1306                 if (col != NULL) {
1307                         mname = (char *)g_memdup (desc, col - desc + 1);
1308                         mname [col - desc] = 0;
1309                 } else {
1310                         mname = g_strdup (desc);
1311                 }
1312                 if (!load_embedded_profiler (desc, mname)) {
1313                         libname = g_strdup_printf ("mono-profiler-%s", mname);
1314                         res = load_profiler_from_mono_installation (libname, desc);
1315                         if (!res && mono_config_get_assemblies_dir ())
1316                                 res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
1317                         if (!res)
1318                                 res = load_profiler_from_directory (NULL, libname, desc);
1319                         if (!res)
1320                                 g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
1321                         g_free (libname);
1322                 }
1323                 g_free (mname);
1324         }
1325         g_free (cdesc);
1326 }
1327