Example #1
0
        private static void CompareTypes(IDiaSymbol diaType, PdbType pdbType, HashSet <Tuple <uint, PdbType> > checkedTypes)
        {
            if (diaType == null)
            {
                Assert.True(pdbType.TypeIndex.IsNoneType);
                return;
            }

            uint diaSymbolId       = diaType.symIndexId;
            var  checkedTypesTuple = Tuple.Create(diaSymbolId, pdbType);

            if (checkedTypes.Contains(checkedTypesTuple))
            {
                return;
            }
            checkedTypes.Add(checkedTypesTuple);

            Assert.Equal(diaType.length, pdbType.Size);
            Assert.Equal(diaType.constType, pdbType.ModifierOptions.HasFlag(ModifierOptions.Const));
            Assert.Equal(diaType.unalignedType, pdbType.ModifierOptions.HasFlag(ModifierOptions.Unaligned));
            Assert.Equal(diaType.volatileType, pdbType.ModifierOptions.HasFlag(ModifierOptions.Volatile));
            if (diaType.symTag == SymTagEnum.UDT)
            {
                Assert.IsAssignableFrom <PdbUserDefinedType>(pdbType);
                PdbUserDefinedType pdbUdt = (PdbUserDefinedType)pdbType;

                if (pdbType.Name != "<unnamed-tag>")
                {
                    Assert.Equal(diaType.name, pdbType.Name);
                }
                Assert.Equal(diaType.nested, pdbUdt.IsNested);
                Assert.Equal(diaType.scoped, pdbUdt.IsScoped);
                Assert.Equal(diaType.packed, pdbUdt.IsPacked);
                Assert.Equal(diaType.overloadedOperator, pdbUdt.HasOverloadedOperator);
                Assert.Equal(diaType.hasNestedTypes, pdbUdt.ContainsNestedClass);
                Assert.Equal(diaType.hasAssignmentOperator, pdbUdt.HasOverloadedAssignmentOperator);
                Assert.Equal(diaType.constructor, pdbUdt.HasConstructorOrDestructor);

                // Fields
                var diaData   = diaType.GetChildren(SymTagEnum.Data).ToArray();
                var diaFields = diaData.Where(d => d.locationType == LocationType.ThisRel || d.locationType == LocationType.BitField).ToArray();
                var pdbFields = pdbUdt.Fields;

                Assert.Equal(diaFields.Length, pdbFields.Count);
                for (int i = 0; i < pdbFields.Count; i++)
                {
                    if (pdbFields[i] is PdbTypeBitField bitField)
                    {
                        Assert.Equal(LocationType.BitField, diaFields[i].locationType);
                        Assert.Equal(diaFields[i].bitPosition, bitField.BitOffset);
                        Assert.Equal(diaFields[i].length, bitField.BitSize);
                    }
                    Assert.Equal(diaFields[i].access, (uint)pdbFields[i].Access);
                    Assert.Equal(diaFields[i].name, pdbFields[i].Name);
                    Assert.Equal((ulong)diaFields[i].offset, pdbFields[i].Offset);
                    CompareTypes(diaFields[i].type, pdbFields[i].Type, checkedTypes);
                }

                // Constants
                var diaConstants = diaData.Where(d => d.locationType == LocationType.Constant).ToArray();
                var pdbConstants = pdbUdt.StaticFields.OfType <PdbTypeConstant>().ToArray();

                Assert.Equal(diaConstants.Length, pdbConstants.Length);
                for (int i = 0; i < pdbConstants.Length; i++)
                {
                    Assert.Equal(diaConstants[i].access, (uint)pdbConstants[i].Access);
                    Assert.Equal(diaConstants[i].name, pdbConstants[i].Name);
                    Assert.Equal(diaConstants[i].value.ToString(), pdbConstants[i].Value.ToString());
                    CompareTypes(diaConstants[i].type, pdbConstants[i].Type, checkedTypes);
                }

                // Thread local storage
                var diaTls = diaData.Where(d => d.locationType == LocationType.TLS).ToArray();
                var pdbTls = pdbUdt.StaticFields.OfType <PdbTypeThreadLocalStorage>().ToArray();

                Assert.Equal(diaTls.Length, pdbTls.Length);
                for (int i = 0; i < pdbTls.Length; i++)
                {
                    Assert.Equal(diaTls[i].access, (uint)pdbTls[i].Access);
                    Assert.Equal(diaTls[i].name, pdbTls[i].Name);
                    Assert.Equal(diaTls[i].addressSection, pdbTls[i].Segment);
                    Assert.Equal(diaTls[i].addressOffset, pdbTls[i].Offset);
                    CompareTypes(diaTls[i].type, pdbTls[i].Type, checkedTypes);
                }

                // Static fields
                var diaStaticFields = diaData.Where(d => d.locationType == LocationType.Static).ToArray();
                var pdbStaticFields = pdbUdt.StaticFields.Where(sf => !(sf is PdbTypeConstant) && !(sf is PdbTypeThreadLocalStorage)).ToArray();

                Assert.Equal(diaStaticFields.Length, pdbStaticFields.Length);
                for (int i = 0; i < pdbStaticFields.Length; i++)
                {
                    Assert.Equal(diaStaticFields[i].access, (uint)pdbStaticFields[i].Access);
                    Assert.Equal(diaStaticFields[i].name, pdbStaticFields[i].Name);
                    if (pdbStaticFields[i] is PdbTypeRegularStaticField regularStaticField)
                    {
                        Assert.Equal(diaStaticFields[i].addressSection, regularStaticField.Segment);
                        Assert.Equal(diaStaticFields[i].addressOffset, regularStaticField.Offset);
                        Assert.Equal(diaStaticFields[i].relativeVirtualAddress, regularStaticField.RelativeVirtualAddress);
                    }
                    CompareTypes(diaStaticFields[i].type, pdbStaticFields[i].Type, checkedTypes);
                }

                // Base classes
                var diaAllBaseClasses = diaType.GetChildren(SymTagEnum.BaseClass).Concat(diaType.GetChildren(SymTagEnum.BaseInterface)).ToArray();
                var diaBaseClasses    = diaAllBaseClasses.Where(b => !b.virtualBaseClass).ToArray();

                Assert.Equal(diaBaseClasses.Length, pdbUdt.BaseClasses.Count);
                for (int i = 0; i < diaBaseClasses.Length; i++)
                {
                    Assert.Equal(diaBaseClasses[i].access, (uint)pdbUdt.BaseClasses[i].Access);
                    Assert.Equal(diaBaseClasses[i].offset, (int)pdbUdt.BaseClasses[i].Offset);
                    CompareTypes(diaBaseClasses[i].type, pdbUdt.BaseClasses[i].BaseType, checkedTypes);
                }

                // Virtual base classes
                var diaVirtualBaseClasses = diaAllBaseClasses.Where(b => b.virtualBaseClass).ToArray();

                Assert.Equal(diaVirtualBaseClasses.Length, pdbUdt.VirtualBaseClasses.Count);
                for (int i = 0; i < diaVirtualBaseClasses.Length; i++)
                {
                    Assert.Equal(diaVirtualBaseClasses[i].access, (uint)pdbUdt.VirtualBaseClasses[i].Access);
                    Assert.Equal(diaVirtualBaseClasses[i].virtualBaseDispIndex, (uint)pdbUdt.VirtualBaseClasses[i].VirtualTableIndex);
                    Assert.Equal(diaVirtualBaseClasses[i].virtualBasePointerOffset, (int)pdbUdt.VirtualBaseClasses[i].VirtualBasePointerOffset);
                    CompareTypes(diaVirtualBaseClasses[i].type, pdbUdt.VirtualBaseClasses[i].BaseType, checkedTypes);
                    CompareTypes(diaVirtualBaseClasses[i].virtualBaseTableType, pdbUdt.VirtualBaseClasses[i].VirtualBasePointerType, checkedTypes);
                }
            }
            else if (diaType.symTag == SymTagEnum.Enum)
            {
                Assert.IsAssignableFrom <PdbEnumType>(pdbType);
                PdbEnumType pdbEnumType = (PdbEnumType)pdbType;

                Assert.Equal(diaType.name, pdbType.Name);
                Assert.Equal(diaType.nested, pdbEnumType.IsNested);
                Assert.Equal(diaType.scoped, pdbEnumType.IsScoped);
                Assert.Equal(diaType.packed, pdbEnumType.IsPacked);
                Assert.Equal(diaType.overloadedOperator, pdbEnumType.HasOverloadedOperator);
                Assert.Equal(diaType.hasNestedTypes, pdbEnumType.ContainsNestedClass);
                Assert.Equal(diaType.hasAssignmentOperator, pdbEnumType.HasOverloadedAssignmentOperator);
                Assert.Equal(diaType.constructor, pdbEnumType.HasConstructorOrDestructor);
                CompareBaseType(diaType.type, pdbEnumType.UnderlyingType);
                CompareBaseType(diaType, pdbEnumType.UnderlyingType);

                // Compare enumeration values
                var diaValues = diaType.GetChildren(SymTagEnum.Data).ToArray();

                Assert.Equal(diaValues.Length, pdbEnumType.Values.Count);
                for (int i = 0; i < diaValues.Length; i++)
                {
                    Assert.Equal(DataKind.Constant, diaValues[i].dataKind);
                    Assert.Equal(diaValues[i].name, pdbEnumType.Values[i].Name);
                    Assert.Equal(diaValues[i].value.ToString(), pdbEnumType.Values[i].Value.ToString());
                }
            }
            else if (diaType.symTag == SymTagEnum.BaseType)
            {
                CompareBaseType(diaType, pdbType);
            }
            else if (diaType.symTag == SymTagEnum.ArrayType)
            {
                Assert.IsAssignableFrom <PdbArrayType>(pdbType);
                PdbArrayType pdbArrayType = (PdbArrayType)pdbType;

                Assert.Equal(diaType.count, pdbArrayType.Count);
                CompareTypes(diaType.type, pdbArrayType.ElementType, checkedTypes);
                CompareTypes(diaType.arrayIndexType, pdbArrayType.IndexType, checkedTypes);
            }
            else if (diaType.symTag == SymTagEnum.PointerType)
            {
                Assert.IsAssignableFrom <PdbPointerType>(pdbType);
                PdbPointerType pdbPointerType = (PdbPointerType)pdbType;

                Assert.Equal(diaType.reference, pdbPointerType.IsLValueReference);
                Assert.Equal(diaType.RValueReference, pdbPointerType.IsRValueReference);
                CompareTypes(diaType.type, pdbPointerType.ElementType, checkedTypes);
            }
            else if (diaType.symTag == SymTagEnum.FunctionType)
            {
                PdbType           returnType;
                CallingConvention callingConvention;
                ushort            parameterCount;
                PdbType[]         pdbArguments;

                if (pdbType is PdbFunctionType)
                {
                    Assert.IsAssignableFrom <PdbFunctionType>(pdbType);
                    PdbFunctionType pdbFunctionType = (PdbFunctionType)pdbType;

                    returnType        = pdbFunctionType.ReturnType;
                    callingConvention = pdbFunctionType.CallingConvention;
                    parameterCount    = pdbFunctionType.ParameterCount;
                    pdbArguments      = pdbFunctionType.Arguments;
                }
                else
                {
                    Assert.IsAssignableFrom <PdbMemberFunctionType>(pdbType);
                    PdbMemberFunctionType pdbMemberFunctionType = (PdbMemberFunctionType)pdbType;

                    returnType        = pdbMemberFunctionType.ReturnType;
                    callingConvention = pdbMemberFunctionType.CallingConvention;
                    parameterCount    = pdbMemberFunctionType.ParameterCount;
                    pdbArguments      = pdbMemberFunctionType.Arguments;

                    CompareTypes(diaType.objectPointerType, pdbMemberFunctionType.ThisType, checkedTypes);
                    Assert.Equal(diaType.thisAdjust, pdbMemberFunctionType.ThisPointerAdjustment);
                }

                Assert.Equal(diaType.callingConvention, (uint)callingConvention);
                Assert.Equal(diaType.count, parameterCount);
                CompareTypes(diaType.type, returnType, checkedTypes);

                IDiaSymbol[] diaArguments = diaType.GetChildren(SymTagEnum.FunctionArgType).ToArray();

                Assert.Equal(diaArguments.Length, pdbArguments.Length);
                for (int i = 0; i < diaArguments.Length; i++)
                {
                    CompareTypes(diaArguments[i].type, pdbArguments[i], checkedTypes);
                }
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Example #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeField"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="dataMemberRecord">The data member record.</param>
 internal PdbTypeField(PdbUserDefinedType containerType, DataMemberRecord dataMemberRecord)
 {
     ContainerType    = containerType;
     DataMemberRecord = dataMemberRecord;
 }
Example #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeRegularStaticField"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="staticDataMemberRecord">The static data member record.</param>
 /// <param name="data">Data symbol for this static field.</param>
 internal PdbTypeRegularStaticField(PdbUserDefinedType containerType, StaticDataMemberRecord staticDataMemberRecord, DataSymbol data)
     : base(containerType, staticDataMemberRecord)
 {
     Data = data;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeBitField"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="dataMemberRecord">The data member record.</param>
 /// <param name="bitFieldRecord">The bit field record.</param>
 internal PdbTypeBitField(PdbUserDefinedType containerType, DataMemberRecord dataMemberRecord, BitFieldRecord bitFieldRecord)
     : base(containerType, dataMemberRecord)
 {
     BitFieldRecord = bitFieldRecord;
 }
Example #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeStaticField"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="staticDataMemberRecord">The static data member record.</param>
 internal PdbTypeStaticField(PdbUserDefinedType containerType, StaticDataMemberRecord staticDataMemberRecord)
 {
     ContainerType          = containerType;
     StaticDataMemberRecord = staticDataMemberRecord;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeConstant"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="staticDataMemberRecord">The static data member record.</param>
 /// <param name="constant">The constant symbol.</param>
 internal PdbTypeConstant(PdbUserDefinedType containerType, StaticDataMemberRecord staticDataMemberRecord, ConstantSymbol constant)
     : base(containerType, staticDataMemberRecord)
 {
     Constant = constant;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PdbTypeThreadLocalStorage"/> class.
 /// </summary>
 /// <param name="containerType">Type that contains this field.</param>
 /// <param name="staticDataMemberRecord">The static data member record.</param>
 /// <param name="threadLocalData">The thread local data.</param>
 internal PdbTypeThreadLocalStorage(PdbUserDefinedType containerType, StaticDataMemberRecord staticDataMemberRecord, ThreadLocalDataSymbol threadLocalData)
     : base(containerType, staticDataMemberRecord)
 {
     ThreadLocalData = threadLocalData;
 }
Example #8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PdbFileReader"/> class.
        /// </summary>
        /// <param name="pdbFile">Opened PDB file.</param>
        private PdbFileReader(PdbFile pdbFile)
        {
            PdbFile               = pdbFile;
            typesByIndex          = new DictionaryCache <TypeIndex, PdbType>(CreateType);
            userDefinedTypesCache = SimpleCache.CreateStruct(() =>
            {
                List <PdbType> types        = new List <PdbType>();
                var references              = PdbFile.TpiStream.References;
                TypeLeafKind[] allowedKinds = ClassRecord.Kinds.Concat(UnionRecord.Kinds).Concat(EnumRecord.Kinds).ToArray();

                for (int i = 0; i < references.Count; i++)
                {
                    if (allowedKinds.Contains(references[i].Kind))
                    {
                        TypeIndex typeIndex   = TypeIndex.FromArrayIndex(i);
                        TypeRecord typeRecord = PdbFile.TpiStream[typeIndex];
                        PdbType pdbType       = typesByIndex[typeIndex];

                        if (typeRecord is TagRecord tagRecord)
                        {
                            // Check if it is forward reference and if it has been resolved.
                            PdbUserDefinedType pdbUserDefinedType = (PdbUserDefinedType)pdbType;

                            if (pdbUserDefinedType.TagRecord != tagRecord)
                            {
                                continue;
                            }
                        }
                        types.Add(pdbType);
                    }
                }
                return((IReadOnlyList <PdbType>)types);
            });
            globalVarablesCache = SimpleCache.CreateStruct(() =>
            {
                var data = PdbFile.GlobalsStream.Data;
                PdbGlobalVariable[] globalVariables = new PdbGlobalVariable[data.Count];

                for (int i = 0; i < data.Count; i++)
                {
                    globalVariables[i] = new PdbGlobalVariable(this, data[i]);
                }
                return(globalVariables);
            });
            publicSymbolsCache = SimpleCache.CreateStruct(() =>
            {
                PdbPublicSymbol[] publicSymbols = new PdbPublicSymbol[PdbFile.PublicsStream.PublicSymbols.Count];

                for (int i = 0; i < publicSymbols.Length; i++)
                {
                    publicSymbols[i] = new PdbPublicSymbol(this, PdbFile.PublicsStream.PublicSymbols[i]);
                }
                return(publicSymbols);
            });
            functionsCache = SimpleCache.CreateStruct(() =>
            {
                List <PdbFunction> functions = new List <PdbFunction>();
                var references = PdbFile.PdbSymbolStream?.References;
                var modules    = PdbFile.DbiStream?.Modules;

                if (references != null && modules != null)
                {
                    HashSet <uint>[] selectedFunctions = new HashSet <uint> [modules.Count];

                    for (int i = 0; i < references.Count; i++)
                    {
                        ProcedureSymbol procedure = null;

                        switch (references[i].Kind)
                        {
                        // ProcedureSymbol
                        case SymbolRecordKind.S_GPROC32:
                        case SymbolRecordKind.S_LPROC32:
                        case SymbolRecordKind.S_GPROC32_ID:
                        case SymbolRecordKind.S_LPROC32_ID:
                        case SymbolRecordKind.S_LPROC32_DPC:
                        case SymbolRecordKind.S_LPROC32_DPC_ID:
                            procedure = PdbFile.PdbSymbolStream[i] as ProcedureSymbol;
                            break;

                        // ProcedureReferenceSymbol
                        case SymbolRecordKind.S_PROCREF:
                        case SymbolRecordKind.S_LPROCREF:
                            {
                                ProcedureReferenceSymbol procedureReference = PdbFile.PdbSymbolStream[i] as ProcedureReferenceSymbol;
                                int moduleIndex = procedureReference.Module - 1;

                                if (moduleIndex >= 0 && moduleIndex < modules.Count)
                                {
                                    var module = modules[moduleIndex];

                                    if (selectedFunctions[moduleIndex] == null)
                                    {
                                        selectedFunctions[moduleIndex] = new HashSet <uint>();
                                    }
                                    if (!selectedFunctions[moduleIndex].Contains(procedureReference.Offset) &&
                                        module.LocalSymbolStream.TryGetSymbolRecordByOffset(procedureReference.Offset, out SymbolRecord procedureSymbol))
                                    {
                                        procedure = procedureSymbol as ProcedureSymbol;
                                        selectedFunctions[moduleIndex].Add(procedureReference.Offset);
                                    }
                                }
                            }
                            break;
                        }

                        if (procedure != null)
                        {
                            functions.Add(new PdbFunction(this, procedure));
                        }
                    }
                }
                return(functions);
            });
        }