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