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}).");
            }
        }
Esempio n. 2
0
        LogEvent ReadEvent(LogReader _reader, LogBufferHeader _bufferHeader)
        {
            var type      = _reader.ReadByte();
            var basicType = (LogEventType)(type & 0xf);
            var extType   = (LogEventType)(type & 0xf0);

            var _time = ReadTime(_reader, _bufferHeader);

            if (minimalTime > _time)
            {
                minimalTime = _time;
                _time       = 0;
            }
            else
            {
                _time = _time - minimalTime;
            }
            LogEvent ev = null;

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

                    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(_reader, _bufferHeader),
                        Backtrace     = ReadBacktrace(extType == LogEventType.GCHandleCreationBacktrace, _reader, _bufferHeader),
                    };
                    break;

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

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

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

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

                case LogEventType.GCFinalizeObjectEnd:
                    ev = new GCFinalizeObjectEndEvent {
                        ObjectPointer = ReadObject(_reader, _bufferHeader),
                    };
                    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(_reader, _bufferHeader),
                            ImagePointer = ReadPointer(_reader, _bufferHeader),
                            Name         = _reader.ReadCString(),
                        };
                    }
                    else
                    {
                        throw new LogException("Invalid class metadata event.");
                    }
                    break;

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

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

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

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

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

                case LogMetadataType.VTable:
                    if (load)
                    {
                        ev = new VTableLoadEvent {
                            VTablePointer = ReadPointer(_reader, _bufferHeader),
                            AppDomainId   = ReadPointer(_reader, _bufferHeader),
                            ClassPointer  = ReadPointer(_reader, _bufferHeader),
                        };
                    }
                    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(_reader, _bufferHeader),
                    };
                    break;

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

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

                case LogEventType.MethodJit:
                    ev = new JitEvent {
                        MethodPointer = ReadMethod(_reader, _bufferHeader),
                        CodePointer   = ReadPointer(_reader, _bufferHeader),
                        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(_reader, _bufferHeader),
                        Backtrace     = ReadBacktrace(extType == LogEventType.ExceptionThrowBacktrace, _reader, _bufferHeader),
                    };
                    break;

                case LogEventType.ExceptionClause:
                    ev = new ExceptionClauseEvent {
                        Type          = (LogExceptionClause)_reader.ReadByte(),
                        Index         = (long)_reader.ReadULeb128(),
                        MethodPointer = ReadMethod(_reader, _bufferHeader),
                        ObjectPointer = StreamHeader.FormatVersion >= 14 ? ReadObject(_reader, _bufferHeader) : 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(_reader, _bufferHeader),
                        Backtrace     = ReadBacktrace(extType == LogEventType.MonitorBacktrace, _reader, _bufferHeader),
                    };
                    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(_reader, _bufferHeader),
                        VTablePointer = StreamHeader.FormatVersion >= 15 ? ReadPointer(_reader, _bufferHeader) : 0,
                        ObjectSize    = (long)_reader.ReadULeb128(),
                    };

                    var listTo = new long[(int)_reader.ReadULeb128()];
                    var listAt = new ushort[listTo.Length];

                    for (var i = 0; i < listTo.Length; i++)
                    {
                        listAt[i] = (ushort)_reader.ReadULeb128();
                        listTo[i] = ReadObject(_reader, _bufferHeader);
                    }

                    hoe.ReferencesAt = listAt;
                    hoe.ReferencesTo = listTo;
                    ev = hoe;

                    break;
                }

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

                    for (var i = 0; i < list.Length; i++)
                    {
                        list[i] = new HeapRootsEvent.HeapRoot {
                            AddressPointer = StreamHeader.FormatVersion >= 15 ? ReadPointer(_reader, _bufferHeader) : 0,
                            ObjectPointer  = ReadObject(_reader, _bufferHeader)
                        };
                    }

                    hre.Roots = list;
                    ev        = hre;

                    break;
                }

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

                case LogEventType.HeapRootUnregister:
                    ev = new HeapRootUnregisterEvent {
                        RootPointer = ReadPointer(_reader, _bufferHeader),
                    };
                    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(_reader, _bufferHeader),
                        UnmanagedBacktrace = ReadBacktrace(true, _reader, _bufferHeader, false),
                        ManagedBacktrace   = ReadBacktrace(true, _reader, _bufferHeader).Reverse().ToArray(),
                    };
                    break;

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

                case LogEventType.SampleUnmanagedBinary:
                    ev = new UnmanagedBinaryEvent {
                        SegmentPointer = StreamHeader.FormatVersion >= 14 ? ReadPointer(_reader, _bufferHeader) : _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();

                    ev = new JitHelperEvent {
                        Type          = helperType,
                        BufferPointer = ReadPointer(_reader, _bufferHeader),
                        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;

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

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

            ev.Timestamp = _time;

            return(ev);
        }