3f17ced8a9b45c30a1b33d80d5252458f82eea52
[mono.git] / mono / profiler / proflog.c
1 /*
2  * proflog.c: mono log profiler
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Alex Rønne Petersen (alexrp@xamarin.com)
7  *
8  * Copyright 2010 Novell, Inc (http://www.novell.com)
9  * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12
13 #include <config.h>
14 #include "../mini/jit.h"
15 #include "../metadata/metadata-internals.h"
16 #include <mono/metadata/profiler.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/mono-gc.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/mono-perfcounters.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/metadata/assembly.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/tabledefs.h>
25 #include <mono/utils/atomic.h>
26 #include <mono/utils/mono-membar.h>
27 #include <mono/utils/mono-mmap.h>
28 #include <mono/utils/mono-counters.h>
29 #include <mono/utils/mono-os-mutex.h>
30 #include <mono/utils/mono-os-semaphore.h>
31 #include <mono/utils/mono-conc-hashtable.h>
32 #include <mono/utils/mono-linked-list-set.h>
33 #include <mono/utils/lock-free-alloc.h>
34 #include <mono/utils/lock-free-queue.h>
35 #include <mono/utils/hazard-pointer.h>
36 #include <mono/utils/mono-threads.h>
37 #include <mono/utils/mono-threads-api.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <assert.h>
41 #include <glib.h>
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #ifdef HAVE_SCHED_GETAFFINITY
46 #include <sched.h>
47 #endif
48 #include <fcntl.h>
49 #include <errno.h>
50 #if defined(HOST_WIN32) || defined(DISABLE_SOCKETS)
51 #define DISABLE_HELPER_THREAD 1
52 #endif
53
54 #ifndef _GNU_SOURCE
55 #define _GNU_SOURCE
56 #endif
57 #ifdef HAVE_DLFCN_H
58 #include <dlfcn.h>
59 #endif
60 #ifdef HAVE_EXECINFO_H
61 #include <execinfo.h>
62 #endif
63 #ifdef HAVE_LINK_H
64 #include <link.h>
65 #endif
66
67 #ifndef DISABLE_HELPER_THREAD
68 #include <sys/types.h>
69 #include <sys/socket.h>
70 #include <netinet/in.h>
71 #include <sys/select.h>
72 #endif
73
74 #ifdef HOST_WIN32
75 #include <windows.h>
76 #else
77 #include <pthread.h>
78 #endif
79
80 #ifdef HAVE_SYS_STAT_H
81 #include <sys/stat.h>
82 #endif
83
84 #include "utils.c"
85 #include "proflog.h"
86
87 #if defined (HAVE_SYS_ZLIB)
88 #include <zlib.h>
89 #endif
90
91 #if defined(__linux__)
92
93 #include <unistd.h>
94 #include <sys/syscall.h>
95
96 #ifdef ENABLE_PERF_EVENTS
97 #include <linux/perf_event.h>
98
99 #define USE_PERF_EVENTS 1
100
101 static int read_perf_mmap (MonoProfiler* prof, int cpu);
102 #endif
103
104 #endif
105
106 #define BUFFER_SIZE (4096 * 16)
107
108 /* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
109 #define LEB128_SIZE 10
110 /* Size of a value encoded as a single byte. */
111 #define BYTE_SIZE 1
112 /* Size in bytes of the event prefix (ID + time). */
113 #define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
114
115 static int nocalls = 0;
116 static int notraces = 0;
117 static int use_zip = 0;
118 static int do_report = 0;
119 static int do_heap_shot = 0;
120 static int max_call_depth = 100;
121 static volatile int runtime_inited = 0;
122 static int need_helper_thread = 0;
123 static int command_port = 0;
124 static int heapshot_requested = 0;
125 static int sample_type = 0;
126 static int sample_freq = 0;
127 static int do_mono_sample = 0;
128 static int in_shutdown = 0;
129 static int do_debug = 0;
130 static int do_counters = 0;
131 static int do_coverage = 0;
132 static gboolean debug_coverage = FALSE;
133 static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
134 static int max_allocated_sample_hits;
135
136 static gint32 sample_hits;
137 static gint32 sample_flushes;
138 static gint32 sample_allocations;
139 static gint32 buffer_allocations;
140 static gint32 thread_starts;
141 static gint32 thread_ends;
142 static gint32 domain_loads;
143 static gint32 domain_unloads;
144 static gint32 context_loads;
145 static gint32 context_unloads;
146 static gint32 assembly_loads;
147 static gint32 assembly_unloads;
148 static gint32 image_loads;
149 static gint32 image_unloads;
150 static gint32 class_loads;
151 static gint32 class_unloads;
152
153 static MonoLinkedListSet profiler_thread_list;
154
155 /*
156  * file format:
157  * [header] [buffer]*
158  *
159  * The file is composed by a header followed by 0 or more buffers.
160  * Each buffer contains events that happened on a thread: for a given thread
161  * buffers that appear later in the file are guaranteed to contain events
162  * that happened later in time. Buffers from separate threads could be interleaved,
163  * though.
164  * Buffers are not required to be aligned.
165  *
166  * header format:
167  * [id: 4 bytes] constant value: LOG_HEADER_ID
168  * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler
169  * [format: 1 byte] version of the data format for the rest of the file
170  * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program
171  * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started
172  * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer
173  * [flags: 4 bytes] file format flags, should be 0 for now
174  * [pid: 4 bytes] pid of the profiled process
175  * [port: 2 bytes] tcp port for server if != 0
176  * [sysid: 2 bytes] operating system and architecture identifier
177  *
178  * The multiple byte integers are in little-endian format.
179  *
180  * buffer format:
181  * [buffer header] [event]*
182  * Buffers have a fixed-size header followed by 0 or more bytes of event data.
183  * Timing information and other values in the event data are usually stored
184  * as uleb128 or sleb128 integers. To save space, as noted for each item below,
185  * some data is represented as a difference between the actual value and
186  * either the last value of the same type (like for timing information) or
187  * as the difference from a value stored in a buffer header.
188  *
189  * For timing information the data is stored as uleb128, since timing
190  * increases in a monotonic way in each thread: the value is the number of
191  * nanoseconds to add to the last seen timing data in a buffer. The first value
192  * in a buffer will be calculated from the time_base field in the buffer head.
193  *
194  * Object or heap sizes are stored as uleb128.
195  * Pointer differences are stored as sleb128, instead.
196  *
197  * If an unexpected value is found, the rest of the buffer should be ignored,
198  * as generally the later values need the former to be interpreted correctly.
199  *
200  * buffer header format:
201  * [bufid: 4 bytes] constant value: BUF_ID
202  * [len: 4 bytes] size of the data following the buffer header
203  * [time_base: 8 bytes] time base in nanoseconds since an unspecified epoch
204  * [ptr_base: 8 bytes] base value for pointers
205  * [obj_base: 8 bytes] base value for object addresses
206  * [thread id: 8 bytes] system-specific thread ID (pthread_t for example)
207  * [method_base: 8 bytes] base value for MonoMethod pointers
208  *
209  * event format:
210  * [extended info: upper 4 bits] [type: lower 4 bits] [data]*
211  * The data that follows depends on type and the extended info.
212  * Type is one of the enum values in proflog.h: TYPE_ALLOC, TYPE_GC,
213  * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
214  * The extended info bits are interpreted based on type, see
215  * each individual event description below.
216  * strings are represented as a 0-terminated utf8 sequence.
217  *
218  * backtrace format:
219  * [num: uleb128] number of frames following
220  * [frame: sleb128]* num MonoMethod pointers as differences from ptr_base
221  *
222  * type alloc format:
223  * type: TYPE_ALLOC
224  * exinfo: flags: TYPE_ALLOC_BT
225  * [time diff: uleb128] nanoseconds since last timing
226  * [ptr: sleb128] class as a byte difference from ptr_base
227  * [obj: sleb128] object address as a byte difference from obj_base
228  * [size: uleb128] size of the object in the heap
229  * If the TYPE_ALLOC_BT flag is set, a backtrace follows.
230  *
231  * type GC format:
232  * type: TYPE_GC
233  * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
234  * TYPE_GC_HANDLE_DESTROYED[_BT]
235  * [time diff: uleb128] nanoseconds since last timing
236  * if exinfo == TYPE_GC_RESIZE
237  *      [heap_size: uleb128] new heap size
238  * if exinfo == TYPE_GC_EVENT
239  *      [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
240  *      [generation: byte] GC generation event refers to
241  * if exinfo == TYPE_GC_MOVE
242  *      [num_objects: uleb128] number of object moves that follow
243  *      [objaddr: sleb128]+ num_objects object pointer differences from obj_base
244  *      num is always an even number: the even items are the old
245  *      addresses, the odd numbers are the respective new object addresses
246  * if exinfo == TYPE_GC_HANDLE_CREATED[_BT]
247  *      [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
248  *      upper bits reserved as flags
249  *      [handle: uleb128] GC handle value
250  *      [objaddr: sleb128] object pointer differences from obj_base
251  *      If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows.
252  * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT]
253  *      [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
254  *      upper bits reserved as flags
255  *      [handle: uleb128] GC handle value
256  *      If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
257  *
258  * type metadata format:
259  * type: TYPE_METADATA
260  * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN)
261  * [time diff: uleb128] nanoseconds since last timing
262  * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
263  * TYPE_THREAD, TYPE_CONTEXT
264  * [pointer: sleb128] pointer of the metadata type depending on mtype
265  * if mtype == TYPE_CLASS
266  *      [image: sleb128] MonoImage* as a pointer difference from ptr_base
267  *      [name: string] full class name
268  * if mtype == TYPE_IMAGE
269  *      [name: string] image file name
270  * if mtype == TYPE_ASSEMBLY
271  *      [name: string] assembly name
272  * if mtype == TYPE_DOMAIN && exinfo == 0
273  *      [name: string] domain friendly name
274  * if mtype == TYPE_CONTEXT
275  *      [domain: sleb128] domain id as pointer
276  * if mtype == TYPE_THREAD && exinfo == 0
277  *      [name: string] thread name
278  *
279  * type method format:
280  * type: TYPE_METHOD
281  * exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
282  * [time diff: uleb128] nanoseconds since last timing
283  * [method: sleb128] MonoMethod* as a pointer difference from the last such
284  * pointer or the buffer method_base
285  * if exinfo == TYPE_JIT
286  *      [code address: sleb128] pointer to the native code as a diff from ptr_base
287  *      [code size: uleb128] size of the generated code
288  *      [name: string] full method name
289  *
290  * type runtime format:
291  * type: TYPE_RUNTIME
292  * exinfo: one of: TYPE_JITHELPER
293  * [time diff: uleb128] nanoseconds since last timing
294  * if exinfo == TYPE_JITHELPER
295  *      [type: byte] MonoProfilerCodeBufferType enum value
296  *      [buffer address: sleb128] pointer to the native code as a diff from ptr_base
297  *      [buffer size: uleb128] size of the generated code
298  *      if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
299  *              [name: string] buffer description name
300  *
301  * type monitor format:
302  * type: TYPE_MONITOR
303  * exinfo: TYPE_MONITOR_BT flag and one of: MONO_PROFILER_MONITOR_(CONTENTION|FAIL|DONE)
304  * [time diff: uleb128] nanoseconds since last timing
305  * [object: sleb128] the lock object as a difference from obj_base
306  * if exinfo.low3bits == MONO_PROFILER_MONITOR_CONTENTION
307  *      If the TYPE_MONITOR_BT flag is set, a backtrace follows.
308  *
309  * type heap format
310  * type: TYPE_HEAP
311  * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
312  * if exinfo == TYPE_HEAP_START
313  *      [time diff: uleb128] nanoseconds since last timing
314  * if exinfo == TYPE_HEAP_END
315  *      [time diff: uleb128] nanoseconds since last timing
316  * if exinfo == TYPE_HEAP_OBJECT
317  *      [object: sleb128] the object as a difference from obj_base
318  *      [class: sleb128] the object MonoClass* as a difference from ptr_base
319  *      [size: uleb128] size of the object on the heap
320  *      [num_refs: uleb128] number of object references
321  *      each referenced objref is preceded by a uleb128 encoded offset: the
322  *      first offset is from the object address and each next offset is relative
323  *      to the previous one
324  *      [objrefs: sleb128]+ object referenced as a difference from obj_base
325  *      The same object can appear multiple times, but only the first time
326  *      with size != 0: in the other cases this data will only be used to
327  *      provide additional referenced objects.
328  * if exinfo == TYPE_HEAP_ROOT
329  *      [num_roots: uleb128] number of root references
330  *      [num_gc: uleb128] number of major gcs
331  *      [object: sleb128] the object as a difference from obj_base
332  *      [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
333  *      [extra_info: uleb128] the extra_info value
334  *      object, root_type and extra_info are repeated num_roots times
335  *
336  * type sample format
337  * type: TYPE_SAMPLE
338  * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
339  * if exinfo == TYPE_SAMPLE_HIT
340  *      [sample_type: byte] type of sample (SAMPLE_*)
341  *      [timestamp: uleb128] nanoseconds since startup (note: different from other timestamps!)
342  *      [thread: sleb128] thread id as difference from ptr_base
343  *      [count: uleb128] number of following instruction addresses
344  *      [ip: sleb128]* instruction pointer as difference from ptr_base
345  *      [mbt_count: uleb128] number of managed backtrace frames
346  *      [method: sleb128]* MonoMethod* as a pointer difference from the last such
347  *      pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
348  * if exinfo == TYPE_SAMPLE_USYM
349  *      [address: sleb128] symbol address as a difference from ptr_base
350  *      [size: uleb128] symbol size (may be 0 if unknown)
351  *      [name: string] symbol name
352  * if exinfo == TYPE_SAMPLE_UBIN
353  *      [time diff: uleb128] nanoseconds since last timing
354  *      [address: sleb128] address where binary has been loaded
355  *      [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
356  *      [size: uleb128] memory size
357  *      [name: string] binary name
358  * if exinfo == TYPE_SAMPLE_COUNTERS_DESC
359  *      [len: uleb128] number of counters
360  *      for i = 0 to len
361  *              [section: uleb128] section of counter
362  *              if section == MONO_COUNTER_PERFCOUNTERS:
363  *                      [section_name: string] section name of counter
364  *              [name: string] name of counter
365  *              [type: byte] type of counter
366  *              [unit: byte] unit of counter
367  *              [variance: byte] variance of counter
368  *              [index: uleb128] unique index of counter
369  * if exinfo == TYPE_SAMPLE_COUNTERS
370  *      [timestamp: uleb128] sampling timestamp
371  *      while true:
372  *              [index: uleb128] unique index of counter
373  *              if index == 0:
374  *                      break
375  *              [type: byte] type of counter value
376  *              if type == string:
377  *                      if value == null:
378  *                              [0: uleb128] 0 -> value is null
379  *                      else:
380  *                              [1: uleb128] 1 -> value is not null
381  *                              [value: string] counter value
382  *              else:
383  *                      [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type)
384  *
385  * type coverage format
386  * type: TYPE_COVERAGE
387  * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS
388  * if exinfo == TYPE_COVERAGE_METHOD
389  *  [assembly: string] name of assembly
390  *  [class: string] name of the class
391  *  [name: string] name of the method
392  *  [signature: string] the signature of the method
393  *  [filename: string] the file path of the file that contains this method
394  *  [token: uleb128] the method token
395  *  [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS
396  *  [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method
397  * if exinfo == TYPE_COVERAGE_STATEMENTS
398  *  [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with
399  *  [offset: uleb128] the il offset relative to the previous offset
400  *  [counter: uleb128] the counter for this instruction
401  *  [line: uleb128] the line of filename containing this instruction
402  *  [column: uleb128] the column containing this instruction
403  * if exinfo == TYPE_COVERAGE_ASSEMBLY
404  *  [name: string] assembly name
405  *  [guid: string] assembly GUID
406  *  [filename: string] assembly filename
407  *  [number_of_methods: uleb128] the number of methods in this assembly
408  *  [fully_covered: uleb128] the number of fully covered methods
409  *  [partially_covered: uleb128] the number of partially covered methods
410  *    currently partially_covered will always be 0, and fully_covered is the
411  *    number of methods that are fully and partially covered.
412  * if exinfo == TYPE_COVERAGE_CLASS
413  *  [name: string] assembly name
414  *  [class: string] class name
415  *  [number_of_methods: uleb128] the number of methods in this class
416  *  [fully_covered: uleb128] the number of fully covered methods
417  *  [partially_covered: uleb128] the number of partially covered methods
418  *    currently partially_covered will always be 0, and fully_covered is the
419  *    number of methods that are fully and partially covered.
420  *
421  * type meta format:
422  * type: TYPE_META
423  * exinfo: one of: TYPE_SYNC_POINT
424  * [time diff: uleb128] nanoseconds since last timing
425  * if exinfo == TYPE_SYNC_POINT
426  *      [type: byte] MonoProfilerSyncPointType enum value
427  */
428
429 // Pending data to be written to the log, for a single thread.
430 // Threads periodically flush their own LogBuffers by calling safe_send
431 typedef struct _LogBuffer LogBuffer;
432 struct _LogBuffer {
433         // Next (older) LogBuffer in processing queue
434         LogBuffer *next;
435
436         uint64_t time_base;
437         uint64_t last_time;
438         uintptr_t ptr_base;
439         uintptr_t method_base;
440         uintptr_t last_method;
441         uintptr_t obj_base;
442         uintptr_t thread_id;
443
444         // Bytes allocated for this LogBuffer
445         int size;
446
447         // Start of currently unused space in buffer
448         unsigned char* cursor;
449
450         // Pointer to start-of-structure-plus-size (for convenience)
451         unsigned char* buf_end;
452
453         // Start of data in buffer. Contents follow "buffer format" described above.
454         unsigned char buf [1];
455 };
456
457 typedef struct {
458         MonoLinkedListSetNode node;
459
460         // The current log buffer for this thread.
461         LogBuffer *buffer;
462
463         // Methods referenced by events in `buffer`, see `MethodInfo`.
464         GPtrArray *methods;
465
466         // Current call depth for enter/leave events.
467         int call_depth;
468
469         // Indicates whether this thread is currently writing to its `buffer`.
470         int busy;
471 } MonoProfilerThread;
472
473 static inline void
474 ign_res (int G_GNUC_UNUSED unused, ...)
475 {
476 }
477
478 /*
479  * These macros create a scope to avoid leaking the buffer returned
480  * from ensure_logbuf () as it may have been invalidated by a GC
481  * thread during STW. If you called init_thread () with add_to_lls =
482  * FALSE, then don't use these macros.
483  */
484
485 #define ENTER_LOG \
486         do { \
487                 buffer_lock (); \
488                 g_assert (!PROF_TLS_GET ()->busy++ && "Why are we trying to write a new event while already writing one?")
489
490 #define EXIT_LOG \
491                 PROF_TLS_GET ()->busy--; \
492                 buffer_unlock (); \
493         } while (0)
494
495 static volatile gint32 buffer_rwlock_count;
496 static volatile gpointer buffer_rwlock_exclusive;
497
498 // Can be used recursively.
499 static void
500 buffer_lock (void)
501 {
502         /*
503          * If the thread holding the exclusive lock tries to modify the
504          * reader count, just make it a no-op. This way, we also avoid
505          * invoking the GC safe point macros below, which could break if
506          * done from a thread that is currently the initiator of STW.
507          *
508          * In other words, we rely on the fact that the GC thread takes
509          * the exclusive lock in the gc_event () callback when the world
510          * is about to stop.
511          */
512         if (InterlockedReadPointer (&buffer_rwlock_exclusive) != (gpointer) thread_id ()) {
513                 MONO_ENTER_GC_SAFE;
514
515                 while (InterlockedReadPointer (&buffer_rwlock_exclusive))
516                         mono_thread_info_yield ();
517
518                 InterlockedIncrement (&buffer_rwlock_count);
519
520                 MONO_EXIT_GC_SAFE;
521         }
522
523         mono_memory_barrier ();
524 }
525
526 static void
527 buffer_unlock (void)
528 {
529         mono_memory_barrier ();
530
531         // See the comment in buffer_lock ().
532         if (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id ())
533                 return;
534
535         g_assert (InterlockedRead (&buffer_rwlock_count) && "Why are we trying to decrement a zero reader count?");
536
537         InterlockedDecrement (&buffer_rwlock_count);
538 }
539
540 // Cannot be used recursively.
541 static void
542 buffer_lock_excl (void)
543 {
544         gpointer tid = (gpointer) thread_id ();
545
546         g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) != tid && "Why are we taking the exclusive lock twice?");
547
548         MONO_ENTER_GC_SAFE;
549
550         while (InterlockedCompareExchangePointer (&buffer_rwlock_exclusive, tid, 0))
551                 mono_thread_info_yield ();
552
553         while (InterlockedRead (&buffer_rwlock_count))
554                 mono_thread_info_yield ();
555
556         MONO_EXIT_GC_SAFE;
557
558         mono_memory_barrier ();
559 }
560
561 static void
562 buffer_unlock_excl (void)
563 {
564         mono_memory_barrier ();
565
566         g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why is the exclusive lock not held?");
567         g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why does another thread hold the exclusive lock?");
568         g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why are there readers when the exclusive lock is held?");
569
570         InterlockedWritePointer (&buffer_rwlock_exclusive, NULL);
571 }
572
573 typedef struct _BinaryObject BinaryObject;
574 struct _BinaryObject {
575         BinaryObject *next;
576         void *addr;
577         char *name;
578 };
579
580 struct _MonoProfiler {
581         FILE* file;
582 #if defined (HAVE_SYS_ZLIB)
583         gzFile gzfile;
584 #endif
585         uint64_t startup_time;
586         int pipe_output;
587         int last_gc_gen_started;
588         int command_port;
589         int server_socket;
590         int pipes [2];
591 #ifndef HOST_WIN32
592         pthread_t helper_thread;
593         pthread_t writer_thread;
594         pthread_t dumper_thread;
595 #endif
596         volatile gint32 run_writer_thread;
597         MonoLockFreeAllocSizeClass writer_entry_size_class;
598         MonoLockFreeAllocator writer_entry_allocator;
599         MonoLockFreeQueue writer_queue;
600         MonoSemType writer_queue_sem;
601         MonoConcurrentHashTable *method_table;
602         mono_mutex_t method_table_mutex;
603         volatile gint32 run_dumper_thread;
604         MonoLockFreeQueue dumper_queue;
605         MonoSemType dumper_queue_sem;
606         MonoLockFreeAllocSizeClass sample_size_class;
607         MonoLockFreeAllocator sample_allocator;
608         MonoLockFreeQueue sample_reuse_queue;
609         BinaryObject *binary_objects;
610         GPtrArray *coverage_filters;
611 };
612
613 typedef struct {
614         MonoLockFreeQueueNode node;
615         GPtrArray *methods;
616         LogBuffer *buffer;
617 } WriterQueueEntry;
618
619 #define WRITER_ENTRY_BLOCK_SIZE (mono_pagesize ())
620
621 typedef struct {
622         MonoMethod *method;
623         MonoJitInfo *ji;
624         uint64_t time;
625 } MethodInfo;
626
627 #ifdef HOST_WIN32
628
629 #define PROF_TLS_SET(VAL) (TlsSetValue (profiler_tls, (VAL)))
630 #define PROF_TLS_GET() ((MonoProfilerThread *) TlsGetValue (profiler_tls))
631 #define PROF_TLS_INIT() (profiler_tls = TlsAlloc ())
632 #define PROF_TLS_FREE() (TlsFree (profiler_tls))
633
634 static DWORD profiler_tls;
635
636 #elif HAVE_KW_THREAD
637
638 #define PROF_TLS_SET(VAL) (profiler_tls = (VAL))
639 #define PROF_TLS_GET() (profiler_tls)
640 #define PROF_TLS_INIT()
641 #define PROF_TLS_FREE()
642
643 static __thread MonoProfilerThread *profiler_tls;
644
645 #else
646
647 #define PROF_TLS_SET(VAL) (pthread_setspecific (profiler_tls, (VAL)))
648 #define PROF_TLS_GET() ((MonoProfilerThread *) pthread_getspecific (profiler_tls))
649 #define PROF_TLS_INIT() (pthread_key_create (&profiler_tls, NULL))
650 #define PROF_TLS_FREE() (pthread_key_delete (&profiler_tls))
651
652 static pthread_key_t profiler_tls;
653
654 #endif
655
656 static char*
657 pstrdup (const char *s)
658 {
659         int len = strlen (s) + 1;
660         char *p = (char *)malloc (len);
661         memcpy (p, s, len);
662         return p;
663 }
664
665 static LogBuffer*
666 create_buffer (void)
667 {
668         LogBuffer* buf = (LogBuffer *)alloc_buffer (BUFFER_SIZE);
669
670         InterlockedIncrement (&buffer_allocations);
671
672         buf->size = BUFFER_SIZE;
673         buf->time_base = current_time ();
674         buf->last_time = buf->time_base;
675         buf->buf_end = (unsigned char*)buf + buf->size;
676         buf->cursor = buf->buf;
677         return buf;
678 }
679
680 static void
681 init_buffer_state (MonoProfilerThread *thread)
682 {
683         thread->buffer = create_buffer ();
684         thread->methods = NULL;
685 }
686
687 static void
688 clear_hazard_pointers (MonoThreadHazardPointers *hp)
689 {
690         mono_hazard_pointer_clear (hp, 0);
691         mono_hazard_pointer_clear (hp, 1);
692         mono_hazard_pointer_clear (hp, 2);
693 }
694
695 static MonoProfilerThread *
696 init_thread (gboolean add_to_lls)
697 {
698         MonoProfilerThread *thread = PROF_TLS_GET ();
699
700         /*
701          * Sometimes we may try to initialize a thread twice. One example is the
702          * main thread: We initialize it when setting up the profiler, but we will
703          * also get a thread_start () callback for it. Another example is when
704          * attaching new threads to the runtime: We may get a gc_alloc () callback
705          * for that thread's thread object (where we initialize it), soon followed
706          * by a thread_start () callback.
707          *
708          * These cases are harmless anyhow. Just return if we've already done the
709          * initialization work.
710          */
711         if (thread)
712                 return thread;
713
714         thread = malloc (sizeof (MonoProfilerThread));
715         thread->node.key = thread_id ();
716         thread->call_depth = 0;
717         thread->busy = 0;
718
719         init_buffer_state (thread);
720
721         /*
722          * Some internal profiler threads don't need to be cleaned up
723          * by the main thread on shutdown.
724          */
725         if (add_to_lls) {
726                 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
727                 g_assert (mono_lls_insert (&profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
728                 clear_hazard_pointers (hp);
729         }
730
731         PROF_TLS_SET (thread);
732
733         return thread;
734 }
735
736 // Only valid if init_thread () was called with add_to_lls = FALSE.
737 static void
738 deinit_thread (MonoProfilerThread *thread)
739 {
740         free (thread);
741         PROF_TLS_SET (NULL);
742 }
743
744 static LogBuffer *
745 ensure_logbuf_inner (LogBuffer *old, int bytes)
746 {
747         if (old && old->cursor + bytes + 100 < old->buf_end)
748                 return old;
749
750         LogBuffer *new_ = create_buffer ();
751         new_->next = old;
752
753         return new_;
754 }
755
756 // Only valid if init_thread () was called with add_to_lls = FALSE.
757 static LogBuffer *
758 ensure_logbuf_unsafe (int bytes)
759 {
760         MonoProfilerThread *thread = PROF_TLS_GET ();
761         LogBuffer *old = thread->buffer;
762         LogBuffer *new_ = ensure_logbuf_inner (old, bytes);
763
764         if (new_ == old)
765                 return old; // Still enough space.
766
767         thread->buffer = new_;
768
769         return new_;
770 }
771
772 /*
773  * Any calls to this function should be wrapped in the ENTER_LOG and
774  * EXIT_LOG macros to prevent the returned pointer from leaking
775  * outside of the critical region created by the calls to buffer_lock ()
776  * and buffer_unlock () that those macros insert. If the pointer leaks,
777  * it can and will lead to crashes as the GC or helper thread may
778  * invalidate the pointer at any time.
779  *
780  * Note: If you're calling from a thread that called init_thread () with
781  * add_to_lls = FALSE, you should use ensure_logbuf_unsafe () and omit
782  * the macros.
783  */
784 static LogBuffer*
785 ensure_logbuf (int bytes)
786 {
787         g_assert (PROF_TLS_GET ()->busy && "Why are we trying to expand our buffer without the busy flag set?");
788
789         return ensure_logbuf_unsafe (bytes);
790 }
791
792 static void
793 emit_byte (LogBuffer *logbuffer, int value)
794 {
795         logbuffer->cursor [0] = value;
796         logbuffer->cursor++;
797         assert (logbuffer->cursor <= logbuffer->buf_end);
798 }
799
800 static void
801 emit_value (LogBuffer *logbuffer, int value)
802 {
803         encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
804         assert (logbuffer->cursor <= logbuffer->buf_end);
805 }
806
807 static void
808 emit_time (LogBuffer *logbuffer, uint64_t value)
809 {
810         uint64_t tdiff = value - logbuffer->last_time;
811         //if (value < logbuffer->last_time)
812         //      printf ("time went backwards\n");
813         //if (tdiff > 1000000)
814         //      printf ("large time offset: %llu\n", tdiff);
815         encode_uleb128 (tdiff, logbuffer->cursor, &logbuffer->cursor);
816         /*if (tdiff != decode_uleb128 (p, &p))
817                 printf ("incorrect encoding: %llu\n", tdiff);*/
818         logbuffer->last_time = value;
819         assert (logbuffer->cursor <= logbuffer->buf_end);
820 }
821
822 static void
823 emit_event_time (LogBuffer *logbuffer, int event, uint64_t time)
824 {
825         emit_byte (logbuffer, event);
826         emit_time (logbuffer, time);
827 }
828
829 static void
830 emit_event (LogBuffer *logbuffer, int event)
831 {
832         emit_event_time (logbuffer, event, current_time ());
833 }
834
835 static void
836 emit_svalue (LogBuffer *logbuffer, int64_t value)
837 {
838         encode_sleb128 (value, logbuffer->cursor, &logbuffer->cursor);
839         assert (logbuffer->cursor <= logbuffer->buf_end);
840 }
841
842 static void
843 emit_uvalue (LogBuffer *logbuffer, uint64_t value)
844 {
845         encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
846         assert (logbuffer->cursor <= logbuffer->buf_end);
847 }
848
849 static void
850 emit_ptr (LogBuffer *logbuffer, void *ptr)
851 {
852         if (!logbuffer->ptr_base)
853                 logbuffer->ptr_base = (uintptr_t)ptr;
854         emit_svalue (logbuffer, (intptr_t)ptr - logbuffer->ptr_base);
855         assert (logbuffer->cursor <= logbuffer->buf_end);
856 }
857
858 static void
859 emit_method_inner (LogBuffer *logbuffer, void *method)
860 {
861         if (!logbuffer->method_base) {
862                 logbuffer->method_base = (intptr_t)method;
863                 logbuffer->last_method = (intptr_t)method;
864         }
865         encode_sleb128 ((intptr_t)((char*)method - (char*)logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor);
866         logbuffer->last_method = (intptr_t)method;
867         assert (logbuffer->cursor <= logbuffer->buf_end);
868 }
869
870 /*
871 typedef struct {
872         MonoMethod *method;
873         MonoJitInfo *found;
874 } MethodSearch;
875
876 static void
877 find_method (MonoDomain *domain, void *user_data)
878 {
879         MethodSearch *search = user_data;
880
881         if (search->found)
882                 return;
883
884         MonoJitInfo *ji = mono_get_jit_info_from_method (domain, search->method);
885
886         // It could be AOT'd, so we need to get it from the AOT runtime's cache.
887         if (!ji) {
888                 void *ip = mono_aot_get_method (domain, search->method);
889
890                 // Avoid a slow path in mono_jit_info_table_find ().
891                 if (ip)
892                         ji = mono_jit_info_table_find (domain, ip);
893         }
894
895         if (ji)
896                 search->found = ji;
897 }
898 */
899
900 static void
901 register_method_local (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji)
902 {
903         if (!mono_conc_hashtable_lookup (prof->method_table, method)) {
904                 /*
905                  * FIXME: In some cases, we crash while looking up JIT info for AOT'd methods.
906                  * This usually happens for static constructors. This code is disabled for now
907                  * as we don't need this info for anything critical.
908                  *
909                  * https://bugzilla.xamarin.com/show_bug.cgi?id=35171
910                  */
911                 /*
912                 if (!ji) {
913                         MethodSearch search = { method, NULL };
914
915                         mono_domain_foreach (find_method, &search);
916
917                         ji = search.found;
918                 }
919                 */
920
921                 /*
922                  * FIXME: We can't always find JIT info for a generic shared method, especially
923                  * if we obtained the MonoMethod during an async stack walk. For now, we deal
924                  * with this by giving the generic shared method name and dummy code start/size
925                  * information (i.e. zeroes).
926                  */
927                 //g_assert (ji);
928
929                 MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo));
930
931                 info->method = method;
932                 info->ji = ji;
933                 info->time = current_time ();
934
935                 MonoProfilerThread *thread = PROF_TLS_GET ();
936                 GPtrArray *arr = thread->methods ? thread->methods : (thread->methods = g_ptr_array_new ());
937                 g_ptr_array_add (arr, info);
938         }
939 }
940
941 static void
942 emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
943 {
944         register_method_local (prof, method, NULL);
945         emit_method_inner (logbuffer, method);
946 }
947
948 static void
949 emit_obj (LogBuffer *logbuffer, void *ptr)
950 {
951         if (!logbuffer->obj_base)
952                 logbuffer->obj_base = (uintptr_t)ptr >> 3;
953         emit_svalue (logbuffer, ((uintptr_t)ptr >> 3) - logbuffer->obj_base);
954         assert (logbuffer->cursor <= logbuffer->buf_end);
955 }
956
957 static void
958 emit_string (LogBuffer *logbuffer, const char *str, size_t size)
959 {
960         size_t i = 0;
961         if (str) {
962                 for (; i < size; i++) {
963                         if (str[i] == '\0')
964                                 break;
965                         emit_byte (logbuffer, str [i]);
966                 }
967         }
968         emit_byte (logbuffer, '\0');
969 }
970
971 static void
972 emit_double (LogBuffer *logbuffer, double value)
973 {
974         int i;
975         unsigned char buffer[8];
976         memcpy (buffer, &value, 8);
977 #if G_BYTE_ORDER == G_BIG_ENDIAN
978         for (i = 7; i >= 0; i--)
979 #else
980         for (i = 0; i < 8; i++)
981 #endif
982                 emit_byte (logbuffer, buffer[i]);
983 }
984
985 static char*
986 write_int16 (char *buf, int32_t value)
987 {
988         int i;
989         for (i = 0; i < 2; ++i) {
990                 buf [i] = value;
991                 value >>= 8;
992         }
993         return buf + 2;
994 }
995
996 static char*
997 write_int32 (char *buf, int32_t value)
998 {
999         int i;
1000         for (i = 0; i < 4; ++i) {
1001                 buf [i] = value;
1002                 value >>= 8;
1003         }
1004         return buf + 4;
1005 }
1006
1007 static char*
1008 write_int64 (char *buf, int64_t value)
1009 {
1010         int i;
1011         for (i = 0; i < 8; ++i) {
1012                 buf [i] = value;
1013                 value >>= 8;
1014         }
1015         return buf + 8;
1016 }
1017
1018 static void
1019 dump_header (MonoProfiler *profiler)
1020 {
1021         char hbuf [128];
1022         char *p = hbuf;
1023         p = write_int32 (p, LOG_HEADER_ID);
1024         *p++ = LOG_VERSION_MAJOR;
1025         *p++ = LOG_VERSION_MINOR;
1026         *p++ = LOG_DATA_VERSION;
1027         *p++ = sizeof (void*);
1028         p = write_int64 (p, ((uint64_t)time (NULL)) * 1000); /* startup time */
1029         p = write_int32 (p, get_timer_overhead ()); /* timer overhead */
1030         p = write_int32 (p, 0); /* flags */
1031         p = write_int32 (p, process_id ()); /* pid */
1032         p = write_int16 (p, profiler->command_port); /* port */
1033         p = write_int16 (p, 0); /* opsystem */
1034 #if defined (HAVE_SYS_ZLIB)
1035         if (profiler->gzfile) {
1036                 gzwrite (profiler->gzfile, hbuf, p - hbuf);
1037         } else {
1038                 fwrite (hbuf, p - hbuf, 1, profiler->file);
1039         }
1040 #else
1041         fwrite (hbuf, p - hbuf, 1, profiler->file);
1042         fflush (profiler->file);
1043 #endif
1044 }
1045
1046 static void
1047 send_buffer (MonoProfiler *prof, MonoProfilerThread *thread)
1048 {
1049         WriterQueueEntry *entry = mono_lock_free_alloc (&prof->writer_entry_allocator);
1050         entry->methods = thread->methods;
1051         entry->buffer = thread->buffer;
1052
1053         mono_lock_free_queue_node_init (&entry->node, FALSE);
1054
1055         mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
1056         mono_os_sem_post (&prof->writer_queue_sem);
1057 }
1058
1059 static void
1060 remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_callback)
1061 {
1062         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
1063
1064         if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) {
1065                 LogBuffer *buffer = thread->buffer;
1066
1067                 /*
1068                  * No need to take the buffer lock here as no other threads can
1069                  * be accessing this buffer anymore.
1070                  */
1071
1072                 if (!from_callback) {
1073                         /*
1074                          * The thread is being cleaned up by the main thread during
1075                          * shutdown. This typically happens for internal runtime
1076                          * threads. We need to synthesize a thread end event.
1077                          */
1078
1079                         buffer = ensure_logbuf_inner (buffer,
1080                                 EVENT_SIZE /* event */ +
1081                                 BYTE_SIZE /* type */ +
1082                                 LEB128_SIZE /* tid */
1083                         );
1084
1085                         emit_event (buffer, TYPE_END_UNLOAD | TYPE_METADATA);
1086                         emit_byte (buffer, TYPE_THREAD);
1087                         emit_ptr (buffer, (void *) thread->node.key);
1088                 }
1089
1090                 send_buffer (prof, thread);
1091
1092                 mono_thread_hazardous_try_free (thread, free);
1093         }
1094
1095         clear_hazard_pointers (hp);
1096
1097         if (from_callback)
1098                 PROF_TLS_SET (NULL);
1099 }
1100
1101 static void
1102 dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
1103 {
1104         char hbuf [128];
1105         char *p = hbuf;
1106         if (buf->next)
1107                 dump_buffer (profiler, buf->next);
1108         p = write_int32 (p, BUF_ID);
1109         p = write_int32 (p, buf->cursor - buf->buf);
1110         p = write_int64 (p, buf->time_base);
1111         p = write_int64 (p, buf->ptr_base);
1112         p = write_int64 (p, buf->obj_base);
1113         p = write_int64 (p, buf->thread_id);
1114         p = write_int64 (p, buf->method_base);
1115 #if defined (HAVE_SYS_ZLIB)
1116         if (profiler->gzfile) {
1117                 gzwrite (profiler->gzfile, hbuf, p - hbuf);
1118                 gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
1119         } else {
1120 #endif
1121                 fwrite (hbuf, p - hbuf, 1, profiler->file);
1122                 fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
1123                 fflush (profiler->file);
1124 #if defined (HAVE_SYS_ZLIB)
1125         }
1126 #endif
1127         free_buffer (buf, buf->size);
1128 }
1129
1130 static void
1131 dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf)
1132 {
1133         for (LogBuffer *iter = buf; iter; iter = iter->next)
1134                 iter->thread_id = 0;
1135
1136         dump_buffer (profiler, buf);
1137 }
1138
1139 static void
1140 process_requests (MonoProfiler *profiler)
1141 {
1142         if (heapshot_requested)
1143                 mono_gc_collect (mono_gc_max_generation ());
1144 }
1145
1146 static void counters_init (MonoProfiler *profiler);
1147 static void counters_sample (MonoProfiler *profiler, uint64_t timestamp);
1148
1149 static void
1150 safe_send (MonoProfiler *profiler)
1151 {
1152         /* We need the runtime initialized so that we have threads and hazard
1153          * pointers available. Otherwise, the lock free queue will not work and
1154          * there won't be a thread to process the data.
1155          *
1156          * While the runtime isn't initialized, we just accumulate data in the
1157          * thread local buffer list.
1158          */
1159         if (!InterlockedRead (&runtime_inited))
1160                 return;
1161
1162         MonoProfilerThread *thread = PROF_TLS_GET ();
1163
1164         buffer_lock ();
1165
1166         send_buffer (profiler, thread);
1167         init_buffer_state (thread);
1168
1169         buffer_unlock ();
1170 }
1171
1172 static void
1173 send_if_needed (MonoProfiler *prof)
1174 {
1175         if (PROF_TLS_GET ()->buffer->next)
1176                 safe_send (prof);
1177 }
1178
1179 static void
1180 safe_send_threadless (MonoProfiler *prof)
1181 {
1182         LogBuffer *buf = PROF_TLS_GET ()->buffer;
1183
1184         for (LogBuffer *iter = buf; iter; iter = iter->next)
1185                 iter->thread_id = 0;
1186
1187         safe_send (prof);
1188 }
1189
1190 static void
1191 send_if_needed_threadless (MonoProfiler *prof)
1192 {
1193         if (PROF_TLS_GET ()->buffer->next)
1194                 safe_send_threadless (prof);
1195 }
1196
1197 // Assumes that the exclusive lock is held.
1198 static void
1199 sync_point_flush (MonoProfiler *prof)
1200 {
1201         g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
1202
1203         MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
1204                 send_buffer (prof, thread);
1205                 init_buffer_state (thread);
1206         } MONO_LLS_FOREACH_SAFE_END
1207 }
1208
1209 // Assumes that the exclusive lock is held.
1210 static void
1211 sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type)
1212 {
1213         g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
1214
1215         ENTER_LOG;
1216
1217         LogBuffer *logbuffer = ensure_logbuf (
1218                 EVENT_SIZE /* event */ +
1219                 LEB128_SIZE /* type */
1220         );
1221
1222         emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
1223         emit_byte (logbuffer, type);
1224
1225         EXIT_LOG;
1226
1227         switch (type) {
1228         case SYNC_POINT_PERIODIC:
1229                 safe_send_threadless (prof);
1230                 break;
1231         case SYNC_POINT_WORLD_STOP:
1232         case SYNC_POINT_WORLD_START:
1233                 safe_send (prof);
1234                 break;
1235         default:
1236                 g_assert_not_reached ();
1237                 break;
1238         }
1239 }
1240
1241 // Assumes that the exclusive lock is held.
1242 static void
1243 sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type)
1244 {
1245         sync_point_flush (prof);
1246         sync_point_mark (prof, type);
1247 }
1248
1249 static int
1250 gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data)
1251 {
1252         /* account for object alignment in the heap */
1253         size += 7;
1254         size &= ~7;
1255
1256         ENTER_LOG;
1257
1258         LogBuffer *logbuffer = ensure_logbuf (
1259                 EVENT_SIZE /* event */ +
1260                 LEB128_SIZE /* obj */ +
1261                 LEB128_SIZE /* klass */ +
1262                 LEB128_SIZE /* size */ +
1263                 LEB128_SIZE /* num */ +
1264                 num * (
1265                         LEB128_SIZE /* offset */ +
1266                         LEB128_SIZE /* ref */
1267                 )
1268         );
1269
1270         emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
1271         emit_obj (logbuffer, obj);
1272         emit_ptr (logbuffer, klass);
1273         emit_value (logbuffer, size);
1274         emit_value (logbuffer, num);
1275
1276         uintptr_t last_offset = 0;
1277
1278         for (int i = 0; i < num; ++i) {
1279                 emit_value (logbuffer, offsets [i] - last_offset);
1280                 last_offset = offsets [i];
1281                 emit_obj (logbuffer, refs [i]);
1282         }
1283
1284         EXIT_LOG;
1285
1286         return 0;
1287 }
1288
1289 static unsigned int hs_mode_ms = 0;
1290 static unsigned int hs_mode_gc = 0;
1291 static unsigned int hs_mode_ondemand = 0;
1292 static unsigned int gc_count = 0;
1293 static uint64_t last_hs_time = 0;
1294
1295 static void
1296 heap_walk (MonoProfiler *profiler)
1297 {
1298         if (!do_heap_shot)
1299                 return;
1300
1301         gboolean do_walk = 0;
1302         uint64_t now = current_time ();
1303
1304         if (hs_mode_ms && (now - last_hs_time) / 1000000 >= hs_mode_ms)
1305                 do_walk = TRUE;
1306         else if (hs_mode_gc && (gc_count % hs_mode_gc) == 0)
1307                 do_walk = TRUE;
1308         else if (hs_mode_ondemand)
1309                 do_walk = heapshot_requested;
1310         else if (!hs_mode_ms && !hs_mode_gc && profiler->last_gc_gen_started == mono_gc_max_generation ())
1311                 do_walk = TRUE;
1312
1313         if (!do_walk)
1314                 return;
1315
1316         heapshot_requested = 0;
1317
1318         ENTER_LOG;
1319
1320         LogBuffer *logbuffer = ensure_logbuf (
1321                 EVENT_SIZE /* event */
1322         );
1323
1324         emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
1325
1326         EXIT_LOG;
1327
1328         mono_gc_walk_heap (0, gc_reference, NULL);
1329
1330         ENTER_LOG;
1331
1332         LogBuffer *logbuffer = ensure_logbuf (
1333                 EVENT_SIZE /* event */
1334         );
1335
1336         now = current_time ();
1337
1338         emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
1339
1340         EXIT_LOG;
1341
1342         last_hs_time = now;
1343 }
1344
1345 static void
1346 gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation)
1347 {
1348         ENTER_LOG;
1349
1350         LogBuffer *logbuffer = ensure_logbuf (
1351                 EVENT_SIZE /* event */ +
1352                 BYTE_SIZE /* gc event */ +
1353                 BYTE_SIZE /* generation */
1354         );
1355
1356         emit_event (logbuffer, TYPE_GC_EVENT | TYPE_GC);
1357         emit_byte (logbuffer, ev);
1358         emit_byte (logbuffer, generation);
1359
1360         EXIT_LOG;
1361
1362         switch (ev) {
1363         case MONO_GC_EVENT_START:
1364                 /* to deal with nested gen1 after gen0 started */
1365                 profiler->last_gc_gen_started = generation;
1366
1367                 if (generation == mono_gc_max_generation ())
1368                         gc_count++;
1369                 break;
1370         case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
1371                 /*
1372                  * Ensure that no thread can be in the middle of writing to
1373                  * a buffer when the world stops...
1374                  */
1375                 buffer_lock_excl ();
1376                 break;
1377         case MONO_GC_EVENT_POST_STOP_WORLD:
1378                 /*
1379                  * ... So that we now have a consistent view of all buffers.
1380                  * This allows us to flush them. We need to do this because
1381                  * they may contain object allocation events that need to be
1382                  * committed to the log file before any object move events
1383                  * that will be produced during this GC.
1384                  */
1385                 sync_point (profiler, SYNC_POINT_WORLD_STOP);
1386                 break;
1387         case MONO_GC_EVENT_PRE_START_WORLD:
1388                 heap_walk (profiler);
1389                 break;
1390         case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
1391                 /*
1392                  * Similarly, we must now make sure that any object moves
1393                  * written to the GC thread's buffer are flushed. Otherwise,
1394                  * object allocation events for certain addresses could come
1395                  * after the move events that made those addresses available.
1396                  */
1397                 sync_point_mark (profiler, SYNC_POINT_WORLD_START);
1398
1399                 /*
1400                  * Finally, it is safe to allow other threads to write to
1401                  * their buffers again.
1402                  */
1403                 buffer_unlock_excl ();
1404                 break;
1405         default:
1406                 break;
1407         }
1408 }
1409
1410 static void
1411 gc_resize (MonoProfiler *profiler, int64_t new_size)
1412 {
1413         ENTER_LOG;
1414
1415         LogBuffer *logbuffer = ensure_logbuf (
1416                 EVENT_SIZE /* event */ +
1417                 LEB128_SIZE /* new size */
1418         );
1419
1420         emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
1421         emit_value (logbuffer, new_size);
1422
1423         EXIT_LOG;
1424 }
1425
1426 // If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
1427 #define MAX_FRAMES 32
1428
1429 typedef struct {
1430         int count;
1431         MonoMethod* methods [MAX_FRAMES];
1432         int32_t il_offsets [MAX_FRAMES];
1433         int32_t native_offsets [MAX_FRAMES];
1434 } FrameData;
1435
1436 static int num_frames = MAX_FRAMES;
1437
1438 static mono_bool
1439 walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_bool managed, void* data)
1440 {
1441         FrameData *frame = (FrameData *)data;
1442         if (method && frame->count < num_frames) {
1443                 frame->il_offsets [frame->count] = il_offset;
1444                 frame->native_offsets [frame->count] = native_offset;
1445                 frame->methods [frame->count++] = method;
1446                 //printf ("In %d %s at %d (native: %d)\n", frame->count, mono_method_get_name (method), il_offset, native_offset);
1447         }
1448         return frame->count == num_frames;
1449 }
1450
1451 /*
1452  * a note about stack walks: they can cause more profiler events to fire,
1453  * so we need to make sure they don't happen after we started emitting an
1454  * event, hence the collect_bt/emit_bt split.
1455  */
1456 static void
1457 collect_bt (FrameData *data)
1458 {
1459         data->count = 0;
1460         mono_stack_walk_no_il (walk_stack, data);
1461 }
1462
1463 static void
1464 emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
1465 {
1466         /* FIXME: this is actually tons of data and we should
1467          * just output it the first time and use an id the next
1468          */
1469         if (data->count > num_frames)
1470                 printf ("bad num frames: %d\n", data->count);
1471         emit_value (logbuffer, data->count);
1472         //if (*p != data.count) {
1473         //      printf ("bad num frames enc at %d: %d -> %d\n", count, data.count, *p); printf ("frames end: %p->%p\n", p, logbuffer->cursor); exit(0);}
1474         while (data->count) {
1475                 emit_method (prof, logbuffer, data->methods [--data->count]);
1476         }
1477 }
1478
1479 static void
1480 gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
1481 {
1482         init_thread (TRUE);
1483
1484         int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
1485         FrameData data;
1486         uintptr_t len = mono_object_get_size (obj);
1487         /* account for object alignment in the heap */
1488         len += 7;
1489         len &= ~7;
1490
1491         if (do_bt)
1492                 collect_bt (&data);
1493
1494         ENTER_LOG;
1495
1496         LogBuffer *logbuffer = ensure_logbuf (
1497                 EVENT_SIZE /* event */ +
1498                 LEB128_SIZE /* klass */ +
1499                 LEB128_SIZE /* obj */ +
1500                 LEB128_SIZE /* size */ +
1501                 (do_bt ? (
1502                         LEB128_SIZE /* count */ +
1503                         data.count * (
1504                                 LEB128_SIZE /* method */
1505                         )
1506                 ) : 0)
1507         );
1508
1509         emit_event (logbuffer, do_bt | TYPE_ALLOC);
1510         emit_ptr (logbuffer, klass);
1511         emit_obj (logbuffer, obj);
1512         emit_value (logbuffer, len);
1513
1514         if (do_bt)
1515                 emit_bt (prof, logbuffer, &data);
1516
1517         EXIT_LOG;
1518
1519         send_if_needed (prof);
1520
1521         process_requests (prof);
1522 }
1523
1524 static void
1525 gc_moves (MonoProfiler *prof, void **objects, int num)
1526 {
1527         ENTER_LOG;
1528
1529         LogBuffer *logbuffer = ensure_logbuf (
1530                 EVENT_SIZE /* event */ +
1531                 LEB128_SIZE /* num */ +
1532                 num * (
1533                         LEB128_SIZE /* object */
1534                 )
1535         );
1536
1537         emit_event (logbuffer, TYPE_GC_MOVE | TYPE_GC);
1538         emit_value (logbuffer, num);
1539
1540         for (int i = 0; i < num; ++i)
1541                 emit_obj (logbuffer, objects [i]);
1542
1543         EXIT_LOG;
1544 }
1545
1546 static void
1547 gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info)
1548 {
1549         ENTER_LOG;
1550
1551         LogBuffer *logbuffer = ensure_logbuf (
1552                 EVENT_SIZE /* event */ +
1553                 LEB128_SIZE /* num */ +
1554                 LEB128_SIZE /* collections */ +
1555                 num * (
1556                         LEB128_SIZE /* object */ +
1557                         LEB128_SIZE /* root type */ +
1558                         LEB128_SIZE /* extra info */
1559                 )
1560         );
1561
1562         emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
1563         emit_value (logbuffer, num);
1564         emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ()));
1565
1566         for (int i = 0; i < num; ++i) {
1567                 emit_obj (logbuffer, objects [i]);
1568                 emit_byte (logbuffer, root_types [i]);
1569                 emit_value (logbuffer, extra_info [i]);
1570         }
1571
1572         EXIT_LOG;
1573 }
1574
1575 static void
1576 gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj)
1577 {
1578         int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces;
1579         FrameData data;
1580
1581         if (do_bt)
1582                 collect_bt (&data);
1583
1584         ENTER_LOG;
1585
1586         LogBuffer *logbuffer = ensure_logbuf (
1587                 EVENT_SIZE /* event */ +
1588                 LEB128_SIZE /* type */ +
1589                 LEB128_SIZE /* handle */ +
1590                 (op == MONO_PROFILER_GC_HANDLE_CREATED ? (
1591                         LEB128_SIZE /* obj */
1592                 ) : 0) +
1593                 (do_bt ? (
1594                         LEB128_SIZE /* count */ +
1595                         data.count * (
1596                                 LEB128_SIZE /* method */
1597                         )
1598                 ) : 0)
1599         );
1600
1601         if (op == MONO_PROFILER_GC_HANDLE_CREATED)
1602                 emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
1603         else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED)
1604                 emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
1605         else
1606                 g_assert_not_reached ();
1607
1608         emit_value (logbuffer, type);
1609         emit_value (logbuffer, handle);
1610
1611         if (op == MONO_PROFILER_GC_HANDLE_CREATED)
1612                 emit_obj (logbuffer, obj);
1613
1614         if (do_bt)
1615                 emit_bt (prof, logbuffer, &data);
1616
1617         EXIT_LOG;
1618
1619         process_requests (prof);
1620 }
1621
1622 static char*
1623 push_nesting (char *p, MonoClass *klass)
1624 {
1625         MonoClass *nesting;
1626         const char *name;
1627         const char *nspace;
1628         nesting = mono_class_get_nesting_type (klass);
1629         if (nesting) {
1630                 p = push_nesting (p, nesting);
1631                 *p++ = '/';
1632                 *p = 0;
1633         }
1634         name = mono_class_get_name (klass);
1635         nspace = mono_class_get_namespace (klass);
1636         if (*nspace) {
1637                 strcpy (p, nspace);
1638                 p += strlen (nspace);
1639                 *p++ = '.';
1640                 *p = 0;
1641         }
1642         strcpy (p, name);
1643         p += strlen (name);
1644         return p;
1645 }
1646
1647 static char*
1648 type_name (MonoClass *klass)
1649 {
1650         char buf [1024];
1651         char *p;
1652         push_nesting (buf, klass);
1653         p = (char *)malloc (strlen (buf) + 1);
1654         strcpy (p, buf);
1655         return p;
1656 }
1657
1658 static void
1659 image_loaded (MonoProfiler *prof, MonoImage *image, int result)
1660 {
1661         if (result != MONO_PROFILE_OK)
1662                 return;
1663
1664         const char *name = mono_image_get_filename (image);
1665         int nlen = strlen (name) + 1;
1666
1667         ENTER_LOG;
1668
1669         LogBuffer *logbuffer = ensure_logbuf (
1670                 EVENT_SIZE /* event */ +
1671                 BYTE_SIZE /* type */ +
1672                 LEB128_SIZE /* image */ +
1673                 nlen /* name */
1674         );
1675
1676         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
1677         emit_byte (logbuffer, TYPE_IMAGE);
1678         emit_ptr (logbuffer, image);
1679         memcpy (logbuffer->cursor, name, nlen);
1680         logbuffer->cursor += nlen;
1681
1682         EXIT_LOG;
1683
1684         send_if_needed (prof);
1685
1686         process_requests (prof);
1687
1688         InterlockedIncrement (&image_loads);
1689 }
1690
1691 static void
1692 image_unloaded (MonoProfiler *prof, MonoImage *image)
1693 {
1694         const char *name = mono_image_get_filename (image);
1695         int nlen = strlen (name) + 1;
1696
1697         ENTER_LOG;
1698
1699         LogBuffer *logbuffer = ensure_logbuf (
1700                 EVENT_SIZE /* event */ +
1701                 BYTE_SIZE /* type */ +
1702                 LEB128_SIZE /* image */ +
1703                 nlen /* name */
1704         );
1705
1706         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
1707         emit_byte (logbuffer, TYPE_IMAGE);
1708         emit_ptr (logbuffer, image);
1709         memcpy (logbuffer->cursor, name, nlen);
1710         logbuffer->cursor += nlen;
1711
1712         EXIT_LOG;
1713
1714         send_if_needed (prof);
1715
1716         process_requests (prof);
1717
1718         InterlockedIncrement (&image_unloads);
1719 }
1720
1721 static void
1722 assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result)
1723 {
1724         if (result != MONO_PROFILE_OK)
1725                 return;
1726
1727         char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
1728         int nlen = strlen (name) + 1;
1729
1730         ENTER_LOG;
1731
1732         LogBuffer *logbuffer = ensure_logbuf (
1733                 EVENT_SIZE /* event */ +
1734                 BYTE_SIZE /* type */ +
1735                 LEB128_SIZE /* assembly */ +
1736                 nlen /* name */
1737         );
1738
1739         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
1740         emit_byte (logbuffer, TYPE_ASSEMBLY);
1741         emit_ptr (logbuffer, assembly);
1742         memcpy (logbuffer->cursor, name, nlen);
1743         logbuffer->cursor += nlen;
1744
1745         EXIT_LOG;
1746
1747         mono_free (name);
1748
1749         send_if_needed (prof);
1750
1751         process_requests (prof);
1752
1753         InterlockedIncrement (&assembly_loads);
1754 }
1755
1756 static void
1757 assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly)
1758 {
1759         char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
1760         int nlen = strlen (name) + 1;
1761
1762         ENTER_LOG;
1763
1764         LogBuffer *logbuffer = ensure_logbuf (
1765                 EVENT_SIZE /* event */ +
1766                 BYTE_SIZE /* type */ +
1767                 LEB128_SIZE /* assembly */ +
1768                 nlen /* name */
1769         );
1770
1771         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
1772         emit_byte (logbuffer, TYPE_ASSEMBLY);
1773         emit_ptr (logbuffer, assembly);
1774         memcpy (logbuffer->cursor, name, nlen);
1775         logbuffer->cursor += nlen;
1776
1777         EXIT_LOG;
1778
1779         mono_free (name);
1780
1781         send_if_needed (prof);
1782
1783         process_requests (prof);
1784
1785         InterlockedIncrement (&assembly_unloads);
1786 }
1787
1788 static void
1789 class_loaded (MonoProfiler *prof, MonoClass *klass, int result)
1790 {
1791         if (result != MONO_PROFILE_OK)
1792                 return;
1793
1794         char *name;
1795
1796         if (InterlockedRead (&runtime_inited))
1797                 name = mono_type_get_name (mono_class_get_type (klass));
1798         else
1799                 name = type_name (klass);
1800
1801         int nlen = strlen (name) + 1;
1802         MonoImage *image = mono_class_get_image (klass);
1803
1804         ENTER_LOG;
1805
1806         LogBuffer *logbuffer = ensure_logbuf (
1807                 EVENT_SIZE /* event */ +
1808                 BYTE_SIZE /* type */ +
1809                 LEB128_SIZE /* klass */ +
1810                 LEB128_SIZE /* image */ +
1811                 nlen /* name */
1812         );
1813
1814         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
1815         emit_byte (logbuffer, TYPE_CLASS);
1816         emit_ptr (logbuffer, klass);
1817         emit_ptr (logbuffer, image);
1818         memcpy (logbuffer->cursor, name, nlen);
1819         logbuffer->cursor += nlen;
1820
1821         EXIT_LOG;
1822
1823         if (runtime_inited)
1824                 mono_free (name);
1825         else
1826                 free (name);
1827
1828         send_if_needed (prof);
1829
1830         process_requests (prof);
1831
1832         InterlockedIncrement (&class_loads);
1833 }
1834
1835 static void
1836 class_unloaded (MonoProfiler *prof, MonoClass *klass)
1837 {
1838         char *name;
1839
1840         if (InterlockedRead (&runtime_inited))
1841                 name = mono_type_get_name (mono_class_get_type (klass));
1842         else
1843                 name = type_name (klass);
1844
1845         int nlen = strlen (name) + 1;
1846         MonoImage *image = mono_class_get_image (klass);
1847
1848         ENTER_LOG;
1849
1850         LogBuffer *logbuffer = ensure_logbuf (
1851                 EVENT_SIZE /* event */ +
1852                 BYTE_SIZE /* type */ +
1853                 LEB128_SIZE /* klass */ +
1854                 LEB128_SIZE /* image */ +
1855                 nlen /* name */
1856         );
1857
1858         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
1859         emit_byte (logbuffer, TYPE_CLASS);
1860         emit_ptr (logbuffer, klass);
1861         emit_ptr (logbuffer, image);
1862         memcpy (logbuffer->cursor, name, nlen);
1863         logbuffer->cursor += nlen;
1864
1865         EXIT_LOG;
1866
1867         if (runtime_inited)
1868                 mono_free (name);
1869         else
1870                 free (name);
1871
1872         send_if_needed (prof);
1873
1874         process_requests (prof);
1875
1876         InterlockedIncrement (&class_unloads);
1877 }
1878
1879 #ifndef DISABLE_HELPER_THREAD
1880 static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method);
1881 #endif /* DISABLE_HELPER_THREAD */
1882
1883 static void
1884 method_enter (MonoProfiler *prof, MonoMethod *method)
1885 {
1886 #ifndef DISABLE_HELPER_THREAD
1887         process_method_enter_coverage (prof, method);
1888 #endif /* DISABLE_HELPER_THREAD */
1889
1890         if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) {
1891                 ENTER_LOG;
1892
1893                 LogBuffer *logbuffer = ensure_logbuf (
1894                         EVENT_SIZE /* event */ +
1895                         LEB128_SIZE /* method */
1896                 );
1897
1898                 emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
1899                 emit_method (prof, logbuffer, method);
1900
1901                 EXIT_LOG;
1902         }
1903
1904         send_if_needed (prof);
1905
1906         process_requests (prof);
1907 }
1908
1909 static void
1910 method_leave (MonoProfiler *prof, MonoMethod *method)
1911 {
1912         if (--PROF_TLS_GET ()->call_depth <= max_call_depth) {
1913                 ENTER_LOG;
1914
1915                 LogBuffer *logbuffer = ensure_logbuf (
1916                         EVENT_SIZE /* event */ +
1917                         LEB128_SIZE /* method */
1918                 );
1919
1920                 emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
1921                 emit_method (prof, logbuffer, method);
1922
1923                 EXIT_LOG;
1924         }
1925
1926         send_if_needed (prof);
1927
1928         process_requests (prof);
1929 }
1930
1931 static void
1932 method_exc_leave (MonoProfiler *prof, MonoMethod *method)
1933 {
1934         if (!nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) {
1935                 ENTER_LOG;
1936
1937                 LogBuffer *logbuffer = ensure_logbuf (
1938                         EVENT_SIZE /* event */ +
1939                         LEB128_SIZE /* method */
1940                 );
1941
1942                 emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
1943                 emit_method (prof, logbuffer, method);
1944
1945                 EXIT_LOG;
1946         }
1947
1948         send_if_needed (prof);
1949
1950         process_requests (prof);
1951 }
1952
1953 static void
1954 method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int result)
1955 {
1956         if (result != MONO_PROFILE_OK)
1957                 return;
1958
1959         register_method_local (prof, method, ji);
1960
1961         process_requests (prof);
1962 }
1963
1964 static void
1965 code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data)
1966 {
1967         char *name;
1968         int nlen;
1969
1970         if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
1971                 name = (char *) data;
1972                 nlen = strlen (name) + 1;
1973         } else {
1974                 name = NULL;
1975                 nlen = 0;
1976         }
1977
1978         ENTER_LOG;
1979
1980         LogBuffer *logbuffer = ensure_logbuf (
1981                 EVENT_SIZE /* event */ +
1982                 BYTE_SIZE /* type */ +
1983                 LEB128_SIZE /* buffer */ +
1984                 LEB128_SIZE /* size */ +
1985                 (name ? (
1986                         nlen /* name */
1987                 ) : 0)
1988         );
1989
1990         emit_event (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
1991         emit_byte (logbuffer, type);
1992         emit_ptr (logbuffer, buffer);
1993         emit_value (logbuffer, size);
1994
1995         if (name) {
1996                 memcpy (logbuffer->cursor, name, nlen);
1997                 logbuffer->cursor += nlen;
1998         }
1999
2000         EXIT_LOG;
2001
2002         process_requests (prof);
2003 }
2004
2005 static void
2006 throw_exc (MonoProfiler *prof, MonoObject *object)
2007 {
2008         int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_EXCEPTION_BT : 0;
2009         FrameData data;
2010
2011         if (do_bt)
2012                 collect_bt (&data);
2013
2014         ENTER_LOG;
2015
2016         LogBuffer *logbuffer = ensure_logbuf (
2017                 EVENT_SIZE /* event */ +
2018                 LEB128_SIZE /* object */ +
2019                 (do_bt ? (
2020                         LEB128_SIZE /* count */ +
2021                         data.count * (
2022                                 LEB128_SIZE /* method */
2023                         )
2024                 ) : 0)
2025         );
2026
2027         emit_event (logbuffer, do_bt | TYPE_EXCEPTION);
2028         emit_obj (logbuffer, object);
2029
2030         if (do_bt)
2031                 emit_bt (prof, logbuffer, &data);
2032
2033         EXIT_LOG;
2034
2035         process_requests (prof);
2036 }
2037
2038 static void
2039 clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num)
2040 {
2041         ENTER_LOG;
2042
2043         LogBuffer *logbuffer = ensure_logbuf (
2044                 EVENT_SIZE /* event */ +
2045                 BYTE_SIZE /* clause type */ +
2046                 LEB128_SIZE /* clause num */ +
2047                 LEB128_SIZE /* method */
2048         );
2049
2050         emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
2051         emit_byte (logbuffer, clause_type);
2052         emit_value (logbuffer, clause_num);
2053         emit_method (prof, logbuffer, method);
2054
2055         EXIT_LOG;
2056
2057         process_requests (prof);
2058 }
2059
2060 static void
2061 monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEvent event)
2062 {
2063         int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces && event == MONO_PROFILER_MONITOR_CONTENTION) ? TYPE_MONITOR_BT : 0;
2064         FrameData data;
2065
2066         if (do_bt)
2067                 collect_bt (&data);
2068
2069         ENTER_LOG;
2070
2071         LogBuffer *logbuffer = ensure_logbuf (
2072                 EVENT_SIZE /* event */ +
2073                 LEB128_SIZE /* object */ +
2074                 (do_bt ? (
2075                         LEB128_SIZE /* count */ +
2076                         data.count * (
2077                                 LEB128_SIZE /* method */
2078                         )
2079                 ) : 0)
2080         );
2081
2082         emit_event (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
2083         emit_obj (logbuffer, object);
2084
2085         if (do_bt)
2086                 emit_bt (profiler, logbuffer, &data);
2087
2088         EXIT_LOG;
2089
2090         process_requests (profiler);
2091 }
2092
2093 static void
2094 thread_start (MonoProfiler *prof, uintptr_t tid)
2095 {
2096         init_thread (TRUE);
2097
2098         ENTER_LOG;
2099
2100         LogBuffer *logbuffer = ensure_logbuf (
2101                 EVENT_SIZE /* event */ +
2102                 BYTE_SIZE /* type */ +
2103                 LEB128_SIZE /* tid */
2104         );
2105
2106         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
2107         emit_byte (logbuffer, TYPE_THREAD);
2108         emit_ptr (logbuffer, (void*) tid);
2109
2110         EXIT_LOG;
2111
2112         send_if_needed (prof);
2113
2114         process_requests (prof);
2115
2116         InterlockedIncrement (&thread_starts);
2117 }
2118
2119 static void
2120 thread_end (MonoProfiler *prof, uintptr_t tid)
2121 {
2122         ENTER_LOG;
2123
2124         LogBuffer *logbuffer = ensure_logbuf (
2125                 EVENT_SIZE /* event */ +
2126                 BYTE_SIZE /* type */ +
2127                 LEB128_SIZE /* tid */
2128         );
2129
2130         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
2131         emit_byte (logbuffer, TYPE_THREAD);
2132         emit_ptr (logbuffer, (void*) tid);
2133
2134         EXIT_LOG;
2135
2136         // Don't process requests as the thread is detached from the runtime.
2137
2138         remove_thread (prof, PROF_TLS_GET (), TRUE);
2139
2140         InterlockedIncrement (&thread_ends);
2141 }
2142
2143 static void
2144 domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result)
2145 {
2146         if (result != MONO_PROFILE_OK)
2147                 return;
2148
2149         ENTER_LOG;
2150
2151         LogBuffer *logbuffer = ensure_logbuf (
2152                 EVENT_SIZE /* event */ +
2153                 BYTE_SIZE /* type */ +
2154                 LEB128_SIZE /* domain id */
2155         );
2156
2157         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
2158         emit_byte (logbuffer, TYPE_DOMAIN);
2159         emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
2160
2161         EXIT_LOG;
2162
2163         send_if_needed (prof);
2164
2165         process_requests (prof);
2166
2167         InterlockedIncrement (&domain_loads);
2168 }
2169
2170 static void
2171 domain_unloaded (MonoProfiler *prof, MonoDomain *domain)
2172 {
2173         ENTER_LOG;
2174
2175         LogBuffer *logbuffer = ensure_logbuf (
2176                 EVENT_SIZE /* event */ +
2177                 BYTE_SIZE /* type */ +
2178                 LEB128_SIZE /* domain id */
2179         );
2180
2181         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
2182         emit_byte (logbuffer, TYPE_DOMAIN);
2183         emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
2184
2185         EXIT_LOG;
2186
2187         send_if_needed (prof);
2188
2189         process_requests (prof);
2190
2191         InterlockedIncrement (&domain_unloads);
2192 }
2193
2194 static void
2195 domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name)
2196 {
2197         int nlen = strlen (name) + 1;
2198
2199         ENTER_LOG;
2200
2201         LogBuffer *logbuffer = ensure_logbuf (
2202                 EVENT_SIZE /* event */ +
2203                 BYTE_SIZE /* type */ +
2204                 LEB128_SIZE /* domain id */ +
2205                 nlen /* name */
2206         );
2207
2208         emit_event (logbuffer, TYPE_METADATA);
2209         emit_byte (logbuffer, TYPE_DOMAIN);
2210         emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
2211         memcpy (logbuffer->cursor, name, nlen);
2212         logbuffer->cursor += nlen;
2213
2214         EXIT_LOG;
2215
2216         send_if_needed (prof);
2217
2218         process_requests (prof);
2219 }
2220
2221 static void
2222 context_loaded (MonoProfiler *prof, MonoAppContext *context)
2223 {
2224         ENTER_LOG;
2225
2226         LogBuffer *logbuffer = ensure_logbuf (
2227                 EVENT_SIZE /* event */ +
2228                 BYTE_SIZE /* type */ +
2229                 LEB128_SIZE /* context id */ +
2230                 LEB128_SIZE /* domain id */
2231         );
2232
2233         emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
2234         emit_byte (logbuffer, TYPE_CONTEXT);
2235         emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
2236         emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
2237
2238         EXIT_LOG;
2239
2240         send_if_needed (prof);
2241
2242         process_requests (prof);
2243
2244         InterlockedIncrement (&context_loads);
2245 }
2246
2247 static void
2248 context_unloaded (MonoProfiler *prof, MonoAppContext *context)
2249 {
2250         ENTER_LOG;
2251
2252         LogBuffer *logbuffer = ensure_logbuf (
2253                 EVENT_SIZE /* event */ +
2254                 BYTE_SIZE /* type */ +
2255                 LEB128_SIZE /* context id */ +
2256                 LEB128_SIZE /* domain id */
2257         );
2258
2259         emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
2260         emit_byte (logbuffer, TYPE_CONTEXT);
2261         emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
2262         emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
2263
2264         EXIT_LOG;
2265
2266         send_if_needed (prof);
2267
2268         process_requests (prof);
2269
2270         InterlockedIncrement (&context_unloads);
2271 }
2272
2273 static void
2274 thread_name (MonoProfiler *prof, uintptr_t tid, const char *name)
2275 {
2276         int len = strlen (name) + 1;
2277
2278         ENTER_LOG;
2279
2280         LogBuffer *logbuffer = ensure_logbuf (
2281                 EVENT_SIZE /* event */ +
2282                 BYTE_SIZE /* type */ +
2283                 LEB128_SIZE /* tid */ +
2284                 len /* name */
2285         );
2286
2287         emit_event (logbuffer, TYPE_METADATA);
2288         emit_byte (logbuffer, TYPE_THREAD);
2289         emit_ptr (logbuffer, (void*)tid);
2290         memcpy (logbuffer->cursor, name, len);
2291         logbuffer->cursor += len;
2292
2293         EXIT_LOG;
2294
2295         send_if_needed (prof);
2296
2297         process_requests (prof);
2298 }
2299
2300 typedef struct {
2301         MonoMethod *method;
2302         MonoDomain *domain;
2303         void *base_address;
2304         int offset;
2305 } AsyncFrameInfo;
2306
2307 typedef struct {
2308         MonoLockFreeQueueNode node;
2309         MonoProfiler *prof;
2310         uint64_t time;
2311         uintptr_t tid;
2312         void *ip;
2313         int count;
2314         AsyncFrameInfo frames [MONO_ZERO_LEN_ARRAY];
2315 } SampleHit;
2316
2317 static mono_bool
2318 async_walk_stack (MonoMethod *method, MonoDomain *domain, void *base_address, int offset, void *data)
2319 {
2320         SampleHit *sample = (SampleHit *) data;
2321
2322         if (sample->count < num_frames) {
2323                 int i = sample->count;
2324
2325                 sample->frames [i].method = method;
2326                 sample->frames [i].domain = domain;
2327                 sample->frames [i].base_address = base_address;
2328                 sample->frames [i].offset = offset;
2329
2330                 sample->count++;
2331         }
2332
2333         return sample->count == num_frames;
2334 }
2335
2336 #define SAMPLE_SLOT_SIZE(FRAMES) (sizeof (SampleHit) + sizeof (AsyncFrameInfo) * (FRAMES - MONO_ZERO_LEN_ARRAY))
2337 #define SAMPLE_BLOCK_SIZE (mono_pagesize ())
2338
2339 static void
2340 enqueue_sample_hit (gpointer p)
2341 {
2342         SampleHit *sample = p;
2343
2344         mono_lock_free_queue_node_unpoison (&sample->node);
2345         mono_lock_free_queue_enqueue (&sample->prof->dumper_queue, &sample->node);
2346         mono_os_sem_post (&sample->prof->dumper_queue_sem);
2347
2348         InterlockedIncrement (&sample_flushes);
2349 }
2350
2351 static void
2352 mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
2353 {
2354         /*
2355          * Please note: We rely on the runtime loading the profiler with
2356          * MONO_DL_EAGER (RTLD_NOW) so that references to runtime functions within
2357          * this function (and its siblings) are resolved when the profiler is
2358          * loaded. Otherwise, we would potentially invoke the dynamic linker when
2359          * invoking runtime functions, which is not async-signal-safe.
2360          */
2361
2362         if (in_shutdown)
2363                 return;
2364
2365         InterlockedIncrement (&sample_hits);
2366
2367         SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
2368
2369         if (!sample) {
2370                 /*
2371                  * If we're out of reusable sample events and we're not allowed to
2372                  * allocate more, we have no choice but to drop the event.
2373                  */
2374                 if (InterlockedRead (&sample_allocations) >= max_allocated_sample_hits)
2375                         return;
2376
2377                 sample = mono_lock_free_alloc (&profiler->sample_allocator);
2378                 sample->prof = profiler;
2379                 mono_lock_free_queue_node_init (&sample->node, TRUE);
2380
2381                 InterlockedIncrement (&sample_allocations);
2382         }
2383
2384         sample->count = 0;
2385         mono_stack_walk_async_safe (&async_walk_stack, context, sample);
2386
2387         sample->time = current_time ();
2388         sample->tid = thread_id ();
2389         sample->ip = ip;
2390
2391         if (do_debug) {
2392                 int len;
2393                 char buf [256];
2394                 snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) sample->tid, (unsigned long long int) ((sample->time - profiler->startup_time) / 10000 / 100));
2395                 len = strlen (buf);
2396                 ign_res (write (2, buf, len));
2397         }
2398
2399         mono_thread_hazardous_try_free (sample, enqueue_sample_hit);
2400 }
2401
2402 static uintptr_t *code_pages = 0;
2403 static int num_code_pages = 0;
2404 static int size_code_pages = 0;
2405 #define CPAGE_SHIFT (9)
2406 #define CPAGE_SIZE (1 << CPAGE_SHIFT)
2407 #define CPAGE_MASK (~(CPAGE_SIZE - 1))
2408 #define CPAGE_ADDR(p) ((p) & CPAGE_MASK)
2409
2410 static uintptr_t
2411 add_code_page (uintptr_t *hash, uintptr_t hsize, uintptr_t page)
2412 {
2413         uintptr_t i;
2414         uintptr_t start_pos;
2415         start_pos = (page >> CPAGE_SHIFT) % hsize;
2416         i = start_pos;
2417         do {
2418                 if (hash [i] && CPAGE_ADDR (hash [i]) == CPAGE_ADDR (page)) {
2419                         return 0;
2420                 } else if (!hash [i]) {
2421                         hash [i] = page;
2422                         return 1;
2423                 }
2424                 /* wrap around */
2425                 if (++i == hsize)
2426                         i = 0;
2427         } while (i != start_pos);
2428         /* should not happen */
2429         printf ("failed code page store\n");
2430         return 0;
2431 }
2432
2433 static void
2434 add_code_pointer (uintptr_t ip)
2435 {
2436         uintptr_t i;
2437         if (num_code_pages * 2 >= size_code_pages) {
2438                 uintptr_t *n;
2439                 uintptr_t old_size = size_code_pages;
2440                 size_code_pages *= 2;
2441                 if (size_code_pages == 0)
2442                         size_code_pages = 16;
2443                 n = (uintptr_t *)calloc (sizeof (uintptr_t) * size_code_pages, 1);
2444                 for (i = 0; i < old_size; ++i) {
2445                         if (code_pages [i])
2446                                 add_code_page (n, size_code_pages, code_pages [i]);
2447                 }
2448                 if (code_pages)
2449                         free (code_pages);
2450                 code_pages = n;
2451         }
2452         num_code_pages += add_code_page (code_pages, size_code_pages, ip & CPAGE_MASK);
2453 }
2454
2455 /* ELF code crashes on some systems. */
2456 //#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
2457 #if 0
2458 static void
2459 dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
2460 {
2461         int len = strlen (filename) + 1;
2462
2463         ENTER_LOG;
2464
2465         LogBuffer *logbuffer = ensure_logbuf (
2466                 EVENT_SIZE /* event */ +
2467                 LEB128_SIZE /* load address */ +
2468                 LEB128_SIZE /* offset */ +
2469                 LEB128_SIZE /* size */ +
2470                 nlen /* file name */
2471         );
2472
2473         emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
2474         emit_svalue (logbuffer, load_addr);
2475         emit_uvalue (logbuffer, offset);
2476         emit_uvalue (logbuffer, size);
2477         memcpy (logbuffer->cursor, filename, len);
2478         logbuffer->cursor += len;
2479
2480         EXIT_LOG;
2481 }
2482 #endif
2483
2484 static void
2485 dump_usym (const char *name, uintptr_t value, uintptr_t size)
2486 {
2487         int len = strlen (name) + 1;
2488
2489         ENTER_LOG;
2490
2491         LogBuffer *logbuffer = ensure_logbuf (
2492                 EVENT_SIZE /* event */ +
2493                 LEB128_SIZE /* value */ +
2494                 LEB128_SIZE /* size */ +
2495                 len /* name */
2496         );
2497
2498         emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
2499         emit_ptr (logbuffer, (void*)value);
2500         emit_value (logbuffer, size);
2501         memcpy (logbuffer->cursor, name, len);
2502         logbuffer->cursor += len;
2503
2504         EXIT_LOG;
2505 }
2506
2507 /* ELF code crashes on some systems. */
2508 //#if defined(ELFMAG0)
2509 #if 0
2510
2511 #if SIZEOF_VOID_P == 4
2512 #define ELF_WSIZE 32
2513 #else
2514 #define ELF_WSIZE 64
2515 #endif
2516 #ifndef ElfW
2517 #define ElfW(type)      _ElfW (Elf, ELF_WSIZE, type)
2518 #define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
2519 #define _ElfW_1(e,w,t)  e##w##t
2520 #endif
2521
2522 static void
2523 dump_elf_symbols (ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
2524 {
2525         int i;
2526         for (i = 0; i < num_symbols; ++i) {
2527                 const char* sym;
2528                 sym =  strtab + symbols [i].st_name;
2529                 if (!symbols [i].st_name || !symbols [i].st_size || (symbols [i].st_info & 0xf) != STT_FUNC)
2530                         continue;
2531                 //printf ("symbol %s at %d\n", sym, symbols [i].st_value);
2532                 dump_usym (sym, (uintptr_t)load_addr + symbols [i].st_value, symbols [i].st_size);
2533         }
2534 }
2535
2536 static int
2537 read_elf_symbols (MonoProfiler *prof, const char *filename, void *load_addr)
2538 {
2539         int fd, i;
2540         void *data;
2541         struct stat statb;
2542         uint64_t file_size;
2543         ElfW(Ehdr) *header;
2544         ElfW(Shdr) *sheader;
2545         ElfW(Shdr) *shstrtabh;
2546         ElfW(Shdr) *symtabh = NULL;
2547         ElfW(Shdr) *strtabh = NULL;
2548         ElfW(Sym) *symbols = NULL;
2549         const char *strtab;
2550         int num_symbols;
2551
2552         fd = open (filename, O_RDONLY);
2553         if (fd < 0)
2554                 return 0;
2555         if (fstat (fd, &statb) != 0) {
2556                 close (fd);
2557                 return 0;
2558         }
2559         file_size = statb.st_size;
2560         data = mmap (NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
2561         close (fd);
2562         if (data == MAP_FAILED)
2563                 return 0;
2564         header = data;
2565         if (header->e_ident [EI_MAG0] != ELFMAG0 ||
2566                         header->e_ident [EI_MAG1] != ELFMAG1 ||
2567                         header->e_ident [EI_MAG2] != ELFMAG2 ||
2568                         header->e_ident [EI_MAG3] != ELFMAG3 ) {
2569                 munmap (data, file_size);
2570                 return 0;
2571         }
2572         sheader = (void*)((char*)data + header->e_shoff);
2573         shstrtabh = (void*)((char*)sheader + (header->e_shentsize * header->e_shstrndx));
2574         strtab = (const char*)data + shstrtabh->sh_offset;
2575         for (i = 0; i < header->e_shnum; ++i) {
2576                 //printf ("section header: %d\n", sheader->sh_type);
2577                 if (sheader->sh_type == SHT_SYMTAB) {
2578                         symtabh = sheader;
2579                         strtabh = (void*)((char*)data + header->e_shoff + sheader->sh_link * header->e_shentsize);
2580                         /*printf ("symtab section header: %d, .strstr: %d\n", i, sheader->sh_link);*/
2581                         break;
2582                 }
2583                 sheader = (void*)((char*)sheader + header->e_shentsize);
2584         }
2585         if (!symtabh || !strtabh) {
2586                 munmap (data, file_size);
2587                 return 0;
2588         }
2589         strtab = (const char*)data + strtabh->sh_offset;
2590         num_symbols = symtabh->sh_size / symtabh->sh_entsize;
2591         symbols = (void*)((char*)data + symtabh->sh_offset);
2592         dump_elf_symbols (symbols, num_symbols, strtab, load_addr);
2593         munmap (data, file_size);
2594         return 1;
2595 }
2596 #endif
2597
2598 /* ELF code crashes on some systems. */
2599 //#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
2600 #if 0
2601 static int
2602 elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data)
2603 {
2604         MonoProfiler *prof = data;
2605         char buf [256];
2606         const char *filename;
2607         BinaryObject *obj;
2608         char *a = (void*)info->dlpi_addr;
2609         int i, num_sym;
2610         ElfW(Dyn) *dyn = NULL;
2611         ElfW(Sym) *symtab = NULL;
2612         ElfW(Word) *hash_table = NULL;
2613         ElfW(Ehdr) *header = NULL;
2614         const char* strtab = NULL;
2615         for (obj = prof->binary_objects; obj; obj = obj->next) {
2616                 if (obj->addr == a)
2617                         return 0;
2618         }
2619         filename = info->dlpi_name;
2620         if (!filename)
2621                 return 0;
2622         if (!info->dlpi_addr && !filename [0]) {
2623                 int l = readlink ("/proc/self/exe", buf, sizeof (buf) - 1);
2624                 if (l > 0) {
2625                         buf [l] = 0;
2626                         filename = buf;
2627                 }
2628         }
2629         obj = calloc (sizeof (BinaryObject), 1);
2630         obj->addr = (void*)info->dlpi_addr;
2631         obj->name = pstrdup (filename);
2632         obj->next = prof->binary_objects;
2633         prof->binary_objects = obj;
2634         //printf ("loaded file: %s at %p, segments: %d\n", filename, (void*)info->dlpi_addr, info->dlpi_phnum);
2635         a = NULL;
2636         for (i = 0; i < info->dlpi_phnum; ++i) {
2637                 //printf ("segment type %d file offset: %d, size: %d\n", info->dlpi_phdr[i].p_type, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
2638                 if (info->dlpi_phdr[i].p_type == PT_LOAD && !header) {
2639                         header = (ElfW(Ehdr)*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
2640                         if (header->e_ident [EI_MAG0] != ELFMAG0 ||
2641                                         header->e_ident [EI_MAG1] != ELFMAG1 ||
2642                                         header->e_ident [EI_MAG2] != ELFMAG2 ||
2643                                         header->e_ident [EI_MAG3] != ELFMAG3 ) {
2644                                 header = NULL;
2645                         }
2646                         dump_ubin (filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
2647                 } else if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
2648                         dyn = (ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
2649                 }
2650         }
2651         if (read_elf_symbols (prof, filename, (void*)info->dlpi_addr))
2652                 return 0;
2653         if (!info->dlpi_name || !info->dlpi_name[0])
2654                 return 0;
2655         if (!dyn)
2656                 return 0;
2657         for (i = 0; dyn [i].d_tag != DT_NULL; ++i) {
2658                 if (dyn [i].d_tag == DT_SYMTAB) {
2659                         if (symtab && do_debug)
2660                                 printf ("multiple symtabs: %d\n", i);
2661                         symtab = (ElfW(Sym) *)(a + dyn [i].d_un.d_ptr);
2662                 } else if (dyn [i].d_tag == DT_HASH) {
2663                         hash_table = (ElfW(Word) *)(a + dyn [i].d_un.d_ptr);
2664                 } else if (dyn [i].d_tag == DT_STRTAB) {
2665                         strtab = (const char*)(a + dyn [i].d_un.d_ptr);
2666                 }
2667         }
2668         if (!hash_table)
2669                 return 0;
2670         num_sym = hash_table [1];
2671         dump_elf_symbols (symtab, num_sym, strtab, (void*)info->dlpi_addr);
2672         return 0;
2673 }
2674
2675 static int
2676 load_binaries (MonoProfiler *prof)
2677 {
2678         dl_iterate_phdr (elf_dl_callback, prof);
2679         return 1;
2680 }
2681 #else
2682 static int
2683 load_binaries (MonoProfiler *prof)
2684 {
2685         return 0;
2686 }
2687 #endif
2688
2689 static const char*
2690 symbol_for (uintptr_t code)
2691 {
2692 #ifdef HAVE_DLADDR
2693         void *ip = (void*)code;
2694         Dl_info di;
2695         if (dladdr (ip, &di)) {
2696                 if (di.dli_sname)
2697                         return di.dli_sname;
2698         } else {
2699         /*      char **names;
2700                 names = backtrace_symbols (&ip, 1);
2701                 if (names) {
2702                         const char* p = names [0];
2703                         free (names);
2704                         return p;
2705                 }
2706                 */
2707         }
2708 #endif
2709         return NULL;
2710 }
2711
2712 static void
2713 dump_unmanaged_coderefs (MonoProfiler *prof)
2714 {
2715         int i;
2716         const char* last_symbol;
2717         uintptr_t addr, page_end;
2718
2719         if (load_binaries (prof))
2720                 return;
2721         for (i = 0; i < size_code_pages; ++i) {
2722                 const char* sym;
2723                 if (!code_pages [i] || code_pages [i] & 1)
2724                         continue;
2725                 last_symbol = NULL;
2726                 addr = CPAGE_ADDR (code_pages [i]);
2727                 page_end = addr + CPAGE_SIZE;
2728                 code_pages [i] |= 1;
2729                 /* we dump the symbols for the whole page */
2730                 for (; addr < page_end; addr += 16) {
2731                         sym = symbol_for (addr);
2732                         if (sym && sym == last_symbol)
2733                                 continue;
2734                         last_symbol = sym;
2735                         if (!sym)
2736                                 continue;
2737                         dump_usym (sym, addr, 0); /* let's not guess the size */
2738                         //printf ("found symbol at %p: %s\n", (void*)addr, sym);
2739                 }
2740         }
2741 }
2742
2743 static int
2744 mono_cpu_count (void)
2745 {
2746 #ifdef PLATFORM_ANDROID
2747         /* Android tries really hard to save power by powering off CPUs on SMP phones which
2748          * means the normal way to query cpu count returns a wrong value with userspace API.
2749          * Instead we use /sys entries to query the actual hardware CPU count.
2750          */
2751         int count = 0;
2752         char buffer[8] = {'\0'};
2753         int present = open ("/sys/devices/system/cpu/present", O_RDONLY);
2754         /* Format of the /sys entry is a cpulist of indexes which in the case
2755          * of present is always of the form "0-(n-1)" when there is more than
2756          * 1 core, n being the number of CPU cores in the system. Otherwise
2757          * the value is simply 0
2758          */
2759         if (present != -1 && read (present, (char*)buffer, sizeof (buffer)) > 3)
2760                 count = strtol (((char*)buffer) + 2, NULL, 10);
2761         if (present != -1)
2762                 close (present);
2763         if (count > 0)
2764                 return count + 1;
2765 #endif
2766
2767 #if defined(HOST_ARM) || defined (HOST_ARM64)
2768
2769         /* ARM platforms tries really hard to save power by powering off CPUs on SMP phones which
2770          * means the normal way to query cpu count returns a wrong value with userspace API. */
2771
2772 #ifdef _SC_NPROCESSORS_CONF
2773         {
2774                 int count = sysconf (_SC_NPROCESSORS_CONF);
2775                 if (count > 0)
2776                         return count;
2777         }
2778 #endif
2779
2780 #else
2781
2782 #ifdef HAVE_SCHED_GETAFFINITY
2783         {
2784                 cpu_set_t set;
2785                 if (sched_getaffinity (getpid (), sizeof (set), &set) == 0)
2786                         return CPU_COUNT (&set);
2787         }
2788 #endif
2789 #ifdef _SC_NPROCESSORS_ONLN
2790         {
2791                 int count = sysconf (_SC_NPROCESSORS_ONLN);
2792                 if (count > 0)
2793                         return count;
2794         }
2795 #endif
2796
2797 #endif /* defined(HOST_ARM) || defined (HOST_ARM64) */
2798
2799 #ifdef USE_SYSCTL
2800         {
2801                 int count;
2802                 int mib [2];
2803                 size_t len = sizeof (int);
2804                 mib [0] = CTL_HW;
2805                 mib [1] = HW_NCPU;
2806                 if (sysctl (mib, 2, &count, &len, NULL, 0) == 0)
2807                         return count;
2808         }
2809 #endif
2810 #ifdef HOST_WIN32
2811         {
2812                 SYSTEM_INFO info;
2813                 GetSystemInfo (&info);
2814                 return info.dwNumberOfProcessors;
2815         }
2816 #endif
2817         /* FIXME: warn */
2818         return 1;
2819 }
2820
2821 #if USE_PERF_EVENTS
2822
2823 typedef struct {
2824         int perf_fd;
2825         unsigned int prev_pos;
2826         void *mmap_base;
2827         struct perf_event_mmap_page *page_desc;
2828 } PerfData ;
2829
2830 static PerfData *perf_data = NULL;
2831 static int num_perf;
2832 #define PERF_PAGES_SHIFT 4
2833 static int num_pages = 1 << PERF_PAGES_SHIFT;
2834 static unsigned int mmap_mask;
2835
2836 typedef struct {
2837         struct perf_event_header h;
2838         uint64_t ip;
2839         uint32_t pid;
2840         uint32_t tid;
2841         uint64_t timestamp;
2842         uint64_t period;
2843         uint64_t nframes;
2844 } PSample;
2845
2846 static int
2847 perf_event_syscall (struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
2848 {
2849         attr->size = PERF_ATTR_SIZE_VER0;
2850         //printf ("perf attr size: %d\n", attr->size);
2851 #if defined(__x86_64__)
2852         return syscall(/*__NR_perf_event_open*/ 298, attr, pid, cpu, group_fd, flags);
2853 #elif defined(__i386__)
2854         return syscall(/*__NR_perf_event_open*/ 336, attr, pid, cpu, group_fd, flags);
2855 #elif defined(__arm__) || defined (__aarch64__)
2856         return syscall(/*__NR_perf_event_open*/ 364, attr, pid, cpu, group_fd, flags);
2857 #else
2858         return -1;
2859 #endif
2860 }
2861
2862 static int
2863 setup_perf_map (PerfData *perf)
2864 {
2865         perf->mmap_base = mmap (NULL, (num_pages + 1) * getpagesize (), PROT_READ|PROT_WRITE, MAP_SHARED, perf->perf_fd, 0);
2866         if (perf->mmap_base == MAP_FAILED) {
2867                 if (do_debug)
2868                         printf ("failed mmap\n");
2869                 return 0;
2870         }
2871         perf->page_desc = perf->mmap_base;
2872         if (do_debug)
2873                 printf ("mmap version: %d\n", perf->page_desc->version);
2874         return 1;
2875 }
2876
2877 static void
2878 dump_perf_hits (MonoProfiler *prof, void *buf, int size)
2879 {
2880         int count = 1;
2881         int mbt_count = 0;
2882         void *end = (char*)buf + size;
2883         int samples = 0;
2884         int pid = getpid ();
2885
2886         while (buf < end) {
2887                 PSample *s = buf;
2888                 if (s->h.size == 0)
2889                         break;
2890                 if (pid != s->pid) {
2891                         if (do_debug)
2892                                 printf ("event for different pid: %d\n", s->pid);
2893                         buf = (char*)buf + s->h.size;
2894                         continue;
2895                 }
2896                 /*ip = (void*)s->ip;
2897                 printf ("sample: %d, size: %d, ip: %p (%s), timestamp: %llu, nframes: %llu\n",
2898                         s->h.type, s->h.size, ip, symbol_for (ip), s->timestamp, s->nframes);*/
2899
2900                 ENTER_LOG;
2901
2902                 LogBuffer *logbuffer = ensure_logbuf (
2903                         EVENT_SIZE /* event */ +
2904                         BYTE_SIZE /* type */ +
2905                         LEB128_SIZE /* tid */ +
2906                         LEB128_SIZE /* count */ +
2907                         count * (
2908                                 LEB128_SIZE /* ip */
2909                         ) +
2910                         LEB128_SIZE /* managed count */ +
2911                         mbt_count * (
2912                                 LEB128_SIZE /* method */
2913                         )
2914                 );
2915
2916                 emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
2917                 emit_byte (logbuffer, sample_type);
2918                 /*
2919                  * No useful thread ID to write here, since throughout the
2920                  * profiler we use pthread_self () but the ID we get from
2921                  * perf is the kernel's thread ID.
2922                  */
2923                 emit_ptr (logbuffer, 0);
2924                 emit_value (logbuffer, count);
2925                 emit_ptr (logbuffer, (void*)(uintptr_t)s->ip);
2926                 /* no support here yet for the managed backtrace */
2927                 emit_uvalue (logbuffer, mbt_count);
2928
2929                 EXIT_LOG;
2930
2931                 add_code_pointer (s->ip);
2932                 buf = (char*)buf + s->h.size;
2933                 samples++;
2934         }
2935         if (do_debug)
2936                 printf ("dumped %d samples\n", samples);
2937         dump_unmanaged_coderefs (prof);
2938 }
2939
2940 /* read events from the ring buffer */
2941 static int
2942 read_perf_mmap (MonoProfiler* prof, int cpu)
2943 {
2944         PerfData *perf = perf_data + cpu;
2945         unsigned char *buf;
2946         unsigned char *data = (unsigned char*)perf->mmap_base + getpagesize ();
2947         unsigned int head = perf->page_desc->data_head;
2948         int diff, size;
2949         unsigned int old;
2950
2951         mono_memory_read_barrier ();
2952
2953         old = perf->prev_pos;
2954         diff = head - old;
2955         if (diff < 0) {
2956                 if (do_debug)
2957                         printf ("lost mmap events: old: %d, head: %d\n", old, head);
2958                 old = head;
2959         }
2960         size = head - old;
2961         if ((old & mmap_mask) + size != (head & mmap_mask)) {
2962                 buf = data + (old & mmap_mask);
2963                 size = mmap_mask + 1 - (old & mmap_mask);
2964                 old += size;
2965                 /* size bytes at buf */
2966                 if (do_debug)
2967                         printf ("found1 bytes of events: %d\n", size);
2968                 dump_perf_hits (prof, buf, size);
2969         }
2970         buf = data + (old & mmap_mask);
2971         size = head - old;
2972         /* size bytes at buf */
2973         if (do_debug)
2974                 printf ("found bytes of events: %d\n", size);
2975         dump_perf_hits (prof, buf, size);
2976         old += size;
2977         perf->prev_pos = old;
2978         perf->page_desc->data_tail = old;
2979         return 0;
2980 }
2981
2982 static int
2983 setup_perf_event_for_cpu (PerfData *perf, int cpu)
2984 {
2985         struct perf_event_attr attr;
2986         memset (&attr, 0, sizeof (attr));
2987         attr.type = PERF_TYPE_HARDWARE;
2988         switch (sample_type) {
2989         case SAMPLE_CYCLES: attr.config = PERF_COUNT_HW_CPU_CYCLES; break;
2990         case SAMPLE_INSTRUCTIONS: attr.config = PERF_COUNT_HW_INSTRUCTIONS; break;
2991         case SAMPLE_CACHE_MISSES: attr.config = PERF_COUNT_HW_CACHE_MISSES; break;
2992         case SAMPLE_CACHE_REFS: attr.config = PERF_COUNT_HW_CACHE_REFERENCES; break;
2993         case SAMPLE_BRANCHES: attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; break;
2994         case SAMPLE_BRANCH_MISSES: attr.config = PERF_COUNT_HW_BRANCH_MISSES; break;
2995         default: attr.config = PERF_COUNT_HW_CPU_CYCLES; break;
2996         }
2997         attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD | PERF_SAMPLE_TIME;
2998 //      attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
2999         attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID;
3000         attr.inherit = 1;
3001         attr.freq = 1;
3002         attr.sample_freq = sample_freq;
3003
3004         perf->perf_fd = perf_event_syscall (&attr, getpid (), cpu, -1, 0);
3005         if (do_debug)
3006                 printf ("perf fd: %d, freq: %d, event: %llu\n", perf->perf_fd, sample_freq, attr.config);
3007         if (perf->perf_fd < 0) {
3008                 if (perf->perf_fd == -EPERM) {
3009                         fprintf (stderr, "Perf syscall denied, do \"echo 1 > /proc/sys/kernel/perf_event_paranoid\" as root to enable.\n");
3010                 } else {
3011                         if (do_debug)
3012                                 perror ("open perf event");
3013                 }
3014                 return 0;
3015         }
3016         if (!setup_perf_map (perf)) {
3017                 close (perf->perf_fd);
3018                 perf->perf_fd = -1;
3019                 return 0;
3020         }
3021         return 1;
3022 }
3023
3024 static int
3025 setup_perf_event (void)
3026 {
3027         int i, count = 0;
3028         mmap_mask = num_pages * getpagesize () - 1;
3029         num_perf = mono_cpu_count ();
3030         perf_data = calloc (num_perf, sizeof (PerfData));
3031         for (i = 0; i < num_perf; ++i) {
3032                 count += setup_perf_event_for_cpu (perf_data + i, i);
3033         }
3034         if (count)
3035                 return 1;
3036         free (perf_data);
3037         perf_data = NULL;
3038         return 0;
3039 }
3040
3041 #endif /* USE_PERF_EVENTS */
3042
3043 #ifndef DISABLE_HELPER_THREAD
3044
3045 typedef struct MonoCounterAgent {
3046         MonoCounter *counter;
3047         // MonoCounterAgent specific data :
3048         void *value;
3049         size_t value_size;
3050         short index;
3051         short emitted;
3052         struct MonoCounterAgent *next;
3053 } MonoCounterAgent;
3054
3055 static MonoCounterAgent* counters;
3056 static gboolean counters_initialized = FALSE;
3057 static int counters_index = 1;
3058 static mono_mutex_t counters_mutex;
3059
3060 static void
3061 counters_add_agent (MonoCounter *counter)
3062 {
3063         MonoCounterAgent *agent, *item;
3064
3065         if (!counters_initialized)
3066                 return;
3067
3068         mono_os_mutex_lock (&counters_mutex);
3069
3070         for (agent = counters; agent; agent = agent->next) {
3071                 if (agent->counter == counter) {
3072                         agent->value_size = 0;
3073                         if (agent->value) {
3074                                 free (agent->value);
3075                                 agent->value = NULL;
3076                         }
3077                         mono_os_mutex_unlock (&counters_mutex);
3078                         return;
3079                 }
3080         }
3081
3082         agent = (MonoCounterAgent *)malloc (sizeof (MonoCounterAgent));
3083         agent->counter = counter;
3084         agent->value = NULL;
3085         agent->value_size = 0;
3086         agent->index = counters_index++;
3087         agent->emitted = 0;
3088         agent->next = NULL;
3089
3090         if (!counters) {
3091                 counters = agent;
3092         } else {
3093                 item = counters;
3094                 while (item->next)
3095                         item = item->next;
3096                 item->next = agent;
3097         }
3098
3099         mono_os_mutex_unlock (&counters_mutex);
3100 }
3101
3102 static mono_bool
3103 counters_init_foreach_callback (MonoCounter *counter, gpointer data)
3104 {
3105         counters_add_agent (counter);
3106         return TRUE;
3107 }
3108
3109 static void
3110 counters_init (MonoProfiler *profiler)
3111 {
3112         assert (!counters_initialized);
3113
3114         mono_os_mutex_init (&counters_mutex);
3115
3116         counters_initialized = TRUE;
3117
3118         mono_counters_on_register (&counters_add_agent);
3119         mono_counters_foreach (counters_init_foreach_callback, NULL);
3120 }
3121
3122 static void
3123 counters_emit (MonoProfiler *profiler)
3124 {
3125         MonoCounterAgent *agent;
3126         int len = 0;
3127         int size =
3128                 EVENT_SIZE /* event */ +
3129                 LEB128_SIZE /* len */
3130         ;
3131
3132         if (!counters_initialized)
3133                 return;
3134
3135         mono_os_mutex_lock (&counters_mutex);
3136
3137         for (agent = counters; agent; agent = agent->next) {
3138                 if (agent->emitted)
3139                         continue;
3140
3141                 size +=
3142                         LEB128_SIZE /* section */ +
3143                         strlen (mono_counter_get_name (agent->counter)) + 1 /* name */ +
3144                         BYTE_SIZE /* type */ +
3145                         BYTE_SIZE /* unit */ +
3146                         BYTE_SIZE /* variance */ +
3147                         LEB128_SIZE /* index */
3148                 ;
3149
3150                 len += 1;
3151         }
3152
3153         if (!len) {
3154                 mono_os_mutex_unlock (&counters_mutex);
3155                 return;
3156         }
3157
3158         ENTER_LOG;
3159
3160         LogBuffer *logbuffer = ensure_logbuf (size);
3161
3162         emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
3163         emit_value (logbuffer, len);
3164
3165         for (agent = counters; agent; agent = agent->next) {
3166                 const char *name;
3167
3168                 if (agent->emitted)
3169                         continue;
3170
3171                 name = mono_counter_get_name (agent->counter);
3172                 emit_value (logbuffer, mono_counter_get_section (agent->counter));
3173                 emit_string (logbuffer, name, strlen (name) + 1);
3174                 emit_byte (logbuffer, mono_counter_get_type (agent->counter));
3175                 emit_byte (logbuffer, mono_counter_get_unit (agent->counter));
3176                 emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
3177                 emit_value (logbuffer, agent->index);
3178
3179                 agent->emitted = 1;
3180         }
3181
3182         EXIT_LOG;
3183
3184         mono_os_mutex_unlock (&counters_mutex);
3185 }
3186
3187 static void
3188 counters_sample (MonoProfiler *profiler, uint64_t timestamp)
3189 {
3190         MonoCounterAgent *agent;
3191         MonoCounter *counter;
3192         int type;
3193         int buffer_size;
3194         void *buffer;
3195         int size;
3196
3197         if (!counters_initialized)
3198                 return;
3199
3200         counters_emit (profiler);
3201
3202         buffer_size = 8;
3203         buffer = calloc (1, buffer_size);
3204
3205         mono_os_mutex_lock (&counters_mutex);
3206
3207         size =
3208                 EVENT_SIZE /* event */
3209         ;
3210
3211         for (agent = counters; agent; agent = agent->next) {
3212                 size +=
3213                         LEB128_SIZE /* index */ +
3214                         BYTE_SIZE /* type */ +
3215                         mono_counter_get_size (agent->counter) /* value */
3216                 ;
3217         }
3218
3219         size +=
3220                 LEB128_SIZE /* stop marker */
3221         ;
3222
3223         ENTER_LOG;
3224
3225         LogBuffer *logbuffer = ensure_logbuf (size);
3226
3227         emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
3228
3229         for (agent = counters; agent; agent = agent->next) {
3230                 size_t size;
3231
3232                 counter = agent->counter;
3233
3234                 size = mono_counter_get_size (counter);
3235                 if (size < 0) {
3236                         continue; // FIXME error
3237                 } else if (size > buffer_size) {
3238                         buffer_size = size;
3239                         buffer = realloc (buffer, buffer_size);
3240                 }
3241
3242                 memset (buffer, 0, buffer_size);
3243
3244                 if (mono_counters_sample (counter, buffer, size) < 0)
3245                         continue; // FIXME error
3246
3247                 type = mono_counter_get_type (counter);
3248
3249                 if (!agent->value) {
3250                         agent->value = calloc (1, size);
3251                         agent->value_size = size;
3252                 } else {
3253                         if (type == MONO_COUNTER_STRING) {
3254                                 if (strcmp (agent->value, buffer) == 0)
3255                                         continue;
3256                         } else {
3257                                 if (agent->value_size == size && memcmp (agent->value, buffer, size) == 0)
3258                                         continue;
3259                         }
3260                 }
3261
3262                 emit_uvalue (logbuffer, agent->index);
3263                 emit_byte (logbuffer, type);
3264                 switch (type) {
3265                 case MONO_COUNTER_INT:
3266 #if SIZEOF_VOID_P == 4
3267                 case MONO_COUNTER_WORD:
3268 #endif
3269                         emit_svalue (logbuffer, *(int*)buffer - *(int*)agent->value);
3270                         break;
3271                 case MONO_COUNTER_UINT:
3272                         emit_uvalue (logbuffer, *(guint*)buffer - *(guint*)agent->value);
3273                         break;
3274                 case MONO_COUNTER_TIME_INTERVAL:
3275                 case MONO_COUNTER_LONG:
3276 #if SIZEOF_VOID_P == 8
3277                 case MONO_COUNTER_WORD:
3278 #endif
3279                         emit_svalue (logbuffer, *(gint64*)buffer - *(gint64*)agent->value);
3280                         break;
3281                 case MONO_COUNTER_ULONG:
3282                         emit_uvalue (logbuffer, *(guint64*)buffer - *(guint64*)agent->value);
3283                         break;
3284                 case MONO_COUNTER_DOUBLE:
3285                         emit_double (logbuffer, *(double*)buffer);
3286                         break;
3287                 case MONO_COUNTER_STRING:
3288                         if (size == 0) {
3289                                 emit_byte (logbuffer, 0);
3290                         } else {
3291                                 emit_byte (logbuffer, 1);
3292                                 emit_string (logbuffer, (char*)buffer, size);
3293                         }
3294                         break;
3295                 default:
3296                         assert (0);
3297                 }
3298
3299                 if (type == MONO_COUNTER_STRING && size > agent->value_size) {
3300                         agent->value = realloc (agent->value, size);
3301                         agent->value_size = size;
3302                 }
3303
3304                 if (size > 0)
3305                         memcpy (agent->value, buffer, size);
3306         }
3307         free (buffer);
3308
3309         emit_value (logbuffer, 0);
3310
3311         EXIT_LOG;
3312
3313         mono_os_mutex_unlock (&counters_mutex);
3314 }
3315
3316 typedef struct _PerfCounterAgent PerfCounterAgent;
3317 struct _PerfCounterAgent {
3318         PerfCounterAgent *next;
3319         int index;
3320         char *category_name;
3321         char *name;
3322         int type;
3323         gint64 value;
3324         guint8 emitted;
3325         guint8 updated;
3326         guint8 deleted;
3327 };
3328
3329 static PerfCounterAgent *perfcounters = NULL;
3330
3331 static void
3332 perfcounters_emit (MonoProfiler *profiler)
3333 {
3334         PerfCounterAgent *pcagent;
3335         int len = 0;
3336         int size =
3337                 EVENT_SIZE /* event */ +
3338                 LEB128_SIZE /* len */
3339         ;
3340
3341         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
3342                 if (pcagent->emitted)
3343                         continue;
3344
3345                 size +=
3346                         LEB128_SIZE /* section */ +
3347                         strlen (pcagent->category_name) + 1 /* category name */ +
3348                         strlen (pcagent->name) + 1 /* name */ +
3349                         BYTE_SIZE /* type */ +
3350                         BYTE_SIZE /* unit */ +
3351                         BYTE_SIZE /* variance */ +
3352                         LEB128_SIZE /* index */
3353                 ;
3354
3355                 len += 1;
3356         }
3357
3358         if (!len)
3359                 return;
3360
3361         ENTER_LOG;
3362
3363         LogBuffer *logbuffer = ensure_logbuf (size);
3364
3365         emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
3366         emit_value (logbuffer, len);
3367
3368         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
3369                 if (pcagent->emitted)
3370                         continue;
3371
3372                 emit_value (logbuffer, MONO_COUNTER_PERFCOUNTERS);
3373                 emit_string (logbuffer, pcagent->category_name, strlen (pcagent->category_name) + 1);
3374                 emit_string (logbuffer, pcagent->name, strlen (pcagent->name) + 1);
3375                 emit_byte (logbuffer, MONO_COUNTER_LONG);
3376                 emit_byte (logbuffer, MONO_COUNTER_RAW);
3377                 emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
3378                 emit_value (logbuffer, pcagent->index);
3379
3380                 pcagent->emitted = 1;
3381         }
3382
3383         EXIT_LOG;
3384 }
3385
3386 static gboolean
3387 perfcounters_foreach (char *category_name, char *name, unsigned char type, gint64 value, gpointer user_data)
3388 {
3389         PerfCounterAgent *pcagent;
3390
3391         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
3392                 if (strcmp (pcagent->category_name, category_name) != 0 || strcmp (pcagent->name, name) != 0)
3393                         continue;
3394                 if (pcagent->value == value)
3395                         return TRUE;
3396
3397                 pcagent->value = value;
3398                 pcagent->updated = 1;
3399                 pcagent->deleted = 0;
3400                 return TRUE;
3401         }
3402
3403         pcagent = g_new0 (PerfCounterAgent, 1);
3404         pcagent->next = perfcounters;
3405         pcagent->index = counters_index++;
3406         pcagent->category_name = g_strdup (category_name);
3407         pcagent->name = g_strdup (name);
3408         pcagent->type = (int) type;
3409         pcagent->value = value;
3410         pcagent->emitted = 0;
3411         pcagent->updated = 1;
3412         pcagent->deleted = 0;
3413
3414         perfcounters = pcagent;
3415
3416         return TRUE;
3417 }
3418
3419 static void
3420 perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
3421 {
3422         PerfCounterAgent *pcagent;
3423         int size;
3424
3425         if (!counters_initialized)
3426                 return;
3427
3428         mono_os_mutex_lock (&counters_mutex);
3429
3430         /* mark all perfcounters as deleted, foreach will unmark them as necessary */
3431         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next)
3432                 pcagent->deleted = 1;
3433
3434         mono_perfcounter_foreach (perfcounters_foreach, perfcounters);
3435
3436         perfcounters_emit (profiler);
3437
3438         size =
3439                 EVENT_SIZE /* event */
3440         ;
3441
3442         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
3443                 if (pcagent->deleted || !pcagent->updated)
3444                         continue;
3445
3446                 size +=
3447                         LEB128_SIZE /* index */ +
3448                         BYTE_SIZE /* type */ +
3449                         LEB128_SIZE /* value */
3450                 ;
3451         }
3452
3453         size +=
3454                 LEB128_SIZE /* stop marker */
3455         ;
3456
3457         ENTER_LOG;
3458
3459         LogBuffer *logbuffer = ensure_logbuf (size);
3460
3461         emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
3462
3463         for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
3464                 if (pcagent->deleted || !pcagent->updated)
3465                         continue;
3466                 emit_uvalue (logbuffer, pcagent->index);
3467                 emit_byte (logbuffer, MONO_COUNTER_LONG);
3468                 emit_svalue (logbuffer, pcagent->value);
3469
3470                 pcagent->updated = 0;
3471         }
3472
3473         emit_value (logbuffer, 0);
3474
3475         EXIT_LOG;
3476
3477         mono_os_mutex_unlock (&counters_mutex);
3478 }
3479
3480 static void
3481 counters_and_perfcounters_sample (MonoProfiler *prof)
3482 {
3483         uint64_t now = current_time ();
3484
3485         counters_sample (prof, now);
3486         perfcounters_sample (prof, now);
3487 }
3488
3489 #define COVERAGE_DEBUG(x) if (debug_coverage) {x}
3490 static mono_mutex_t coverage_mutex;
3491 static MonoConcurrentHashTable *coverage_methods = NULL;
3492 static MonoConcurrentHashTable *coverage_assemblies = NULL;
3493 static MonoConcurrentHashTable *coverage_classes = NULL;
3494
3495 static MonoConcurrentHashTable *filtered_classes = NULL;
3496 static MonoConcurrentHashTable *entered_methods = NULL;
3497 static MonoConcurrentHashTable *image_to_methods = NULL;
3498 static MonoConcurrentHashTable *suppressed_assemblies = NULL;
3499 static gboolean coverage_initialized = FALSE;
3500
3501 static GPtrArray *coverage_data = NULL;
3502 static int previous_offset = 0;
3503
3504 typedef struct {
3505         MonoLockFreeQueueNode node;
3506         MonoMethod *method;
3507 } MethodNode;
3508
3509 typedef struct {
3510         int offset;
3511         int counter;
3512         char *filename;
3513         int line;
3514         int column;
3515 } CoverageEntry;
3516
3517 static void
3518 free_coverage_entry (gpointer data, gpointer userdata)
3519 {
3520         CoverageEntry *entry = (CoverageEntry *)data;
3521         g_free (entry->filename);
3522         g_free (entry);
3523 }
3524
3525 static void
3526 obtain_coverage_for_method (MonoProfiler *prof, const MonoProfileCoverageEntry *entry)
3527 {
3528         int offset = entry->iloffset - previous_offset;
3529         CoverageEntry *e = g_new (CoverageEntry, 1);
3530
3531         previous_offset = entry->iloffset;
3532
3533         e->offset = offset;
3534         e->counter = entry->counter;
3535         e->filename = g_strdup(entry->filename ? entry->filename : "");
3536         e->line = entry->line;
3537         e->column = entry->col;
3538
3539         g_ptr_array_add (coverage_data, e);
3540 }
3541
3542 static char *
3543 parse_generic_type_names(char *name)
3544 {
3545         char *new_name, *ret;
3546         int within_generic_declaration = 0, generic_members = 1;
3547
3548         if (name == NULL || *name == '\0')
3549                 return g_strdup ("");
3550
3551         if (!(ret = new_name = (char *)calloc (strlen (name) * 4 + 1, sizeof (char))))
3552                 return NULL;
3553
3554         do {
3555                 switch (*name) {
3556                         case '<':
3557                                 within_generic_declaration = 1;
3558                                 break;
3559
3560                         case '>':
3561                                 within_generic_declaration = 0;
3562
3563                                 if (*(name - 1) != '<') {
3564                                         *new_name++ = '`';
3565                                         *new_name++ = '0' + generic_members;
3566                                 } else {
3567                                         memcpy (new_name, "&lt;&gt;", 8);
3568                                         new_name += 8;
3569                                 }
3570
3571                                 generic_members = 0;
3572                                 break;
3573
3574                         case ',':
3575                                 generic_members++;
3576                                 break;
3577
3578                         default:
3579                                 if (!within_generic_declaration)
3580                                         *new_name++ = *name;
3581
3582                                 break;
3583                 }
3584         } while (*name++);
3585
3586         return ret;
3587 }
3588
3589 static int method_id;
3590 static void
3591 build_method_buffer (gpointer key, gpointer value, gpointer userdata)
3592 {
3593         MonoMethod *method = (MonoMethod *)value;
3594         MonoProfiler *prof = (MonoProfiler *)userdata;
3595         MonoClass *klass;
3596         MonoImage *image;
3597         char *class_name;
3598         const char *image_name, *method_name, *sig, *first_filename;
3599         guint i;
3600
3601         previous_offset = 0;
3602         coverage_data = g_ptr_array_new ();
3603
3604         mono_profiler_coverage_get (prof, method, obtain_coverage_for_method);
3605
3606         klass = mono_method_get_class (method);
3607         image = mono_class_get_image (klass);
3608         image_name = mono_image_get_name (image);
3609
3610         sig = mono_signature_get_desc (mono_method_signature (method), TRUE);
3611         class_name = parse_generic_type_names (mono_type_get_name (mono_class_get_type (klass)));
3612         method_name = mono_method_get_name (method);
3613
3614         if (coverage_data->len != 0) {
3615                 CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[0];
3616                 first_filename = entry->filename ? entry->filename : "";
3617         } else
3618                 first_filename = "";
3619
3620         image_name = image_name ? image_name : "";
3621         sig = sig ? sig : "";
3622         method_name = method_name ? method_name : "";
3623
3624         ENTER_LOG;
3625
3626         LogBuffer *logbuffer = ensure_logbuf (
3627                 EVENT_SIZE /* event */ +
3628                 strlen (image_name) + 1 /* image name */ +
3629                 strlen (class_name) + 1 /* class name */ +
3630                 strlen (method_name) + 1 /* method name */ +
3631                 strlen (sig) + 1 /* signature */ +
3632                 strlen (first_filename) + 1 /* first file name */ +
3633                 LEB128_SIZE /* token */ +
3634                 LEB128_SIZE /* method id */ +
3635                 LEB128_SIZE /* entries */
3636         );
3637
3638         emit_event (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
3639         emit_string (logbuffer, image_name, strlen (image_name) + 1);
3640         emit_string (logbuffer, class_name, strlen (class_name) + 1);
3641         emit_string (logbuffer, method_name, strlen (method_name) + 1);
3642         emit_string (logbuffer, sig, strlen (sig) + 1);
3643         emit_string (logbuffer, first_filename, strlen (first_filename) + 1);
3644
3645         emit_uvalue (logbuffer, mono_method_get_token (method));
3646         emit_uvalue (logbuffer, method_id);
3647         emit_value (logbuffer, coverage_data->len);
3648
3649         EXIT_LOG;
3650
3651         send_if_needed (prof);
3652
3653         for (i = 0; i < coverage_data->len; i++) {
3654                 CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
3655
3656                 ENTER_LOG;
3657
3658                 LogBuffer *logbuffer = ensure_logbuf (
3659                         EVENT_SIZE /* event */ +
3660                         LEB128_SIZE /* method id */ +
3661                         LEB128_SIZE /* offset */ +
3662                         LEB128_SIZE /* counter */ +
3663                         LEB128_SIZE /* line */ +
3664                         LEB128_SIZE /* column */
3665                 );
3666
3667                 emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
3668                 emit_uvalue (logbuffer, method_id);
3669                 emit_uvalue (logbuffer, entry->offset);
3670                 emit_uvalue (logbuffer, entry->counter);
3671                 emit_uvalue (logbuffer, entry->line);
3672                 emit_uvalue (logbuffer, entry->column);
3673
3674                 EXIT_LOG;
3675
3676                 send_if_needed (prof);
3677         }
3678
3679         method_id++;
3680
3681         g_free (class_name);
3682
3683         g_ptr_array_foreach (coverage_data, free_coverage_entry, NULL);
3684         g_ptr_array_free (coverage_data, TRUE);
3685         coverage_data = NULL;
3686 }
3687
3688 /* This empties the queue */
3689 static guint
3690 count_queue (MonoLockFreeQueue *queue)
3691 {
3692         MonoLockFreeQueueNode *node;
3693         guint count = 0;
3694
3695         while ((node = mono_lock_free_queue_dequeue (queue))) {
3696                 count++;
3697                 mono_thread_hazardous_try_free (node, free);
3698         }
3699
3700         return count;
3701 }
3702
3703 static void
3704 build_class_buffer (gpointer key, gpointer value, gpointer userdata)
3705 {
3706         MonoClass *klass = (MonoClass *)key;
3707         MonoLockFreeQueue *class_methods = (MonoLockFreeQueue *)value;
3708         MonoProfiler *prof = (MonoProfiler *)userdata;
3709         MonoImage *image;
3710         char *class_name;
3711         const char *assembly_name;
3712         int number_of_methods, partially_covered;
3713         guint fully_covered;
3714
3715         image = mono_class_get_image (klass);
3716         assembly_name = mono_image_get_name (image);
3717         class_name = mono_type_get_name (mono_class_get_type (klass));
3718
3719         assembly_name = assembly_name ? assembly_name : "";
3720         number_of_methods = mono_class_num_methods (klass);
3721         fully_covered = count_queue (class_methods);
3722         /* We don't handle partial covered yet */
3723         partially_covered = 0;
3724
3725         ENTER_LOG;
3726
3727         LogBuffer *logbuffer = ensure_logbuf (
3728                 EVENT_SIZE /* event */ +
3729                 strlen (assembly_name) + 1 /* assembly name */ +
3730                 strlen (class_name) + 1 /* class name */ +
3731                 LEB128_SIZE /* no. methods */ +
3732                 LEB128_SIZE /* fully covered */ +
3733                 LEB128_SIZE /* partially covered */
3734         );
3735
3736         emit_event (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
3737         emit_string (logbuffer, assembly_name, strlen (assembly_name) + 1);
3738         emit_string (logbuffer, class_name, strlen (class_name) + 1);
3739         emit_uvalue (logbuffer, number_of_methods);
3740         emit_uvalue (logbuffer, fully_covered);
3741         emit_uvalue (logbuffer, partially_covered);
3742
3743         EXIT_LOG;
3744
3745         send_if_needed (prof);
3746
3747         g_free (class_name);
3748 }
3749
3750 static void
3751 get_coverage_for_image (MonoImage *image, int *number_of_methods, guint *fully_covered, int *partially_covered)
3752 {
3753         MonoLockFreeQueue *image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
3754
3755         *number_of_methods = mono_image_get_table_rows (image, MONO_TABLE_METHOD);
3756         if (image_methods)
3757                 *fully_covered = count_queue (image_methods);
3758         else
3759                 *fully_covered = 0;
3760
3761         // FIXME: We don't handle partially covered yet.
3762         *partially_covered = 0;
3763 }
3764
3765 static void
3766 build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
3767 {
3768         MonoAssembly *assembly = (MonoAssembly *)value;
3769         MonoProfiler *prof = (MonoProfiler *)userdata;
3770         MonoImage *image = mono_assembly_get_image (assembly);
3771         const char *name, *guid, *filename;
3772         int number_of_methods = 0, partially_covered = 0;
3773         guint fully_covered = 0;
3774
3775         name = mono_image_get_name (image);
3776         guid = mono_image_get_guid (image);
3777         filename = mono_image_get_filename (image);
3778
3779         name = name ? name : "";
3780         guid = guid ? guid : "";
3781         filename = filename ? filename : "";
3782
3783         get_coverage_for_image (image, &number_of_methods, &fully_covered, &partially_covered);
3784
3785         ENTER_LOG;
3786
3787         LogBuffer *logbuffer = ensure_logbuf (
3788                 EVENT_SIZE /* event */ +
3789                 strlen (name) + 1 /* name */ +
3790                 strlen (guid) + 1 /* guid */ +
3791                 strlen (filename) + 1 /* file name */ +
3792                 LEB128_SIZE /* no. methods */ +
3793                 LEB128_SIZE /* fully covered */ +
3794                 LEB128_SIZE /* partially covered */
3795         );
3796
3797         emit_event (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
3798         emit_string (logbuffer, name, strlen (name) + 1);
3799         emit_string (logbuffer, guid, strlen (guid) + 1);
3800         emit_string (logbuffer, filename, strlen (filename) + 1);
3801         emit_uvalue (logbuffer, number_of_methods);
3802         emit_uvalue (logbuffer, fully_covered);
3803         emit_uvalue (logbuffer, partially_covered);
3804
3805         EXIT_LOG;
3806
3807         send_if_needed (prof);
3808 }
3809
3810 static void
3811 dump_coverage (MonoProfiler *prof)
3812 {
3813         if (!coverage_initialized)
3814                 return;
3815
3816         COVERAGE_DEBUG(fprintf (stderr, "Coverage: Started dump\n");)
3817         method_id = 0;
3818
3819         mono_os_mutex_lock (&coverage_mutex);
3820         mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, prof);
3821         mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, prof);
3822         mono_conc_hashtable_foreach (coverage_methods, build_method_buffer, prof);
3823         mono_os_mutex_unlock (&coverage_mutex);
3824
3825         COVERAGE_DEBUG(fprintf (stderr, "Coverage: Finished dump\n");)
3826 }
3827
3828 static void
3829 process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method)
3830 {
3831         MonoClass *klass;
3832         MonoImage *image;
3833
3834         if (!coverage_initialized)
3835                 return;
3836
3837         klass = mono_method_get_class (method);
3838         image = mono_class_get_image (klass);
3839
3840         if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)))
3841                 return;
3842
3843         mono_os_mutex_lock (&coverage_mutex);
3844         mono_conc_hashtable_insert (entered_methods, method, method);
3845         mono_os_mutex_unlock (&coverage_mutex);
3846 }
3847
3848 static MonoLockFreeQueueNode *
3849 create_method_node (MonoMethod *method)
3850 {
3851         MethodNode *node = (MethodNode *)g_malloc (sizeof (MethodNode));
3852         mono_lock_free_queue_node_init ((MonoLockFreeQueueNode *) node, FALSE);
3853         node->method = method;
3854
3855         return (MonoLockFreeQueueNode *) node;
3856 }
3857
3858 static gboolean
3859 coverage_filter (MonoProfiler *prof, MonoMethod *method)
3860 {
3861         MonoError error;
3862         MonoClass *klass;
3863         MonoImage *image;
3864         MonoAssembly *assembly;
3865         MonoMethodHeader *header;
3866         guint32 iflags, flags, code_size;
3867         char *fqn, *classname;
3868         gboolean has_positive, found;
3869         MonoLockFreeQueue *image_methods, *class_methods;
3870         MonoLockFreeQueueNode *node;
3871
3872         if (!coverage_initialized)
3873                 return FALSE;
3874
3875         COVERAGE_DEBUG(fprintf (stderr, "Coverage filter for %s\n", mono_method_get_name (method));)
3876
3877         flags = mono_method_get_flags (method, &iflags);
3878         if ((iflags & 0x1000 /*METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL*/) ||
3879             (flags & 0x2000 /*METHOD_ATTRIBUTE_PINVOKE_IMPL*/)) {
3880                 COVERAGE_DEBUG(fprintf (stderr, "   Internal call or pinvoke - ignoring\n");)
3881                 return FALSE;
3882         }
3883
3884         // Don't need to do anything else if we're already tracking this method
3885         if (mono_conc_hashtable_lookup (coverage_methods, method)) {
3886                 COVERAGE_DEBUG(fprintf (stderr, "   Already tracking\n");)
3887                 return TRUE;
3888         }
3889
3890         klass = mono_method_get_class (method);
3891         image = mono_class_get_image (klass);
3892
3893         // Don't handle coverage for the core assemblies
3894         if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)) != NULL)
3895                 return FALSE;
3896
3897         if (prof->coverage_filters) {
3898                 /* Check already filtered classes first */
3899                 if (mono_conc_hashtable_lookup (filtered_classes, klass)) {
3900                         COVERAGE_DEBUG(fprintf (stderr, "   Already filtered\n");)
3901                         return FALSE;
3902                 }
3903
3904                 classname = mono_type_get_name (mono_class_get_type (klass));
3905
3906                 fqn = g_strdup_printf ("[%s]%s", mono_image_get_name (image), classname);
3907
3908                 COVERAGE_DEBUG(fprintf (stderr, "   Looking for %s in filter\n", fqn);)
3909                 // Check positive filters first
3910                 has_positive = FALSE;
3911                 found = FALSE;
3912                 for (guint i = 0; i < prof->coverage_filters->len; ++i) {
3913                         char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
3914
3915                         if (filter [0] == '+') {
3916                                 filter = &filter [1];
3917
3918                                 COVERAGE_DEBUG(fprintf (stderr, "   Checking against +%s ...", filter);)
3919
3920                                 if (strstr (fqn, filter) != NULL) {
3921                                         COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
3922                                         found = TRUE;
3923                                 } else
3924                                         COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
3925
3926                                 has_positive = TRUE;
3927                         }
3928                 }
3929
3930                 if (has_positive && !found) {
3931                         COVERAGE_DEBUG(fprintf (stderr, "   Positive match was not found\n");)
3932
3933                         mono_os_mutex_lock (&coverage_mutex);
3934                         mono_conc_hashtable_insert (filtered_classes, klass, klass);
3935                         mono_os_mutex_unlock (&coverage_mutex);
3936                         g_free (fqn);
3937                         g_free (classname);
3938
3939                         return FALSE;
3940                 }
3941
3942                 for (guint i = 0; i < prof->coverage_filters->len; ++i) {
3943                         // FIXME: Is substring search sufficient?
3944                         char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
3945                         if (filter [0] == '+')
3946                                 continue;
3947
3948                         // Skip '-'
3949                         filter = &filter [1];
3950                         COVERAGE_DEBUG(fprintf (stderr, "   Checking against -%s ...", filter);)
3951
3952                         if (strstr (fqn, filter) != NULL) {
3953                                 COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
3954
3955                                 mono_os_mutex_lock (&coverage_mutex);
3956                                 mono_conc_hashtable_insert (filtered_classes, klass, klass);
3957                                 mono_os_mutex_unlock (&coverage_mutex);
3958                                 g_free (fqn);
3959                                 g_free (classname);
3960
3961                                 return FALSE;
3962                         } else
3963                                 COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
3964
3965                 }
3966
3967                 g_free (fqn);
3968                 g_free (classname);
3969         }
3970
3971         COVERAGE_DEBUG(fprintf (stderr, "   Handling coverage for %s\n", mono_method_get_name (method));)
3972         header = mono_method_get_header_checked (method, &error);
3973         mono_error_cleanup (&error);
3974
3975         mono_method_header_get_code (header, &code_size, NULL);
3976
3977         assembly = mono_image_get_assembly (image);
3978
3979         // Need to keep the assemblies around for as long as they are kept in the hashtable
3980         // Nunit, for example, has a habit of unloading them before the coverage statistics are
3981         // generated causing a crash. See https://bugzilla.xamarin.com/show_bug.cgi?id=39325
3982         mono_assembly_addref (assembly);
3983
3984         mono_os_mutex_lock (&coverage_mutex);
3985         mono_conc_hashtable_insert (coverage_methods, method, method);
3986         mono_conc_hashtable_insert (coverage_assemblies, assembly, assembly);
3987         mono_os_mutex_unlock (&coverage_mutex);
3988
3989         image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
3990
3991         if (image_methods == NULL) {
3992                 image_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue));
3993                 mono_lock_free_queue_init (image_methods);
3994                 mono_os_mutex_lock (&coverage_mutex);
3995                 mono_conc_hashtable_insert (image_to_methods, image, image_methods);
3996                 mono_os_mutex_unlock (&coverage_mutex);
3997         }
3998
3999         node = create_method_node (method);
4000         mono_lock_free_queue_enqueue (image_methods, node);
4001
4002         class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (coverage_classes, klass);
4003
4004         if (class_methods == NULL) {
4005                 class_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue));
4006                 mono_lock_free_queue_init (class_methods);
4007                 mono_os_mutex_lock (&coverage_mutex);
4008                 mono_conc_hashtable_insert (coverage_classes, klass, class_methods);
4009                 mono_os_mutex_unlock (&coverage_mutex);
4010         }
4011
4012         node = create_method_node (method);
4013         mono_lock_free_queue_enqueue (class_methods, node);
4014
4015         return TRUE;
4016 }
4017
4018 #define LINE_BUFFER_SIZE 4096
4019 /* Max file limit of 128KB */
4020 #define MAX_FILE_SIZE 128 * 1024
4021 static char *
4022 get_file_content (FILE *stream)
4023 {
4024         char *buffer;
4025         ssize_t bytes_read;
4026         long filesize;
4027         int res, offset = 0;
4028
4029         res = fseek (stream, 0, SEEK_END);
4030         if (res < 0)
4031           return NULL;
4032
4033         filesize = ftell (stream);
4034         if (filesize < 0)
4035           return NULL;
4036
4037         res = fseek (stream, 0, SEEK_SET);
4038         if (res < 0)
4039           return NULL;
4040
4041         if (filesize > MAX_FILE_SIZE)
4042           return NULL;
4043
4044         buffer = (char *)g_malloc ((filesize + 1) * sizeof (char));
4045         while ((bytes_read = fread (buffer + offset, 1, LINE_BUFFER_SIZE, stream)) > 0)
4046                 offset += bytes_read;
4047
4048         /* NULL terminate our buffer */
4049         buffer[filesize] = '\0';
4050         return buffer;
4051 }
4052
4053 static char *
4054 get_next_line (char *contents, char **next_start)
4055 {
4056         char *p = contents;
4057
4058         if (p == NULL || *p == '\0') {
4059                 *next_start = NULL;
4060                 return NULL;
4061         }
4062
4063         while (*p != '\n' && *p != '\0')
4064                 p++;
4065
4066         if (*p == '\n') {
4067                 *p = '\0';
4068                 *next_start = p + 1;
4069         } else
4070                 *next_start = NULL;
4071
4072         return contents;
4073 }
4074
4075 static void
4076 init_suppressed_assemblies (void)
4077 {
4078         char *content;
4079         char *line;
4080         FILE *sa_file;
4081
4082         suppressed_assemblies = mono_conc_hashtable_new (g_str_hash, g_str_equal);
4083         sa_file = fopen (SUPPRESSION_DIR "/mono-profiler-log.suppression", "r");
4084         if (sa_file == NULL)
4085                 return;
4086
4087         /* Don't need to free @content as it is referred to by the lines stored in @suppressed_assemblies */
4088         content = get_file_content (sa_file);
4089         if (content == NULL) {
4090                 g_error ("mono-profiler-log.suppression is greater than 128kb - aborting\n");
4091         }
4092
4093         while ((line = get_next_line (content, &content))) {
4094                 line = g_strchomp (g_strchug (line));
4095                 /* No locking needed as we're doing initialization */
4096                 mono_conc_hashtable_insert (suppressed_assemblies, line, line);
4097         }
4098
4099         fclose (sa_file);
4100 }
4101
4102 #endif /* DISABLE_HELPER_THREAD */
4103
4104 static void
4105 coverage_init (MonoProfiler *prof)
4106 {
4107 #ifndef DISABLE_HELPER_THREAD
4108         assert (!coverage_initialized);
4109
4110         COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");)
4111
4112         mono_os_mutex_init (&coverage_mutex);
4113         coverage_methods = mono_conc_hashtable_new (NULL, NULL);
4114         coverage_assemblies = mono_conc_hashtable_new (NULL, NULL);
4115         coverage_classes = mono_conc_hashtable_new (NULL, NULL);
4116         filtered_classes = mono_conc_hashtable_new (NULL, NULL);
4117         entered_methods = mono_conc_hashtable_new (NULL, NULL);
4118         image_to_methods = mono_conc_hashtable_new (NULL, NULL);
4119         init_suppressed_assemblies ();
4120
4121         coverage_initialized = TRUE;
4122 #endif /* DISABLE_HELPER_THREAD */
4123 }
4124
4125 static void
4126 unref_coverage_assemblies (gpointer key, gpointer value, gpointer userdata)
4127 {
4128         MonoAssembly *assembly = (MonoAssembly *)value;
4129         mono_assembly_close (assembly);
4130 }
4131
4132 static void
4133 free_sample_hit (gpointer p)
4134 {
4135         mono_lock_free_free (p, SAMPLE_BLOCK_SIZE);
4136 }
4137
4138 static void
4139 cleanup_reusable_samples (MonoProfiler *prof)
4140 {
4141         SampleHit *sample;
4142
4143         while ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->sample_reuse_queue)))
4144                 mono_thread_hazardous_try_free (sample, free_sample_hit);
4145 }
4146
4147 static void
4148 log_shutdown (MonoProfiler *prof)
4149 {
4150         void *res;
4151
4152         in_shutdown = 1;
4153 #ifndef DISABLE_HELPER_THREAD
4154         counters_and_perfcounters_sample (prof);
4155
4156         dump_coverage (prof);
4157
4158         if (prof->command_port) {
4159                 char c = 1;
4160                 ign_res (write (prof->pipes [1], &c, 1));
4161                 pthread_join (prof->helper_thread, &res);
4162         }
4163 #endif
4164 #if USE_PERF_EVENTS
4165         if (perf_data) {
4166                 int i;
4167                 for (i = 0; i < num_perf; ++i)
4168                         read_perf_mmap (prof, i);
4169         }
4170 #endif
4171
4172         /*
4173          * Ensure that we empty the LLS completely, even if some nodes are
4174          * not immediately removed upon calling mono_lls_remove (), by
4175          * iterating until the head is NULL.
4176          */
4177         while (profiler_thread_list.head) {
4178                 MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
4179                         remove_thread (prof, thread, FALSE);
4180                 } MONO_LLS_FOREACH_SAFE_END
4181         }
4182
4183         InterlockedWrite (&prof->run_dumper_thread, 0);
4184         mono_os_sem_post (&prof->dumper_queue_sem);
4185         pthread_join (prof->dumper_thread, &res);
4186         mono_os_sem_destroy (&prof->dumper_queue_sem);
4187
4188         InterlockedWrite (&prof->run_writer_thread, 0);
4189         mono_os_sem_post (&prof->writer_queue_sem);
4190         pthread_join (prof->writer_thread, &res);
4191         mono_os_sem_destroy (&prof->writer_queue_sem);
4192
4193         cleanup_reusable_samples (prof);
4194
4195         g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why is the reader count still non-zero?");
4196         g_assert (!InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why does someone still hold the exclusive lock?");
4197
4198 #if defined (HAVE_SYS_ZLIB)
4199         if (prof->gzfile)
4200                 gzclose (prof->gzfile);
4201 #endif
4202         if (prof->pipe_output)
4203                 pclose (prof->file);
4204         else
4205                 fclose (prof->file);
4206
4207         mono_conc_hashtable_destroy (prof->method_table);
4208         mono_os_mutex_destroy (&prof->method_table_mutex);
4209
4210         if (coverage_initialized) {
4211                 mono_os_mutex_lock (&coverage_mutex);
4212                 mono_conc_hashtable_foreach (coverage_assemblies, unref_coverage_assemblies, prof);
4213                 mono_os_mutex_unlock (&coverage_mutex);
4214
4215                 mono_conc_hashtable_destroy (coverage_methods);
4216                 mono_conc_hashtable_destroy (coverage_assemblies);
4217                 mono_conc_hashtable_destroy (coverage_classes);
4218                 mono_conc_hashtable_destroy (filtered_classes);
4219
4220                 mono_conc_hashtable_destroy (entered_methods);
4221                 mono_conc_hashtable_destroy (image_to_methods);
4222                 mono_conc_hashtable_destroy (suppressed_assemblies);
4223                 mono_os_mutex_destroy (&coverage_mutex);
4224         }
4225
4226         PROF_TLS_FREE ();
4227
4228         free (prof);
4229 }
4230
4231 static char*
4232 new_filename (const char* filename)
4233 {
4234         time_t t = time (NULL);
4235         int pid = process_id ();
4236         char pid_buf [16];
4237         char time_buf [16];
4238         char *res, *d;
4239         const char *p;
4240         int count_dates = 0;
4241         int count_pids = 0;
4242         int s_date, s_pid;
4243         struct tm *ts;
4244         for (p = filename; *p; p++) {
4245                 if (*p != '%')
4246                         continue;
4247                 p++;
4248                 if (*p == 't')
4249                         count_dates++;
4250                 else if (*p == 'p')
4251                         count_pids++;
4252                 else if (*p == 0)
4253                         break;
4254         }
4255         if (!count_dates && !count_pids)
4256                 return pstrdup (filename);
4257         snprintf (pid_buf, sizeof (pid_buf), "%d", pid);
4258         ts = gmtime (&t);
4259         snprintf (time_buf, sizeof (time_buf), "%d%02d%02d%02d%02d%02d",
4260                 1900 + ts->tm_year, 1 + ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
4261         s_date = strlen (time_buf);
4262         s_pid = strlen (pid_buf);
4263         d = res = (char *)malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids);
4264         for (p = filename; *p; p++) {
4265                 if (*p != '%') {
4266                         *d++ = *p;
4267                         continue;
4268                 }
4269                 p++;
4270                 if (*p == 't') {
4271                         strcpy (d, time_buf);
4272                         d += s_date;
4273                         continue;
4274                 } else if (*p == 'p') {
4275                         strcpy (d, pid_buf);
4276                         d += s_pid;
4277                         continue;
4278                 } else if (*p == '%') {
4279                         *d++ = '%';
4280                         continue;
4281                 } else if (*p == 0)
4282                         break;
4283                 *d++ = '%';
4284                 *d++ = *p;
4285         }
4286         *d = 0;
4287         return res;
4288 }
4289
4290 //this is exposed by the JIT, but it's not meant to be a supported API for now.
4291 extern void mono_threads_attach_tools_thread (void);
4292
4293 #ifndef DISABLE_HELPER_THREAD
4294
4295 static void*
4296 helper_thread (void* arg)
4297 {
4298         MonoProfiler* prof = (MonoProfiler *)arg;
4299         int command_socket;
4300         int len;
4301         char buf [64];
4302         MonoThread *thread = NULL;
4303
4304         mono_threads_attach_tools_thread ();
4305         mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
4306
4307         init_thread (FALSE);
4308
4309         //fprintf (stderr, "Server listening\n");
4310         command_socket = -1;
4311         while (1) {
4312                 fd_set rfds;
4313                 struct timeval tv;
4314                 int max_fd = -1;
4315                 FD_ZERO (&rfds);
4316                 FD_SET (prof->server_socket, &rfds);
4317                 max_fd = prof->server_socket;
4318                 FD_SET (prof->pipes [0], &rfds);
4319                 if (max_fd < prof->pipes [0])
4320                         max_fd = prof->pipes [0];
4321                 if (command_socket >= 0) {
4322                         FD_SET (command_socket, &rfds);
4323                         if (max_fd < command_socket)
4324                                 max_fd = command_socket;
4325                 }
4326 #if USE_PERF_EVENTS
4327                 if (perf_data) {
4328                         int i;
4329                         for ( i = 0; i < num_perf; ++i) {
4330                                 if (perf_data [i].perf_fd < 0)
4331                                         continue;
4332                                 FD_SET (perf_data [i].perf_fd, &rfds);
4333                                 if (max_fd < perf_data [i].perf_fd)
4334                                         max_fd = perf_data [i].perf_fd;
4335                         }
4336                 }
4337 #endif
4338
4339                 counters_and_perfcounters_sample (prof);
4340
4341                 buffer_lock_excl ();
4342
4343                 sync_point (prof, SYNC_POINT_PERIODIC);
4344
4345                 buffer_unlock_excl ();
4346
4347                 tv.tv_sec = 1;
4348                 tv.tv_usec = 0;
4349                 len = select (max_fd + 1, &rfds, NULL, NULL, &tv);
4350
4351                 if (len < 0) {
4352                         if (errno == EINTR)
4353                                 continue;
4354
4355                         g_warning ("Error in proflog server: %s", strerror (errno));
4356                         return NULL;
4357                 }
4358
4359                 if (FD_ISSET (prof->pipes [0], &rfds)) {
4360                         char c;
4361                         read (prof->pipes [0], &c, 1);
4362                         if (thread)
4363                                 mono_thread_detach (thread);
4364                         if (do_debug)
4365                                 fprintf (stderr, "helper shutdown\n");
4366 #if USE_PERF_EVENTS
4367                         if (perf_data) {
4368                                 int i;
4369                                 for ( i = 0; i < num_perf; ++i) {
4370                                         if (perf_data [i].perf_fd < 0)
4371                                                 continue;
4372                                         if (FD_ISSET (perf_data [i].perf_fd, &rfds))
4373                                                 read_perf_mmap (prof, i);
4374                                 }
4375                         }
4376 #endif
4377                         safe_send_threadless (prof);
4378                         return NULL;
4379                 }
4380 #if USE_PERF_EVENTS
4381                 if (perf_data) {
4382                         int i;
4383                         for ( i = 0; i < num_perf; ++i) {
4384                                 if (perf_data [i].perf_fd < 0)
4385                                         continue;
4386                                 if (FD_ISSET (perf_data [i].perf_fd, &rfds)) {
4387                                         read_perf_mmap (prof, i);
4388                                         send_if_needed_threadless (prof);
4389                                 }
4390                         }
4391                 }
4392 #endif
4393                 if (command_socket >= 0 && FD_ISSET (command_socket, &rfds)) {
4394                         len = read (command_socket, buf, sizeof (buf) - 1);
4395                         if (len < 0)
4396                                 continue;
4397                         if (len == 0) {
4398                                 close (command_socket);
4399                                 command_socket = -1;
4400                                 continue;
4401                         }
4402                         buf [len] = 0;
4403                         if (strcmp (buf, "heapshot\n") == 0) {
4404                                 heapshot_requested = 1;
4405                                 //fprintf (stderr, "perform heapshot\n");
4406                                 if (InterlockedRead (&runtime_inited) && !thread) {
4407                                         thread = mono_thread_attach (mono_get_root_domain ());
4408                                         /*fprintf (stderr, "attached\n");*/
4409                                 }
4410                                 if (thread) {
4411                                         process_requests (prof);
4412                                         mono_thread_detach (thread);
4413                                         thread = NULL;
4414                                 }
4415                         }
4416                         continue;
4417                 }
4418                 if (!FD_ISSET (prof->server_socket, &rfds)) {
4419                         continue;
4420                 }
4421                 command_socket = accept (prof->server_socket, NULL, NULL);
4422                 if (command_socket < 0)
4423                         continue;
4424                 //fprintf (stderr, "Accepted connection\n");
4425         }
4426
4427         mono_thread_info_detach ();
4428
4429         return NULL;
4430 }
4431
4432 static int
4433 start_helper_thread (MonoProfiler* prof)
4434 {
4435         struct sockaddr_in server_address;
4436         int r;
4437         socklen_t slen;
4438         if (pipe (prof->pipes) < 0) {
4439                 fprintf (stderr, "Cannot create pipe\n");
4440                 return 0;
4441         }
4442         prof->server_socket = socket (PF_INET, SOCK_STREAM, 0);
4443         if (prof->server_socket < 0) {
4444                 fprintf (stderr, "Cannot create server socket\n");
4445                 return 0;
4446         }
4447         memset (&server_address, 0, sizeof (server_address));
4448         server_address.sin_family = AF_INET;
4449         server_address.sin_addr.s_addr = INADDR_ANY;
4450         server_address.sin_port = htons (prof->command_port);
4451         if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) < 0) {
4452                 fprintf (stderr, "Cannot bind server socket, port: %d: %s\n", prof->command_port, strerror (errno));
4453                 close (prof->server_socket);
4454                 return 0;
4455         }
4456         if (listen (prof->server_socket, 1) < 0) {
4457                 fprintf (stderr, "Cannot listen server socket\n");
4458                 close (prof->server_socket);
4459                 return 0;
4460         }
4461         slen = sizeof (server_address);
4462         if (getsockname (prof->server_socket, (struct sockaddr *)&server_address, &slen) == 0) {
4463                 prof->command_port = ntohs (server_address.sin_port);
4464                 /*fprintf (stderr, "Assigned server port: %d\n", prof->command_port);*/
4465         }
4466
4467         r = pthread_create (&prof->helper_thread, NULL, helper_thread, prof);
4468         if (r) {
4469                 close (prof->server_socket);
4470                 return 0;
4471         }
4472         return 1;
4473 }
4474 #endif
4475
4476 static void
4477 free_writer_entry (gpointer p)
4478 {
4479         mono_lock_free_free (p, WRITER_ENTRY_BLOCK_SIZE);
4480 }
4481
4482 static gboolean
4483 handle_writer_queue_entry (MonoProfiler *prof)
4484 {
4485         WriterQueueEntry *entry;
4486
4487         if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
4488                 if (!entry->methods)
4489                         goto no_methods;
4490
4491                 LogBuffer *buf = NULL;
4492
4493                 /*
4494                  * Encode the method events in a temporary log buffer that we
4495                  * flush to disk before the main buffer, ensuring that all
4496                  * methods have metadata emitted before they're referenced.
4497                  *
4498                  * We use a 'proper' thread-local buffer for this as opposed
4499                  * to allocating and freeing a buffer by hand because the call
4500                  * to mono_method_full_name () below may trigger class load
4501                  * events when it retrieves the signature of the method. So a
4502                  * thread-local buffer needs to exist when such events occur.
4503                  */
4504                 for (guint i = 0; i < entry->methods->len; i++) {
4505                         MethodInfo *info = (MethodInfo *) g_ptr_array_index (entry->methods, i);
4506
4507                         if (mono_conc_hashtable_lookup (prof->method_table, info->method))
4508                                 goto free_info; // This method already has metadata emitted.
4509
4510                         /*
4511                          * Other threads use this hash table to get a general
4512                          * idea of whether a method has already been emitted to
4513                          * the stream. Due to the way we add to this table, it
4514                          * can easily happen that multiple threads queue up the
4515                          * same methods, but that's OK since eventually all
4516                          * methods will be in this table and the thread-local
4517                          * method lists will just be empty for the rest of the
4518                          * app's lifetime.
4519                          */
4520                         mono_os_mutex_lock (&prof->method_table_mutex);
4521                         mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
4522                         mono_os_mutex_unlock (&prof->method_table_mutex);
4523
4524                         char *name = mono_method_full_name (info->method, 1);
4525                         int nlen = strlen (name) + 1;
4526                         void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
4527                         int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
4528
4529                         buf = ensure_logbuf_unsafe (
4530                                 EVENT_SIZE /* event */ +
4531                                 LEB128_SIZE /* method */ +
4532                                 LEB128_SIZE /* start */ +
4533                                 LEB128_SIZE /* size */ +
4534                                 nlen /* name */
4535                         );
4536
4537                         emit_event_time (buf, TYPE_JIT | TYPE_METHOD, info->time);
4538                         emit_method_inner (buf, info->method);
4539                         emit_ptr (buf, cstart);
4540                         emit_value (buf, csize);
4541
4542                         memcpy (buf->cursor, name, nlen);
4543                         buf->cursor += nlen;
4544
4545                         mono_free (name);
4546
4547                 free_info:
4548                         free (info);
4549                 }
4550
4551                 g_ptr_array_free (entry->methods, TRUE);
4552
4553                 if (buf) {
4554                         dump_buffer_threadless (prof, buf);
4555                         init_buffer_state (PROF_TLS_GET ());
4556                 }
4557
4558         no_methods:
4559                 dump_buffer (prof, entry->buffer);
4560
4561                 mono_thread_hazardous_try_free (entry, free_writer_entry);
4562
4563                 return TRUE;
4564         }
4565
4566         return FALSE;
4567 }
4568
4569 static void *
4570 writer_thread (void *arg)
4571 {
4572         MonoProfiler *prof = (MonoProfiler *)arg;
4573
4574         mono_threads_attach_tools_thread ();
4575         mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler writer");
4576
4577         dump_header (prof);
4578
4579         MonoProfilerThread *thread = init_thread (FALSE);
4580
4581         while (InterlockedRead (&prof->run_writer_thread)) {
4582                 mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
4583                 handle_writer_queue_entry (prof);
4584         }
4585
4586         /* Drain any remaining entries on shutdown. */
4587         while (handle_writer_queue_entry (prof));
4588
4589         free_buffer (thread->buffer, thread->buffer->size);
4590         deinit_thread (thread);
4591
4592         mono_thread_info_detach ();
4593
4594         return NULL;
4595 }
4596
4597 static int
4598 start_writer_thread (MonoProfiler* prof)
4599 {
4600         InterlockedWrite (&prof->run_writer_thread, 1);
4601
4602         return !pthread_create (&prof->writer_thread, NULL, writer_thread, prof);
4603 }
4604
4605 static void
4606 reuse_sample_hit (gpointer p)
4607 {
4608         SampleHit *sample = p;
4609
4610         mono_lock_free_queue_node_unpoison (&sample->node);
4611         mono_lock_free_queue_enqueue (&sample->prof->sample_reuse_queue, &sample->node);
4612 }
4613
4614 static gboolean
4615 handle_dumper_queue_entry (MonoProfiler *prof)
4616 {
4617         SampleHit *sample;
4618
4619         if ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->dumper_queue))) {
4620                 for (int i = 0; i < sample->count; ++i) {
4621                         MonoMethod *method = sample->frames [i].method;
4622                         MonoDomain *domain = sample->frames [i].domain;
4623                         void *address = sample->frames [i].base_address;
4624
4625                         if (!method) {
4626                                 g_assert (domain && "What happened to the domain pointer?");
4627                                 g_assert (address && "What happened to the instruction pointer?");
4628
4629                                 MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *) address);
4630
4631                                 if (ji)
4632                                         sample->frames [i].method = mono_jit_info_get_method (ji);
4633                         }
4634                 }
4635
4636                 LogBuffer *logbuffer = ensure_logbuf_unsafe (
4637                         EVENT_SIZE /* event */ +
4638                         BYTE_SIZE /* type */ +
4639                         LEB128_SIZE /* tid */ +
4640                         LEB128_SIZE /* count */ +
4641                         1 * (
4642                                 LEB128_SIZE /* ip */
4643                         ) +
4644                         LEB128_SIZE /* managed count */ +
4645                         sample->count * (
4646                                 LEB128_SIZE /* method */
4647                         )
4648                 );
4649
4650                 emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time);
4651                 emit_byte (logbuffer, sample_type);
4652                 emit_ptr (logbuffer, (void *) sample->tid);
4653                 emit_value (logbuffer, 1);
4654
4655                 // TODO: Actual native unwinding.
4656                 for (int i = 0; i < 1; ++i) {
4657                         emit_ptr (logbuffer, sample->ip);
4658                         add_code_pointer ((uintptr_t) sample->ip);
4659                 }
4660
4661                 /* new in data version 6 */
4662                 emit_uvalue (logbuffer, sample->count);
4663
4664                 for (int i = 0; i < sample->count; ++i)
4665                         emit_method (prof, logbuffer, sample->frames [i].method);
4666
4667                 mono_thread_hazardous_try_free (sample, reuse_sample_hit);
4668
4669                 dump_unmanaged_coderefs (prof);
4670
4671                 send_if_needed_threadless (prof);
4672         }
4673
4674         return FALSE;
4675 }
4676
4677 static void *
4678 dumper_thread (void *arg)
4679 {
4680         MonoProfiler *prof = (MonoProfiler *)arg;
4681
4682         mono_threads_attach_tools_thread ();
4683         mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
4684
4685         MonoProfilerThread *thread = init_thread (FALSE);
4686
4687         while (InterlockedRead (&prof->run_dumper_thread)) {
4688                 mono_os_sem_wait (&prof->dumper_queue_sem, MONO_SEM_FLAGS_NONE);
4689                 handle_dumper_queue_entry (prof);
4690         }
4691
4692         /* Drain any remaining entries on shutdown. */
4693         while (handle_dumper_queue_entry (prof));
4694
4695         safe_send_threadless (prof);
4696         deinit_thread (thread);
4697
4698         mono_thread_info_detach ();
4699
4700         return NULL;
4701 }
4702
4703 static int
4704 start_dumper_thread (MonoProfiler* prof)
4705 {
4706         InterlockedWrite (&prof->run_dumper_thread, 1);
4707
4708         return !pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof);
4709 }
4710
4711 static void
4712 runtime_initialized (MonoProfiler *profiler)
4713 {
4714 #ifndef DISABLE_HELPER_THREAD
4715         if (hs_mode_ondemand || need_helper_thread) {
4716                 if (!start_helper_thread (profiler))
4717                         profiler->command_port = 0;
4718         }
4719 #endif
4720
4721         start_writer_thread (profiler);
4722         start_dumper_thread (profiler);
4723
4724         InterlockedWrite (&runtime_inited, 1);
4725 #ifndef DISABLE_HELPER_THREAD
4726         counters_init (profiler);
4727         counters_sample (profiler, 0);
4728 #endif
4729         /* ensure the main thread data and startup are available soon */
4730         safe_send (profiler);
4731 }
4732
4733 static MonoProfiler*
4734 create_profiler (const char *filename, GPtrArray *filters)
4735 {
4736         MonoProfiler *prof;
4737         char *nf;
4738         int force_delete = 0;
4739         prof = (MonoProfiler *)calloc (1, sizeof (MonoProfiler));
4740
4741         prof->command_port = command_port;
4742         if (filename && *filename == '-') {
4743                 force_delete = 1;
4744                 filename++;
4745         }
4746         if (!filename) {
4747                 if (do_report)
4748                         filename = "|mprof-report -";
4749                 else
4750                         filename = "output.mlpd";
4751                 nf = (char*)filename;
4752         } else {
4753                 nf = new_filename (filename);
4754                 if (do_report) {
4755                         int s = strlen (nf) + 32;
4756                         char *p = (char *)malloc (s);
4757                         snprintf (p, s, "|mprof-report '--out=%s' -", nf);
4758                         free (nf);
4759                         nf = p;
4760                 }
4761         }
4762         if (*nf == '|') {
4763                 prof->file = popen (nf + 1, "w");
4764                 prof->pipe_output = 1;
4765         } else if (*nf == '#') {
4766                 int fd = strtol (nf + 1, NULL, 10);
4767                 prof->file = fdopen (fd, "a");
4768         } else {
4769                 if (force_delete)
4770                         unlink (nf);
4771                 prof->file = fopen (nf, "wb");
4772         }
4773         if (!prof->file) {
4774                 fprintf (stderr, "Cannot create profiler output: %s\n", nf);
4775                 exit (1);
4776         }
4777 #if defined (HAVE_SYS_ZLIB)
4778         if (use_zip)
4779                 prof->gzfile = gzdopen (fileno (prof->file), "wb");
4780 #endif
4781 #if USE_PERF_EVENTS
4782         if (sample_type && !do_mono_sample)
4783                 need_helper_thread = setup_perf_event ();
4784         if (!perf_data) {
4785                 /* FIXME: warn if different freq or sample type */
4786                 do_mono_sample = 1;
4787         }
4788 #endif
4789         if (do_mono_sample) {
4790                 need_helper_thread = 1;
4791         }
4792         if (do_counters && !need_helper_thread) {
4793                 need_helper_thread = 1;
4794         }
4795
4796         /*
4797          * If you hit this assert while increasing MAX_FRAMES, you need to increase
4798          * SAMPLE_BLOCK_SIZE as well.
4799          */
4800         g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE));
4801
4802         // FIXME: We should free this stuff too.
4803         mono_lock_free_allocator_init_size_class (&prof->sample_size_class, SAMPLE_SLOT_SIZE (num_frames), SAMPLE_BLOCK_SIZE);
4804         mono_lock_free_allocator_init_allocator (&prof->sample_allocator, &prof->sample_size_class);
4805
4806         mono_lock_free_queue_init (&prof->sample_reuse_queue);
4807
4808 #ifdef DISABLE_HELPER_THREAD
4809         if (hs_mode_ondemand)
4810                 fprintf (stderr, "Ondemand heapshot unavailable on this arch.\n");
4811
4812         if (do_coverage)
4813                 fprintf (stderr, "Coverage unavailable on this arch.\n");
4814
4815 #endif
4816
4817         g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
4818
4819         // FIXME: We should free this stuff too.
4820         mono_lock_free_allocator_init_size_class (&prof->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
4821         mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class);
4822
4823         mono_lock_free_queue_init (&prof->writer_queue);
4824         mono_os_sem_init (&prof->writer_queue_sem, 0);
4825
4826         mono_lock_free_queue_init (&prof->dumper_queue);
4827         mono_os_sem_init (&prof->dumper_queue_sem, 0);
4828
4829         mono_os_mutex_init (&prof->method_table_mutex);
4830         prof->method_table = mono_conc_hashtable_new (NULL, NULL);
4831
4832         if (do_coverage)
4833                 coverage_init (prof);
4834         prof->coverage_filters = filters;
4835
4836         prof->startup_time = current_time ();
4837         return prof;
4838 }
4839
4840 static void
4841 usage (int do_exit)
4842 {
4843         printf ("Log profiler version %d.%d (format: %d)\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
4844         printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
4845         printf ("Options:\n");
4846         printf ("\thelp                 show this usage info\n");
4847         printf ("\t[no]alloc            enable/disable recording allocation info\n");
4848         printf ("\t[no]calls            enable/disable recording enter/leave method events\n");
4849         printf ("\theapshot[=MODE]      record heap shot info (by default at each major collection)\n");
4850         printf ("\t                     MODE: every XXms milliseconds, every YYgc collections, ondemand\n");
4851         printf ("\tcounters             sample counters every 1s\n");
4852         printf ("\tsample[=TYPE]        use statistical sampling mode (by default cycles/100)\n");
4853         printf ("\t                     TYPE: cycles,instr,cacherefs,cachemiss,branches,branchmiss\n");
4854         printf ("\t                     TYPE can be followed by /FREQUENCY\n");
4855         printf ("\ttime=fast            use a faster (but more inaccurate) timer\n");
4856         printf ("\tmaxframes=NUM        collect up to NUM stack frames\n");
4857         printf ("\tcalldepth=NUM        ignore method events for call chain depth bigger than NUM\n");
4858         printf ("\toutput=FILENAME      write the data to file FILENAME (-FILENAME to overwrite)\n");
4859         printf ("\toutput=|PROGRAM      write the data to the stdin of PROGRAM\n");
4860         printf ("\t                     %%t is subtituted with date and time, %%p with the pid\n");
4861         printf ("\treport               create a report instead of writing the raw data to a file\n");
4862         printf ("\tzip                  compress the output data\n");
4863         printf ("\tport=PORTNUM         use PORTNUM for the listening command server\n");
4864         printf ("\tcoverage             enable collection of code coverage data\n");
4865         printf ("\tcovfilter=ASSEMBLY   add an assembly to the code coverage filters\n");
4866         printf ("\t                     add a + to include the assembly or a - to exclude it\n");
4867         printf ("\t                     filter=-mscorlib\n");
4868         printf ("\tcovfilter-file=FILE  use FILE to generate the list of assemblies to be filtered\n");
4869         if (do_exit)
4870                 exit (1);
4871 }
4872
4873 static const char*
4874 match_option (const char* p, const char *opt, char **rval)
4875 {
4876         int len = strlen (opt);
4877         if (strncmp (p, opt, len) == 0) {
4878                 if (rval) {
4879                         if (p [len] == '=' && p [len + 1]) {
4880                                 const char *opt = p + len + 1;
4881                                 const char *end = strchr (opt, ',');
4882                                 char *val;
4883                                 int l;
4884                                 if (end == NULL) {
4885                                         l = strlen (opt);
4886                                 } else {
4887                                         l = end - opt;
4888                                 }
4889                                 val = (char *)malloc (l + 1);
4890                                 memcpy (val, opt, l);
4891                                 val [l] = 0;
4892                                 *rval = val;
4893                                 return opt + l;
4894                         }
4895                         if (p [len] == 0 || p [len] == ',') {
4896                                 *rval = NULL;
4897                                 return p + len + (p [len] == ',');
4898                         }
4899                         usage (1);
4900                 } else {
4901                         if (p [len] == 0)
4902                                 return p + len;
4903                         if (p [len] == ',')
4904                                 return p + len + 1;
4905                 }
4906         }
4907         return p;
4908 }
4909
4910 typedef struct {
4911         const char *name;
4912         int sample_mode;
4913 } SampleMode;
4914
4915 static const SampleMode sample_modes [] = {
4916         {"cycles", SAMPLE_CYCLES},
4917         {"instr", SAMPLE_INSTRUCTIONS},
4918         {"cachemiss", SAMPLE_CACHE_MISSES},
4919         {"cacherefs", SAMPLE_CACHE_REFS},
4920         {"branches", SAMPLE_BRANCHES},
4921         {"branchmiss", SAMPLE_BRANCH_MISSES},
4922         {NULL, 0}
4923 };
4924
4925 static void
4926 set_sample_mode (char* val, int allow_empty)
4927 {
4928         char *end;
4929         char *maybe_freq = NULL;
4930         unsigned int count;
4931         const SampleMode *smode = sample_modes;
4932 #ifndef USE_PERF_EVENTS
4933         do_mono_sample = 1;
4934 #endif
4935         if (allow_empty && !val) {
4936                 sample_type = SAMPLE_CYCLES;
4937                 sample_freq = 100;
4938                 return;
4939         }
4940         if (strcmp (val, "mono") == 0) {
4941                 do_mono_sample = 1;
4942                 sample_type = SAMPLE_CYCLES;
4943                 free (val);
4944                 return;
4945         }
4946         for (smode = sample_modes; smode->name; smode++) {
4947                 int l = strlen (smode->name);
4948                 if (strncmp (val, smode->name, l) == 0) {
4949                         sample_type = smode->sample_mode;
4950                         maybe_freq = val + l;
4951                         break;
4952                 }
4953         }
4954         if (!smode->name)
4955                 usage (1);
4956         if (*maybe_freq == '/') {
4957                 count = strtoul (maybe_freq + 1, &end, 10);
4958                 if (maybe_freq + 1 == end)
4959                         usage (1);
4960                 sample_freq = count;
4961         } else if (*maybe_freq != 0) {
4962                 usage (1);
4963         } else {
4964                 sample_freq = 100;
4965         }
4966         free (val);
4967 }
4968
4969 static void
4970 set_hsmode (char* val, int allow_empty)
4971 {
4972         char *end;
4973         unsigned int count;
4974         if (allow_empty && !val)
4975                 return;
4976         if (strcmp (val, "ondemand") == 0) {
4977                 hs_mode_ondemand = 1;
4978                 free (val);
4979                 return;
4980         }
4981         count = strtoul (val, &end, 10);
4982         if (val == end)
4983                 usage (1);
4984         if (strcmp (end, "ms") == 0)
4985                 hs_mode_ms = count;
4986         else if (strcmp (end, "gc") == 0)
4987                 hs_mode_gc = count;
4988         else
4989                 usage (1);
4990         free (val);
4991 }
4992
4993 /*
4994  * declaration to silence the compiler: this is the entry point that
4995  * mono will load from the shared library and call.
4996  */
4997 extern void
4998 mono_profiler_startup (const char *desc);
4999
5000 extern void
5001 mono_profiler_startup_log (const char *desc);
5002
5003 /*
5004  * this is the entry point that will be used when the profiler
5005  * is embedded inside the main executable.
5006  */
5007 void
5008 mono_profiler_startup_log (const char *desc)
5009 {
5010         mono_profiler_startup (desc);
5011 }
5012
5013 void
5014 mono_profiler_startup (const char *desc)
5015 {
5016         MonoProfiler *prof;
5017         GPtrArray *filters = NULL;
5018         char *filename = NULL;
5019         const char *p;
5020         const char *opt;
5021         int fast_time = 0;
5022         int calls_enabled = 0;
5023         int allocs_enabled = 0;
5024         int only_counters = 0;
5025         int only_coverage = 0;
5026         int events = MONO_PROFILE_GC|MONO_PROFILE_ALLOCATIONS|
5027                 MONO_PROFILE_GC_MOVES|MONO_PROFILE_CLASS_EVENTS|MONO_PROFILE_THREADS|
5028                 MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS|
5029                 MONO_PROFILE_MONITOR_EVENTS|MONO_PROFILE_MODULE_EVENTS|MONO_PROFILE_GC_ROOTS|
5030                 MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
5031                 MONO_PROFILE_ASSEMBLY_EVENTS;
5032
5033         max_allocated_sample_hits = mono_cpu_count () * 1000;
5034
5035         mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
5036         mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
5037         mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
5038         mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
5039         mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
5040         mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
5041         mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
5042         mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
5043         mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
5044         mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
5045         mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
5046         mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
5047         mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
5048         mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
5049         mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
5050         mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
5051
5052         p = desc;
5053         if (strncmp (p, "log", 3))
5054                 usage (1);
5055         p += 3;
5056         if (*p == ':')
5057                 p++;
5058         for (; *p; p = opt) {
5059                 char *val;
5060                 if (*p == ',') {
5061                         opt = p + 1;
5062                         continue;
5063                 }
5064                 if ((opt = match_option (p, "help", NULL)) != p) {
5065                         usage (0);
5066                         continue;
5067                 }
5068                 if ((opt = match_option (p, "calls", NULL)) != p) {
5069                         calls_enabled = 1;
5070                         continue;
5071                 }
5072                 if ((opt = match_option (p, "nocalls", NULL)) != p) {
5073                         events &= ~MONO_PROFILE_ENTER_LEAVE;
5074                         nocalls = 1;
5075                         continue;
5076                 }
5077                 if ((opt = match_option (p, "alloc", NULL)) != p) {
5078                         allocs_enabled = 1;
5079                         continue;
5080                 }
5081                 if ((opt = match_option (p, "noalloc", NULL)) != p) {
5082                         events &= ~MONO_PROFILE_ALLOCATIONS;
5083                         continue;
5084                 }
5085                 if ((opt = match_option (p, "time", &val)) != p) {
5086                         if (strcmp (val, "fast") == 0)
5087                                 fast_time = 1;
5088                         else if (strcmp (val, "null") == 0)
5089                                 fast_time = 2;
5090                         else
5091                                 usage (1);
5092                         free (val);
5093                         continue;
5094                 }
5095                 if ((opt = match_option (p, "report", NULL)) != p) {
5096                         do_report = 1;
5097                         continue;
5098                 }
5099                 if ((opt = match_option (p, "debug", NULL)) != p) {
5100                         do_debug = 1;
5101                         continue;
5102                 }
5103                 if ((opt = match_option (p, "sampling-real", NULL)) != p) {
5104                         sampling_mode = MONO_PROFILER_STAT_MODE_REAL;
5105                         continue;
5106                 }
5107                 if ((opt = match_option (p, "sampling-process", NULL)) != p) {
5108                         sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
5109                         continue;
5110                 }
5111                 if ((opt = match_option (p, "heapshot", &val)) != p) {
5112                         events &= ~MONO_PROFILE_ALLOCATIONS;
5113                         events &= ~MONO_PROFILE_ENTER_LEAVE;
5114                         nocalls = 1;
5115                         do_heap_shot = 1;
5116                         set_hsmode (val, 1);
5117                         continue;
5118                 }
5119                 if ((opt = match_option (p, "sample", &val)) != p) {
5120                         events &= ~MONO_PROFILE_ALLOCATIONS;
5121                         events &= ~MONO_PROFILE_ENTER_LEAVE;
5122                         nocalls = 1;
5123                         set_sample_mode (val, 1);
5124                         continue;
5125                 }
5126                 if ((opt = match_option (p, "hsmode", &val)) != p) {
5127                         fprintf (stderr, "The hsmode profiler option is obsolete, use heapshot=MODE.\n");
5128                         set_hsmode (val, 0);
5129                         continue;
5130                 }
5131                 if ((opt = match_option (p, "zip", NULL)) != p) {
5132                         use_zip = 1;
5133                         continue;
5134                 }
5135                 if ((opt = match_option (p, "output", &val)) != p) {
5136                         filename = val;
5137                         continue;
5138                 }
5139                 if ((opt = match_option (p, "port", &val)) != p) {
5140                         char *end;
5141                         command_port = strtoul (val, &end, 10);
5142                         free (val);
5143                         continue;
5144                 }
5145                 if ((opt = match_option (p, "maxframes", &val)) != p) {
5146                         char *end;
5147                         num_frames = strtoul (val, &end, 10);
5148                         if (num_frames > MAX_FRAMES)
5149                                 num_frames = MAX_FRAMES;
5150                         free (val);
5151                         notraces = num_frames == 0;
5152                         continue;
5153                 }
5154                 if ((opt = match_option (p, "maxsamples", &val)) != p) {
5155                         char *end;
5156                         max_allocated_sample_hits = strtoul (val, &end, 10);
5157                         if (!max_allocated_sample_hits)
5158                                 max_allocated_sample_hits = G_MAXINT32;
5159                         free (val);
5160                         continue;
5161                 }
5162                 if ((opt = match_option (p, "calldepth", &val)) != p) {
5163                         char *end;
5164                         max_call_depth = strtoul (val, &end, 10);
5165                         free (val);
5166                         continue;
5167                 }
5168                 if ((opt = match_option (p, "counters", NULL)) != p) {
5169                         do_counters = 1;
5170                         continue;
5171                 }
5172                 if ((opt = match_option (p, "countersonly", NULL)) != p) {
5173                         only_counters = 1;
5174                         continue;
5175                 }
5176                 if ((opt = match_option (p, "coverage", NULL)) != p) {
5177                         do_coverage = 1;
5178                         events |= MONO_PROFILE_ENTER_LEAVE;
5179                         debug_coverage = (g_getenv ("MONO_PROFILER_DEBUG_COVERAGE") != NULL);
5180                         continue;
5181                 }
5182                 if ((opt = match_option (p, "onlycoverage", NULL)) != p) {
5183                         only_coverage = 1;
5184                         continue;
5185                 }
5186                 if ((opt = match_option (p, "covfilter-file", &val)) != p) {
5187                         FILE *filter_file;
5188                         char *line, *content;
5189
5190                         if (filters == NULL)
5191                                 filters = g_ptr_array_new ();
5192
5193                         filter_file = fopen (val, "r");
5194                         if (filter_file == NULL) {
5195                                 fprintf (stderr, "Unable to open %s\n", val);
5196                                 exit (0);
5197                         }
5198
5199                         /* Don't need to free content as it is referred to by the lines stored in @filters */
5200                         content = get_file_content (filter_file);
5201                         if (content == NULL)
5202                                 fprintf (stderr, "WARNING: %s is greater than 128kb - ignoring\n", val);
5203
5204                         while ((line = get_next_line (content, &content)))
5205                                 g_ptr_array_add (filters, g_strchug (g_strchomp (line)));
5206
5207                         fclose (filter_file);
5208                         continue;
5209                 }
5210                 if ((opt = match_option (p, "covfilter", &val)) != p) {
5211                         if (filters == NULL)
5212                                 filters = g_ptr_array_new ();
5213
5214                         g_ptr_array_add (filters, val);
5215                         continue;
5216                 }
5217                 if (opt == p) {
5218                         usage (0);
5219                         exit (0);
5220                 }
5221         }
5222         if (calls_enabled) {
5223                 events |= MONO_PROFILE_ENTER_LEAVE;
5224                 nocalls = 0;
5225         }
5226         if (allocs_enabled)
5227                 events |= MONO_PROFILE_ALLOCATIONS;
5228         if (only_counters)
5229                 events = 0;
5230         if (only_coverage)
5231                 events = MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE;
5232
5233         utils_init (fast_time);
5234
5235         PROF_TLS_INIT ();
5236
5237         prof = create_profiler (filename, filters);
5238         if (!prof) {
5239                 PROF_TLS_FREE ();
5240                 return;
5241         }
5242
5243         mono_lls_init (&profiler_thread_list, NULL);
5244
5245         init_thread (TRUE);
5246
5247         mono_profiler_install (prof, log_shutdown);
5248         mono_profiler_install_gc (gc_event, gc_resize);
5249         mono_profiler_install_allocation (gc_alloc);
5250         mono_profiler_install_gc_moves (gc_moves);
5251         mono_profiler_install_gc_roots (gc_handle, gc_roots);
5252         mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL);
5253         mono_profiler_install_appdomain_name (domain_name);
5254         mono_profiler_install_context (context_loaded, context_unloaded);
5255         mono_profiler_install_class (NULL, class_loaded, class_unloaded, NULL);
5256         mono_profiler_install_module (NULL, image_loaded, image_unloaded, NULL);
5257         mono_profiler_install_assembly (NULL, assembly_loaded, assembly_unloaded, NULL);
5258         mono_profiler_install_thread (thread_start, thread_end);
5259         mono_profiler_install_thread_name (thread_name);
5260         mono_profiler_install_enter_leave (method_enter, method_leave);
5261         mono_profiler_install_jit_end (method_jitted);
5262         mono_profiler_install_code_buffer_new (code_buffer_new);
5263         mono_profiler_install_exception (throw_exc, method_exc_leave, clause_exc);
5264         mono_profiler_install_monitor (monitor_event);
5265         mono_profiler_install_runtime_initialized (runtime_initialized);
5266         if (do_coverage)
5267                 mono_profiler_install_coverage_filter (coverage_filter);
5268
5269         if (do_mono_sample && sample_type == SAMPLE_CYCLES && !only_counters) {
5270                 events |= MONO_PROFILE_STATISTICAL;
5271                 mono_profiler_set_statistical_mode (sampling_mode, sample_freq);
5272                 mono_profiler_install_statistical (mono_sample_hit);
5273         }
5274
5275         mono_profiler_set_events ((MonoProfileFlags)events);
5276 }