1 /*
2 * Licensed to the .NET Foundation under one or more agreements.
3 * The .NET Foundation licenses this file to you under the MIT license.
4 * See the LICENSE file in the project root for more information.
5 */
6
7 #include <config.h>
8 #include <mono/metadata/assembly.h>
9 #include <mono/metadata/gc-internals.h>
10 #include <mono/metadata/mono-config-dirs.h>
11 #include <mono/metadata/mono-debug.h>
12 #include <mono/metadata/profiler-private.h>
13 #include <mono/metadata/debug-internals.h>
14 #include <mono/utils/mono-dl.h>
15 #include <mono/utils/mono-error-internals.h>
16 #include <mono/utils/mono-logger-internals.h>
17
18 MonoProfilerState mono_profiler_state;
19
20 typedef void (*MonoProfilerInitializer) (const char *);
21
22 #define OLD_INITIALIZER_NAME "mono_profiler_startup"
23 #define NEW_INITIALIZER_NAME "mono_profiler_init"
24
25 static gboolean
load_profiler(MonoDl * module,const char * name,const char * desc)26 load_profiler (MonoDl *module, const char *name, const char *desc)
27 {
28 if (!module)
29 return FALSE;
30
31 char *err, *old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
32 MonoProfilerInitializer func;
33
34 if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
35 mono_profiler_printf_err ("Found old-style startup symbol '%s' for the '%s' profiler; it has not been migrated to the new API.", old_name, name);
36 g_free (old_name);
37 return FALSE;
38 }
39
40 g_free (err);
41 g_free (old_name);
42
43 char *new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", name);
44
45 if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
46 g_free (err);
47 g_free (new_name);
48 return FALSE;
49 }
50
51 g_free (new_name);
52
53 func (desc);
54
55 return TRUE;
56 }
57
58 static gboolean
load_profiler_from_executable(const char * name,const char * desc)59 load_profiler_from_executable (const char *name, const char *desc)
60 {
61 char *err;
62
63 /*
64 * Some profilers (such as ours) may need to call back into the runtime
65 * from their sampling callback (which is called in async-signal context).
66 * They need to be able to know that all references back to the runtime
67 * have been resolved; otherwise, calling runtime functions may result in
68 * invoking the dynamic linker which is not async-signal-safe. Passing
69 * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
70 */
71 MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
72
73 if (!module) {
74 mono_profiler_printf_err ("Could not open main executable: %s", err);
75 g_free (err);
76 return FALSE;
77 }
78
79 return load_profiler (module, name, desc);
80 }
81
82 static gboolean
load_profiler_from_directory(const char * directory,const char * libname,const char * name,const char * desc)83 load_profiler_from_directory (const char *directory, const char *libname, const char *name, const char *desc)
84 {
85 char* path;
86 void *iter = NULL;
87
88 while ((path = mono_dl_build_path (directory, libname, &iter))) {
89 // See the comment in load_embedded_profiler ().
90 MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL);
91
92 g_free (path);
93
94 if (module)
95 return load_profiler (module, name, desc);
96 }
97
98 return FALSE;
99 }
100
101 static gboolean
load_profiler_from_installation(const char * libname,const char * name,const char * desc)102 load_profiler_from_installation (const char *libname, const char *name, const char *desc)
103 {
104 char *err;
105 MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
106
107 g_free (err);
108
109 if (module)
110 return load_profiler (module, name, desc);
111
112 return FALSE;
113 }
114
115 /**
116 * mono_profiler_load:
117 *
118 * Loads a profiler module based on the specified description. \p desc can be
119 * of the form \c name:args or just \c name. For example, \c log:sample and
120 * \c log will both load \c libmono-profiler-log.so. The description is passed
121 * to the module after it has been loaded. If the specified module has already
122 * been loaded, this function has no effect.
123 *
124 * A module called \c foo should declare an entry point like so:
125 *
126 * \code
127 * void mono_profiler_init_foo (const char *desc)
128 * {
129 * }
130 * \endcode
131 *
132 * This function is \b not async safe.
133 *
134 * This function may \b only be called by embedders prior to running managed
135 * code.
136 */
137 void
mono_profiler_load(const char * desc)138 mono_profiler_load (const char *desc)
139 {
140 if (!desc || !strcmp ("default", desc))
141 desc = "log:report";
142
143 const char *col = strchr (desc, ':');
144 char *mname;
145
146 if (col != NULL) {
147 mname = (char *) g_memdup (desc, col - desc + 1);
148 mname [col - desc] = 0;
149 } else
150 mname = g_strdup (desc);
151
152 if (!load_profiler_from_executable (mname, desc)) {
153 char *libname = g_strdup_printf ("mono-profiler-%s", mname);
154 gboolean res = load_profiler_from_installation (libname, mname, desc);
155
156 if (!res && mono_config_get_assemblies_dir ())
157 res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, mname, desc);
158
159 if (!res)
160 res = load_profiler_from_directory (NULL, libname, mname, desc);
161
162 if (!res)
163 mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
164
165 g_free (libname);
166 }
167
168 g_free (mname);
169 }
170
171 /**
172 * mono_profiler_create:
173 *
174 * Installs a profiler and returns a handle for it. The handle is used with the
175 * other functions in the profiler API (e.g. for setting up callbacks). The
176 * given structure pointer, \p prof, will be passed to all callbacks from the
177 * profiler API. It can be \c NULL.
178 *
179 * Example usage:
180 *
181 * \code
182 * struct _MonoProfiler {
183 * int my_stuff;
184 * // ...
185 * };
186 *
187 * MonoProfiler *prof = malloc (sizeof (MonoProfiler));
188 * prof->my_stuff = 42;
189 * MonoProfilerHandle handle = mono_profiler_create (prof);
190 * mono_profiler_set_shutdown_callback (handle, my_shutdown_cb);
191 * \endcode
192 *
193 * This function is \b not async safe.
194 *
195 * This function may \b only be called from a profiler's init function or prior
196 * to running managed code.
197 */
198 MonoProfilerHandle
mono_profiler_create(MonoProfiler * prof)199 mono_profiler_create (MonoProfiler *prof)
200 {
201 MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
202
203 handle->prof = prof;
204 handle->next = mono_profiler_state.profilers;
205
206 mono_profiler_state.profilers = handle;
207
208 return handle;
209 }
210
211 /**
212 * mono_profiler_set_cleanup_callback:
213 *
214 * Sets a profiler cleanup function. This function will be invoked at shutdown
215 * when the profiler API is cleaning up its internal structures. It's mainly
216 * intended for a profiler to free the structure pointer that was passed to
217 * \c mono_profiler_create, if necessary.
218 *
219 * This function is async safe.
220 */
221 void
mono_profiler_set_cleanup_callback(MonoProfilerHandle handle,MonoProfilerCleanupCallback cb)222 mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb)
223 {
224 mono_atomic_store_ptr (&handle->cleanup_callback, (gpointer) cb);
225 }
226
227 /**
228 * mono_profiler_enable_coverage:
229 *
230 * Enables support for code coverage instrumentation. At the moment, this means
231 * enabling the debug info subsystem. If this function is not called, it will
232 * not be possible to use \c mono_profiler_get_coverage_data. Returns \c TRUE
233 * if code coverage support was enabled, or \c FALSE if the function was called
234 * too late for this to be possible.
235 *
236 * This function is \b not async safe.
237 *
238 * This function may \b only be called from a profiler's init function or prior
239 * to running managed code.
240 */
241 mono_bool
mono_profiler_enable_coverage(void)242 mono_profiler_enable_coverage (void)
243 {
244 if (mono_profiler_state.startup_done)
245 return FALSE;
246
247 mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
248 mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
249
250 if (!mono_debug_enabled ())
251 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
252
253 return mono_profiler_state.code_coverage = TRUE;
254 }
255
256 /**
257 * mono_profiler_set_coverage_filter_callback:
258 *
259 * Sets a code coverage filter function. The profiler API will invoke filter
260 * functions from all installed profilers. If any of them return \c TRUE, then
261 * the given method will be instrumented for coverage analysis. All filters are
262 * guaranteed to be called at least once per method, even if an earlier filter
263 * has already returned \c TRUE.
264 *
265 * Note that filter functions must be installed before a method is compiled in
266 * order to have any effect, i.e. a filter should be registered in a profiler's
267 * init function or prior to running managed code (if embedding).
268 *
269 * This function is async safe.
270 */
271 void
mono_profiler_set_coverage_filter_callback(MonoProfilerHandle handle,MonoProfilerCoverageFilterCallback cb)272 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
273 {
274 mono_atomic_store_ptr (&handle->coverage_filter, (gpointer) cb);
275 }
276
277 static void
coverage_lock(void)278 coverage_lock (void)
279 {
280 mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
281 }
282
283 static void
coverage_unlock(void)284 coverage_unlock (void)
285 {
286 mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
287 }
288
289 /**
290 * mono_profiler_get_coverage_data:
291 *
292 * Retrieves all coverage data for \p method and invokes \p cb for each entry.
293 * Source location information will only be filled out if \p method has debug
294 * info available. Returns \c TRUE if \p method was instrumented for code
295 * coverage; otherwise, \c FALSE.
296 *
297 * Please note that the structure passed to \p cb is only valid for the
298 * duration of the callback.
299 *
300 * This function is \b not async safe.
301 */
302 mono_bool
mono_profiler_get_coverage_data(MonoProfilerHandle handle,MonoMethod * method,MonoProfilerCoverageCallback cb)303 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
304 {
305 if (!mono_profiler_state.code_coverage)
306 return FALSE;
307
308 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
309 return FALSE;
310
311 coverage_lock ();
312
313 MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
314
315 coverage_unlock ();
316
317 MonoError error;
318 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
319 mono_error_assert_ok (&error);
320
321 guint32 size;
322
323 const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
324 const unsigned char *end = start + size;
325 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
326
327 if (!info) {
328 char *source_file;
329 int i, n_il_offsets;
330 int *source_files;
331 GPtrArray *source_file_list;
332 MonoSymSeqPoint *sym_seq_points;
333
334 if (!minfo)
335 return TRUE;
336
337 /* Return 0 counts for all locations */
338
339 mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
340 for (i = 0; i < n_il_offsets; ++i) {
341 MonoSymSeqPoint *sp = &sym_seq_points [i];
342 const char *srcfile = "";
343
344 if (source_files [i] != -1) {
345 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
346 srcfile = sinfo->source_file;
347 }
348
349 MonoProfilerCoverageData data = {
350 .method = method,
351 .il_offset = sp->il_offset,
352 .counter = 0,
353 .file_name = srcfile,
354 .line = sp->line,
355 .column = 0,
356 };
357
358 cb (handle->prof, &data);
359 }
360
361 g_free (source_files);
362 g_free (sym_seq_points);
363 g_ptr_array_free (source_file_list, TRUE);
364
365 mono_metadata_free_mh (header);
366 return TRUE;
367 }
368
369 for (guint32 i = 0; i < info->entries; i++) {
370 guchar *cil_code = info->data [i].cil_code;
371
372 if (cil_code && cil_code >= start && cil_code < end) {
373 guint32 offset = cil_code - start;
374
375 MonoProfilerCoverageData data = {
376 .method = method,
377 .il_offset = offset,
378 .counter = info->data [i].count,
379 .line = 1,
380 .column = 1,
381 };
382
383 if (minfo) {
384 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
385
386 if (loc) {
387 data.file_name = g_strdup (loc->source_file);
388 data.line = loc->row;
389 data.column = loc->column;
390
391 mono_debug_free_source_location (loc);
392 }
393 }
394
395 cb (handle->prof, &data);
396
397 g_free ((char *) data.file_name);
398 }
399 }
400
401 mono_metadata_free_mh (header);
402
403 return TRUE;
404 }
405
406 MonoProfilerCoverageInfo *
mono_profiler_coverage_alloc(MonoMethod * method,guint32 entries)407 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
408 {
409 if (!mono_profiler_state.code_coverage)
410 return FALSE;
411
412 if (method->wrapper_type)
413 return FALSE;
414
415 gboolean cover = FALSE;
416
417 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
418 MonoProfilerCoverageFilterCallback cb = handle->coverage_filter;
419
420 if (cb)
421 cover |= cb (handle->prof, method);
422 }
423
424 if (!cover)
425 return NULL;
426
427 coverage_lock ();
428
429 MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries);
430
431 info->entries = entries;
432
433 g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
434
435 coverage_unlock ();
436
437 return info;
438 }
439
440 /**
441 * mono_profiler_enable_sampling:
442 *
443 * Enables the sampling thread. Users must call this function if they intend
444 * to use statistical sampling; \c mono_profiler_set_sample_mode will have no
445 * effect if this function has not been called. The first profiler to call this
446 * function will get ownership over sampling settings (mode and frequency) so
447 * that no other profiler can change those settings. Returns \c TRUE if the
448 * sampling thread was enabled, or \c FALSE if the function was called too late
449 * for this to be possible.
450 *
451 * Note that \c mono_profiler_set_sample_mode must still be called with a mode
452 * other than \c MONO_PROFILER_SAMPLE_MODE_NONE to actually start sampling.
453 *
454 * This function is \b not async safe.
455 *
456 * This function may \b only be called from a profiler's init function or prior
457 * to running managed code.
458 */
459 mono_bool
mono_profiler_enable_sampling(MonoProfilerHandle handle)460 mono_profiler_enable_sampling (MonoProfilerHandle handle)
461 {
462 if (mono_profiler_state.startup_done)
463 return FALSE;
464
465 if (mono_profiler_state.sampling_owner)
466 return TRUE;
467
468 mono_profiler_state.sampling_owner = handle;
469 mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
470 mono_profiler_state.sample_freq = 100;
471 mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
472
473 return TRUE;
474 }
475
476 /**
477 * mono_profiler_set_sample_mode:
478 *
479 * Sets the sampling mode and frequency (in Hz). \p freq must be a positive
480 * number. If the calling profiler has ownership over sampling settings, the
481 * settings will be changed and this function will return \c TRUE; otherwise,
482 * it returns \c FALSE without changing any settings.
483 *
484 * This function is async safe.
485 */
486 mono_bool
mono_profiler_set_sample_mode(MonoProfilerHandle handle,MonoProfilerSampleMode mode,uint32_t freq)487 mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
488 {
489 if (handle != mono_profiler_state.sampling_owner)
490 return FALSE;
491
492 mono_profiler_state.sample_mode = mode;
493 mono_profiler_state.sample_freq = freq;
494
495 mono_profiler_sampling_thread_post ();
496
497 return TRUE;
498 }
499
500 /**
501 * mono_profiler_get_sample_mode:
502 *
503 * Retrieves the current sampling mode and/or frequency (in Hz). Returns
504 * \c TRUE if the calling profiler is allowed to change the sampling settings;
505 * otherwise, \c FALSE.
506 *
507 * This function is async safe.
508 */
509 mono_bool
mono_profiler_get_sample_mode(MonoProfilerHandle handle,MonoProfilerSampleMode * mode,uint32_t * freq)510 mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
511 {
512 if (mode)
513 *mode = mono_profiler_state.sample_mode;
514
515 if (freq)
516 *freq = mono_profiler_state.sample_freq;
517
518 return handle == mono_profiler_state.sampling_owner;
519 }
520
521 gboolean
mono_profiler_sampling_enabled(void)522 mono_profiler_sampling_enabled (void)
523 {
524 return !!mono_profiler_state.sampling_owner;
525 }
526
527 void
mono_profiler_sampling_thread_post(void)528 mono_profiler_sampling_thread_post (void)
529 {
530 mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
531 }
532
533 void
mono_profiler_sampling_thread_wait(void)534 mono_profiler_sampling_thread_wait (void)
535 {
536 mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
537 }
538
539 /**
540 * mono_profiler_enable_allocations:
541 *
542 * Enables instrumentation of GC allocations. This is necessary so that managed
543 * allocators can be instrumented with a call into the profiler API.
544 * Allocations will not be reported unless this function is called. Returns
545 * \c TRUE if allocation instrumentation was enabled, or \c FALSE if the
546 * function was called too late for this to be possible.
547 *
548 * This function is \b not async safe.
549 *
550 * This function may \b only be called from a profiler's init function or prior
551 * to running managed code.
552 */
553 mono_bool
mono_profiler_enable_allocations(void)554 mono_profiler_enable_allocations (void)
555 {
556 if (mono_profiler_state.startup_done)
557 return FALSE;
558
559 return mono_profiler_state.allocations = TRUE;
560 }
561
562 /**
563 * mono_profiler_set_call_instrumentation_filter_callback:
564 *
565 * Sets a call instrumentation filter function. The profiler API will invoke
566 * filter functions from all installed profilers. If any of them return flags
567 * other than \c MONO_PROFILER_CALL_INSTRUMENTATION_NONE, then the given method
568 * will be instrumented as requested. All filters are guaranteed to be called
569 * exactly once per method, even if earlier filters have already specified all
570 * flags.
571 *
572 * Note that filter functions must be installed before a method is compiled in
573 * order to have any effect, i.e. a filter should be registered in a profiler's
574 * init function or prior to running managed code (if embedding). Also, to
575 * instrument a method that's going to be AOT-compiled, a filter must be
576 * installed at AOT time. This can be done in exactly the same way as one would
577 * normally, i.e. by passing the \c --profile option on the command line, by
578 * calling \c mono_profiler_load, or simply by using the profiler API as an
579 * embedder.
580 *
581 * Indiscriminate method instrumentation is extremely heavy and will slow down
582 * most applications to a crawl. Users should consider sampling as a possible
583 * alternative to such heavy-handed instrumentation.
584 *
585 * This function is async safe.
586 */
587 void
mono_profiler_set_call_instrumentation_filter_callback(MonoProfilerHandle handle,MonoProfilerCallInstrumentationFilterCallback cb)588 mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
589 {
590 mono_atomic_store_ptr (&handle->call_instrumentation_filter, (gpointer) cb);
591 }
592
593 /**
594 * mono_profiler_enable_call_context_introspection:
595 *
596 * Enables support for retrieving stack frame data from a call context. At the
597 * moment, this means enabling the debug info subsystem. If this function is not
598 * called, it will not be possible to use the call context introspection
599 * functions (they will simply return \c NULL). Returns \c TRUE if call context
600 * introspection was enabled, or \c FALSE if the function was called too late for
601 * this to be possible.
602 *
603 * Please note: Mono's LLVM backend does not support this feature. This means
604 * that methods with call context instrumentation will be handled by Mono's
605 * JIT even in LLVM mode. There is also a special case when Mono is compiling
606 * in LLVM-only mode: Since LLVM does not provide a way to implement call
607 * contexts, a \c NULL context will always be passed to enter/leave events even
608 * though this method returns \c TRUE.
609 *
610 * This function is \b not async safe.
611 *
612 * This function may \b only be called from a profiler's init function or prior
613 * to running managed code.
614 */
615 mono_bool
mono_profiler_enable_call_context_introspection(void)616 mono_profiler_enable_call_context_introspection (void)
617 {
618 if (mono_profiler_state.startup_done)
619 return FALSE;
620
621 mono_profiler_state.context_enable ();
622
623 return mono_profiler_state.call_contexts = TRUE;
624 }
625
626 /**
627 * mono_profiler_call_context_get_this:
628 *
629 * Given a valid call context from an enter/leave event, retrieves a pointer to
630 * the \c this reference for the method. Returns \c NULL if none exists (i.e.
631 * it's a static method) or if call context introspection was not enabled.
632 *
633 * The buffer returned by this function must be freed with
634 * \c mono_profiler_call_context_free_buffer.
635 *
636 * Please note that a call context is only valid for the duration of the
637 * enter/leave callback it was passed to.
638 *
639 * This function is \b not async safe.
640 */
641 void *
mono_profiler_call_context_get_this(MonoProfilerCallContext * context)642 mono_profiler_call_context_get_this (MonoProfilerCallContext *context)
643 {
644 if (!mono_profiler_state.call_contexts)
645 return NULL;
646
647 return mono_profiler_state.context_get_this (context);
648 }
649
650 /**
651 * mono_profiler_call_context_get_argument:
652 *
653 * Given a valid call context from an enter/leave event, retrieves a pointer to
654 * the method argument at the given position. Returns \c NULL if \p position is
655 * out of bounds or if call context introspection was not enabled.
656 *
657 * The buffer returned by this function must be freed with
658 * \c mono_profiler_call_context_free_buffer.
659 *
660 * Please note that a call context is only valid for the duration of the
661 * enter/leave callback it was passed to.
662 *
663 * This function is \b not async safe.
664 */
665 void *
mono_profiler_call_context_get_argument(MonoProfilerCallContext * context,uint32_t position)666 mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position)
667 {
668 if (!mono_profiler_state.call_contexts)
669 return NULL;
670
671 return mono_profiler_state.context_get_argument (context, position);
672 }
673
674 /**
675 * mono_profiler_call_context_get_local:
676 *
677 * Given a valid call context from an enter/leave event, retrieves a pointer to
678 * the local variable at the given position. Returns \c NULL if \p position is
679 * out of bounds or if call context introspection was not enabled.
680 *
681 * The buffer returned by this function must be freed with
682 * \c mono_profiler_call_context_free_buffer.
683 *
684 * Please note that a call context is only valid for the duration of the
685 * enter/leave callback it was passed to.
686 *
687 * This function is \b not async safe.
688 */
689 void *
mono_profiler_call_context_get_local(MonoProfilerCallContext * context,uint32_t position)690 mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position)
691 {
692 if (!mono_profiler_state.call_contexts)
693 return NULL;
694
695 return mono_profiler_state.context_get_local (context, position);
696 }
697
698 /**
699 * mono_profiler_call_context_get_result:
700 *
701 * Given a valid call context from an enter/leave event, retrieves a pointer to
702 * return value of a method. Returns \c NULL if the method has no return value
703 * (i.e. it returns \c void), if the leave event was the result of a tail call,
704 * if the function is called on a context from an enter event, or if call
705 * context introspection was not enabled.
706 *
707 * The buffer returned by this function must be freed with
708 * \c mono_profiler_call_context_free_buffer.
709 *
710 * Please note that a call context is only valid for the duration of the
711 * enter/leave callback it was passed to.
712 *
713 * This function is \b not async safe.
714 */
715 void *
mono_profiler_call_context_get_result(MonoProfilerCallContext * context)716 mono_profiler_call_context_get_result (MonoProfilerCallContext *context)
717 {
718 if (!mono_profiler_state.call_contexts)
719 return NULL;
720
721 return mono_profiler_state.context_get_result (context);
722 }
723
724 /**
725 * mono_profiler_call_context_free_buffer:
726 *
727 * Frees a buffer returned by one of the call context introspection functions.
728 * Passing a \c NULL value for \p buffer is allowed, which makes this function
729 * a no-op.
730 *
731 * This function is \b not async safe.
732 */
733 void
mono_profiler_call_context_free_buffer(void * buffer)734 mono_profiler_call_context_free_buffer (void *buffer)
735 {
736 mono_profiler_state.context_free_buffer (buffer);
737 }
738
739 MonoProfilerCallInstrumentationFlags
mono_profiler_get_call_instrumentation_flags(MonoMethod * method)740 mono_profiler_get_call_instrumentation_flags (MonoMethod *method)
741 {
742 MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
743
744 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
745 MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter;
746
747 if (cb)
748 flags |= cb (handle->prof, method);
749 }
750
751 return flags;
752 }
753
754 void
mono_profiler_started(void)755 mono_profiler_started (void)
756 {
757 mono_profiler_state.startup_done = TRUE;
758 }
759
760 void
mono_profiler_cleanup(void)761 mono_profiler_cleanup (void)
762 {
763 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
764 #define _MONO_PROFILER_EVENT(name) \
765 mono_profiler_set_ ## name ## _callback (handle, NULL); \
766 g_assert (!handle->name ## _cb);
767 #define MONO_PROFILER_EVENT_0(name, type) \
768 _MONO_PROFILER_EVENT(name)
769 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
770 _MONO_PROFILER_EVENT(name)
771 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
772 _MONO_PROFILER_EVENT(name)
773 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
774 _MONO_PROFILER_EVENT(name)
775 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
776 _MONO_PROFILER_EVENT(name)
777 #include <mono/metadata/profiler-events.h>
778 #undef MONO_PROFILER_EVENT_0
779 #undef MONO_PROFILER_EVENT_1
780 #undef MONO_PROFILER_EVENT_2
781 #undef MONO_PROFILER_EVENT_3
782 #undef MONO_PROFILER_EVENT_4
783 #undef _MONO_PROFILER_EVENT
784 }
785
786 #define _MONO_PROFILER_EVENT(name, type) \
787 g_assert (!mono_profiler_state.name ## _count);
788 #define MONO_PROFILER_EVENT_0(name, type) \
789 _MONO_PROFILER_EVENT(name, type)
790 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
791 _MONO_PROFILER_EVENT(name, type)
792 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
793 _MONO_PROFILER_EVENT(name, type)
794 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
795 _MONO_PROFILER_EVENT(name, type)
796 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
797 _MONO_PROFILER_EVENT(name, type)
798 #include <mono/metadata/profiler-events.h>
799 #undef MONO_PROFILER_EVENT_0
800 #undef MONO_PROFILER_EVENT_1
801 #undef MONO_PROFILER_EVENT_2
802 #undef MONO_PROFILER_EVENT_3
803 #undef MONO_PROFILER_EVENT_4
804 #undef _MONO_PROFILER_EVENT
805
806 MonoProfilerHandle head = mono_profiler_state.profilers;
807
808 while (head) {
809 MonoProfilerCleanupCallback cb = head->cleanup_callback;
810
811 if (cb)
812 cb (head->prof);
813
814 MonoProfilerHandle cur = head;
815 head = head->next;
816
817 g_free (cur);
818 }
819
820 if (mono_profiler_state.code_coverage) {
821 mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex);
822
823 GHashTableIter iter;
824
825 g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash);
826
827 MonoProfilerCoverageInfo *info;
828
829 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
830 g_free (info);
831
832 g_hash_table_destroy (mono_profiler_state.coverage_hash);
833 }
834
835 if (mono_profiler_state.sampling_owner)
836 mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore);
837 }
838
839 static void
update_callback(volatile gpointer * location,gpointer new_,volatile gint32 * counter)840 update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
841 {
842 gpointer old;
843
844 do {
845 old = mono_atomic_load_ptr (location);
846 } while (mono_atomic_cas_ptr (location, new_, old) != old);
847
848 /*
849 * At this point, we could have installed a NULL callback while the counter
850 * is still non-zero, i.e. setting the callback and modifying the counter
851 * is not a single atomic operation. This is fine as we make sure callbacks
852 * are non-NULL before invoking them (see the code below that generates the
853 * raise functions), and besides, updating callbacks at runtime is an
854 * inherently racy operation.
855 */
856
857 if (old)
858 mono_atomic_dec_i32 (counter);
859
860 if (new_)
861 mono_atomic_inc_i32 (counter);
862 }
863
864 #define _MONO_PROFILER_EVENT(name, type) \
865 void \
866 mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
867 { \
868 update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
869 }
870 #define MONO_PROFILER_EVENT_0(name, type) \
871 _MONO_PROFILER_EVENT(name, type)
872 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
873 _MONO_PROFILER_EVENT(name, type)
874 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
875 _MONO_PROFILER_EVENT(name, type)
876 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
877 _MONO_PROFILER_EVENT(name, type)
878 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
879 _MONO_PROFILER_EVENT(name, type)
880 #include <mono/metadata/profiler-events.h>
881 #undef MONO_PROFILER_EVENT_0
882 #undef MONO_PROFILER_EVENT_1
883 #undef MONO_PROFILER_EVENT_2
884 #undef MONO_PROFILER_EVENT_3
885 #undef MONO_PROFILER_EVENT_4
886 #undef _MONO_PROFILER_EVENT
887
888 #define _MONO_PROFILER_EVENT(name, type, params, args) \
889 void \
890 mono_profiler_raise_ ## name params \
891 { \
892 for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
893 MonoProfiler ## type ## Callback cb = h->name ## _cb; \
894 if (cb) \
895 cb args; \
896 } \
897 }
898 #define MONO_PROFILER_EVENT_0(name, type) \
899 _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
900 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
901 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
902 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
903 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
904 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
905 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name))
906 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
907 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name))
908 #include <mono/metadata/profiler-events.h>
909 #undef MONO_PROFILER_EVENT_0
910 #undef MONO_PROFILER_EVENT_1
911 #undef MONO_PROFILER_EVENT_2
912 #undef MONO_PROFILER_EVENT_3
913 #undef MONO_PROFILER_EVENT_4
914 #undef _MONO_PROFILER_EVENT
915
916 /*
917 * The following code is here to maintain compatibility with a few profiler API
918 * functions used by Xamarin.{Android,iOS,Mac} so that they keep working
919 * regardless of which system Mono version is used.
920 *
921 * TODO: Remove this some day if we're OK with breaking compatibility.
922 */
923
924 typedef void *MonoLegacyProfiler;
925
926 typedef void (*MonoLegacyProfileFunc) (MonoLegacyProfiler *prof);
927 typedef void (*MonoLegacyProfileThreadFunc) (MonoLegacyProfiler *prof, uintptr_t tid);
928 typedef void (*MonoLegacyProfileGCFunc) (MonoLegacyProfiler *prof, MonoProfilerGCEvent event, int generation);
929 typedef void (*MonoLegacyProfileGCResizeFunc) (MonoLegacyProfiler *prof, int64_t new_size);
930 typedef void (*MonoLegacyProfileJitResult) (MonoLegacyProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
931 typedef void (*MonoLegacyProfileAllocFunc) (MonoLegacyProfiler *prof, MonoObject *obj, MonoClass *klass);
932 typedef void (*MonoLegacyProfileMethodFunc) (MonoLegacyProfiler *prof, MonoMethod *method);
933 typedef void (*MonoLegacyProfileExceptionFunc) (MonoLegacyProfiler *prof, MonoObject *object);
934 typedef void (*MonoLegacyProfileExceptionClauseFunc) (MonoLegacyProfiler *prof, MonoMethod *method, int clause_type, int clause_num);
935
936 struct _MonoProfiler {
937 MonoProfilerHandle handle;
938 MonoLegacyProfiler *profiler;
939 MonoLegacyProfileFunc shutdown_callback;
940 MonoLegacyProfileThreadFunc thread_start, thread_end;
941 MonoLegacyProfileGCFunc gc_event;
942 MonoLegacyProfileGCResizeFunc gc_heap_resize;
943 MonoLegacyProfileJitResult jit_end2;
944 MonoLegacyProfileAllocFunc allocation;
945 MonoLegacyProfileMethodFunc enter;
946 MonoLegacyProfileMethodFunc leave;
947 MonoLegacyProfileExceptionFunc throw_callback;
948 MonoLegacyProfileMethodFunc exc_method_leave;
949 MonoLegacyProfileExceptionClauseFunc clause_callback;
950 };
951
952 static MonoProfiler *current;
953
954 MONO_API void mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback);
955 MONO_API void mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end);
956 MONO_API void mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback);
957 MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end);
958 MONO_API void mono_profiler_set_events (int flags);
959 MONO_API void mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback);
960 MONO_API void mono_profiler_install_enter_leave (MonoLegacyProfileMethodFunc enter, MonoLegacyProfileMethodFunc fleave);
961 MONO_API void mono_profiler_install_exception (MonoLegacyProfileExceptionFunc throw_callback, MonoLegacyProfileMethodFunc exc_method_leave, MonoLegacyProfileExceptionClauseFunc clause_callback);
962
963 static void
shutdown_cb(MonoProfiler * prof)964 shutdown_cb (MonoProfiler *prof)
965 {
966 prof->shutdown_callback (prof->profiler);
967 }
968
969 void
mono_profiler_install(MonoLegacyProfiler * prof,MonoLegacyProfileFunc callback)970 mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback)
971 {
972 current = g_new0 (MonoProfiler, 1);
973 current->handle = mono_profiler_create (current);
974 current->profiler = prof;
975 current->shutdown_callback = callback;
976
977 if (callback)
978 mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb);
979 }
980
981 static void
thread_start_cb(MonoProfiler * prof,uintptr_t tid)982 thread_start_cb (MonoProfiler *prof, uintptr_t tid)
983 {
984 prof->thread_start (prof->profiler, tid);
985 }
986
987 static void
thread_stop_cb(MonoProfiler * prof,uintptr_t tid)988 thread_stop_cb (MonoProfiler *prof, uintptr_t tid)
989 {
990 prof->thread_end (prof->profiler, tid);
991 }
992
993 void
mono_profiler_install_thread(MonoLegacyProfileThreadFunc start,MonoLegacyProfileThreadFunc end)994 mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end)
995 {
996 current->thread_start = start;
997 current->thread_end = end;
998
999 if (start)
1000 mono_profiler_set_thread_started_callback (current->handle, thread_start_cb);
1001
1002 if (end)
1003 mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb);
1004 }
1005
1006 static void
gc_event_cb(MonoProfiler * prof,MonoProfilerGCEvent event,uint32_t generation)1007 gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation)
1008 {
1009 prof->gc_event (prof->profiler, event, generation);
1010 }
1011
1012 static void
gc_resize_cb(MonoProfiler * prof,uintptr_t size)1013 gc_resize_cb (MonoProfiler *prof, uintptr_t size)
1014 {
1015 prof->gc_heap_resize (prof->profiler, size);
1016 }
1017
1018 void
mono_profiler_install_gc(MonoLegacyProfileGCFunc callback,MonoLegacyProfileGCResizeFunc heap_resize_callback)1019 mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback)
1020 {
1021 current->gc_event = callback;
1022 current->gc_heap_resize = heap_resize_callback;
1023
1024 if (callback)
1025 mono_profiler_set_gc_event_callback (current->handle, gc_event_cb);
1026
1027 if (heap_resize_callback)
1028 mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb);
1029 }
1030
1031 static void
jit_done_cb(MonoProfiler * prof,MonoMethod * method,MonoJitInfo * jinfo)1032 jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
1033 {
1034 prof->jit_end2 (prof->profiler, method, jinfo, 0);
1035 }
1036
1037 static void
jit_failed_cb(MonoProfiler * prof,MonoMethod * method)1038 jit_failed_cb (MonoProfiler *prof, MonoMethod *method)
1039 {
1040 prof->jit_end2 (prof->profiler, method, NULL, 1);
1041 }
1042
1043 void
mono_profiler_install_jit_end(MonoLegacyProfileJitResult end)1044 mono_profiler_install_jit_end (MonoLegacyProfileJitResult end)
1045 {
1046 current->jit_end2 = end;
1047
1048 if (end) {
1049 mono_profiler_set_jit_done_callback (current->handle, jit_done_cb);
1050 mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb);
1051 }
1052 }
1053
1054 void
mono_profiler_set_events(int flags)1055 mono_profiler_set_events (int flags)
1056 {
1057 /* Do nothing. */
1058 }
1059
1060 static void
allocation_cb(MonoProfiler * prof,MonoObject * object)1061 allocation_cb (MonoProfiler *prof, MonoObject* object)
1062 {
1063 prof->allocation (prof->profiler, object, object->vtable->klass);
1064 }
1065
1066 void
mono_profiler_install_allocation(MonoLegacyProfileAllocFunc callback)1067 mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback)
1068 {
1069 current->allocation = callback;
1070
1071 if (callback)
1072 mono_profiler_set_gc_allocation_callback (current->handle, allocation_cb);
1073 }
1074
1075 static void
enter_cb(MonoProfiler * prof,MonoMethod * method,MonoProfilerCallContext * context)1076 enter_cb (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context)
1077 {
1078 prof->enter (prof->profiler, method);
1079 }
1080
1081 static void
leave_cb(MonoProfiler * prof,MonoMethod * method,MonoProfilerCallContext * context)1082 leave_cb (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context)
1083 {
1084 prof->leave (prof->profiler, method);
1085 }
1086
1087 static void
tail_call_cb(MonoProfiler * prof,MonoMethod * method,MonoMethod * target)1088 tail_call_cb (MonoProfiler *prof, MonoMethod *method, MonoMethod *target)
1089 {
1090 prof->leave (prof->profiler, method);
1091 }
1092
1093 void
mono_profiler_install_enter_leave(MonoLegacyProfileMethodFunc enter,MonoLegacyProfileMethodFunc fleave)1094 mono_profiler_install_enter_leave (MonoLegacyProfileMethodFunc enter, MonoLegacyProfileMethodFunc fleave)
1095 {
1096 current->enter = enter;
1097 current->leave = fleave;
1098
1099 if (enter)
1100 mono_profiler_set_method_enter_callback (current->handle, enter_cb);
1101
1102 if (fleave) {
1103 mono_profiler_set_method_leave_callback (current->handle, leave_cb);
1104 mono_profiler_set_method_tail_call_callback (current->handle, tail_call_cb);
1105 }
1106 }
1107
1108 static void
throw_callback_cb(MonoProfiler * prof,MonoObject * exception)1109 throw_callback_cb (MonoProfiler *prof, MonoObject *exception)
1110 {
1111 prof->throw_callback (prof->profiler, exception);
1112 }
1113
1114 static void
exc_method_leave_cb(MonoProfiler * prof,MonoMethod * method,MonoObject * exception)1115 exc_method_leave_cb (MonoProfiler *prof, MonoMethod *method, MonoObject *exception)
1116 {
1117 prof->exc_method_leave (prof->profiler, method);
1118 }
1119
1120 static void
clause_callback_cb(MonoProfiler * prof,MonoMethod * method,uint32_t index,MonoExceptionEnum type,MonoObject * exception)1121 clause_callback_cb (MonoProfiler *prof, MonoMethod *method, uint32_t index, MonoExceptionEnum type, MonoObject *exception)
1122 {
1123 prof->clause_callback (prof->profiler, method, type, index);
1124 }
1125
1126 void
mono_profiler_install_exception(MonoLegacyProfileExceptionFunc throw_callback,MonoLegacyProfileMethodFunc exc_method_leave,MonoLegacyProfileExceptionClauseFunc clause_callback)1127 mono_profiler_install_exception (MonoLegacyProfileExceptionFunc throw_callback, MonoLegacyProfileMethodFunc exc_method_leave, MonoLegacyProfileExceptionClauseFunc clause_callback)
1128 {
1129 current->throw_callback = throw_callback;
1130 current->exc_method_leave = exc_method_leave;
1131 current->clause_callback = clause_callback;
1132
1133 if (throw_callback)
1134 mono_profiler_set_exception_throw_callback (current->handle, throw_callback_cb);
1135
1136 if (exc_method_leave)
1137 mono_profiler_set_method_exception_leave_callback (current->handle, exc_method_leave_cb);
1138
1139 if (clause_callback)
1140 mono_profiler_set_exception_clause_callback (current->handle, clause_callback_cb);
1141 }
1142