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