[mips] Disable div with mul on 32bit mips
[mono.git] / mono / profiler / decode.c
index e8d53afea686ed76588370c99fe74beac2c0718b..338150494dd0315582003170457d0172b9294b31 100644 (file)
@@ -633,7 +633,7 @@ add_class (intptr_t klass, const char *name)
        /* we resolved an unknown class (unless we had the code unloaded) */
        if (cd) {
                /*printf ("resolved unknown: %s\n", name);*/
-               free (cd->name);
+               g_free (cd->name);
                cd->name = pstrdup (name);
                return cd;
        }
@@ -699,7 +699,7 @@ add_method (intptr_t method, const char *name, intptr_t code, int len)
                cd->code = code;
                cd->len = len;
                /*printf ("resolved unknown: %s\n", name);*/
-               free (cd->name);
+               g_free (cd->name);
                cd->name = pstrdup (name);
                return cd;
        }
@@ -1099,7 +1099,7 @@ add_heap_class_rev (HeapClassDesc *from, HeapClassDesc *to)
                                add_rev_class_hashed (n, to->rev_hash_size, to->rev_hash [i].klass, to->rev_hash [i].count);
                }
                if (to->rev_hash)
-                       free (to->rev_hash);
+                       g_free (to->rev_hash);
                to->rev_hash = n;
        }
        to->rev_count += add_rev_class_hashed (to->rev_hash, to->rev_hash_size, from, 1);
@@ -1217,7 +1217,7 @@ add_heap_shot_class (HeapShot *hs, ClassDesc *klass, uint64_t size)
                                add_heap_hashed (n, &res, hs->hash_size, hs->class_hash [i]->klass, hs->class_hash [i]->total_size, hs->class_hash [i]->count);
                }
                if (hs->class_hash)
-                       free (hs->class_hash);
+                       g_free (hs->class_hash);
                hs->class_hash = n;
        }
        res = NULL;
@@ -1269,7 +1269,7 @@ heap_shot_obj_add_refs (HeapShot *hs, uintptr_t objaddr, uintptr_t num, uintptr_
                HeapObjectDesc* ho = alloc_heap_obj (objaddr, hash [i]->hklass, hash [i]->num_refs + num);
                *ref_offset = hash [i]->num_refs;
                memcpy (ho->refs, hash [i]->refs, hash [i]->num_refs * sizeof (uintptr_t));
-               free (hash [i]);
+               g_free (hash [i]);
                hash [i] = ho;
                return ho;
        }
@@ -1319,7 +1319,7 @@ add_heap_shot_obj (HeapShot *hs, HeapObjectDesc *obj)
                                add_heap_hashed_obj (n, hs->objects_hash_size, hs->objects_hash [i]);
                }
                if (hs->objects_hash)
-                       free (hs->objects_hash);
+                       g_free (hs->objects_hash);
                hs->objects_hash = n;
        }
        hs->objects_count += add_heap_hashed_obj (hs->objects_hash, hs->objects_hash_size, obj);
@@ -1413,7 +1413,7 @@ heap_shot_mark_objects (HeapShot *hs)
                }
        }
        fprintf (outfile, "Total unmarked: %zd/%zd\n", num_unmarked, hs->objects_count);
-       free (marks);
+       g_free (marks);
 }
 
 static void
@@ -1423,10 +1423,10 @@ heap_shot_free_objects (HeapShot *hs)
        for (i = 0; i < hs->objects_hash_size; ++i) {
                HeapObjectDesc *ho = hs->objects_hash [i];
                if (ho)
-                       free (ho);
+                       g_free (ho);
        }
        if (hs->objects_hash)
-               free (hs->objects_hash);
+               g_free (hs->objects_hash);
        hs->objects_hash = NULL;
        hs->objects_hash_size = 0;
        hs->objects_count = 0;
@@ -1517,6 +1517,9 @@ typedef struct {
        int timer_overhead;
        int pid;
        int port;
+       char *args;
+       char *arch;
+       char *os;
        uint64_t startup_time;
        ThreadContext *threads;
        ThreadContext *current_thread;
@@ -1723,7 +1726,7 @@ add_trace_bt (BackTrace *bt, TraceDesc *trace, uint64_t value)
                                add_trace_hashed (n, trace->size, trace->traces [i].bt, trace->traces [i].count);
                }
                if (trace->traces)
