Exemplo n.º 1
0
        LogEvent ReadEvent()
        {
            var type      = Reader.ReadByte();
            var basicType = (LogEventType)(type & 0xf);
            var extType   = (LogEventType)(type & 0xf0);

            _time = ReadTime();

            switch (basicType)
            {
            case LogEventType.Allocation:
                switch (extType)
                {
                case LogEventType.AllocationBacktrace:
                case LogEventType.AllocationNoBacktrace:
                    return(new AllocationEvent {
                        ClassPointer = ReadPointer(),
                        ObjectPointer = ReadObject(),
                        ObjectSize = (long)Reader.ReadULeb128(),
                        Backtrace = ReadBacktrace(extType == LogEventType.AllocationBacktrace),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.GC:
                switch (extType)
                {
                case LogEventType.GCEvent:
                    return(new GCEvent {
                        Type = (LogGCEvent)Reader.ReadByte(),
                        Generation = Reader.ReadByte(),
                    });

                case LogEventType.GCResize:
                    return(new GCResizeEvent {
                        NewSize = (long)Reader.ReadULeb128(),
                    });

                case LogEventType.GCMove: {
                    var list = new long [(int)Reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = ReadObject();
                    }

                    return(new GCMoveEvent {
                            OldObjectPointers = list.Where((_, i) => i % 2 == 0).ToArray(),
                            NewObjectPointers = list.Where((_, i) => i % 2 != 0).ToArray(),
                        });
                }

                case LogEventType.GCHandleCreationNoBacktrace:
                case LogEventType.GCHandleCreationBacktrace:
                    return(new GCHandleCreationEvent {
                        Type = (LogGCHandleType)Reader.ReadULeb128(),
                        Handle = (long)Reader.ReadULeb128(),
                        ObjectPointer = ReadObject(),
                        Backtrace = ReadBacktrace(extType == LogEventType.GCHandleCreationBacktrace),
                    });

                case LogEventType.GCHandleDeletionNoBacktrace:
                case LogEventType.GCHandleDeletionBacktrace:
                    return(new GCHandleDeletionEvent {
                        Type = (LogGCHandleType)Reader.ReadULeb128(),
                        Handle = (long)Reader.ReadULeb128(),
                        Backtrace = ReadBacktrace(extType == LogEventType.GCHandleDeletionBacktrace),
                    });

                case LogEventType.GCFinalizeBegin:
                    return(new GCFinalizeBeginEvent());

                case LogEventType.GCFinalizeEnd:
                    return(new GCFinalizeEndEvent());

                case LogEventType.GCFinalizeObjectBegin:
                    return(new GCFinalizeObjectBeginEvent {
                        ObjectPointer = ReadObject(),
                    });

                case LogEventType.GCFinalizeObjectEnd:
                    return(new GCFinalizeObjectEndEvent {
                        ObjectPointer = ReadObject(),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Metadata: {
                var load   = false;
                var unload = false;

                switch (extType)
                {
                case LogEventType.MetadataExtra:
                    break;

                case LogEventType.MetadataEndLoad:
                    load = true;
                    break;

                case LogEventType.MetadataEndUnload:
                    unload = true;
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

                var metadataType = (LogMetadataType)Reader.ReadByte();

                switch (metadataType)
                {
                case LogMetadataType.Class:
                    if (load)
                    {
                        return(new ClassLoadEvent {
                                ClassPointer = ReadPointer(),
                                ImagePointer = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }
                    else
                    {
                        throw new LogException("Invalid class metadata event.");
                    }

                case LogMetadataType.Image:
                    if (load)
                    {
                        return(new ImageLoadEvent {
                                ImagePointer = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }
                    else if (unload)
                    {
                        return(new ImageUnloadEvent {
                                ImagePointer = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }
                    else
                    {
                        throw new LogException("Invalid image metadata event.");
                    }

                case LogMetadataType.Assembly:
                    if (load)
                    {
                        return(new AssemblyLoadEvent {
                                AssemblyPointer = ReadPointer(),
                                ImagePointer = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }
                    else if (unload)
                    {
                        return(new AssemblyUnloadEvent {
                                AssemblyPointer = ReadPointer(),
                                ImagePointer = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }
                    else
                    {
                        throw new LogException("Invalid assembly metadata event.");
                    }

                case LogMetadataType.AppDomain:
                    if (load)
                    {
                        return(new AppDomainLoadEvent {
                                AppDomainId = ReadPointer(),
                            });
                    }
                    else if (unload)
                    {
                        return(new AppDomainUnloadEvent {
                                AppDomainId = ReadPointer(),
                            });
                    }
                    else
                    {
                        return(new AppDomainNameEvent {
                                AppDomainId = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }

                case LogMetadataType.Thread:
                    if (load)
                    {
                        return(new ThreadStartEvent {
                                ThreadId = ReadPointer(),
                            });
                    }
                    else if (unload)
                    {
                        return(new ThreadEndEvent {
                                ThreadId = ReadPointer(),
                            });
                    }
                    else
                    {
                        return(new ThreadNameEvent {
                                ThreadId = ReadPointer(),
                                Name = Reader.ReadCString(),
                            });
                    }

                case LogMetadataType.Context:
                    if (load)
                    {
                        return(new ContextLoadEvent {
                                ContextId = ReadPointer(),
                                AppDomainId = ReadPointer(),
                            });
                    }
                    else if (unload)
                    {
                        return(new ContextUnloadEvent {
                                ContextId = ReadPointer(),
                                AppDomainId = ReadPointer(),
                            });
                    }
                    else
                    {
                        throw new LogException("Invalid context metadata event.");
                    }

                default:
                    throw new LogException($"Invalid metadata type ({metadataType}).");
                }
            }

            case LogEventType.Method:
                switch (extType)
                {
                case LogEventType.MethodLeave:
                    return(new LeaveEvent {
                        MethodPointer = ReadMethod(),
                    });

                case LogEventType.MethodEnter:
                    return(new EnterEvent {
                        MethodPointer = ReadMethod(),
                    });

                case LogEventType.MethodLeaveExceptional:
                    return(new ExceptionalLeaveEvent {
                        MethodPointer = ReadMethod(),
                    });

                case LogEventType.MethodJit:
                    return(new JitEvent {
                        MethodPointer = ReadMethod(),
                        CodePointer = ReadPointer(),
                        CodeSize = (long)Reader.ReadULeb128(),
                        Name = Reader.ReadCString(),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Exception:
                switch (extType)
                {
                case LogEventType.ExceptionThrowNoBacktrace:
                case LogEventType.ExceptionThrowBacktrace:
                    return(new ThrowEvent {
                        ObjectPointer = ReadObject(),
                        Backtrace = ReadBacktrace(extType == LogEventType.ExceptionThrowBacktrace),
                    });

                case LogEventType.ExceptionClause:
                    return(new ExceptionClauseEvent {
                        Type = (LogExceptionClause)Reader.ReadByte(),
                        Index = (long)Reader.ReadULeb128(),
                        MethodPointer = ReadMethod(),
                        ObjectPointer = ReadObject(),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Monitor:
                switch (extType)
                {
                case LogEventType.MonitorNoBacktrace:
                case LogEventType.MonitorBacktrace:
                    return(new MonitorEvent {
                        Event = (LogMonitorEvent)Reader.ReadByte(),
                        ObjectPointer = ReadObject(),
                        Backtrace = ReadBacktrace(extType == LogEventType.MonitorBacktrace),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Heap:
                switch (extType)
                {
                case LogEventType.HeapBegin:
                    return(new HeapBeginEvent());

                case LogEventType.HeapEnd:
                    return(new HeapEndEvent());

                case LogEventType.HeapObject: {
                    var ev = new HeapObjectEvent {
                        ObjectPointer = ReadObject(),
                        ClassPointer  = ReadPointer(),
                        ObjectSize    = (long)Reader.ReadULeb128(),
                    };

                    var list = new HeapObjectEvent.HeapObjectReference [(int)Reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = new HeapObjectEvent.HeapObjectReference {
                            Offset        = (long)Reader.ReadULeb128(),
                            ObjectPointer = ReadObject(),
                        };
                    }

                    ev.References = list;

                    return(ev);
                }

                case LogEventType.HeapRoots: {
                    // TODO: This entire event makes no sense.

                    var ev   = new HeapRootsEvent();
                    var list = new HeapRootsEvent.HeapRoot [(int)Reader.ReadULeb128()];

                    ev.MaxGenerationCollectionCount = (long)Reader.ReadULeb128();

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = new HeapRootsEvent.HeapRoot {
                            ObjectPointer = ReadObject(),
                            Attributes    = (LogHeapRootAttributes)Reader.ReadByte(),
                            ExtraInfo     = (long)Reader.ReadULeb128(),
                        };
                    }

                    ev.Roots = list;

                    return(ev);
                }

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Sample:
                switch (extType)
                {
                case LogEventType.SampleHit:
                    return(new SampleHitEvent {
                        ThreadId = ReadPointer(),
                        UnmanagedBacktrace = ReadBacktrace(true, false),
                        ManagedBacktrace = ReadBacktrace(true),
                    });

                case LogEventType.SampleUnmanagedSymbol:
                    return(new UnmanagedSymbolEvent {
                        CodePointer = ReadPointer(),
                        CodeSize = (long)Reader.ReadULeb128(),
                        Name = Reader.ReadCString(),
                    });

                case LogEventType.SampleUnmanagedBinary:
                    return(new UnmanagedBinaryEvent {
                        SegmentPointer = ReadPointer(),
                        SegmentOffset = (long)Reader.ReadULeb128(),
                        SegmentSize = (long)Reader.ReadULeb128(),
                        FileName = Reader.ReadCString(),
                    });

                case LogEventType.SampleCounterDescriptions: {
                    var ev   = new CounterDescriptionsEvent();
                    var list = new CounterDescriptionsEvent.CounterDescription [(int)Reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        var section = (LogCounterSection)Reader.ReadULeb128();

                        list [i] = new CounterDescriptionsEvent.CounterDescription {
                            Section     = section,
                            SectionName = section == LogCounterSection.User ? Reader.ReadCString() : string.Empty,
                            CounterName = Reader.ReadCString(),
                            Type        = (LogCounterType)Reader.ReadByte(),
                            Unit        = (LogCounterUnit)Reader.ReadByte(),
                            Variance    = (LogCounterVariance)Reader.ReadByte(),
                            Index       = (long)Reader.ReadULeb128(),
                        };
                    }

                    ev.Descriptions = list;

                    return(ev);
                }

                case LogEventType.SampleCounters: {
                    var ev   = new CounterSamplesEvent();
                    var list = new List <CounterSamplesEvent.CounterSample> ();

                    while (true)
                    {
                        var index = (long)Reader.ReadULeb128();

                        if (index == 0)
                        {
                            break;
                        }

                        var counterType = (LogCounterType)Reader.ReadByte();

                        object value = null;

                        switch (counterType)
                        {
                        case LogCounterType.String:
                            value = Reader.ReadByte() == 1 ? Reader.ReadCString() : null;
                            break;

                        case LogCounterType.Int32:
                        case LogCounterType.Word:
                        case LogCounterType.Int64:
                        case LogCounterType.Interval:
                            value = Reader.ReadSLeb128();
                            break;

                        case LogCounterType.UInt32:
                        case LogCounterType.UInt64:
                            value = Reader.ReadULeb128();
                            break;

                        case LogCounterType.Double:
                            value = Reader.ReadDouble();
                            break;

                        default:
                            throw new LogException($"Invalid counter type ({counterType}).");
                        }

                        list.Add(new CounterSamplesEvent.CounterSample {
                                Index = index,
                                Type  = counterType,
                                Value = value,
                            });
                    }

                    ev.Samples = list;

                    return(ev);
                }

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Runtime:
                switch (extType)
                {
                case LogEventType.RuntimeJitHelper: {
                    var helperType = (LogJitHelper)Reader.ReadByte();

                    return(new JitHelperEvent {
                            Type = helperType,
                            BufferPointer = ReadPointer(),
                            BufferSize = (long)Reader.ReadULeb128(),
                            Name = helperType == LogJitHelper.SpecificTrampoline ? Reader.ReadCString() : string.Empty,
                        });
                }

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Coverage:
                switch (extType)
                {
                case LogEventType.CoverageAssembly:
                    return(new AssemblyCoverageEvent {
                        AssemblyName = Reader.ReadCString(),
                        Guid = Guid.Parse(Reader.ReadCString()),
                        FileName = Reader.ReadCString(),
                        NumberOfMethods = (long)Reader.ReadULeb128(),
                        FullyCovered = (long)Reader.ReadULeb128(),
                        PartiallyCovered = (long)Reader.ReadULeb128(),
                    });

                case LogEventType.CoverageMethod:
                    return(new MethodCoverageEvent {
                        AssemblyName = Reader.ReadCString(),
                        ClassName = Reader.ReadCString(),
                        MethodName = Reader.ReadCString(),
                        MethodSignature = Reader.ReadCString(),
                        FileName = Reader.ReadCString(),
                        MetadataToken = Reader.ReadULeb128(),
                        MethodId = (long)Reader.ReadULeb128(),
                        NumberOfStatements = (long)Reader.ReadULeb128(),
                    });

                case LogEventType.CoverageStatement:
                    return(new StatementCoverageEvent {
                        MethodId = (long)Reader.ReadULeb128(),
                        RelativeILOffset = (long)Reader.ReadULeb128(),
                        Counter = Reader.ReadULeb128(),
                        Line = (long)Reader.ReadULeb128(),
                        Column = (long)Reader.ReadULeb128(),
                    });

                case LogEventType.CoverageClass:
                    return(new ClassCoverageEvent {
                        AssemblyName = Reader.ReadCString(),
                        ClassName = Reader.ReadCString(),
                        NumberOfMethods = (long)Reader.ReadULeb128(),
                        FullyCovered = (long)Reader.ReadULeb128(),
                        PartiallyCovered = (long)Reader.ReadULeb128(),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            case LogEventType.Meta:
                switch (extType)
                {
                case LogEventType.MetaSynchronizationPoint:
                    return(new SynchronizationPointEvent {
                        Type = (LogSynchronizationPoint)Reader.ReadByte(),
                    });

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

            default:
                throw new LogException($"Invalid basic event type ({basicType}).");
            }
        }
Exemplo n.º 2
0
        LogEvent ReadEvent()
        {
            var type      = _reader.ReadByte();
            var basicType = (LogEventType)(type & 0xf);
            var extType   = (LogEventType)(type & 0xf0);

            _time = ReadTime();
            LogEvent ev = null;

            switch (basicType)
            {
            case LogEventType.Allocation:
                switch (extType)
                {
                case LogEventType.AllocationBacktrace:
                case LogEventType.AllocationNoBacktrace:
                    ev = new AllocationEvent {
                        ClassPointer  = StreamHeader.FormatVersion < 15 ? ReadPointer() : 0,
                        VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer() : 0,
                        ObjectPointer = ReadObject(),
                        ObjectSize    = (long)_reader.ReadULeb128(),
                        Backtrace     = ReadBacktrace(extType == LogEventType.AllocationBacktrace),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.GC:
                switch (extType)
                {
                case LogEventType.GCEvent:
                    ev = new GCEvent {
                        Type       = (LogGCEvent)_reader.ReadByte(),
                        Generation = _reader.ReadByte(),
                    };
                    break;

                case LogEventType.GCResize:
                    ev = new GCResizeEvent {
                        NewSize = (long)_reader.ReadULeb128(),
                    };
                    break;

                case LogEventType.GCMove: {
                    var list = new long [(int)_reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = ReadObject();
                    }

                    ev = new GCMoveEvent {
                        OldObjectPointers = list.Where((_, i) => i % 2 == 0).ToArray(),
                        NewObjectPointers = list.Where((_, i) => i % 2 != 0).ToArray(),
                    };
                    break;
                }

                case LogEventType.GCHandleCreationNoBacktrace:
                case LogEventType.GCHandleCreationBacktrace:
                    ev = new GCHandleCreationEvent {
                        Type          = (LogGCHandleType)_reader.ReadULeb128(),
                        Handle        = (long)_reader.ReadULeb128(),
                        ObjectPointer = ReadObject(),
                        Backtrace     = ReadBacktrace(extType == LogEventType.GCHandleCreationBacktrace),
                    };
                    break;

                case LogEventType.GCHandleDeletionNoBacktrace:
                case LogEventType.GCHandleDeletionBacktrace:
                    ev = new GCHandleDeletionEvent {
                        Type      = (LogGCHandleType)_reader.ReadULeb128(),
                        Handle    = (long)_reader.ReadULeb128(),
                        Backtrace = ReadBacktrace(extType == LogEventType.GCHandleDeletionBacktrace),
                    };
                    break;

                case LogEventType.GCFinalizeBegin:
                    ev = new GCFinalizeBeginEvent();
                    break;

                case LogEventType.GCFinalizeEnd:
                    ev = new GCFinalizeEndEvent();
                    break;

                case LogEventType.GCFinalizeObjectBegin:
                    ev = new GCFinalizeObjectBeginEvent {
                        ObjectPointer = ReadObject(),
                    };
                    break;

                case LogEventType.GCFinalizeObjectEnd:
                    ev = new GCFinalizeObjectEndEvent {
                        ObjectPointer = ReadObject(),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Metadata: {
                var load   = false;
                var unload = false;

                switch (extType)
                {
                case LogEventType.MetadataExtra:
                    break;

                case LogEventType.MetadataEndLoad:
                    load = true;
                    break;

                case LogEventType.MetadataEndUnload:
                    unload = true;
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }

                var metadataType = (LogMetadataType)_reader.ReadByte();

                switch (metadataType)
                {
                case LogMetadataType.Class:
                    if (load)
                    {
                        ev = new ClassLoadEvent {
                            ClassPointer = ReadPointer(),
                            ImagePointer = ReadPointer(),
                            Name         = _reader.ReadCString(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid class metadata event.");
                    }
                    break;

                case LogMetadataType.Image:
                    if (load)
                    {
                        var ile = new ImageLoadEvent {
                            ImagePointer = ReadPointer(),
                            Name         = _reader.ReadCString(),
                        };

                        if (StreamHeader.FormatVersion >= 16)
                        {
                            var guid = _reader.ReadCString();

                            ile.ModuleVersionId = guid == string.Empty ? Guid.Empty : Guid.Parse(guid);
                        }

                        ev = ile;
                    }
                    else if (unload)
                    {
                        ev = new ImageUnloadEvent {
                            ImagePointer = ReadPointer(),
                            Name         = _reader.ReadCString(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid image metadata event.");
                    }
                    break;

                case LogMetadataType.Assembly:
                    if (load)
                    {
                        ev = new AssemblyLoadEvent {
                            AssemblyPointer = ReadPointer(),
                            ImagePointer    = StreamHeader.FormatVersion >= 14 ? ReadPointer() : 0,
                            Name            = _reader.ReadCString(),
                        };
                    }
                    else if (unload)
                    {
                        ev = new AssemblyUnloadEvent {
                            AssemblyPointer = ReadPointer(),
                            ImagePointer    = StreamHeader.FormatVersion >= 14 ? ReadPointer() : 0,
                            Name            = _reader.ReadCString(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid assembly metadata event.");
                    }
                    break;

                case LogMetadataType.AppDomain:
                    if (load)
                    {
                        ev = new AppDomainLoadEvent {
                            AppDomainId = ReadPointer(),
                        };
                    }
                    else if (unload)
                    {
                        ev = new AppDomainUnloadEvent {
                            AppDomainId = ReadPointer(),
                        };
                    }
                    else
                    {
                        ev = new AppDomainNameEvent {
                            AppDomainId = ReadPointer(),
                            Name        = _reader.ReadCString(),
                        };
                    }
                    break;

                case LogMetadataType.Thread:
                    if (load)
                    {
                        ev = new ThreadStartEvent {
                            ThreadId = ReadPointer(),
                        };
                    }
                    else if (unload)
                    {
                        ev = new ThreadEndEvent {
                            ThreadId = ReadPointer(),
                        };
                    }
                    else
                    {
                        ev = new ThreadNameEvent {
                            ThreadId = ReadPointer(),
                            Name     = _reader.ReadCString(),
                        };
                    }
                    break;

                case LogMetadataType.Context:
                    if (load)
                    {
                        ev = new ContextLoadEvent {
                            ContextId   = ReadPointer(),
                            AppDomainId = ReadPointer(),
                        };
                    }
                    else if (unload)
                    {
                        ev = new ContextUnloadEvent {
                            ContextId   = ReadPointer(),
                            AppDomainId = ReadPointer(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid context metadata event.");
                    }
                    break;

                case LogMetadataType.VTable:
                    if (load)
                    {
                        ev = new VTableLoadEvent {
                            VTablePointer = ReadPointer(),
                            AppDomainId   = ReadPointer(),
                            ClassPointer  = ReadPointer(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid VTable metadata event.");
                    }
                    break;

                default:
                    throw new LogException($"Invalid metadata type ({metadataType}).");
                }
                break;
            }

            case LogEventType.Method:
                switch (extType)
                {
                case LogEventType.MethodLeave:
                    ev = new LeaveEvent {
                        MethodPointer = ReadMethod(),
                    };
                    break;

                case LogEventType.MethodEnter:
                    ev = new EnterEvent {
                        MethodPointer = ReadMethod(),
                    };
                    break;

                case LogEventType.MethodLeaveExceptional:
                    ev = new ExceptionalLeaveEvent {
                        MethodPointer = ReadMethod(),
                    };
                    break;

                case LogEventType.MethodJit:
                    ev = new JitEvent {
                        MethodPointer = ReadMethod(),
                        CodePointer   = ReadPointer(),
                        CodeSize      = (long)_reader.ReadULeb128(),
                        Name          = _reader.ReadCString(),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Exception:
                switch (extType)
                {
                case LogEventType.ExceptionThrowNoBacktrace:
                case LogEventType.ExceptionThrowBacktrace:
                    ev = new ThrowEvent {
                        ObjectPointer = ReadObject(),
                        Backtrace     = ReadBacktrace(extType == LogEventType.ExceptionThrowBacktrace),
                    };
                    break;

                case LogEventType.ExceptionClause:
                    ev = new ExceptionClauseEvent {
                        Type          = (LogExceptionClause)_reader.ReadByte(),
                        Index         = (long)_reader.ReadULeb128(),
                        MethodPointer = ReadMethod(),
                        ObjectPointer = StreamHeader.FormatVersion >= 14 ? ReadObject() : 0,
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Monitor:
                if (StreamHeader.FormatVersion < 14)
                {
                    if (extType.HasFlag(LogEventType.MonitorBacktrace))
                    {
                        extType = LogEventType.MonitorBacktrace;
                    }
                    else
                    {
                        extType = LogEventType.MonitorNoBacktrace;
                    }
                }
                switch (extType)
                {
                case LogEventType.MonitorNoBacktrace:
                case LogEventType.MonitorBacktrace:
                    ev = new MonitorEvent {
                        Event = StreamHeader.FormatVersion >= 14 ?
                                (LogMonitorEvent)_reader.ReadByte() :
                                (LogMonitorEvent)((((byte)type & 0xf0) >> 4) & 0x3),
                        ObjectPointer = ReadObject(),
                        Backtrace     = ReadBacktrace(extType == LogEventType.MonitorBacktrace),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Heap:
                switch (extType)
                {
                case LogEventType.HeapBegin:
                    ev = new HeapBeginEvent();
                    break;

                case LogEventType.HeapEnd:
                    ev = new HeapEndEvent();
                    break;

                case LogEventType.HeapObject: {
                    HeapObjectEvent hoe = new HeapObjectEvent {
                        ObjectPointer = ReadObject(),
                        ClassPointer  = StreamHeader.FormatVersion < 15 ? ReadPointer() : 0,
                        VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer() : 0,
                        ObjectSize    = (long)_reader.ReadULeb128(),
                        Generation    = StreamHeader.FormatVersion >= 16 ? _reader.ReadByte() : 0,
                    };

                    var list = new HeapObjectEvent.HeapObjectReference [(int)_reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = new HeapObjectEvent.HeapObjectReference {
                            Offset        = (long)_reader.ReadULeb128(),
                            ObjectPointer = ReadObject(),
                        };
                    }

                    hoe.References = list;
                    ev             = hoe;

                    break;
                }

                case LogEventType.HeapRoots: {
                    var hre  = new HeapRootsEvent();
                    var list = new HeapRootsEvent.HeapRoot [(int)_reader.ReadULeb128()];

                    if (StreamHeader.FormatVersion < 15)
                    {
                        hre.MaxGenerationCollectionCount = (long)_reader.ReadULeb128();
                    }

                    for (var i = 0; i < list.Length; i++)
                    {
                        list [i] = new HeapRootsEvent.HeapRoot {
                            SlotPointer   = StreamHeader.FormatVersion >= 15 ? ReadPointer() : 0,
                            ObjectPointer = ReadObject(),
                            Attributes    = StreamHeader.FormatVersion < 15 ?
                                            (StreamHeader.FormatVersion == 13 ?
                                             (LogHeapRootAttributes)_reader.ReadByte() :
                                             (LogHeapRootAttributes)_reader.ReadULeb128()) :
                                            0,
                            ExtraInfo = StreamHeader.FormatVersion < 15 ? (long)_reader.ReadULeb128() : 0,
                        };
                    }

                    hre.Roots = list;
                    ev        = hre;

                    break;
                }

                case LogEventType.HeapRootRegister:
                    ev = new HeapRootRegisterEvent {
                        RootPointer = ReadPointer(),
                        RootSize    = (long)_reader.ReadULeb128(),
                        Source      = (LogHeapRootSource)_reader.ReadByte(),
                        Key         = ReadPointer(),
                        Name        = _reader.ReadCString(),
                    };
                    break;

                case LogEventType.HeapRootUnregister:
                    ev = new HeapRootUnregisterEvent {
                        RootPointer = ReadPointer(),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Sample:
                switch (extType)
                {
                case LogEventType.SampleHit:
                    if (StreamHeader.FormatVersion < 14)
                    {
                        // Read SampleType (always set to .Cycles) for versions < 14
                        _reader.ReadByte();
                    }
                    ev = new SampleHitEvent {
                        ThreadId           = ReadPointer(),
                        UnmanagedBacktrace = ReadBacktrace(true, false),
                        ManagedBacktrace   = ReadBacktrace(true).Reverse().ToArray(),
                    };
                    break;

                case LogEventType.SampleUnmanagedSymbol:
                    ev = new UnmanagedSymbolEvent {
                        CodePointer = ReadPointer(),
                        CodeSize    = (long)_reader.ReadULeb128(),
                        Name        = _reader.ReadCString(),
                    };
                    break;

                case LogEventType.SampleUnmanagedBinary:
                    ev = new UnmanagedBinaryEvent {
                        SegmentPointer = StreamHeader.FormatVersion >= 14 ? ReadPointer() : _reader.ReadSLeb128(),
                        SegmentOffset  = (long)_reader.ReadULeb128(),
                        SegmentSize    = (long)_reader.ReadULeb128(),
                        FileName       = _reader.ReadCString(),
                    };
                    break;

                case LogEventType.SampleCounterDescriptions: {
                    var cde  = new CounterDescriptionsEvent();
                    var list = new CounterDescriptionsEvent.CounterDescription [(int)_reader.ReadULeb128()];

                    for (var i = 0; i < list.Length; i++)
                    {
                        var section = (LogCounterSection)_reader.ReadULeb128();

                        list [i] = new CounterDescriptionsEvent.CounterDescription {
                            Section     = section,
                            SectionName = section == LogCounterSection.User ? _reader.ReadCString() : null,
                            CounterName = _reader.ReadCString(),
                            Type        = StreamHeader.FormatVersion < 15 ? (LogCounterType)_reader.ReadByte() : (LogCounterType)_reader.ReadULeb128(),
                            Unit        = StreamHeader.FormatVersion < 15 ? (LogCounterUnit)_reader.ReadByte() : (LogCounterUnit)_reader.ReadULeb128(),
                            Variance    = StreamHeader.FormatVersion < 15 ? (LogCounterVariance)_reader.ReadByte() : (LogCounterVariance)_reader.ReadULeb128(),
                            Index       = (long)_reader.ReadULeb128(),
                        };
                    }

                    cde.Descriptions = list;
                    ev = cde;

                    break;
                }

                case LogEventType.SampleCounters: {
                    var cse  = new CounterSamplesEvent();
                    var list = new List <CounterSamplesEvent.CounterSample> ();

                    while (true)
                    {
                        var index = (long)_reader.ReadULeb128();

                        if (index == 0)
                        {
                            break;
                        }

                        var counterType = StreamHeader.FormatVersion < 15 ? (LogCounterType)_reader.ReadByte() : (LogCounterType)_reader.ReadULeb128();

                        object value = null;

                        switch (counterType)
                        {
                        case LogCounterType.String:
                            value = _reader.ReadByte() == 1 ? _reader.ReadCString() : null;
                            break;

                        case LogCounterType.Int32:
                        case LogCounterType.Word:
                        case LogCounterType.Int64:
                        case LogCounterType.Interval:
                            value = _reader.ReadSLeb128();
                            break;

                        case LogCounterType.UInt32:
                        case LogCounterType.UInt64:
                            value = _reader.ReadULeb128();
                            break;

                        case LogCounterType.Double:
                            value = _reader.ReadDouble();
                            break;

                        default:
                            throw new LogException($"Invalid counter type ({counterType}).");
                        }

                        list.Add(new CounterSamplesEvent.CounterSample {
                                Index = index,
                                Type  = counterType,
                                Value = value,
                            });
                    }

                    cse.Samples = list;
                    ev          = cse;

                    break;
                }

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Runtime:
                switch (extType)
                {
                case LogEventType.RuntimeJitHelper: {
                    var helperType = (LogJitHelper)_reader.ReadByte();

                    if (StreamHeader.FormatVersion < 14)
                    {
                        helperType--;
                    }

                    ev = new JitHelperEvent {
                        Type          = helperType,
                        BufferPointer = ReadPointer(),
                        BufferSize    = (long)_reader.ReadULeb128(),
                        Name          = helperType == LogJitHelper.SpecificTrampoline ? _reader.ReadCString() : null,
                    };
                    break;
                }

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            case LogEventType.Meta:
                switch (extType)
                {
                case LogEventType.MetaSynchronizationPoint:
                    ev = new SynchronizationPointEvent {
                        Type = (LogSynchronizationPoint)_reader.ReadByte(),
                    };
                    break;

                case LogEventType.MetaAotId:
                    ev = new AotIdEvent {
                        AotId = Guid.Parse(_reader.ReadCString()),
                    };
                    break;

                default:
                    throw new LogException($"Invalid extended event type ({extType}).");
                }
                break;

            default:
                throw new LogException($"Invalid basic event type ({basicType}).");
            }

            ev.Timestamp = _time;
            ev.Buffer    = _bufferHeader;

            return(ev);
        }