private void Test(TpiStream tpiStream) { Assert.Equal(tpiStream.TypeRecordCount, tpiStream.references.Count); Assert.NotEmpty(tpiStream.HashValues); if (tpiStream.HashAdjusters != null) { Assert.NotEmpty(tpiStream.HashAdjusters.Dictionary); } // Verify that type offsets are correct in references array foreach (TypeIndexOffset offset in tpiStream.TypeIndexOffsets) { var reference = tpiStream.references[(int)offset.Type.ArrayIndex]; Assert.Equal(offset.Offset, reference.DataOffset - RecordPrefix.Size); } // Verify that all types can be read for (int i = 0; i < tpiStream.references.Count; i++) { Assert.NotNull(tpiStream[TypeIndex.FromArrayIndex(i)]); } // Check that getting types by kind works correctly TypeLeafKind[] kinds = tpiStream.references.Select(r => r.Kind).Distinct().ToArray(); foreach (TypeLeafKind kind in kinds) { Assert.Equal(tpiStream.references.Count(r => r.Kind == kind), tpiStream[kind].Length); } }
public void ToStringTest() { TypeIndex typeIndexByte = new TypeIndex(SimpleTypeKind.Byte, SimpleTypeMode.Direct); TypeIndex typeIndexArray10 = TypeIndex.FromArrayIndex(10); Assert.NotNull(typeIndexByte.ToString()); Assert.NotNull(typeIndexArray10.ToString()); }
public void ArrayIndex() { TypeIndex typeIndex = TypeIndex.FromArrayIndex(10); Assert.False(typeIndex.IsSimple); Assert.False(typeIndex.IsNoneType); Assert.Equal(10U, typeIndex.ArrayIndex); }
/// <summary> /// Gets all type indexes for the specified type record kind. /// </summary> /// <param name="kind">Type record kind.</param> public IEnumerable <TypeIndex> GetIndexes(TypeLeafKind kind) { for (int i = 0; i < references.Count; i++) { if (references[i].Kind == kind) { yield return(TypeIndex.FromArrayIndex(i)); } } }
private void ReadTpiStream(TpiStream tpiStream) { if (tpiStream.HashSubstream != null) { Assert.NotNull(tpiStream.HashValues); Assert.NotEmpty(tpiStream.TypeIndexOffsets); } else { Assert.Null(tpiStream.HashValues); Assert.Null(tpiStream.TypeIndexOffsets); } if (tpiStream.HashSubstream != null && tpiStream.Header.HashAdjustersBuffer.Length > 0) { Assert.NotNull(tpiStream.HashAdjusters); } else { Assert.Null(tpiStream.HashAdjusters); } var references = tpiStream.References; Assert.NotNull(references); Assert.Equal(references.Count, tpiStream.TypeRecordCount); for (int i = 0; i < references.Count; i++) { Assert.NotNull(tpiStream[TypeIndex.FromArrayIndex(i)]); } var kinds = references.Select(r => r.Kind).Distinct().ToArray(); foreach (var kind in kinds) { Assert.NotEmpty(tpiStream.GetIndexes(kind)); Assert.NotEmpty(tpiStream[kind]); } // Check type record kinds var allKinds = new[] { ArgumentListRecord.Kinds, ArrayRecord.Kinds, BaseClassRecord.Kinds, BitFieldRecord.Kinds, BuildInfoRecord.Kinds, ClassRecord.Kinds, DataMemberRecord.Kinds, EnumeratorRecord.Kinds, EnumRecord.Kinds, FieldListRecord.Kinds, FunctionIdRecord.Kinds, LabelRecord.Kinds, ListContinuationRecord.Kinds, MemberFunctionIdRecord.Kinds, MemberFunctionRecord.Kinds, MethodOverloadListRecord.Kinds, ModifierRecord.Kinds, NestedTypeRecord.Kinds, OneMethodRecord.Kinds, OverloadedMethodRecord.Kinds, PointerRecord.Kinds, StaticDataMemberRecord.Kinds, StringIdRecord.Kinds, StringListRecord.Kinds, UdtModuleSourceLineRecord.Kinds, UnionRecord.Kinds, VirtualBaseClassRecord.Kinds, VirtualFunctionPointerRecord.Kinds, VirtualFunctionTableShapeRecord.Kinds, }; if (references.Count > 0) { Assert.NotEmpty(allKinds.SelectMany(ka => ka.SelectMany(k => tpiStream[k]))); } }
/// <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); }); }
private static void TestUdts(IDiaSession diaSession, PdbFile pdb) { // Extract all udts from PDB var typeRecordReferences = pdb.TpiStream.References; List <ClassRecord> classRecords = new List <ClassRecord>(); List <UnionRecord> unionRecords = new List <UnionRecord>(); for (int i = 0; i < typeRecordReferences.Count; i++) { if (ClassRecord.Kinds.Contains(typeRecordReferences[i].Kind)) { classRecords.Add((ClassRecord)pdb.TpiStream[TypeIndex.FromArrayIndex(i)]); } else if (UnionRecord.Kinds.Contains(typeRecordReferences[i].Kind)) { unionRecords.Add((UnionRecord)pdb.TpiStream[TypeIndex.FromArrayIndex(i)]); } } // Extract UDTs from DIA IDiaSymbol[] udts = diaSession.globalScope.GetChildren(SymTagEnum.UDT).ToArray(); HashSet <string> checkedUdts = new HashSet <string>(); List <Tuple <uint, TypeRecord> > checkedTypes = new List <Tuple <uint, TypeRecord> >(); foreach (IDiaSymbol udt in udts) { string name = udt.name; if (udt.length > 0 && !checkedUdts.Contains(name)) { UdtKind udtKind = (UdtKind)udt.udtKind; TagRecord record; if (udtKind == UdtKind.Union) { UnionRecord unionRecord = unionRecords.FirstOrDefault(cr => !cr.IsForwardReference && cr.Name.String == name); if (unionRecord == null) { unionRecord = unionRecords.FirstOrDefault(cr => cr.Name.String == name); } Assert.NotNull(unionRecord); record = unionRecord; } else { ClassRecord classRecord = classRecords.FirstOrDefault(cr => !cr.IsForwardReference && cr.Name.String == name); if (classRecord == null) { classRecord = classRecords.FirstOrDefault(cr => cr.Name.String == name); } Assert.NotNull(classRecord); record = classRecord; } CompareTypes(udt, pdb, record, checkedTypes); checkedUdts.Add(name); } } }
/// <summary> /// Creates new <see cref="PdbSymbol"/> for the specified type index. /// </summary> /// <param name="index">Type index in the TPI stream.</param> private PdbSymbol CreateSymbol(int index) { TypeIndex typeIndex = TypeIndex.FromArrayIndex(index); return(new PdbSymbol(this, typeIndex.Index, PdbFile.TpiStream[typeIndex])); }