-                       free (trace->traces);
+                       g_free (trace->traces);
                trace->traces = n;
        }
        trace->count += add_trace_hashed (trace->traces, trace->size, bt, value);
@@ -1862,9 +1865,23 @@ gc_event_name (int ev)
        case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
        case MONO_GC_EVENT_END: return "end";
        case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
        case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
        case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
        case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
+       default:
+               return "unknown";
+       }
+}
+
+static const char*
+sync_point_name (int type)
+{
+       switch (type) {
+       case SYNC_POINT_PERIODIC: return "periodic";
+       case SYNC_POINT_WORLD_STOP: return "world stop";
+       case SYNC_POINT_WORLD_START: return "world start";
        default:
                return "unknown";
        }
@@ -1956,21 +1973,25 @@ get_root_name (int rtype)
 }
 
 static MethodDesc**
-decode_bt (MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base)
+decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
 {
        MethodDesc **frames;
        int i;
-       int flags = decode_uleb128 (p, &p);
+       if (ctx->data_version < 13)
+               decode_uleb128 (p, &p); /* flags */
        int count = decode_uleb128 (p, &p);
-       if (flags != 0)
-               return NULL;
        if (count > *size)
                frames = (MethodDesc **)malloc (count * sizeof (void*));
        else
                frames = sframes;
        for (i = 0; i < count; ++i) {
                intptr_t ptrdiff = decode_sleb128 (p, &p);
-               frames [i] = lookup_method (ptr_base + ptrdiff);
+               if (ctx->data_version > 12) {
+                       *method_base += ptrdiff;
+                       frames [i] = lookup_method (*method_base);
+               } else {
+                       frames [i] = lookup_method (ptr_base + ptrdiff);
+               }
        }
        *size = count;
        *endp = p;
@@ -2279,8 +2300,16 @@ decode_buffer (ProfContext *ctx)
                                if (new_size > max_heap_size)
                                        max_heap_size = new_size;
                        } else if (subtype == TYPE_GC_EVENT) {
-                               uint64_t ev = decode_uleb128 (p, &p);
-                               int gen = decode_uleb128 (p, &p);
+                               uint64_t ev;
+                               if (ctx->data_version > 12)
+                                       ev = *p++;
+                               else
+                                       ev = decode_uleb128 (p, &p);
+                               int gen;
+                               if (ctx->data_version > 12)
+                                       gen = *p++;
+                               else
+                                       gen = decode_uleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
                                if (gen > 2) {
@@ -2318,7 +2347,7 @@ decode_buffer (ProfContext *ctx)
                                intptr_t objdiff = decode_sleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2342,7 +2371,7 @@ decode_buffer (ProfContext *ctx)
                                if (debug)
                                        fprintf (outfile, "handle (%s) %u created for object %p\n", get_handle_name (htype), handle, (void*)OBJ_ADDR (objdiff));
                                if (frames != sframes)
-                                       free (frames);
+                                       g_free (frames);
                        } else if (subtype == TYPE_GC_HANDLE_DESTROYED || subtype == TYPE_GC_HANDLE_DESTROYED_BT) {
                                int has_bt = subtype == TYPE_GC_HANDLE_DESTROYED_BT;
                                int num_bt = 0;
@@ -2352,7 +2381,7 @@ decode_buffer (ProfContext *ctx)
                                uint32_t handle = decode_uleb128 (p, &p);
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2373,7 +2402,22 @@ decode_buffer (ProfContext *ctx)
                                if (debug)
                                        fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
                                if (frames != sframes)
-                                       free (frames);
+                                       g_free (frames);
+                       } else if (subtype == TYPE_GC_FINALIZE_START) {
+                               // TODO: Generate a finalizer report based on these events.
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_END) {
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
                        }
                        break;
                }
