public void PdbStream_TypeSystemRowCounts() { var rowCounts = new int[MetadataTokens.TableCount]; rowCounts[(int)TableIndex.MethodDef] = 0xFFFFFF; rowCounts[(int)TableIndex.TypeDef] = 0x123456; var mdBuilder = new MetadataBuilder(); var pdbBuilder = new PortablePdbBuilder( mdBuilder, ImmutableArray.Create(rowCounts), MetadataTokens.MethodDefinitionHandle(0x123456), _ => new BlobContentId(new Guid("44332211-6655-8877-AA99-010203040506"), 0xFFEEDDCC)); var builder = new BlobBuilder(); pdbBuilder.Serialize(builder); AssertEx.Equal(new byte[] { // PDB ID 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xAA, 0x99, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xCC, 0xDD, 0xEE, 0xFF, // EntryPoint 0x56, 0x34, 0x12, 0x06, // ReferencedTypeSystemTables 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TypeSystemTableRows 0x56, 0x34, 0x12, 0x00, 0xFF, 0xFF, 0xFF, 0x00 }, builder.Slice(124, -40)); }
public void Hello() { var metadata = new MetadataBuilder(0, 0, 0, 0); var location = Assembly.GetExecutingAssembly().Location; var pdbPath = Path.ChangeExtension(location, "pdb"); using (var fileStream = new FileStream(pdbPath, FileMode.Open)) { var readerProvider = MetadataReaderProvider.FromPortablePdbStream(fileStream, MetadataStreamOptions.Default); var reader = readerProvider.GetMetadataReader(MetadataReaderOptions.ApplyWindowsRuntimeProjections, null); var debugDir = new DebugDirectoryBuilder(); debugDir.AddEmbeddedPortablePdbEntry(null, 0); var blob = new BlobBuilder(); var methodHandle = new MethodDefinitionHandle(); var pdb = new PortablePdbBuilder(metadata, ImmutableArray <int> .Empty, methodHandle, null); var blobContentId = pdb.Serialize(blob); blob.ToArray(); } }
public void Serialize_Errors() { var mdBuilder = new MetadataBuilder(); var pdbBuilder = new PortablePdbBuilder(mdBuilder, MetadataRootBuilder.EmptyRowCounts, default(MethodDefinitionHandle)); var builder = new BlobBuilder(); Assert.Throws <ArgumentNullException>(() => pdbBuilder.Serialize(null)); }
public void Serialize_Errors() { var mdBuilder = new MetadataBuilder(); var pdbBuilder = new PortablePdbBuilder(mdBuilder, MetadataRootBuilder.EmptyRowCounts, default(MethodDefinitionHandle)); var builder = new BlobBuilder(); Assert.Throws<ArgumentNullException>(() => pdbBuilder.Serialize(null)); }
public static void Convert(Stream peStream, Stream sourcePdbStream, Stream targetPdbStream) { var metadataBuilder = new MetadataBuilder(); ImmutableArray <int> typeSystemRowCounts; var debugEntryPointToken = default(MethodDefinitionHandle); var pdbId = default(BlobContentId); try { using (var peReader = new PEReader(peStream)) { pdbId = ReadPdbId(peReader); var symReader = SymReaderFactory.CreateWindowsPdbReader(sourcePdbStream, peReader); var metadataReader = peReader.GetMetadataReader(); var metadataModel = new MetadataModel(metadataReader); typeSystemRowCounts = metadataModel.GetRowCounts(); debugEntryPointToken = ReadEntryPointHandle(symReader); // documents: var documentIndex = new Dictionary <string, DocumentHandle>(StringComparer.Ordinal); var documents = symReader.GetDocuments(); metadataBuilder.SetCapacity(TableIndex.Document, documents.Length); bool vbSemantics = false; foreach (var document in documents) { string name = document.GetName(); Guid language = document.GetLanguage(); // TODO: // won't work for IL-merged assmemblies vbSemantics |= language == SymReaderHelpers.VisualBasicLanguageGuid; var rid = metadataBuilder.AddDocument( name: metadataBuilder.GetOrAddDocumentName(name), hashAlgorithm: metadataBuilder.GetOrAddGuid(document.GetHashAlgorithm()), hash: metadataBuilder.GetOrAddBlob(document.GetChecksum()), language: metadataBuilder.GetOrAddGuid(language)); documentIndex.Add(name, rid); } var lastLocalVariableHandle = default(LocalVariableHandle); var lastLocalConstantHandle = default(LocalConstantHandle); var importStringsByMethod = new Dictionary <int, ImmutableArray <string> >(); var importScopesByMethod = new Dictionary <int, ImportScopeHandle>(); // Maps import scope content to import scope handles var importScopeIndex = new Dictionary <ImportScopeInfo, ImportScopeHandle>(); var importScopes = new List <ImportScopeInfo>(); // reserve slot for module import scope: importScopes.Add(default(ImportScopeInfo)); var externAliasImports = new List <ImportInfo>(); var externAliasStringSet = new HashSet <string>(StringComparer.Ordinal); string vbDefaultNamespace = null; var vbProjectLevelImports = new List <ImportInfo>(); // first pass: foreach (var methodHandle in metadataReader.MethodDefinitions) { int methodToken = MetadataTokens.GetToken(methodHandle); ImmutableArray <ImmutableArray <ImportInfo> > importGroups; if (vbSemantics) { var importStrings = CustomDebugInfoReader.GetVisualBasicImportStrings( methodToken, symReader, getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr)); if (importStrings.IsEmpty) { // no debug info continue; } var vbFileLevelImports = ArrayBuilder <ImportInfo> .GetInstance(); foreach (var importString in importStrings) { if (TryParseImportString(importString, out var import, vbSemantics: true)) { if (import.Kind == ImportTargetKind.DefaultNamespace) { vbDefaultNamespace = import.Target; } else if (import.Scope == VBImportScopeKind.Project) { vbProjectLevelImports.Add(import); } else { vbFileLevelImports.Add(import); } } } importGroups = ImmutableArray.Create(vbFileLevelImports.ToImmutableAndFree()); } else { var importStringGroups = CustomDebugInfoReader.GetCSharpGroupedImportStrings( methodToken, symReader, getMethodCustomDebugInfo: (token, sr) => sr.GetCustomDebugInfo(token, methodVersion: 1), getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr), externAliasStrings: out var localExternAliasStrings); if (importStringGroups.IsDefault) { // no debug info continue; } if (!localExternAliasStrings.IsDefault) { foreach (var externAlias in localExternAliasStrings) { if (externAliasStringSet.Add(externAlias) && TryParseImportString(externAlias, out var import, vbSemantics: false)) { externAliasImports.Add(import); } } } importGroups = ImmutableArray.CreateRange(importStringGroups.Select(g => ParseImportStrings(g, vbSemantics: false))); } var importScopeHandle = DefineImportScope(importGroups, importScopeIndex, importScopes); importScopesByMethod.Add(methodToken, importScopeHandle); } // import scopes: metadataBuilder.AddImportScope( parentScope: default(ImportScopeHandle), imports: SerializeModuleImportScope(metadataBuilder, externAliasImports, vbProjectLevelImports, vbDefaultNamespace, metadataModel)); for (int i = 1; i < importScopes.Count; i++) { metadataBuilder.AddImportScope( parentScope: importScopes[i].Parent, imports: SerializeImportsBlob(metadataBuilder, importScopes[i].Imports, metadataModel)); } var dynamicNames = new Dictionary <string, DynamicLocalInfo>(); var dynamicSlots = new Dictionary <int, DynamicLocalInfo>(); // methods: metadataBuilder.SetCapacity(TableIndex.MethodDebugInformation, metadataReader.MethodDefinitions.Count); foreach (var methodHandle in metadataReader.MethodDefinitions) { var methodDef = metadataReader.GetMethodDefinition(methodHandle); int methodToken = MetadataTokens.GetToken(methodHandle); var symMethod = symReader.GetMethod(methodToken); if (symMethod == null) { metadataBuilder.AddMethodDebugInformation(default(DocumentHandle), sequencePoints: default(BlobHandle)); continue; } // method debug info: int localSignatureRowId; if (methodDef.RelativeVirtualAddress != 0) { var methodBody = peReader.GetMethodBody(methodDef.RelativeVirtualAddress); localSignatureRowId = methodBody.LocalSignature.IsNil ? 0 : MetadataTokens.GetRowNumber(methodBody.LocalSignature); } else { localSignatureRowId = 0; } var symSequencePoints = symMethod.GetSequencePoints().ToImmutableArray(); DocumentHandle singleDocumentHandle; BlobHandle sequencePointsBlob = SerializeSequencePoints(metadataBuilder, localSignatureRowId, symSequencePoints, documentIndex, out singleDocumentHandle); metadataBuilder.AddMethodDebugInformation( document: singleDocumentHandle, sequencePoints: sequencePointsBlob); // state machine and async info: var symAsyncMethod = symMethod.AsAsyncMethod(); if (symAsyncMethod != null) { var kickoffToken = MetadataTokens.Handle(symAsyncMethod.GetKickoffMethod()); metadataBuilder.AddStateMachineMethod( moveNextMethod: methodHandle, kickoffMethod: (MethodDefinitionHandle)kickoffToken); metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob), value: SerializeAsyncMethodSteppingInfo(metadataBuilder, symAsyncMethod, MetadataTokens.GetRowNumber(methodHandle))); } // custom debug information: var dynamicLocals = default(ImmutableArray <DynamicLocalInfo>); byte[] customDebugInfoBytes = symReader.GetCustomDebugInfo(methodToken, methodVersion: 1); if (customDebugInfoBytes != null) { foreach (var record in CustomDebugInfoReader.GetCustomDebugInfoRecords(customDebugInfoBytes)) { switch (record.Kind) { case CustomDebugInfoKind.DynamicLocals: dynamicLocals = CustomDebugInfoReader.DecodeDynamicLocalsRecord(record.Data); break; case CustomDebugInfoKind.StateMachineHoistedLocalScopes: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap), value: SerializeStateMachineHoistedLocalsBlob(metadataBuilder, CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(record.Data))); break; case CustomDebugInfoKind.EditAndContinueLocalSlotMap: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap), value: metadataBuilder.GetOrAddBlob(record.Data)); break; case CustomDebugInfoKind.EditAndContinueLambdaMap: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), value: metadataBuilder.GetOrAddBlob(record.Data)); break; } } } var rootScope = symMethod.GetRootScope(); if (rootScope.GetNamespaces().Length == 0 || rootScope.GetLocals().Length == 0 || rootScope.GetConstants().Length == 0) { dynamicNames.Clear(); dynamicSlots.Clear(); foreach (var dynamicLocal in dynamicLocals) { if (dynamicLocal.SlotId == 0) { // All dynamic constants have slot id == 0, // but a variable can also have slot id == 0 if (!dynamicNames.ContainsKey(dynamicLocal.LocalName)) { dynamicNames.Add(dynamicLocal.LocalName, dynamicLocal); } else { // TODO: warning } } else if (!dynamicSlots.ContainsKey(dynamicLocal.SlotId)) { dynamicSlots.Add(dynamicLocal.SlotId, dynamicLocal); } else { // TODO: warning } } foreach (ISymUnmanagedScope scope in rootScope.GetChildren()) { SerializeScope( metadataBuilder, metadataModel, methodHandle, importScopesByMethod[methodToken], scope, dynamicSlots, dynamicNames, vbSemantics, ref lastLocalVariableHandle, ref lastLocalConstantHandle); } } else { // TODO: warning: // "Root scope must be empty (method 0x{0:x8})", MetadataTokens.GetToken(methodHandle)) } } } } catch (COMException e) { // TODO: loc throw new BadImageFormatException("Invalid PDB format: " + e.Message, e); } var serializer = new PortablePdbBuilder(metadataBuilder, typeSystemRowCounts, debugEntryPointToken, idProvider: _ => pdbId); BlobBuilder blobBuilder = new BlobBuilder(); serializer.Serialize(blobBuilder); blobBuilder.WriteContentTo(targetPdbStream); }
public void Headers() { var mdBuilder = new MetadataBuilder(); var pdbBuilder = new PortablePdbBuilder( mdBuilder, MetadataRootBuilder.EmptyRowCounts, MetadataTokens.MethodDefinitionHandle(0x123456), _ => new BlobContentId(new Guid("44332211-6655-8877-AA99-010203040506"), 0xFFEEDDCC)); var builder = new BlobBuilder(); pdbBuilder.Serialize(builder); AssertEx.Equal(new byte[] { // signature: 0x42, 0x53, 0x4A, 0x42, // major version (1) 0x01, 0x00, // minor version (1) 0x01, 0x00, // reserved (0) 0x00, 0x00, 0x00, 0x00, // padded version length: 0x0C, 0x00, 0x00, 0x00, // padded version: (byte)'P', (byte)'D', (byte)'B', (byte)' ', (byte)'v', (byte)'1', (byte)'.', (byte)'0', 0x00, 0x00, 0x00, 0x00, // flags (0): 0x00, 0x00, // stream count: 0x06, 0x00, // stream headers (offset, size, padded name) 0x7C, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, (byte)'#', (byte)'P', (byte)'d', (byte)'b', 0x00, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, (byte)'#', (byte)'~', 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, (byte)'#', (byte)'S', (byte)'t', (byte)'r', (byte)'i', (byte)'n', (byte)'g', (byte)'s', 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, (byte)'#', (byte)'U', (byte)'S', 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)'#', (byte)'G', (byte)'U', (byte)'I', (byte)'D', 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, (byte)'#', (byte)'B', (byte)'l', (byte)'o', (byte)'b', 0x00, 0x00, 0x00, // -------- // #Pdb // -------- // PDB ID 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xAA, 0x99, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xCC, 0xDD, 0xEE, 0xFF, // EntryPoint 0x56, 0x34, 0x12, 0x06, // ReferencedTypeSystemTables 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TypeSystemTableRows (empty) // -------- // #~ // -------- // Reserved (0) 0x00, 0x00, 0x00, 0x00, // Major Version (2) 0x02, // Minor Version (0) 0x00, // Heap Sizes 0x00, // Reserved (1) 0x01, // Present tables 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Sorted tables 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Rows (empty) // Tables (empty) // Padding and alignment 0x00, 0x00, 0x00, 0x00, // -------- // #Strings // -------- 0x00, 0x00, 0x00, 0x00, // -------- // #US // -------- 0x00, 0x00, 0x00, 0x00, // -------- // #GUID // -------- // -------- // #Blob // -------- 0x00, 0x00, 0x00, 0x00, }, builder.ToArray()); }
public static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, Func <Stream> getPeStream, Func <Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool allowMissingMethodBodies, bool isDeterministic, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); MetadataWriter mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken); ModulePropertiesForSerialization properties = context.Module.SerializationProperties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(properties.PersistentIdentifier == default(Guid)); BlobBuilder ilBuilder = new BlobBuilder(32 * 1024); BlobBuilder mappedFieldDataBuilder = new BlobBuilder(); BlobBuilder managedResourceBuilder = new BlobBuilder(1024); mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, out Blob mvidFixup, out Blob mvidStringFixup); mdWriter.GetEntryPoints(out MethodDefinitionHandle entryPointHandle, out MethodDefinitionHandle debugEntryPointHandle); if (!debugEntryPointHandle.IsNil) { nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle)); } if (nativePdbWriterOpt != null) { if (mdWriter.Module.OutputKind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } // embedded text not currently supported for native PDB and we should have validated that Debug.Assert(!mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments.Any()); } Stream peStream = getPeStream(); if (peStream == null) { return(false); } BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(BlobContentId); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; ushort portablePdbVersion = 0; MetadataRootBuilder metadataRootBuilder = mdWriter.GetRootBuilder(); PEHeaderBuilder peHeaderBuilder = new PEHeaderBuilder( machine: properties.Machine, sectionAlignment: properties.SectionAlignment, fileAlignment: properties.FileAlignment, imageBase: properties.BaseAddress, majorLinkerVersion: properties.LinkerMajorVersion, minorLinkerVersion: properties.LinkerMinorVersion, majorOperatingSystemVersion: 4, minorOperatingSystemVersion: 0, majorImageVersion: 0, minorImageVersion: 0, majorSubsystemVersion: properties.MajorSubsystemVersion, minorSubsystemVersion: properties.MinorSubsystemVersion, subsystem: properties.Subsystem, dllCharacteristics: properties.DllCharacteristics, imageCharacteristics: properties.ImageCharacteristics, sizeOfStackReserve: properties.SizeOfStackReserve, sizeOfStackCommit: properties.SizeOfStackCommit, sizeOfHeapReserve: properties.SizeOfHeapReserve, sizeOfHeapCommit: properties.SizeOfHeapCommit); Func <IEnumerable <Blob>, BlobContentId> deterministicIdProvider = isDeterministic ? new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) : null; BlobBuilder portablePdbToEmbed = null; if (mdWriter.EmitStandaloneDebugMetadata) { mdWriter.AddRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments); BlobBuilder portablePdbBlob = new BlobBuilder(); PortablePdbBuilder portablePdbBuilder = mdWriter.GetPortablePdbBuilder(metadataRootBuilder.Sizes.RowCounts, debugEntryPointHandle, deterministicIdProvider); pdbContentId = portablePdbBuilder.Serialize(portablePdbBlob); portablePdbVersion = portablePdbBuilder.FormatVersion; if (getPortablePdbStreamOpt == null) { // embed to debug directory: portablePdbToEmbed = portablePdbBlob; } else { // write to Portable PDB stream: Stream portablePdbStream = getPortablePdbStreamOpt(); if (portablePdbStream != null) { portablePdbBlob.WriteContentTo(portablePdbStream); } } } DebugDirectoryBuilder debugDirectoryBuilder; if (pdbPathOpt != null || isDeterministic || portablePdbToEmbed != null) { debugDirectoryBuilder = new DebugDirectoryBuilder(); if (pdbPathOpt != null) { string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt); debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion); } if (isDeterministic) { debugDirectoryBuilder.AddReproducibleEntry(); } if (portablePdbToEmbed != null) { debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbToEmbed, portablePdbVersion); } } else { debugDirectoryBuilder = null; } ManagedPEBuilder peBuilder = new ManagedPEBuilder( peHeaderBuilder, metadataRootBuilder, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, CreateNativeResourceSectionSerializer(context.Module), debugDirectoryBuilder, CalculateStrongNameSignatureSize(context.Module), entryPointHandle, properties.CorFlags, deterministicIdProvider); BlobBuilder peBlob = new BlobBuilder(); BlobContentId peContentId = peBuilder.Serialize(peBlob); PatchModuleVersionIds(mvidFixup, mvidStringFixup, peContentId.Guid); try { peBlob.WriteContentTo(peStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new PeWritingException(e); } return(true); }