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