Beispiel #1
0
        /// <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);
            });
        }
Beispiel #2
0
        /// <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);
            });
        }