/// <summary> /// Initializes a new instance of the <see cref="PdbStringTable"/> class. /// </summary> /// <param name="reader">Stream binary reader.</param> public PdbStringTable(IBinaryReader reader) { // Read header Signature = reader.ReadUint(); HashVersion = reader.ReadUint(); StringsStreamSize = reader.ReadUint(); // Read strings table StringsStream = reader.ReadSubstream(StringsStreamSize); stringsCache = new DictionaryCache <uint, string>((uint offset) => { StringsStream.Position = offset; return(StringsStream.ReadCString().String); }); // Read table of offsets that can be accessed by hash function uint offsetsCount = reader.ReadUint(); Offsets = reader.ReadUintArray((int)offsetsCount); // Read epilogue StringsCount = reader.ReadInt(); dictionaryCache = SimpleCache.CreateStruct(() => { Dictionary <uint, string> strings = new Dictionary <uint, string>(); foreach (uint offset in Offsets) { strings[offset] = stringsCache[offset]; } return(strings); }); }
/// <summary> /// Initializes a new instance of the <see cref="NamedStreamMap"/> class. /// </summary> /// <param name="reader">Stream binary reader.</param> public NamedStreamMap(IBinaryReader reader) { uint stringsSizeInBytes = reader.ReadUint(); StringsStream = reader.ReadSubstream(stringsSizeInBytes); HashTable = new HashTable(reader); streamsCache = SimpleCache.CreateStruct(() => { Dictionary <string, int> streams = new Dictionary <string, int>(); IBinaryReader stringsReader = StringsStream.Duplicate(); foreach (var kvp in HashTable.Dictionary) { stringsReader.Position = kvp.Key; streams.Add(stringsReader.ReadCString().String, (int)kvp.Value); } return(streams); }); streamsUppercaseCache = SimpleCache.CreateStruct(() => { Dictionary <string, int> streams = new Dictionary <string, int>(); foreach (var kvp in Streams) { streams.Add(kvp.Key.ToUpperInvariant(), kvp.Value); } return(streams); }); }
public void Assignment() { int count = 0; SimpleCacheStruct <int> cache = SimpleCache.CreateStruct(() => { count++; return(42); }); var cache2 = cache; Assert.Equal(0, count); Assert.False(cache.Cached); Assert.Equal(42, cache.Value); Assert.Equal(1, count); Assert.True(cache.Cached); Assert.False(cache2.Cached); Assert.Equal(42, cache2.Value); Assert.Equal(2, count); Assert.True(cache2.Cached); var cache3 = cache; Assert.True(cache3.Cached); Assert.Equal(42, cache3.Value); Assert.Equal(2, count); }
/// <summary> /// Initializes a new instance of the <see cref="PdbModule"/> class. /// </summary> /// <param name="module">The XML module description.</param> /// <param name="pdbFile">Already opened PDB file.</param> public PdbModule(XmlModule module, PdbFile pdbFile) { PdbFile = pdbFile; Name = !string.IsNullOrEmpty(module.Name) ? module.Name : Path.GetFileNameWithoutExtension(module.SymbolsPath).ToLower(); Namespace = module.Namespace; globalScopeCache = SimpleCache.CreateStruct(() => new PdbGlobalScope(this)); builtinSymbolsCache = new DictionaryCache <TypeIndex, PdbSymbol>(CreateBuiltinSymbol); allSymbolsCache = new ArrayCache <PdbSymbol>(PdbFile.TpiStream.TypeRecordCount, CreateSymbol); definedSymbolsCache = new ArrayCache <PdbSymbol>(PdbFile.TpiStream.TypeRecordCount, true, GetDefinedSymbol); constantsCache = SimpleCache.CreateStruct(() => { Dictionary <string, ConstantSymbol> constants = new Dictionary <string, ConstantSymbol>(); foreach (SymbolRecordKind kind in ConstantSymbol.Kinds) { foreach (ConstantSymbol c in PdbFile.PdbSymbolStream[kind].OfType <ConstantSymbol>()) { if (!constants.ContainsKey(c.Name)) { constants.Add(c.Name, c); } } } return((IReadOnlyDictionary <string, ConstantSymbol>)constants); }); }
/// <summary> /// Initializes a new instance of the <see cref="PdbSource"/> class. /// </summary> /// <param name="pdbFile">Portable PDB file reader.</param> /// <param name="handle">Our metadata reader handle.</param> internal PdbSource(PdbFile pdbFile, DocumentHandle handle) { PdbFile = pdbFile; documentCache = SimpleCache.CreateStruct(() => PdbFile.Reader.GetDocument(handle)); hashCache = SimpleCache.CreateStruct(() => PdbFile.Reader.GetBlobBytes(Document.Hash)); nameCache = SimpleCache.CreateStruct(() => PdbFile.Reader.GetString(Document.Name)); }
/// <summary> /// Initializes a new instance of the <see cref="PublicsStream"/> class. /// </summary> /// <param name="file">PDB file containing this stream.</param> /// <param name="reader">Binary stream reader.</param> public PublicsStream(PdbFile file, IBinaryReader reader) { if (reader.BytesRemaining < PublicsStreamHeader.Size) { throw new Exception("Publics Stream does not contain a header."); } // Read header Header = PublicsStreamHeader.Read(reader); // Read globals hash table if (reader.BytesRemaining < Header.SymbolHashStreamSize) { throw new Exception("Publics Stream does not contain a header."); } GlobalsStream = new GlobalsStream(file, reader.ReadSubstream(Header.SymbolHashStreamSize)); // Read address map if (reader.BytesRemaining < Header.AddressMapSize) { throw new Exception("Could not read an address map."); } AddressMap = reader.ReadUintArray((int)(Header.AddressMapSize / 4)); // 4 = sizeof(uint) // Read thunk map if (reader.BytesRemaining < Header.NumberOfThunks * 4) // 4 = sizeof(uint) { throw new Exception("Could not read a thunk map."); } ThunkMap = reader.ReadUintArray((int)Header.NumberOfThunks); // Read sections if (reader.BytesRemaining < Header.NumberOfSections * PublicsStreamSectionOffset.Size) { throw new Exception("Publics stream doesn't contain all sections specified in the header."); } PublicsStreamSectionOffset[] sections = new PublicsStreamSectionOffset[Header.NumberOfSections]; for (int i = 0; i < sections.Length; i++) { sections[i] = PublicsStreamSectionOffset.Read(reader); } Sections = sections; if (reader.BytesRemaining > 0) { throw new Exception("Corrupted publics stream."); } publicSymbolsCache = SimpleCache.CreateStruct(() => { Public32Symbol[] publicSymbols = new Public32Symbol[GlobalsStream.Symbols.Count]; for (int i = 0; i < publicSymbols.Length; i++) { publicSymbols[i] = GlobalsStream.Symbols[i] as Public32Symbol; } return(publicSymbols); }); }
/// <summary> /// Initializes a new instance of the <see cref="UserTypeTransformation"/> class. /// </summary> /// <param name="transformation">The XML transformation definition.</param> /// <param name="typeConverter">The type converter.</param> /// <param name="ownerUserType">The owner user type.</param> /// <param name="type">The type that should be transformed to user type.</param> public UserTypeTransformation(XmlTypeTransformation transformation, Func <string, string> typeConverter, UserType ownerUserType, Symbol type) { Transformation = transformation; this.typeConverter = typeConverter; this.ownerUserType = ownerUserType; this.type = type; typeStringCache = SimpleCache.CreateStruct(() => Transformation.TransformType(type.Name, typeConverter)); }
/// <summary> /// Initializes a new instance of the <see cref="InteractiveExecutionBehavior"/> class. /// </summary> public InteractiveExecutionBehavior() { userTypeMetadata = Context.UserTypeMetadata; interactiveScriptBase = SimpleCache.CreateStruct(() => { return(new InteractiveScriptBase { ObjectWriter = new DefaultObjectWriter(), _InternalObjectWriter_ = new ConsoleObjectWriter(), }); }); }
/// <summary> /// Initializes a new instance of the <see cref="UserType"/> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">User type factory that contains this element.</param> public UserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) { Symbol = symbol; Factory = factory; InnerTypes = new List <UserType>(); DerivedClasses = new HashSet <UserType>(); typeNameCache = SimpleCache.CreateStruct(() => GetTypeName()); fullTypeNameCache = SimpleCache.CreateStruct(() => GetFullTypeName()); constructorNameCache = SimpleCache.CreateStruct(() => GetConstructorName()); namespaceCache = SimpleCache.CreateStruct(() => GetNamespace(nameSpace)); membersCache = SimpleCache.CreateStruct(() => GetMembers().ToArray()); constructorsCache = SimpleCache.CreateStruct(() => GetConstructors().ToArray()); baseClassCache = SimpleCache.CreateStruct(() => GetBaseClass(Symbol)); memoryBufferOffsetCache = SimpleCache.CreateStruct(() => GetMemoryBufferOffset()); }
public void Disposable() { int disposedCount = 0; using (SimpleCacheStruct <DisposableAction> cache = SimpleCache.CreateStruct(() => new DisposableAction(() => disposedCount++))) { var v0 = cache.Value; cache.InvalidateCache(); Assert.Equal(1, disposedCount); var v1 = cache.Value; } Assert.Equal(2, disposedCount); }
/// <summary> /// Initializes a new instance of the <see cref="HashTable"/> class. /// </summary> /// <param name="reader">Stream binary reader.</param> public HashTable(IBinaryReader reader) { Size = reader.ReadUint(); Capacity = reader.ReadUint(); if (Capacity == 0) { throw new Exception("Invalid Hash Table Capacity"); } if (Size > MaxLoad(Capacity)) { throw new Exception("Invalid Hash Table Size"); } buckets = new Tuple <uint, uint> [Capacity]; present = ReadSparseBitArray(reader); if (CountBits(present) != Size) { throw new Exception("Present bit vector does not match size!"); } deleted = ReadSparseBitArray(reader); if (BitsIntersect(present, deleted)) { throw new Exception("Present bit vector interesects deleted!"); } for (int i = 0, index = 0; i < present.Length; i++) { for (uint j = 0, bit = 1; j < 32; j++, bit <<= 1, index++) { if ((present[i] & bit) != 0) { buckets[index] = Tuple.Create(reader.ReadUint(), reader.ReadUint()); } } } dictionaryCache = SimpleCache.CreateStruct(() => { Dictionary <uint, uint> dictionary = new Dictionary <uint, uint>(); foreach (var tuple in buckets) { if (tuple != null) { dictionary.Add(tuple.Item1, tuple.Item2); } } return(dictionary); }); }
/// <summary> /// Initializes a new instance of the <see cref="PdbLocalScope"/> class. /// </summary> /// <param name="function">Function that contains this scope.</param> /// <param name="block">Block symbol read from PDB.</param> /// <param name="parent">Parent scope.</param> internal PdbLocalScope(PdbFunction function, BlockSymbol block, PdbLocalScope parent = null) { Function = function; Block = block; Parent = parent; childrenCache = SimpleCache.CreateStruct(() => { IEnumerable <BlockSymbol> blocks = Block.Children.OfType <BlockSymbol>(); int count = blocks.Count(); IPdbLocalScope[] children = new IPdbLocalScope[count]; int i = 0; foreach (BlockSymbol b in blocks) { children[i++] = new PdbLocalScope(Function, b, this); } return(children); }); constantsCache = SimpleCache.CreateStruct(() => { IEnumerable <ConstantSymbol> symbols = Block.Children.OfType <ConstantSymbol>(); int count = symbols.Count(); IPdbLocalConstant[] constants = new IPdbLocalConstant[count]; int i = 0; foreach (ConstantSymbol symbol in symbols) { constants[i++] = new PdbLocalConstant(this, symbol); } return(constants); }); variablesCache = SimpleCache.CreateStruct(() => { IEnumerable <AttributeSlotSymbol> slots = Block.Children.OfType <AttributeSlotSymbol>(); int count = slots.Count(); IPdbLocalVariable[] variables = new IPdbLocalVariable[count]; int i = 0; foreach (AttributeSlotSymbol slot in slots) { variables[i++] = new PdbLocalVariable(this, slot); } return(variables); }); }
/// <summary> /// Initializes a new instance of the <see cref="PdbFile"/> class. /// </summary> /// <param name="reader">Portable PDB metadata reader.</param> internal PdbFile(MetadataReader reader) { Reader = reader; idCache = SimpleCache.CreateStruct(() => new BlobContentId(Reader.DebugMetadataHeader.Id)); functionsCache = SimpleCache.CreateStruct(() => { IPdbFunction[] functions = new IPdbFunction[Reader.MethodDebugInformation.Count]; int i = 0; foreach (var f in Reader.MethodDebugInformation) { functions[i++] = functionsByHandle[f]; } return(functions); }); sourcesCache = new DictionaryCache <DocumentHandle, IPdbSource>(GetSource); functionsByHandle = new DictionaryCache <MethodDebugInformationHandle, PdbFunction>(f => new PdbFunction(this, f)); }
public void SingleEvaluation() { int count = 0; SimpleCacheStruct <int> cache = SimpleCache.CreateStruct(() => { count++; return(42); }); Assert.Equal(0, count); Assert.False(cache.Cached); Assert.Equal(42, cache.Value); Assert.Equal(1, count); Assert.True(cache.Cached); Assert.Equal(42, cache.Value); Assert.Equal(1, count); Assert.Single(cache, 42); }
/// <summary> /// Initializes a new instance of the <see cref="PdbFile"/> class. /// </summary> /// <param name="file">File loaded into memory for faster parsing.</param> public PdbFile(MemoryLoadedFile file) { Reader = new SharpPdb.Windows.PdbFile(file); functionsCache = SimpleCache.CreateStruct(() => { List <IPdbFunction> functions = new List <IPdbFunction>(); foreach (var dbiModule in Reader.DbiStream.Modules) { var symbolStream = dbiModule.LocalSymbolStream; foreach (var kind in ManagedProcedureSymbol.Kinds) { foreach (ManagedProcedureSymbol procedure in symbolStream[kind]) { functions.Add(new PdbFunction(this, procedure, dbiModule)); } } } return(functions); }); sourcesCache = new DictionaryCache <FileChecksumSubsection, PdbSource>(checksum => new PdbSource(this, checksum)); functionsByTokenCache = SimpleCache.CreateStruct(() => Functions.ToDictionary(f => f.Token)); tokenRidMapCache = SimpleCache.CreateStruct(() => { var reader = Reader.DbiStream.GetKnownDebugStream(KnownDebugStreamIndex.TokenRidMap)?.Reader; if (reader == null) { return(null); } int count = (int)(reader.Length / 4); // 4 = sizeof(uint) uint[] tokenRidMap = new uint[count]; for (int i = 0; i < count; i++) { tokenRidMap[i] = reader.ReadUint(); } return(tokenRidMap); }); this.file = file; }
public void EvaluationAfterInvalidate() { int count = 0; SimpleCacheStruct <int> cache = SimpleCache.CreateStruct(() => { count++; return(42); }); Assert.Equal(0, count); Assert.Equal(42, cache.Value); Assert.Equal(1, count); Assert.Equal(42, cache.Value); Assert.Equal(1, count); cache.InvalidateCache(); Assert.Equal(1, count); Assert.Equal(42, cache.Value); Assert.Equal(2, count); }
public void SettingValue() { int count = 0; SimpleCacheStruct <int> cache = SimpleCache.CreateStruct(() => { count++; return(42); }); Assert.Equal(0, count); Assert.Equal(42, cache.Value); Assert.Equal(1, count); cache.Value = 12345; Assert.Equal(12345, cache.Value); Assert.Equal(1, count); cache.InvalidateCache(); Assert.Equal(1, count); Assert.Equal(42, cache.Value); Assert.Equal(2, count); }
/// <summary> /// Initializes a new instance of the <see cref="PdbFunction"/> class. /// </summary> /// <param name="pdbFile">Portable PDB file reader.</param> /// <param name="procedure">Managed procedure symbol from PDB.</param> /// <param name="dbiModule">DBI module descriptor from PDB.</param> internal PdbFunction(PdbFile pdbFile, ManagedProcedureSymbol procedure, DbiModuleDescriptor dbiModule) { PdbFile = pdbFile; Procedure = procedure; DbiModule = dbiModule; localScopesCache = SimpleCache.CreateStruct(() => { IEnumerable <BlockSymbol> blocks = Procedure.Children.OfType <BlockSymbol>(); int count = blocks.Count(); IPdbLocalScope[] scopes = new IPdbLocalScope[count]; int i = 0; foreach (BlockSymbol block in blocks) { scopes[i++] = new PdbLocalScope(this, block); } return(scopes); }); sequencePointsCache = SimpleCache.CreateStruct(() => { var checksums = DbiModule.DebugSubsectionStream[DebugSubsectionKind.FileChecksums]; var linesSubsections = dbiModule.DebugSubsectionStream[DebugSubsectionKind.Lines]; List <IPdbSequencePoint> sequencePoints = new List <IPdbSequencePoint>(); foreach (LinesSubsection linesSubsection in linesSubsections) { foreach (var file in linesSubsection.Files) { var checksum = (FileChecksumSubsection)checksums[file.Index]; var source = PdbFile[checksum]; foreach (var line in file.Lines) { sequencePoints.Add(new PdbSequencePoint(this, source, line)); } } } return(sequencePoints); }); }
/// <summary> /// Initializes a new instance of the <see cref="PdbLocalScope"/> class. /// </summary> /// <param name="function">Function that contains this scope.</param> /// <param name="handle">Our metadata reader handle.</param> /// <param name="parent">Parent scope.</param> internal PdbLocalScope(PdbFunction function, LocalScopeHandle handle, IPdbLocalScope parent = null) { Function = function; localScopeCache = SimpleCache.CreateStruct(() => function.PdbFile.Reader.GetLocalScope(handle)); childrenCache = SimpleCache.CreateStruct(() => { var enumerator = LocalScope.GetChildren(); List <IPdbLocalScope> children = new List <IPdbLocalScope>(); while (enumerator.MoveNext()) { children.Add(new PdbLocalScope(function, enumerator.Current, this)); } return(children); }); constantsCache = SimpleCache.CreateStruct(() => { var localConstants = LocalScope.GetLocalConstants(); IPdbLocalConstant[] constants = new IPdbLocalConstant[localConstants.Count]; int i = 0; foreach (var c in localConstants) { constants[i++] = new PdbLocalConstant(this, c); } return(constants); }); variablesCache = SimpleCache.CreateStruct(() => { var localVariables = LocalScope.GetLocalVariables(); IPdbLocalVariable[] variables = new IPdbLocalVariable[localVariables.Count]; int i = 0; foreach (var v in localVariables) { variables[i++] = new PdbLocalVariable(this, v); } return(variables); }); }
/// <summary> /// Initializes a new instance of the <see cref="DbiModuleDescriptor"/> class. /// </summary> /// <param name="reader">Stream binary reader.</param> /// <param name="moduleList">Owning module list.</param> public DbiModuleDescriptor(IBinaryReader reader, DbiModuleList moduleList) { ModuleList = moduleList; filesCache = SimpleCache.CreateStruct(() => { string[] files = new string[NumberOfFiles]; for (int i = 0; i < files.Length; i++) { files[i] = ModuleList.GetFileName(i + StartingFileIndex); } return(files); }); Header = ModuleInfoHeader.Read(reader); ModuleName = reader.ReadCString(); ObjectFileName = reader.ReadCString(); // Descriptors should be aligned at 4 bytes if (reader.Position % 4 != 0) { reader.Position += 4 - reader.Position % 4; } }
/// <summary> /// Initializes a new instance of the <see cref="PdbSource"/> class. /// </summary> /// <param name="pdbFile">Portable PDB file reader.</param> /// <param name="checksum">File checksum subsection.</param> internal PdbSource(PdbFile pdbFile, FileChecksumSubsection checksum) { PdbFile = pdbFile; Checksum = checksum; hashCache = SimpleCache.CreateStruct(() => GuidStream?.ChecksumReader.ReadAllBytes() ?? Checksum.HashReader.ReadAllBytes()); nameCache = SimpleCache.CreateStruct(() => PdbFile.NamesStream.Dictionary[checksum.NameIndex]); guidStreamCache = SimpleCache.CreateStruct(() => { int guidStreamIndex; if (PdbFile.Reader.InfoStream.NamedStreamMap.Streams.TryGetValue("/src/files/" + Name, out guidStreamIndex) || PdbFile.Reader.InfoStream.NamedStreamMap.StreamsUppercase.TryGetValue("/SRC/FILES/" + Name.ToUpperInvariant(), out guidStreamIndex)) { PdbStream guidStream = PdbFile.Reader.GetStream(guidStreamIndex); if (guidStream != null) { return(new GuidStream(guidStream)); } } return(null); }); }
/// <summary> /// Initializes a new instance of the <see cref="PdbFunction"/> class. /// </summary> /// <param name="pdbFile">Portable PDB file reader.</param> /// <param name="handle">Our metadata reader handle.</param> internal PdbFunction(PdbFile pdbFile, MethodDebugInformationHandle handle) { PdbFile = pdbFile; methodDebugInformationCache = SimpleCache.CreateStruct(() => pdbFile.Reader.GetMethodDebugInformation(handle)); localScopesCache = SimpleCache.CreateStruct(() => { var localScopes = pdbFile.Reader.GetLocalScopes(handle); IPdbLocalScope[] scopes = new IPdbLocalScope[localScopes.Count]; int i = 0; foreach (var l in localScopes) { scopes[i++] = new PdbLocalScope(this, l); } return(scopes); }); sequencePointsCache = SimpleCache.CreateStruct(() => { var sequencePoints = MethodDebugInformation.GetSequencePoints(); return(sequencePoints.Select(sp => new PdbSequencePoint(this, sp)).OfType <IPdbSequencePoint>().ToArray()); }); Token = System.Reflection.Metadata.Ecma335.MetadataTokens.GetToken(handle.ToDefinitionHandle()); }
/// <summary> /// Initializes a new instance of the <see cref="Symbol"/> class. /// </summary> /// <param name="module">The module.</param> public Symbol(Module module) { Module = module; fields = SimpleCache.CreateStruct(() => GetFields().ToArray()); baseClasses = SimpleCache.CreateStruct(() => GetBaseClasses().ToArray()); elementType = SimpleCache.CreateStruct(() => GetElementType()); pointerType = SimpleCache.CreateStruct(() => GetPointerType()); enumValues = SimpleCache.CreateStruct(() => GetEnumValues().ToArray()); enumValuesByValue = SimpleCache.CreateStruct(() => { Dictionary <string, string> values = new Dictionary <string, string>(); foreach (var kvp in EnumValues) { if (!values.ContainsKey(kvp.Item2)) { values.Add(kvp.Item2, kvp.Item1); } } return(values); }); namespaces = SimpleCache.CreateStruct(() => SymbolNameHelper.GetSymbolNamespaces(Name)); userType = SimpleCache.CreateStruct(() => (UserType)null); }
/// <summary> /// Initializes a new instance of the <see cref="PdbFile"/> class. /// </summary> /// <param name="path">Path to PDB file.</param> public PdbFile(string path) { File = new MMFile(path); Reader = new MMFileReader(File); // Parse file headers // Initialize MSF super block SuperBlock = MSF.SuperBlock.Read(Reader); SuperBlock.Validate(); if (File.Length % SuperBlock.BlockSize != 0) { throw new Exception("File size is not a multiple of block size"); } // Initialize Free Page Map. // The Fpm exists either at block 1 or block 2 of the MSF. However, this // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and // thusly an equal number of total blocks in the file. For a block size // of 4KiB (very common), this would yield 32KiB total blocks in file, for a // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so // the Fpm is split across the file at `getBlockSize()` intervals. As a // result, every block whose index is of the form |{1,2} + getBlockSize() * k| // for any non-negative integer k is an Fpm block. In theory, we only really // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but // current versions of the MSF format already expect the Fpm to be arranged // at getBlockSize() intervals, so we have to be compatible. // See the function fpmPn() for more information: // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 uint fpmIntervals = (SuperBlock.NumBlocks + 8 * SuperBlock.BlockSize - 1) / (8 * SuperBlock.BlockSize); uint[] fpmBlocks = new uint[fpmIntervals]; uint currentFpmBlock = SuperBlock.FreeBlockMapBlock; for (int i = 0; i < fpmBlocks.Length; i++) { fpmBlocks[i] = currentFpmBlock; currentFpmBlock += SuperBlock.BlockSize; } IBinaryReader fpmStream = new MappedBlockBinaryReader <MMFileReader>(fpmBlocks, SuperBlock.BlockSize, (SuperBlock.NumBlocks + 7) / 8, Reader); FreePageMap = Reader.ReadByteArray((int)fpmStream.Length); // Read directory blocks Reader.Position = (long)SuperBlock.BlockMapOffset; uint[] directoryBlocks = Reader.ReadUintArray((int)SuperBlock.NumDirectoryBlocks); // Parse stream data uint NumStreams = 0; PdbStream directoryStream = new PdbStream(directoryBlocks, SuperBlock.NumDirectoryBytes, this); NumStreams = directoryStream.Reader.ReadUint(); streams = new PdbStream[NumStreams]; uint[] streamSizes = directoryStream.Reader.ReadUintArray(streams.Length); for (int i = 0; i < streams.Length; i++) { uint streamSize = streamSizes[i]; uint NumExpectedStreamBlocks = streamSize == uint.MaxValue ? 0 : SuperBlock.BytesToBlocks(streamSize); uint[] blocks = directoryStream.Reader.ReadUintArray((int)NumExpectedStreamBlocks); foreach (uint block in blocks) { ulong blockEndOffset = SuperBlock.BlocksToBytes(block + 1); if (blockEndOffset > (ulong)File.Length) { throw new Exception("Stream block map is corrupt."); } } streams[i] = new PdbStream(blocks, streamSize, this); } if (directoryStream.Reader.Position != SuperBlock.NumDirectoryBytes) { throw new Exception("Not whole directory stream was read"); } dbiStreamCache = SimpleCache.CreateStruct(() => new DbiStream(streams[(uint)SpecialStream.StreamDBI])); pdbSymbolStreamCache = SimpleCache.CreateStruct(() => new SymbolStream(streams[DbiStream.SymbolRecordStreamIndex])); tpiStreamCache = SimpleCache.CreateStruct(() => new TpiStream(streams[(uint)SpecialStream.StreamTPI])); ipiStreamCache = SimpleCache.CreateStruct(() => new TpiStream(streams[(uint)SpecialStream.StreamIPI])); }
/// <summary> /// Initializes a new instance of the <see cref="PdbStream"/> class. /// </summary> /// <param name="stream">PDB symbol stream.</param> public TpiStream(PdbStream stream) { Stream = stream; if (stream.Reader.BytesRemaining < TpiStreamHeader.Size) { throw new Exception("TPI Stream does not contain a header."); } Header = TpiStreamHeader.Read(stream.Reader); if (Header.Version != PdbTpiVersion.V80) { throw new Exception("Unsupported TPI Version."); } if (Header.HeaderSize != TpiStreamHeader.Size) { throw new Exception("Corrupt TPI Header size."); } if (Header.HashKeySize != 4) // 4 = sizeof(uint) { throw new Exception("TPI Stream expected 4 byte hash key size."); } if (Header.HashBucketsCount < MinTpiHashBuckets || Header.HashBucketsCount > MaxTpiHashBuckets) { throw new Exception("TPI Stream Invalid number of hash buckets."); } // The actual type records themselves come from this stream TypeRecordsSubStream = Stream.Reader.ReadSubstream(Header.TypeRecordBytes); typeRecordsSubStreamPerThread = new System.Threading.ThreadLocal <IBinaryReader>(() => TypeRecordsSubStream.Duplicate()); IBinaryReader reader = TypeRecordsSubStream; long position = reader.Position, end = reader.Length; references = new List <RecordReference>(); while (position < end) { RecordPrefix prefix = RecordPrefix.Read(reader); if (prefix.RecordLength < 2) { throw new Exception("CV corrupt record"); } TypeLeafKind kind = (TypeLeafKind)prefix.RecordKind; ushort dataLen = prefix.DataLen; references.Add(new RecordReference { DataOffset = (uint)position + RecordPrefix.Size, Kind = kind, DataLen = dataLen, }); position += dataLen + RecordPrefix.Size; reader.Move(dataLen); } typesCache = new ArrayCache <TypeRecord>(references.Count, true, ReadType); typesByKindCache = new DictionaryCache <TypeLeafKind, TypeRecord[]>(GetTypesByKind); // Hash indices, hash values, etc come from the hash stream. HashSubstream = Stream.File.GetStream(Header.HashStreamIndex)?.Reader; hashValuesCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null) { // There should be a hash value for every type record, or no hashes at all. uint numHashValues = Header.HashValueBuffer.Length / 4; // 4 = sizeof(uint) if (numHashValues != references.Count && numHashValues != 0) { throw new Exception("TPI hash count does not match with the number of type records."); } HashSubstream.Position = Header.HashValueBuffer.Offset; return(HashSubstream.ReadUintArray(references.Count)); } return(null); }); typeIndexOffsetsCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null) { HashSubstream.Position = Header.IndexOffsetBuffer.Offset; uint numTypeIndexOffsets = Header.IndexOffsetBuffer.Length / TypeIndexOffset.Size; TypeIndexOffset[] typeIndexOffsets = new TypeIndexOffset[numTypeIndexOffsets]; for (uint i = 0; i < typeIndexOffsets.Length; i++) { typeIndexOffsets[i] = TypeIndexOffset.Read(HashSubstream); } return(typeIndexOffsets); } return(null); }); hashAdjustersCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null && Header.HashAdjustersBuffer.Length > 0) { HashSubstream.Position = Header.HashAdjustersBuffer.Offset; return(new HashTable(HashSubstream)); } return(null); }); hashTableCache = SimpleCache.CreateStruct(() => { uint[] hashes = HashValues; if (hashes != null) { // Construct hash table TypeIndexListItem[] hashTable = new TypeIndexListItem[Header.HashBucketsCount]; for (uint ti = Header.TypeIndexBegin, i = 0; ti < Header.TypeIndexEnd; ti++, i++) { uint bucket = hashes[i] % Header.HashBucketsCount; hashTable[bucket] = new TypeIndexListItem(new TypeIndex(ti), hashTable[bucket]); } // Use hash adjusters to improve hash table if (HashAdjusters != null) { var namesMap = Stream.File.InfoStream.NamesMap; foreach (var kvp in HashAdjusters.Dictionary) { uint nameIndex = kvp.Key; TypeIndex typeIndex = new TypeIndex(kvp.Value); string name = namesMap.GetString(nameIndex); uint hash = Windows.HashTable.HashStringV1(name) % (uint)hashTable.Length; // Find type index hash adjusters wants to be head for (TypeIndexListItem item = hashTable[hash], previousItem = null; item != null; previousItem = item, item = item.Next) { if (item.TypeIndex == typeIndex) { if (previousItem == null) { // Our type index is already at the head break; } previousItem.Next = item.Next; item.Next = hashTable[hash]; hashTable[hash] = item; break; } } } } return(hashTable); } return(null); }); }
public DifferentCachesStruct(bool unused) { simpleCache = SimpleCache.Create(() => 42); simpleCacheStruct = SimpleCache.CreateStruct(() => 42); }
public DifferentCaches() { simpleCache = SimpleCache.Create(() => 42); simpleCacheStruct = SimpleCache.CreateStruct(() => 42); simpleCacheWithContext = SimpleCache.CreateWithContext(this, simpleCacheWithContextStaticDelegate); }
/// <summary> /// Initializes a new instance of the <see cref="DbiStream"/> class. /// </summary> /// <param name="stream">PDB stream that contains DBI stream.</param> public DbiStream(PdbStream stream) { Stream = stream; stream.Reader.Position = 0; if (Stream.Length < DbiStreamHeader.Size) { throw new Exception("DBI Stream does not contain a header."); } Header = DbiStreamHeader.Read(stream.Reader); if (Header.VersionSignature != -1) { throw new Exception("Invalid DBI version signature."); } // Require at least version 7, which should be present in all PDBs // produced in the last decade and allows us to avoid having to // special case all kinds of complicated arcane formats. if (Header.Version < DbiStreamVersion.V70) { throw new Exception("Unsupported DBI version."); } int expectedSize = DbiStreamHeader.Size + Header.ModuleInfoSubstreamSize + Header.SectionContributionSubstreamSize + Header.SectionMapSize + Header.FileInfoSize + Header.TypeServerSize + Header.OptionalDebugHeaderSize + Header.ECSubstreamSize; if (Stream.Length != expectedSize) { throw new Exception("DBI Length does not equal sum of substreams."); } // Only certain substreams are guaranteed to be aligned. Validate // them here. if (Header.ModuleInfoSubstreamSize % 4 != 0) { throw new Exception("DBI MODI substream not aligned."); } if (Header.SectionContributionSubstreamSize % 4 != 0) { throw new Exception("DBI section contribution substream not aligned."); } if (Header.SectionMapSize % 4 != 0) { throw new Exception("DBI section map substream not aligned."); } if (Header.FileInfoSize % 4 != 0) { throw new Exception("DBI file info substream not aligned."); } if (Header.TypeServerSize % 4 != 0) { throw new Exception("DBI type server substream not aligned."); } // Get substreams ModuleInfoSubstream = stream.Reader.ReadSubstream(Header.ModuleInfoSubstreamSize); SectionContributionSubstream = stream.Reader.ReadSubstream(Header.SectionContributionSubstreamSize); SectionMapSubstream = stream.Reader.ReadSubstream(Header.SectionMapSize); FileInfoSubstream = stream.Reader.ReadSubstream(Header.FileInfoSize); TypeServerMapSubstream = stream.Reader.ReadSubstream(Header.TypeServerSize); ECSubstream = stream.Reader.ReadSubstream(Header.ECSubstreamSize); DebugStreamIndexes = stream.Reader.ReadUshortArray(Header.OptionalDebugHeaderSize / 2); if (stream.Reader.BytesRemaining > 0) { throw new Exception("Found unexpected bytes in DBI Stream."); } // Create caches for reading substreams modulesCache = SimpleCache.CreateStruct(() => { ModuleInfoSubstream.Position = 0; FileInfoSubstream.Position = 0; return(new DbiModuleList(ModuleInfoSubstream, FileInfoSubstream, this)); }); if (SectionContributionSubstream.Length > 0) { DbiSectionContributionVersion version = (DbiSectionContributionVersion)SectionContributionSubstream.ReadUint(); if (version != DbiSectionContributionVersion.V60 && version != DbiSectionContributionVersion.V2) { throw new Exception("Unsupported DBI Section Contribution version"); } } sectionContributionsCache = SimpleCache.CreateStruct(() => { SectionContributionEntry[] result = null; if (SectionContributionSubstream.Length > 0) { SectionContributionSubstream.Position = 0; DbiSectionContributionVersion version = (DbiSectionContributionVersion)SectionContributionSubstream.ReadUint(); if (version == DbiSectionContributionVersion.V60) { // Read array from the stream result = new SectionContributionEntry[SectionContributionSubstream.BytesRemaining / SectionContributionEntry.Size]; for (int i = 0; i < result.Length; i++) { result[i] = SectionContributionEntry.Read(SectionContributionSubstream); } } else { // Copy values from newer section contributions since it is expanded version of us. SectionContributionEntry2[] result2 = SectionContributions2; if (result2 != null) { result = new SectionContributionEntry[result2.Length]; for (int i = 0; i < result.Length; i++) { result[i] = result2[i].Base; } } } } return(result); }); sectionContributions2Cache = SimpleCache.CreateStruct(() => { SectionContributionEntry2[] result = null; if (SectionContributionSubstream.Length > 0) { SectionContributionSubstream.Position = 0; DbiSectionContributionVersion version = (DbiSectionContributionVersion)SectionContributionSubstream.ReadUint(); if (version == DbiSectionContributionVersion.V2) { // Read array from the stream result = new SectionContributionEntry2[SectionContributionSubstream.BytesRemaining / SectionContributionEntry2.Size]; for (int i = 0; i < result.Length; i++) { result[i] = SectionContributionEntry2.Read(SectionContributionSubstream); } } } return(result); }); CoffSectionHeader[] ReadSectionHeadersStream(IBinaryReader sectionHeaderStream) { if (sectionHeaderStream != null) { sectionHeaderStream.Position = 0; if (sectionHeaderStream.Length % CoffSectionHeader.Size != 0) { throw new Exception("Corrupted section header stream."); } int numSections = (int)(sectionHeaderStream.Length / CoffSectionHeader.Size); CoffSectionHeader[] sectionHeaders = new CoffSectionHeader[numSections]; for (int i = 0; i < numSections; i++) { sectionHeaders[i] = CoffSectionHeader.Read(sectionHeaderStream); } return(sectionHeaders); } return(null); }; sectionHeadersCache = SimpleCache.CreateStruct(() => ReadSectionHeadersStream(GetKnownDebugStream(KnownDebugStreamIndex.SectionHdr)?.Reader)); originalSectionHeadersCache = SimpleCache.CreateStruct(() => ReadSectionHeadersStream(GetKnownDebugStream(KnownDebugStreamIndex.SectionHdrOrig)?.Reader)); sectionMapCache = SimpleCache.CreateStruct(() => { if (SectionMapSubstream.Length > 0) { SectionMapSubstream.Position = 0; ushort secCount = SectionMapSubstream.ReadUshort(); ushort secCountLog = SectionMapSubstream.ReadUshort(); SectionMapEntry[] sectionMap = new SectionMapEntry[secCount]; for (int i = 0; i < sectionMap.Length; i++) { sectionMap[i] = SectionMapEntry.Read(SectionMapSubstream); } return(sectionMap); } return(null); }); fpoStreamCache = SimpleCache.CreateStruct(() => GetKnownDebugStream(KnownDebugStreamIndex.FPO)?.Reader); fpoRecordsCache = SimpleCache.CreateStruct(() => { if (FpoStream != null) { FpoStream.Position = 0; if (FpoStream.Length % FpoData.Size != 0) { throw new Exception("Corrupted New FPO stream."); } int numRecords = (int)(FpoStream.Length / FpoData.Size); FpoData[] fpoRecords = new FpoData[numRecords]; for (int i = 0; i < numRecords; i++) { fpoRecords[i] = FpoData.Read(FpoStream); } return(fpoRecords); } return(null); }); OmapEntry[] LoadOmapStream(IBinaryReader omapReader) { if (omapReader != null) { omapReader.Position = 0; if (omapReader.Length % OmapEntry.Size != 0) { throw new Exception("Corrupted Omap stream."); } int count = (int)(omapReader.Length / OmapEntry.Size); OmapEntry[] entries = new OmapEntry[count]; for (int i = 0; i < count; i++) { entries[i] = OmapEntry.Read(omapReader); } return(entries); } return(null); }; omapToSourceEntriesCache = SimpleCache.CreateStruct(() => LoadOmapStream(GetKnownDebugStream(KnownDebugStreamIndex.OmapToSrc)?.Reader)); omapFromSourceEntriesCache = SimpleCache.CreateStruct(() => LoadOmapStream(GetKnownDebugStream(KnownDebugStreamIndex.OmapFromSrc)?.Reader)); ecNamesCache = SimpleCache.CreateStruct(() => ECSubstream.Length > 0 ? new PdbStringTable(ECSubstream) : null); }
/// <summary> /// Initializes a new instance of the <see cref="DbiModuleList"/> class. /// </summary> /// <param name="moduleInfoStream">Module info stream binary reader.</param> /// <param name="fileInfoStream">File info stream binary reader.</param> public DbiModuleList(IBinaryReader moduleInfoStream, IBinaryReader fileInfoStream) { ModuleInfoStream = moduleInfoStream; modulesCache = SimpleCache.CreateStruct(() => { var descriptors = new List <DbiModuleDescriptor>(); while (ModuleInfoStream.BytesRemaining > 0) { descriptors.Add(new DbiModuleDescriptor(ModuleInfoStream, this)); } return(descriptors); }); FileInfoStream = fileInfoStream; if (fileInfoStream.Length > 0) { // Header: // ushort NumModules; // ushort NumSourceFiles; // Following this header the File Info Substream is laid out as follows: // ushort ModIndices[NumModules]; // ushort ModFileCounts[NumModules]; // uint FileNameOffsets[NumSourceFiles]; // char Names[][NumSourceFiles]; // with the caveat that `NumSourceFiles` cannot be trusted, so // it is computed by summing the `ModFileCounts` array. ushort modulesCount = fileInfoStream.ReadUshort(); ushort headerSourceFilesCount = fileInfoStream.ReadUshort(); // First is an array of `NumModules` module indices. This does not seem to be // used for anything meaningful, so we ignore it. ushort[] moduleIndexes = fileInfoStream.ReadUshortArray(modulesCount); ushort[] moduleFileCounts = fileInfoStream.ReadUshortArray(modulesCount); // Compute the real number of source files. We can't trust the value in // of headerSourceFilesCount because it is an ushort, and the sum of all // source file counts might be larger than an ushort. So we compute the real // count by summing up the individual counts. int sourceFilesCount = 0; for (int i = 0; i < moduleFileCounts.Length; i++) { sourceFilesCount += moduleFileCounts[i]; } // In the reference implementation, this array is where the pointer documented // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that // although the field in ModuleInfoHeader is ignored this array is not, as it // is the authority on where each filename begins in the names buffer. FileNameOffsets = fileInfoStream.ReadUintArray(sourceFilesCount); FileNamesStream = fileInfoStream.ReadSubstream(); fileNameCache = new DictionaryCache <uint, string>((uint namesOffset) => { FileNamesStream.Position = namesOffset; return(FileNamesStream.ReadCString()); }); if (Modules.Count != modulesCount) { throw new Exception("Inconsistent number of modules"); } int nextFileIndex = 0; for (int i = 0; i < modulesCount; i++) { Modules[i].StartingFileIndex = nextFileIndex; nextFileIndex += moduleFileCounts[i]; } } }
/// <summary> /// Initializes a new instance of the <see cref="PdbStream"/> class. /// </summary> /// <param name="stream">PDB symbol stream.</param> public TpiStream(PdbStream stream) { Stream = stream; if (stream.Reader.BytesRemaining < TpiStreamHeader.Size) { throw new Exception("TPI Stream does not contain a header."); } Header = TpiStreamHeader.Read(stream.Reader); if (Header.Version != PdbTpiVersion.V80) { throw new Exception("Unsupported TPI Version."); } if (Header.HeaderSize != TpiStreamHeader.Size) { throw new Exception("Corrupt TPI Header size."); } if (Header.HashKeySize != 4) // 4 = sizeof(uint) { throw new Exception("TPI Stream expected 4 byte hash key size."); } if (Header.HashBucketsCount < MinTpiHashBuckets || Header.HashBucketsCount > MaxTpiHashBuckets) { throw new Exception("TPI Stream Invalid number of hash buckets."); } // The actual type records themselves come from this stream TypeRecordsSubStream = Stream.Reader.ReadSubstream(Header.TypeRecordBytes); typeRecordsSubStreamPerThread = new System.Threading.ThreadLocal <IBinaryReader>(() => TypeRecordsSubStream.Duplicate()); IBinaryReader reader = TypeRecordsSubStream; long position = reader.Position, end = reader.Length; references = new List <RecordReference>(); while (position < end) { RecordPrefix prefix = RecordPrefix.Read(reader); if (prefix.RecordLength < 2) { throw new Exception("CV corrupt record"); } TypeLeafKind kind = (TypeLeafKind)prefix.RecordKind; ushort dataLen = prefix.DataLen; references.Add(new RecordReference { DataOffset = (uint)position + RecordPrefix.Size, Kind = kind, DataLen = dataLen, }); position += dataLen + RecordPrefix.Size; reader.ReadFake(dataLen); } typesCache = new ArrayCache <TypeRecord>(references.Count, true, ReadType); typesByKindCache = new DictionaryCache <TypeLeafKind, TypeRecord[]>(GetTypesByKind); // Hash indices, hash values, etc come from the hash stream. if (Header.HashStreamIndex != InvalidStreamIndex) { if (Header.HashStreamIndex >= Stream.File.Streams.Count) { throw new Exception("Invalid TPI hash stream index."); } HashSubstream = Stream.File.Streams[Header.HashStreamIndex].Reader; } hashValuesCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null) { // There should be a hash value for every type record, or no hashes at all. uint numHashValues = Header.HashValueBuffer.Length / 4; // 4 = sizeof(uint) if (numHashValues != references.Count && numHashValues != 0) { throw new Exception("TPI hash count does not match with the number of type records."); } HashSubstream.Position = Header.HashValueBuffer.Offset; return(HashSubstream.ReadUintArray(references.Count)); } return(null); }); typeIndexOffsetsCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null) { HashSubstream.Position = Header.IndexOffsetBuffer.Offset; uint numTypeIndexOffsets = Header.IndexOffsetBuffer.Length / TypeIndexOffset.Size; TypeIndexOffset[] typeIndexOffsets = new TypeIndexOffset[numTypeIndexOffsets]; for (uint i = 0; i < typeIndexOffsets.Length; i++) { typeIndexOffsets[i] = TypeIndexOffset.Read(HashSubstream); } return(typeIndexOffsets); } return(null); }); hashAdjustersCache = SimpleCache.CreateStruct(() => { if (HashSubstream != null && Header.HashAdjustersBuffer.Length > 0) { HashSubstream.Position = Header.HashAdjustersBuffer.Offset; return(new HashTable(HashSubstream)); } return(null); }); }