@@ -2387,11 +2431,8 @@ decode_buffer (ProfContext *ctx)
                        time_base += tdiff;
                        if (mtype == TYPE_CLASS) {
                                intptr_t imptrdiff = decode_sleb128 (p, &p);
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in class\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2399,11 +2440,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_IMAGE) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in image\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2411,11 +2449,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_ASSEMBLY) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in assembly\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                if (debug)
                                        fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
@@ -2423,11 +2458,8 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (mtype == TYPE_DOMAIN) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in domain\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2443,22 +2475,16 @@ decode_buffer (ProfContext *ctx)
                                        p++;
                                }
                        } else if (mtype == TYPE_CONTEXT) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in context\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                intptr_t domaindiff = decode_sleb128 (p, &p);
                                if (debug)
                                        fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
                                if (subtype == TYPE_END_LOAD)
                                        get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
                        } else if (mtype == TYPE_THREAD) {
-                               uint64_t flags = decode_uleb128 (p, &p);
-                               if (flags) {
-                                       fprintf (outfile, "non-zero flags in thread\n");
-                                       return 0;
-                               }
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
                                ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
                                /* no subtype means it's a name event, rather than start/stop */
                                if (subtype == 0)
@@ -2493,7 +2519,7 @@ decode_buffer (ProfContext *ctx)
                                fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
                        if (has_bt) {
                                num_bt = 8;
-                               frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                               frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                if (!frames) {
                                        fprintf (outfile, "Cannot load backtrace\n");
                                        return 0;
@@ -2517,7 +2543,7 @@ decode_buffer (ProfContext *ctx)
                                        tracked_creation (OBJ_ADDR (objdiff), cd, len, bt, time_base);
                        }
                        if (frames != sframes)
-                               free (frames);
+                               g_free (frames);
                        break;
                }
                case TYPE_METHOD: {
@@ -2561,7 +2587,14 @@ decode_buffer (ProfContext *ctx)
                        if (subtype == TYPE_HEAP_OBJECT) {
                                HeapObjectDesc *ho = NULL;
                                int i;
-                               intptr_t objdiff = decode_sleb128 (p + 1, &p);
+                               intptr_t objdiff;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       objdiff = decode_sleb128 (p, &p);
+                               } else
+                                       objdiff = decode_sleb128 (p + 1, &p);
                                intptr_t ptrdiff = decode_sleb128 (p, &p);
                                uint64_t size = decode_uleb128 (p, &p);
                                uintptr_t num = decode_uleb128 (p, &p);
@@ -2594,12 +2627,23 @@ decode_buffer (ProfContext *ctx)
                                if (debug && size)
                                        fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
                        } else if (subtype == TYPE_HEAP_ROOT) {
-                               uintptr_t num = decode_uleb128 (p + 1, &p);
+                               uintptr_t num;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       num = decode_uleb128 (p, &p);
+                               } else
+                                       num = decode_uleb128 (p + 1, &p);
                                uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
                                int i;
                                for (i = 0; i < num; ++i) {
                                        intptr_t objdiff = decode_sleb128 (p, &p);
-                                       int root_type = decode_uleb128 (p, &p);
+                                       int root_type;
+                                       if (ctx->data_version > 12)
+                                               root_type = *p++;
+                                       else
+                                               root_type = decode_uleb128 (p, &p);
                                        /* we just discard the extra info for now */
                                        uintptr_t extra_info = decode_uleb128 (p, &p);
                                        if (debug)
@@ -2622,9 +2666,9 @@ decode_buffer (ProfContext *ctx)
                                                hs->roots_extra = thread->roots_extra;
                                                hs->roots_types = thread->roots_types;
                                        } else {
-                                               free (thread->roots);
-                                               free (thread->roots_extra);
-                                               free (thread->roots_types);
+                                               g_free (thread->roots);
+                                               g_free (thread->roots_extra);
+                                               g_free (thread->roots_types);
                                        }
                                        thread->num_roots = 0;
                                        thread->size_roots = 0;
@@ -2670,7 +2714,7 @@ decode_buffer (ProfContext *ctx)
                                }
                                if (has_bt) {
                                        num_bt = 8;
-                                       frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2709,12 +2753,12 @@ decode_buffer (ProfContext *ctx)
                        if (debug)
                                fprintf (outfile, "monitor %s for object %p\n", monitor_ev_name (event), (void*)OBJ_ADDR (objdiff));
                        if (frames != sframes)
-                               free (frames);
+                               g_free (frames);
                        break;
                }
                case TYPE_EXCEPTION: {
                        int subtype = *p & 0x70;
-                       int has_bt = *p & TYPE_EXCEPTION_BT;
+                       int has_bt = *p & TYPE_THROW_BT;
                        uint64_t tdiff = decode_uleb128 (p + 1, &p);
                        MethodDesc* sframes [8];
                        MethodDesc** frames = sframes;
@@ -2725,7 +2769,11 @@ decode_buffer (ProfContext *ctx)
                        if (!(time_base >= time_from && time_base < time_to))
                                record = 0;
                        if (subtype == TYPE_CLAUSE) {
-                               int clause_type = decode_uleb128 (p, &p);
+                               int clause_type;
+                               if (ctx->data_version > 12)
+                                       clause_type = *p++;
+                               else
+                                       clause_type = decode_uleb128 (p, &p);
                                int clause_num = decode_uleb128 (p, &p);
                                int64_t ptrdiff = decode_sleb128 (p, &p);
                                method_base += ptrdiff;
@@ -2739,7 +2787,7 @@ decode_buffer (ProfContext *ctx)
                                        throw_count++;
                                if (has_bt) {
                                        has_bt = 8;
-                                       frames = decode_bt (sframes, &has_bt, p, &p, ptr_base);
+                                       frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
                                        if (!frames) {
                                                fprintf (outfile, "Cannot load backtrace\n");
                                                return 0;
@@ -2751,7 +2799,7 @@ decode_buffer (ProfContext *ctx)
                                                add_trace_thread (thread, &exc_traces, 1);
                                }
                                if (frames != sframes)
-                                       free (frames);
+                                       g_free (frames);
                                if (debug)
                                        fprintf (outfile, "throw %p\n", (void*)OBJ_ADDR (objdiff));
                        }
@@ -2763,7 +2811,11 @@ decode_buffer (ProfContext *ctx)
                        LOG_TIME (time_base, tdiff);
                        time_base += tdiff;
                        if (subtype == TYPE_JITHELPER) {
-                               int type = decode_uleb128 (p, &p);
+                               int type;
+                               if (ctx->data_version > 12)
+                                       type = *p++;
+                               else
+                                       type = decode_uleb128 (p, &p);
                                intptr_t codediff = decode_sleb128 (p, &p);
                                int codelen = decode_uleb128 (p, &p);
                                const char *name;
@@ -2785,8 +2837,18 @@ decode_buffer (ProfContext *ctx)
                        int subtype = *p & 0xf0;
                        if (subtype == TYPE_SAMPLE_HIT) {
                                int i;
-                               int sample_type = decode_uleb128 (p + 1, &p);
-                               uint64_t tstamp = decode_uleb128 (p, &p);
+                               int sample_type;
+                               uint64_t tstamp;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       sample_type = *p++;
+                                       tstamp = time_base;
+                               } else {
+                                       sample_type = decode_uleb128 (p + 1, &p);
+                                       tstamp = decode_uleb128 (p, &p);
+                               }
                                void *tid = (void *) thread_id;
                                if (ctx->data_version > 10)
                                        tid = (void *) (ptr_base + decode_sleb128 (p, &p));
@@ -2803,17 +2865,26 @@ decode_buffer (ProfContext *ctx)
                                        for (i = 0; i < count; ++i) {
                                                MethodDesc *method;
                                                int64_t ptrdiff = decode_sleb128 (p, &p);
-                                               int il_offset = decode_sleb128 (p, &p);
-                                               int native_offset = decode_sleb128 (p, &p);
                                                method_base += ptrdiff;
                                                method = lookup_method (method_base);
                                                if (debug)
-                                                       fprintf (outfile, "sample hit bt %d: %s at IL offset %d (native: %d)\n", i, method->name, il_offset, native_offset);
+                                                       fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
+                                               if (ctx->data_version < 13) {
+                                                       decode_sleb128 (p, &p); /* il offset */
+                                                       decode_sleb128 (p, &p); /* native offset */
+                                               }
                                        }
                                }
                        } else if (subtype == TYPE_SAMPLE_USYM) {
                                /* un unmanaged symbol description */
-                               uintptr_t addr = ptr_base + decode_sleb128 (p + 1, &p);
+                               uintptr_t addr;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       addr = ptr_base + decode_sleb128 (p, &p);
+                               } else
+                                       addr = ptr_base + decode_sleb128 (p + 1, &p);
                                uintptr_t size = decode_uleb128 (p, &p);
                                char *name;
                                name = pstrdup ((char*)p);
@@ -2838,7 +2909,14 @@ decode_buffer (ProfContext *ctx)
                                while (*p) p++;
                                p++;
                        } else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
