private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, StandaloneSignatureHandle localSignatureHandleOpt, ref LocalVariableHandle lastLocalVariableHandle, ref LocalConstantHandle lastLocalConstantHandle) { if (bodyOpt == null) { _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle)); return; } bool isIterator = bodyOpt.StateMachineTypeName != null; bool emitDebugInfo = isIterator || bodyOpt.HasAnySequencePoints; if (!emitDebugInfo) { _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle)); return; } var methodHandle = MetadataTokens.MethodDefinitionHandle(methodRid); var bodyImportScope = bodyOpt.ImportScope; var importScopeHandle = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : default(ImportScopeHandle); // documents & sequence points: DocumentHandle singleDocumentHandle; ArrayBuilder <Cci.SequencePoint> sequencePoints = ArrayBuilder <Cci.SequencePoint> .GetInstance(); bodyOpt.GetSequencePoints(sequencePoints); BlobHandle sequencePointsBlob = SerializeSequencePoints(localSignatureHandleOpt, sequencePoints.ToImmutableAndFree(), _documentIndex, out singleDocumentHandle); _debugMetadataOpt.AddMethodDebugInformation(document: singleDocumentHandle, sequencePoints: sequencePointsBlob); // Unlike native PDB we don't emit an empty root scope. // scopes are already ordered by StartOffset ascending then by EndOffset descending (the longest scope first). if (bodyOpt.LocalScopes.Length == 0) { // TODO: the compiler should produce a scope for each debuggable method _debugMetadataOpt.AddLocalScope( method: methodHandle, importScope: importScopeHandle, variableList: NextHandle(lastLocalVariableHandle), constantList: NextHandle(lastLocalConstantHandle), startOffset: 0, length: bodyOpt.IL.Length); } else { foreach (LocalScope scope in bodyOpt.LocalScopes) { _debugMetadataOpt.AddLocalScope( method: methodHandle, importScope: importScopeHandle, variableList: NextHandle(lastLocalVariableHandle), constantList: NextHandle(lastLocalConstantHandle), startOffset: scope.StartOffset, length: scope.Length); foreach (ILocalDefinition local in scope.Variables) { Debug.Assert(local.SlotIndex >= 0); lastLocalVariableHandle = _debugMetadataOpt.AddLocalVariable( attributes: local.PdbAttributes, index: local.SlotIndex, name: _debugMetadataOpt.GetOrAddString(local.Name)); SerializeLocalInfo(local, lastLocalVariableHandle); } foreach (ILocalDefinition constant in scope.Constants) { var mdConstant = constant.CompileTimeValue; Debug.Assert(mdConstant != null); lastLocalConstantHandle = _debugMetadataOpt.AddLocalConstant( name: _debugMetadataOpt.GetOrAddString(constant.Name), signature: SerializeLocalConstantSignature(constant)); SerializeLocalInfo(constant, lastLocalConstantHandle); } } } var asyncDebugInfo = bodyOpt.AsyncDebugInfo; if (asyncDebugInfo != null) { _debugMetadataOpt.AddStateMachineMethod( moveNextMethod: methodHandle, kickoffMethod: GetMethodDefinitionHandle(asyncDebugInfo.KickoffMethod)); SerializeAsyncMethodSteppingInfo(asyncDebugInfo, methodHandle); } SerializeStateMachineLocalScopes(bodyOpt, methodHandle); // delta doesn't need this information - we use information recorded by previous generation emit if (Context.Module.CommonCompilation.Options.EnableEditAndContinue && !IsFullMetadata) { SerializeEncMethodDebugInformation(bodyOpt, methodHandle); } }
public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter) { Debug.Assert(_metadataWriter != null); bool isIterator = methodBody.StateMachineTypeName != null; bool emitDebugInfo = isIterator || methodBody.HasAnySequencePoints; if (!emitDebugInfo) { return; } uint methodToken = _metadataWriter.GetMethodToken(methodBody.MethodDefinition); OpenMethod(methodToken); var localScopes = methodBody.LocalScopes; // CCI originally didn't have the notion of the default scope that is open // when a method is opened. In order to reproduce CSC PDBs, this must be added. Otherwise // a seemingly unnecessary scope that contains only other scopes is put in the PDB. if (localScopes.Length > 0) { this.DefineScopeLocals(localScopes[0], localSignatureToken); } // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal // custom debug info (e.g. there will be no information about the usings that were in scope). if (!isIterator) { IMethodDefinition forwardToMethod; if (customDebugInfoWriter.ShouldForwardNamespaceScopes(Context, methodBody, methodToken, out forwardToMethod)) { if (forwardToMethod != null) { UsingNamespace("@" + _metadataWriter.GetMethodToken(forwardToMethod), methodBody.MethodDefinition); } // otherwise, the forwarding is done via custom debug info } else { this.DefineNamespaceScopes(methodBody); } } DefineLocalScopes(localScopes, localSignatureToken); EmitSequencePoints(methodBody.GetSequencePoints()); AsyncMethodBodyDebugInfo asyncDebugInfo = methodBody.AsyncDebugInfo; if (asyncDebugInfo != null) { SetAsyncInfo( methodToken, _metadataWriter.GetMethodToken(asyncDebugInfo.KickoffMethod), asyncDebugInfo.CatchHandlerOffset, asyncDebugInfo.YieldOffsets, asyncDebugInfo.ResumeOffsets); } var compilationOptions = Context.ModuleBuilder.CommonCompilation.Options; // We need to avoid emitting CDI DynamicLocals = 5 and EditAndContinueLocalSlotMap = 6 for files processed by WinMDExp until // bug #1067635 is fixed and available in SDK. bool suppressNewCustomDebugInfo = !compilationOptions.ExtendedCustomDebugInformation || (compilationOptions.OutputKind == OutputKind.WindowsRuntimeMetadata); bool emitEncInfo = compilationOptions.EnableEditAndContinue && !_metadataWriter.IsFullMetadata; bool emitExternNamespaces; byte[] blob = customDebugInfoWriter.SerializeMethodDebugInfo(Context, methodBody, methodToken, emitEncInfo, suppressNewCustomDebugInfo, out emitExternNamespaces); if (blob != null) { DefineCustomMetadata("MD2", blob); } if (emitExternNamespaces) { this.DefineAssemblyReferenceAliases(); } // TODO: it's not clear why we are closing a scope here with IL length: CloseScope(methodBody.IL.Length); CloseMethod(); }
public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter) { Debug.Assert(_metadataWriter != null); bool isIterator = methodBody.StateMachineTypeName != null; bool emitDebugInfo = isIterator || methodBody.HasAnySequencePoints; if (!emitDebugInfo) { return; } int methodToken = _metadataWriter.GetMethodToken(methodBody.MethodDefinition); OpenMethod((uint)methodToken, methodBody.MethodDefinition); var localScopes = methodBody.LocalScopes; // Define locals, constants and namespaces in the outermost local scope (opened in OpenMethod): if (localScopes.Length > 0) { this.DefineScopeLocals(localScopes[0], localSignatureToken); } // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal // custom debug info (e.g. there will be no information about the usings that were in scope). if (!isIterator && methodBody.ImportScope != null) { IMethodDefinition forwardToMethod; if (customDebugInfoWriter.ShouldForwardNamespaceScopes(Context, methodBody, methodToken, out forwardToMethod)) { if (forwardToMethod != null) { UsingNamespace("@" + _metadataWriter.GetMethodToken(forwardToMethod), methodBody.MethodDefinition); } // otherwise, the forwarding is done via custom debug info } else { this.DefineNamespaceScopes(methodBody); } } DefineLocalScopes(localScopes, localSignatureToken); EmitSequencePoints(methodBody.GetSequencePoints()); AsyncMethodBodyDebugInfo asyncDebugInfo = methodBody.AsyncDebugInfo; if (asyncDebugInfo != null) { SetAsyncInfo( methodToken, _metadataWriter.GetMethodToken(asyncDebugInfo.KickoffMethod), asyncDebugInfo.CatchHandlerOffset, asyncDebugInfo.YieldOffsets, asyncDebugInfo.ResumeOffsets); } var compilationOptions = Context.ModuleBuilder.CommonCompilation.Options; // We need to avoid emitting CDI DynamicLocals = 5 and EditAndContinueLocalSlotMap = 6 for files processed by WinMDExp until // bug #1067635 is fixed and available in SDK. bool suppressNewCustomDebugInfo = !compilationOptions.ExtendedCustomDebugInformation || (compilationOptions.OutputKind == OutputKind.WindowsRuntimeMetadata); bool emitEncInfo = compilationOptions.EnableEditAndContinue && !_metadataWriter.IsFullMetadata; bool emitExternNamespaces; byte[] blob = customDebugInfoWriter.SerializeMethodDebugInfo(Context, methodBody, methodToken, emitEncInfo, suppressNewCustomDebugInfo, out emitExternNamespaces); if (blob != null) { DefineCustomMetadata("MD2", blob); } if (emitExternNamespaces) { this.DefineAssemblyReferenceAliases(); } CloseMethod(methodBody.IL.Length); }
private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int localSignatureRowId) { if (bodyOpt == null) { _methodBodyTable.Add(default(MethodBodyRow)); return; } bool isIterator = bodyOpt.StateMachineTypeName != null; bool emitDebugInfo = isIterator || bodyOpt.HasAnySequencePoints; if (!emitDebugInfo) { _methodBodyTable.Add(default(MethodBodyRow)); return; } var bodyImportScope = bodyOpt.ImportScope; int importScopeRid = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : 0; // documents & sequence points: BlobIdx sequencePointsBlob = SerializeSequencePoints(localSignatureRowId, bodyOpt.GetSequencePoints(), _documentIndex); _methodBodyTable.Add(new MethodBodyRow { SequencePoints = sequencePointsBlob }); // Unlike native PDB we don't emit an empty root scope. // scopes are already ordered by StartOffset ascending then by EndOffset descending (the longest scope first). if (bodyOpt.LocalScopes.Length == 0) { // TODO: the compiler should produce a scope for each debuggable method _localScopeTable.Add(new LocalScopeRow { Method = (uint)methodRid, ImportScope = (uint)importScopeRid, VariableList = (uint)_localVariableTable.Count + 1, ConstantList = (uint)_localConstantTable.Count + 1, StartOffset = 0, Length = (uint)bodyOpt.IL.Length }); } else { foreach (LocalScope scope in bodyOpt.LocalScopes) { _localScopeTable.Add(new LocalScopeRow { Method = (uint)methodRid, ImportScope = (uint)importScopeRid, VariableList = (uint)_localVariableTable.Count + 1, ConstantList = (uint)_localConstantTable.Count + 1, StartOffset = (uint)scope.StartOffset, Length = (uint)scope.Length }); foreach (ILocalDefinition local in scope.Variables) { Debug.Assert(local.SlotIndex >= 0); _localVariableTable.Add(new LocalVariableRow { Attributes = (ushort)local.PdbAttributes, Index = (ushort)local.SlotIndex, Name = _debugHeapsOpt.GetStringIndex(local.Name) }); SerializeDynamicLocalInfo(local, rowId: _localVariableTable.Count, isConstant: false); } foreach (ILocalDefinition constant in scope.Constants) { var mdConstant = constant.CompileTimeValue; Debug.Assert(mdConstant != null); _localConstantTable.Add(new LocalConstantRow { Name = _debugHeapsOpt.GetStringIndex(constant.Name), Signature = SerializeLocalConstantSignature(constant) }); SerializeDynamicLocalInfo(constant, rowId: _localConstantTable.Count, isConstant: true); } } } var asyncDebugInfo = bodyOpt.AsyncDebugInfo; if (asyncDebugInfo != null) { _stateMachineMethodTable.Add(new StateMachineMethodRow { MoveNextMethod = (uint)methodRid, KickoffMethod = (uint)GetMethodDefIndex(asyncDebugInfo.KickoffMethod) }); SerializeAsyncMethodSteppingInfo(asyncDebugInfo, methodRid); } SerializeStateMachineLocalScopes(bodyOpt, methodRid); // delta doesn't need this information - we use information recorded by previous generation emit if (Context.ModuleBuilder.CommonCompilation.Options.EnableEditAndContinue && !IsFullMetadata) { SerializeEncMethodDebugInformation(bodyOpt, methodRid); } }
public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter) { Debug.Assert(peWriter != null); bool isIterator = methodBody.IteratorClassName != null; bool emitDebugInfo = isIterator || methodBody.HasAnyLocations; if (!emitDebugInfo) { return; } uint methodToken = peWriter.GetMethodToken(methodBody.MethodDefinition); OpenMethod(methodToken); var localScopes = methodBody.LocalScopes; // CCI originally didn't have the notion of the default scope that is open // when a method is opened. In order to reproduce CSC PDBs, this must be added. Otherwise // a seemingly unnecessary scope that contains only other scopes is put in the PDB. if (localScopes.Length > 0) { this.DefineScopeLocals(localScopes[0], localSignatureToken); } // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method // that appears in source, not the synthesized ones), Dev10 only emits the ForwardIterator and IteratorLocal // custom debug info (e.g. there will be no information about the usings that were in scope). if (!isIterator) { IMethodDefinition forwardToMethod; if (customDebugInfoWriter.ShouldForwardNamespaceScopes(methodBody, methodToken, out forwardToMethod)) { if (forwardToMethod != null) { string usingString = "@" + peWriter.GetMethodToken(forwardToMethod); Debug.Assert(!peWriter.IsUsingStringTooLong(usingString)); UsingNamespace(usingString, methodBody.MethodDefinition.Name); } // otherwise, the forwarding is done via custom debug info } else { this.DefineNamespaceScopes(methodBody); } } DefineLocalScopes(localScopes, localSignatureToken); EmitSequencePoints(methodBody.GetSequencePoints()); AsyncMethodBodyDebugInfo asyncDebugInfo = methodBody.AsyncMethodDebugInfo; if (asyncDebugInfo != null) { SetAsyncInfo( methodToken, peWriter.GetMethodToken(asyncDebugInfo.KickoffMethod), asyncDebugInfo.CatchHandlerOffset, asyncDebugInfo.YieldOffsets, asyncDebugInfo.ResumeOffsets); } var module = peWriter.Context.Module; bool emitExternNamespaces; byte[] blob = customDebugInfoWriter.SerializeMethodDebugInfo(module, methodBody, methodToken, out emitExternNamespaces); if (blob != null) { DefineCustomMetadata("MD2", blob); } if (emitExternNamespaces) { this.DefineExternAliases(module); } // TODO: it's not clear why we are closing a scope here with IL length: CloseScope((uint)methodBody.IL.Length); CloseMethod(); }