-                               uint64_t i, len = decode_uleb128 (p + 1, &p);
+                               uint64_t i, len;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       len = decode_uleb128 (p, &p);
+                               } else
+                                       len = decode_uleb128 (p + 1, &p);
                                for (i = 0; i < len; i++) {
                                        uint64_t type, unit, variance, index;
                                        uint64_t section = decode_uleb128 (p, &p);
@@ -2851,9 +2929,15 @@ decode_buffer (ProfContext *ctx)
                                        }
                                        name = pstrdup ((char*)p);
                                        while (*p++);
-                                       type = decode_uleb128 (p, &p);
-                                       unit = decode_uleb128 (p, &p);
-                                       variance = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12) {
+                                               type = *p++;
+                                               unit = *p++;
+                                               variance = *p++;
+                                       } else {
+                                               type = decode_uleb128 (p, &p);
+                                               unit = decode_uleb128 (p, &p);
+                                               variance = decode_uleb128 (p, &p);
+                                       }
                                        index = decode_uleb128 (p, &p);
                                        add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
                                }
@@ -2861,7 +2945,14 @@ decode_buffer (ProfContext *ctx)
                                int i;
                                CounterValue *value, *previous = NULL;
                                CounterList *list;
-                               uint64_t timestamp = decode_uleb128 (p + 1, &p);
+                               uint64_t timestamp; // milliseconds since startup
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       timestamp = (time_base - startup_time) / 1000 / 1000;
+                               } else
+                                       timestamp = decode_uleb128 (p + 1, &p);
                                uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
                                while (1) {
                                        uint64_t type, index = decode_uleb128 (p, &p);
@@ -2875,7 +2966,10 @@ decode_buffer (ProfContext *ctx)
                                                }
                                        }
 
-                                       type = decode_uleb128 (p, &p);
+                                       if (ctx->data_version > 12)
+                                               type = *p++;
+                                       else
+                                               type = decode_uleb128 (p, &p);
 
                                        value = (CounterValue *)calloc (1, sizeof (CounterValue));
                                        value->timestamp = timestamp;
@@ -2939,6 +3033,13 @@ decode_buffer (ProfContext *ctx)
                                int token, n_offsets, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly = (const char *)p; while (*p) p++; p++;
                                klass = (const char *)p; while (*p) p++; p++;
                                name = (const char *)p; while (*p) p++; p++;
@@ -2968,6 +3069,13 @@ decode_buffer (ProfContext *ctx)
                                int offset, count, line, column, method_id;
 
                                p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                method_id = decode_uleb128 (p, &p);
                                offset = decode_uleb128 (p, &p);
                                count = decode_uleb128 (p, &p);
@@ -2989,6 +3097,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                name = (char *)p; while (*p) p++; p++;
                                guid = (char *)p; while (*p) p++; p++;
                                filename = (char *)p; while (*p) p++; p++;
@@ -3012,6 +3126,12 @@ decode_buffer (ProfContext *ctx)
                                int number_of_methods, fully_covered, partially_covered;
                                p++;
 
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
                                assembly_name = (char *)p; while (*p) p++; p++;
                                class_name = (char *)p; while (*p) p++; p++;
                                number_of_methods = decode_uleb128 (p, &p);
@@ -3033,6 +3153,18 @@ decode_buffer (ProfContext *ctx)
                        }
                        break;
                }
+               case TYPE_META: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_SYNC_POINT) {
+                               int type = *p++;
+                               if (debug)
+                                       fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
+                       }
+                       break;
+               }
                default:
                        fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
                        exit (1);
@@ -3045,6 +3177,20 @@ decode_buffer (ProfContext *ctx)
        return 1;
 }
 
+static int
+read_header_string (ProfContext *ctx, char **field)
+{
+       if (!load_data (ctx, 4))
+               return 0;
+
+       if (!load_data (ctx, read_int32 (ctx->buf)))
+               return 0;
+
+       *field = pstrdup ((const char *) ctx->buf);
+
+       return 1;
+}
+
 static ProfContext*
 load_file (char *name)
 {
@@ -3062,7 +3208,7 @@ load_file (char *name)
        if (ctx->file != stdin)
                ctx->gzfile = gzdopen (fileno (ctx->file), "rb");
 #endif
-       if (!load_data (ctx, 32))
+       if (!load_data (ctx, 30))
                return NULL;
        p = ctx->buf;
        if (read_int32 (p) != LOG_HEADER_ID || p [6] > LOG_DATA_VERSION)
@@ -3079,6 +3225,17 @@ load_file (char *name)
        ctx->timer_overhead = read_int32 (p + 16);
        ctx->pid = read_int32 (p + 24);
        ctx->port = read_int16 (p + 28);
+       if (ctx->version_major >= 1) {
+               if (!read_header_string (ctx, &ctx->args))
+                       return NULL;
+               if (!read_header_string (ctx, &ctx->arch))
+                       return NULL;
+               if (!read_header_string (ctx, &ctx->os))
+                       return NULL;
+       } else {
+               if (!load_data (ctx, 2)) /* old opsys field, was never used */
+                       return NULL;
+       }
        return ctx;
 }
 
@@ -3116,6 +3273,11 @@ dump_header (ProfContext *ctx)
        fprintf (outfile, "\nMono log profiler data\n");
        fprintf (outfile, "\tProfiler version: %d.%d\n", ctx->version_major, ctx->version_minor);
        fprintf (outfile, "\tData version: %d\n", ctx->data_version);
+       if (ctx->version_major >= 1) {
+               fprintf (outfile, "\tArguments: %s\n", ctx->args);
+               fprintf (outfile, "\tArchitecture: %s\n", ctx->arch);
+               fprintf (outfile, "\tOperating system: %s\n", ctx->os);
+       }
        fprintf (outfile, "\tMean timer overhead: %d nanoseconds\n", ctx->timer_overhead);
        fprintf (outfile, "\tProgram startup: %s", t);
        if (ctx->pid)
@@ -3536,9 +3698,9 @@ heap_shot_summary (HeapShot *hs, int hs_num, HeapShot *last_hs)
                if (cd->root_references)
                        fprintf (outfile, "\t\t%zd root references (%zd pinning)\n", cd->root_references, cd->pinned_references);
                dump_rev_claases (rev_sorted, cd->rev_count);
-               free (rev_sorted);
+               g_free (rev_sorted);
        }
-       free (sorted);
+       g_free (sorted);
 }
 
 static int
@@ -3768,9 +3930,9 @@ dump_stats (void)
        DUMP_EVENT_STAT (TYPE_METHOD, TYPE_EXC_LEAVE);
        DUMP_EVENT_STAT (TYPE_METHOD, TYPE_JIT);
 
-       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW);
+       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_NO_BT);
+       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_BT);
        DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_CLAUSE);
-       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_EXCEPTION_BT);
 
        DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_NO_BT);
        DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_BT);
@@ -3792,6 +3954,8 @@ dump_stats (void)
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
        DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
+
+       DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
 }
 
 
@@ -4052,7 +4216,7 @@ main (int argc, char *argv[])
                        *top++ = 0;
                        from_secs = atof (val);
                        to_secs = atof (top);
-                       free (val);
+                       g_free (val);
                        if (from_secs > to_secs) {
                                usage ();
                                return 1;