public virtual ILGenerator MinimalReplacementGeneratorForBody(IMethodBody methodBody) { var generator = new ILGenerator(host, methodBody.MethodDefinition); AppendEmitExceptionThrow(generator); return generator; }
public SynthesizedMethodBodyDecorator(IMethodBody methodBody, IList<IType> locals, byte[] customBody) : this(methodBody) { this.customBody = customBody; var index = 0; this.locals = locals.Select(t => new SynthesizedLocalVariable(index++, t)).ToList(); }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); this.sourceEmitterOutput.WriteLine(MemberHelper.GetMethodSignature(methodBody.MethodDefinition, NameFormattingOptions.Signature|NameFormattingOptions.ReturnType|NameFormattingOptions.ParameterModifiers|NameFormattingOptions.ParameterName)); sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) PrintScopes(methodBody); else PrintLocals(methodBody.LocalVariables); this.cdfg = ControlAndDataFlowGraph<AiBasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); this.cfgQueries = new ControlGraphQueries<AiBasicBlock<Instruction>, Instruction>(this.cdfg); SingleAssigner<AiBasicBlock<Instruction>, Instruction>.GetInSingleAssignmentForm(host.NameTable, this.cdfg, this.cfgQueries, this.pdbReader); this.valueMappings = new ValueMappings<Instruction>(this.host.PlatformType, new Z3Wrapper.Wrapper(host.PlatformType)); AbstractInterpreter<AiBasicBlock<Instruction>, Instruction>.InterpretUsingAbstractValues(this.cdfg, this.cfgQueries, this.valueMappings); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
internal InstructionParser(SourceMethodBody sourceMethodBody) { Contract.Requires(sourceMethodBody != null); this.sourceMethodBody = sourceMethodBody; this.host = sourceMethodBody.host; Contract.Assume(this.host != null); this.ilMethodBody = sourceMethodBody.ilMethodBody; Contract.Assume(this.ilMethodBody != null); this.MethodDefinition = sourceMethodBody.MethodDefinition; this.nameTable = sourceMethodBody.nameTable; Contract.Assume(this.nameTable != null); this.sourceLocationProvider = sourceMethodBody.sourceLocationProvider; this.localScopeProvider = sourceMethodBody.localScopeProvider; this.options = sourceMethodBody.options; this.platformType = sourceMethodBody.platformType; Contract.Assume(this.platformType != null); this.numberOfAssignmentsToLocal = sourceMethodBody.numberOfAssignmentsToLocal; Contract.Assume(this.numberOfAssignmentsToLocal != null); this.numberOfReferencesToLocal = sourceMethodBody.numberOfReferencesToLocal; Contract.Assume(this.numberOfReferencesToLocal != null); this.gotosThatTarget = sourceMethodBody.gotosThatTarget; Contract.Assume(this.gotosThatTarget != null); this.cdfg = sourceMethodBody.cdfg; Contract.Assume(this.cdfg != null); this.bindingsThatMakeALastUseOfALocalVersion = sourceMethodBody.bindingsThatMakeALastUseOfALocalVersion; Contract.Assume(this.bindingsThatMakeALastUseOfALocalVersion != null); if (this.localScopeProvider != null) { var syncInfo = this.localScopeProvider.GetSynchronizationInformation(sourceMethodBody); if (syncInfo != null) { var syncPointFor = this.synchronizatonPointLocationFor = new Hashtable<SynchronizationPointLocation>(); IDocument doc = Dummy.Document; foreach (var loc in this.MethodDefinition.Locations) { doc = loc.Document; break; } foreach (var syncPoint in syncInfo.SynchronizationPoints) { Contract.Assume(syncPoint != null); var syncLoc = new SynchronizationPointLocation(doc, syncPoint); syncPointFor[syncPoint.SynchronizeOffset] = syncLoc; if (syncPoint.ContinuationMethod == null) syncPointFor[syncPoint.ContinuationOffset] = syncLoc; } } } }
public override ILGenerator DebugReplacementGeneratorForBody(IMethodBody methodBody) { string warningText = "Attempt to execute garbage collected method: " + methodBody.MethodDefinition.ToString(); var generator = new ILGenerator(host, methodBody.MethodDefinition); // emit console warning generator.Emit(OperationCode.Ldstr, warningText); generator.Emit(OperationCode.Call, this.consoleWriteLine); //emit stack trace // pushes stack trace on stack generator.Emit(OperationCode.Call, this.environmentGetStackTrace); // consumes stack trace generator.Emit(OperationCode.Call, this.consoleWriteLine); // may want to flush output? // emit exit generator.Emit(OperationCode.Ldc_I4_M1); generator.Emit(OperationCode.Call, this.environmentExit); // Makes the verifier happy; this should never be reached AppendEmitExceptionThrow(generator); return generator; }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedSingleDimArrayIListSetItemMethod(IType arrayType, ITypeResolver typeResolver) : base("set_Item", arrayType, typeResolver.System.System_Void) { var codeList = new IlCodeBuilder(); codeList.LoadArgument(0); codeList.LoadArgument(1); codeList.LoadArgument(2); codeList.Add(Code.Stelem, 1); codeList.Add(Code.Ret); var locals = new List<IType>(); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, codeList.GetCode()); this._parameters = new List<IParameter>(); this._parameters.Add(typeResolver.System.System_Int32.ToParameter()); this._parameters.Add(arrayType.GetElementType().ToParameter()); this._tokenResolutions = new List<object>(); this._tokenResolutions.Add(arrayType.GetElementType()); }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedSingleDimArrayIListGetEnumeratorMethod(IType arrayType, ITypeResolver typeResolver) : base("GetEnumerator", arrayType, typeResolver.System.System_Collections_Generic_IEnumerator_T.Construct(arrayType.GetElementType())) { var codeList = new IlCodeBuilder(); codeList.LoadArgument(0); codeList.Add(Code.Newobj, 1); codeList.Add(Code.Newobj, 2); codeList.Add(Code.Ret); var locals = new List<IType>(); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, codeList.GetCode()); this._parameters = new List<IParameter>(); this._tokenResolutions = new List<object>(); var arraySegmentType = typeResolver.System.System_ArraySegment_T1.Construct(arrayType.GetElementType()); this._tokenResolutions.Add( IlReader.Constructors(arraySegmentType, typeResolver).First(c => c.GetParameters().Count() == 1)); this._tokenResolutions.Add( IlReader.Constructors(arraySegmentType.GetNestedTypes().First(), typeResolver).First(c => c.GetParameters().Count() == 1)); }
protected void VerifyResult(IMethodBody mb) { var s_actual = mb.StringJoin(Environment.NewLine); s_actual = Regex.Replace(s_actual, @"Snippets.<>c__DisplayClass.*::", "<Closure>::"); s_actual = Regex.Replace(s_actual, @"CS\$<>8__locals.*\)", "<Closure>)"); s_actual = Regex.Replace(s_actual, @"0x[a-fA-f0-9]{8}", "<MetadataToken>"); VerifyResult(s_actual); }
/// <summary> /// Rewrites the target method body. This class will only insert a single call into the beginning of the /// method that writes it's signature using the <see cref="TestUtil"/> class. /// </summary> /// <param name="methodBody"> /// The method body to rewrite. /// </param> /// <returns> /// The rewritten method body. /// </returns> public override IMethodBody Rewrite(IMethodBody methodBody) { if (this.rewriter == null) { throw new InvalidOperationException("Unable to rewrite method body. Call Rewrite(IInstrumentationTarget target) instead of calling this directly."); } return this.rewriter.Rewrite(methodBody); }
public byte[] SerializeMethodDebugInfo(EmitContext context, IMethodBody methodBody, uint methodToken, bool isEncDelta, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces) { emitExternNamespaces = false; // CONSIDER: this may not be the same "first" method as in Dev10, but // it shouldn't matter since all methods will still forward to a method // containing the appropriate information. if (_methodBodyWithModuleInfo == null) //UNDONE: || edit-and-continue { // This module level information could go on every method (and does in // the edit-and-continue case), but - as an optimization - we'll just // put it on the first method we happen to encounter and then put a // reference to the first method's token in every other method (so they // can find the information). if (context.Module.GetAssemblyReferenceAliases(context).Any()) { _methodTokenWithModuleInfo = methodToken; _methodBodyWithModuleInfo = methodBody; emitExternNamespaces = true; } } var customDebugInfo = ArrayBuilder<MemoryStream>.GetInstance(); SerializeIteratorClassMetadata(methodBody, customDebugInfo); // 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). // NOTE: There seems to be an unusual behavior in ISymUnmanagedWriter where, if all the methods in a type are // iterator methods, no custom debug info is emitted for any method. Adding a single non-iterator // method causes the custom debug info to be produced for all methods (including the iterator methods). // Since we are making the same ISymUnmanagedWriter calls as Dev10, we see the same behavior (i.e. this // is not a regression). if (methodBody.StateMachineTypeName == null) { SerializeNamespaceScopeMetadata(context, methodBody, customDebugInfo); SerializeStateMachineLocalScopes(methodBody, customDebugInfo); } if (!suppressNewCustomDebugInfo) { SerializeDynamicLocalInfo(methodBody, customDebugInfo); // delta doesn't need this information - we use information recorded by previous generation emit if (!isEncDelta) { var encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody); SerializeCustomDebugInformation(encMethodInfo, customDebugInfo); } } byte[] result = SerializeCustomDebugMetadata(customDebugInfo); customDebugInfo.Free(); return result; }
public SynthesizedMethodDecorator( IMethod method, IMethodBody methodBody, IEnumerable<IParameter> parameters, IModule module) : this(method) { this.methodBody = methodBody; this.module = module; this.parameters = parameters; }
public override IMethodBody Rewrite(IMethodBody methodBody) { this.cdfg = ControlAndDataFlowGraph<BasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(this.host, methodBody); this.ilGenerator = new ILGenerator(host, methodBody.MethodDefinition); var numberOfBlocks = this.cdfg.BlockFor.Count; this.labelFor = new Hashtable<ILGeneratorLabel>(numberOfBlocks); this.counterFieldsForCurrentMethod = new NestedTypeDefinition() { BaseClasses = new List<ITypeReference>(1) { this.host.PlatformType.SystemObject }, ContainingTypeDefinition = methodBody.MethodDefinition.ContainingTypeDefinition, Fields = new List<IFieldDefinition>((int)numberOfBlocks*2), Methods = new List<IMethodDefinition>(1), InternFactory = this.host.InternFactory, IsBeforeFieldInit = true, IsClass = true, IsSealed = true, IsAbstract = true, Name = this.host.NameTable.GetNameFor(methodBody.MethodDefinition.Name+"_Counters"+methodBody.MethodDefinition.InternedKey), Visibility = TypeMemberVisibility.Assembly, }; this.fieldOffsets = new List<uint>((int)numberOfBlocks*2); foreach (var exceptionInfo in methodBody.OperationExceptionInformation) { this.ilGenerator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType, this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset), this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset), exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null); } if (this.pdbReader == null) { foreach (var localDef in methodBody.LocalVariables) this.ilGenerator.AddVariableToCurrentScope(localDef); } else { foreach (var ns in this.pdbReader.GetNamespaceScopes(methodBody)) { foreach (var uns in ns.UsedNamespaces) this.ilGenerator.UseNamespace(uns.NamespaceName.Value); } this.scopeEnumerator = this.pdbReader.GetLocalScopes(methodBody).GetEnumerator(); this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext(); } foreach (var block in this.cdfg.AllBlocks) this.InstrumentBlock(block); while (this.scopeStack.Count > 0) { this.ilGenerator.EndScope(); this.scopeStack.Pop(); } this.ilGenerator.AdjustBranchSizesToBestFit(); this.InjectMethodToDumpCounters(); return new ILGeneratorMethodBody(this.ilGenerator, methodBody.LocalsAreZeroed, (ushort)(methodBody.MaxStack+2), methodBody.MethodDefinition, methodBody.LocalVariables, IteratorHelper.GetSingletonEnumerable((ITypeDefinition)this.counterFieldsForCurrentMethod)); }
public static ControlFlowGraph DoBuildControlFlowGraph(IMethodBody cil, Symbols symbols) { ReadOnlyDictionary<ControlFlowBlock, ReadOnlyCollection<IILOp>> blocks2parts; var cfg = CreateCarcass.DoCreateCarcass(cil, out blocks2parts); foreach (var cfb in blocks2parts.Keys) { InitialDecompilation.DoPrimaryDecompilation(cfb, blocks2parts[cfb], symbols); } return cfg; }
internal void SerializeMethodDynamicAnalysisData(IMethodBody bodyOpt) { var data = bodyOpt?.DynamicAnalysisData; if (data == null) { _methodTable.Add(default(MethodRow)); return; } BlobHandle spanBlob = SerializeSpans(data.Spans, _documentIndex); _methodTable.Add(new MethodRow { Spans = spanBlob }); }
public override IMethodBody Rewrite(IMethodBody body) { var method = body.MethodDefinition; _log.Info("Rewriting IMethodBody of: " + method + " Pass: " + MutationTarget.PassInfo); var newBody = new SourceMethodBody(Host) { MethodDefinition = method, LocalsAreZeroed = true }; var block = new BlockStatement(); newBody.Block = block; var replacement = method.ContainingTypeDefinition.Methods.Single(m => m.ToString() == MutationTarget.PassInfo); var methodCall = new MethodCall { MethodToCall = replacement, Type = replacement.Type, ThisArgument = new ThisReference() {Type = method.ContainingTypeDefinition} }; foreach (var param in replacement.Parameters) { methodCall.Arguments.Add(new BoundExpression() { Definition = method.Parameters .First(p => ((INamedTypeReference)p.Type).Name.Value == ((INamedTypeReference)param.Type).Name.Value) }); // methodCall.Arguments.Add(method.Parameters.First(p => new )); } if (replacement.Type == Host.PlatformType.SystemVoid) { block.Statements.Add(new ExpressionStatement { Expression = methodCall }); block.Statements.Add(new ReturnStatement()); } else { block.Statements.Add(new ReturnStatement { Expression = methodCall }); } return newBody; }
public override void Visit(IMethodBody body) { var method = body.MethodDefinition; _log.Info("Visiting IMethodBody of: " + method); var methods = FindCandidateMethods(method); var compatibileMethods = methods.Where(m => m.Parameters .All(p => method.Parameters.Any(p2 => p2.Type == p.Type))).ToList(); if(compatibileMethods.Count != 0) { MarkMutationTarget(body, compatibileMethods.First().ToString().InList()); } }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedCtorSBytePtrStartLengthMethod(ITypeResolver typeResolver) : base("CtorSBytePtrStartLengthEncoding", typeResolver.System.System_String, typeResolver.System.System_String) { byte[] code; IList<object> tokenResolutions; IList<IType> locals; IList<IParameter> parameters; StringGen.GetCtorSBytePtrStartLength(typeResolver, out code, out tokenResolutions, out locals, out parameters); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, code); this._parameters = parameters; this._tokenResolutions = tokenResolutions; }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedStrLenMethod(ITypeResolver typeResolver) : base("strlen", typeResolver.System.System_String, typeResolver.System.System_Int32) { byte[] code; IList<object> tokenResolutions; IList<IType> locals; IList<IParameter> parameters; StringGen.GetStrLen(typeResolver, out code, out tokenResolutions, out locals, out parameters); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, code); this._parameters = parameters; this._tokenResolutions = tokenResolutions; }
public override void Traverse(IMethodBody methodBody) { var moduleInfo = _module.ModulesInfo.Single(); var smb = new Microsoft.Cci.ILToCodeModel.SourceMethodBody(methodBody, _module.Host, moduleInfo.PdbReader, moduleInfo.LocalScopeProvider, DecompilerOptions.None); _visitor.MethodBodyEnter(smb); Traverse(smb); var descriptor = _visitor.MethodBodyExit(smb); var targetsDescriptors = _visitor.MutationTargets.Select(t => t.ProcessingContext.Descriptor).ToList(); // _log.Debug("Returned :"+ descriptor+" comparing with mutaion targets: "+ targetsDescriptors.MakeString()); if(targetsDescriptors.Any(a => a.IsContainedIn(descriptor))) { _log.Debug("Adding method body :" + descriptor ); _methodBodies.Add(methodBody, smb); } }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedMultiDimArraySetMethod(IType type, ITypeResolver typeResolver) : base("Set", type, typeResolver.System.System_Void) { object[] code; IList<object> tokenResolutions; IList<IType> locals; IList<IParameter> parameters; ArrayMultiDimensionGen.GetMultiDimensionArraySet(type, typeResolver, out code, out tokenResolutions, out locals, out parameters); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, MethodBodyBank.Transform(code).ToArray()); this._parameters = parameters; this._tokenResolutions = tokenResolutions; }
public override void Traverse(IMethodBody methodBody) { sourceEmitterOutput.WriteLine(""); if (this.pdbReader != null) PrintScopes(methodBody); else PrintLocals(methodBody.LocalVariables); this.cdfg = ControlAndDataFlowGraph<BasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(host, methodBody, this.pdbReader); var numberOfBlocks = this.cdfg.BlockFor.Count; foreach (var block in this.cdfg.AllBlocks) { this.PrintBlock(block); } sourceEmitterOutput.WriteLine("**************************************************************"); sourceEmitterOutput.WriteLine(); }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedEnumToStringMethod(IType type, ITypeResolver typeResolver) : base("ToString", type, typeResolver.System.System_String, isOverride: true) { object[] code; IList<object> tokenResolutions; IList<IType> locals; IList<IParameter> parameters; EnumGen.GetEnumToStringMethod(type, typeResolver, out code, out tokenResolutions, out locals, out parameters); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, MethodBodyBank.Transform(code).ToArray()); this._parameters = parameters; this._tokenResolutions = tokenResolutions; }
/// <summary> /// Tries to get the first field reference in the method body /// </summary> /// <param name="body"></param> /// <param name="field"></param> /// <returns></returns> public static bool TryGetFirstFieldReference(IMethodBody body, out IFieldReference field) { Contract.Requires(body != null); Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn(out field) != null); foreach (var operation in body.Operations) { if (operation.OperationCode == OperationCode.Stfld || operation.OperationCode == OperationCode.Ldfld) { field = (IFieldReference)operation.Value; return field != null; } } field = null; return false; }
public override void Traverse(IMethodBody methodBody) { PrintToken(CSharpToken.LeftCurly); ISourceMethodBody/*?*/ sourceMethodBody = methodBody as ISourceMethodBody; if (sourceMethodBody == null) { var options = DecompilerOptions.Loops; if (!printCompilerGeneratedMembers) options |= (DecompilerOptions.AnonymousDelegates | DecompilerOptions.Iterators); sourceMethodBody = new SourceMethodBody(methodBody, host, pdbReader, pdbReader, options); } if (noIL) Traverse(sourceMethodBody.Block.Statements); else { // this.Traverse(sourceMethodBody.Block); // PrintToken(CSharpToken.NewLine); if (pdbReader != null) PrintScopes(methodBody); else PrintLocals(methodBody.LocalVariables); int currentIndex = -1; // a number no index matches foreach (IOperation operation in methodBody.Operations) { if (pdbReader != null) { foreach (IPrimarySourceLocation psloc in pdbReader.GetPrimarySourceLocationsFor(operation.Location)) { if (psloc.StartIndex != currentIndex) { PrintSourceLocation(psloc); currentIndex = psloc.StartIndex; } } } PrintOperation(operation); } } PrintToken(CSharpToken.RightCurly); }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedMultiDimArrayCtorMethod(IType arrayType, ITypeResolver typeResolver) : base(arrayType, ".ctor") { this.typeResolver = typeResolver; object[] code; IList<object> tokenResolutions; IList<IType> locals; IList<IParameter> parameters; ArrayMultiDimensionGen.GetMultiDimensionArrayCtor(arrayType, typeResolver, out code, out tokenResolutions, out locals, out parameters); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, MethodBodyBank.Transform(code).ToArray()); this._parameters = parameters; this._tokenResolutions = tokenResolutions; }
public override void TraverseChildren(IMethodBody methodBody) { if (this.pdbReader != null) this.PrintScopes(methodBody); else this.PrintLocals(methodBody.LocalVariables); int currentIndex = -1; // a number no index matches foreach (IOperation operation in methodBody.Operations) { if (this.pdbReader != null) { foreach (IPrimarySourceLocation psloc in this.pdbReader.GetPrimarySourceLocationsFor(operation.Location)) { if (psloc.StartIndex != currentIndex) { this.PrintSourceLocation(psloc); currentIndex = psloc.StartIndex; } } } this.PrintOperation(operation); } }
// TODO: Add support for fields, properties, type definitions and attributes as well // // Example: // [Serializable] // public class Foo {} // // The 'Serializable' (Which is not supported on most platforms) is not found public override void Visit(IMethodBody method) { var calls = method.Operations .Where(opcode => opcode.OperationCode == OperationCode.Call || opcode.OperationCode == OperationCode.Callvirt || opcode.OperationCode == OperationCode.Newobj); var foundInterestingCall = false; foreach (var call in calls) { var calledMethod = (IMethodReference)call.Value; var calledId = calledMethod.DocId(); MissingMemberInfo memberInfo = null; if (!_interestingMethods.TryGetValue(calledId, out memberInfo)) { // Try again with unwrapped member var unwrappedId = calledMethod.UnWrapMember().DocId(); _interestingMethods.TryGetValue(unwrappedId, out memberInfo); } if (memberInfo != null) { foundInterestingCall = true; var sourceItems = _pdbReader .GetClosestPrimarySourceLocationsFor(call.Location) .Select(l => GetSourceMappedItem(l, memberInfo)); _foundItems.AddRange(sourceItems); } } // Check signature for interesting return type to catch polymorphic returns // TODO: Does this condition need to be met? Should we check every return type? if (!foundInterestingCall) { CheckReturnType(method); } base.Visit(method); }
/// <summary> /// </summary> /// <param name="type"> /// </param> /// <param name="typeResolver"> /// </param> public SynthesizedSingleDimArrayIListGetCountMethod(IType arrayType, ITypeResolver typeResolver) : base("get_Count", arrayType, typeResolver.System.System_Int32) { var codeList = new IlCodeBuilder(); codeList.LoadArgument(0); codeList.Add(Code.Ldlen); codeList.Add(Code.Ret); var locals = new List<IType>(); this._methodBody = new SynthesizedMethodBodyDecorator( null, locals, codeList.GetCode()); this._parameters = new List<IParameter>(); this._tokenResolutions = new List<object>(); }
/// <summary> /// Returns true if the namespace scope for this method should be forwarded to another method. /// Returns non-null <paramref name="forwardToMethod"/> if the forwarding should be done directly via UsingNamespace, /// null if the forwarding is done via custom debug info. /// </summary> public bool ShouldForwardNamespaceScopes(EmitContext context, IMethodBody methodBody, uint methodToken, out IMethodDefinition forwardToMethod) { if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody) || methodBody.ImportScope == null) { // SerializeNamespaceScopeMetadata will do the actual forwarding in case this is a CSharp method. // VB on the other hand adds a "@methodtoken" to the scopes instead. if (context.Module.GenerateVisualBasicStylePdb) { forwardToMethod = _previousMethodBodyWithUsingInfo.MethodDefinition; } else { forwardToMethod = null; } return true; } _previousMethodBodyWithUsingInfo = methodBody; _previousMethodTokenWithUsingInfo = methodToken; forwardToMethod = null; return false; }
/// <summary> /// Allocates a metadata (IL) representation along with a source level representation of the body of a method or of a property/event accessor. /// </summary> /// <param name="ilMethodBody">A method body whose IL operations should be decompiled into a block of statements that will be the /// result of the Block property of the resulting source method body.</param> /// <param name="host">An object representing the application that is hosting the converter. It is used to obtain access to some global /// objects and services such as the shared name table and the table for interning references.</param> /// <param name="sourceLocationProvider">An object that can map some kinds of ILocation objects to IPrimarySourceLocation objects. May be null.</param> /// <param name="localScopeProvider">An object that can provide information about the local scopes of a method.</param> /// <param name="options">Set of options that control decompilation.</param> public SourceMethodBody(IMethodBody ilMethodBody, IMetadataHost host, ISourceLocationProvider/*?*/ sourceLocationProvider, ILocalScopeProvider/*?*/ localScopeProvider, DecompilerOptions options = DecompilerOptions.None) : base(host, sourceLocationProvider, localScopeProvider) { Contract.Requires(ilMethodBody != null); Contract.Requires(host != null); this.ilMethodBody = ilMethodBody; this.host = host; this.nameTable = host.NameTable; this.sourceLocationProvider = sourceLocationProvider; this.pdbReader = sourceLocationProvider as PdbReader; this.localScopeProvider = localScopeProvider; this.options = options; this.platformType = ilMethodBody.MethodDefinition.ContainingTypeDefinition.PlatformType; if (IteratorHelper.EnumerableIsNotEmpty(ilMethodBody.LocalVariables)) this.LocalsAreZeroed = ilMethodBody.LocalsAreZeroed; else this.LocalsAreZeroed = true; this.MethodDefinition = ilMethodBody.MethodDefinition; this.privateHelperFieldsToRemove = null; this.privateHelperMethodsToRemove = null; this.privateHelperTypesToRemove = null; this.cdfg = ControlAndDataFlowGraph<BasicBlock<Instruction>, Instruction>.GetControlAndDataFlowGraphFor(host, ilMethodBody, localScopeProvider); }
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 isKickoffMethod = bodyOpt.StateMachineTypeName != null; bool emitDebugInfo = isKickoffMethod || !bodyOpt.SequencePoints.IsEmpty; 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; BlobHandle sequencePointsBlob = SerializeSequencePoints( localSignatureHandleOpt, bodyOpt.SequencePoints, _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 moveNextBodyInfo = bodyOpt.MoveNextBodyInfo; if (moveNextBodyInfo != null) { _debugMetadataOpt.AddStateMachineMethod( moveNextMethod: methodHandle, kickoffMethod: GetMethodDefinitionHandle(moveNextBodyInfo.KickoffMethod) ); if (moveNextBodyInfo is AsyncMoveNextBodyDebugInfo asyncInfo) { SerializeAsyncMethodSteppingInfo(asyncInfo, 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); } }
/// <summary> /// Returns zero or more local (block) scopes, each defining an IL range in which an iterator local is defined. /// The scopes are returned by the MoveNext method of the object returned by the iterator method. /// The index of the scope corresponds to the index of the local. Specifically local scope i corresponds /// to the local stored in field <localName>x_i of the class used to store the local values in between /// calls to MoveNext. /// </summary> public virtual IEnumerable <ILocalScope> GetIteratorScopes(IMethodBody methodBody) { return(Enumerable <ILocalScope> .Empty); }
public byte[] SerializeMethodDebugInfo( EmitContext context, IMethodBody methodBody, MethodDefinitionHandle methodHandle, bool emitStateMachineInfo, bool emitEncInfo, bool emitDynamicAndTupleInfo, out bool emitExternNamespaces) { emitExternNamespaces = false; // CONSIDER: this may not be the same "first" method as in Dev10, but // it shouldn't matter since all methods will still forward to a method // containing the appropriate information. if (_methodBodyWithModuleInfo == null) { // This module level information could go on every method (and does in // the edit-and-continue case), but - as an optimization - we'll just // put it on the first method we happen to encounter and then put a // reference to the first method's token in every other method (so they // can find the information). if (context.Module.GetAssemblyReferenceAliases(context).Any()) { _methodWithModuleInfo = methodHandle; _methodBodyWithModuleInfo = methodBody; emitExternNamespaces = true; } } var pooledBuilder = PooledBlobBuilder.GetInstance(); var encoder = new CustomDebugInfoEncoder(pooledBuilder); if (emitStateMachineInfo) { if (methodBody.StateMachineTypeName != null) { encoder.AddStateMachineTypeName(methodBody.StateMachineTypeName); } else { SerializeNamespaceScopeMetadata(ref encoder, context, methodBody); encoder.AddStateMachineHoistedLocalScopes(methodBody.StateMachineHoistedLocalScopes); } } if (emitDynamicAndTupleInfo) { SerializeDynamicLocalInfo(ref encoder, methodBody); SerializeTupleElementNames(ref encoder, methodBody); } if (emitEncInfo) { var encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody); SerializeCustomDebugInformation(ref encoder, encMethodInfo); } byte[] result = encoder.ToArray() ?? Array.Empty <byte>(); pooledBuilder.Free(); return(result); }
private static void SerializeTupleElementNames(ref CustomDebugInfoEncoder encoder, IMethodBody methodBody) { var locals = GetLocalInfoToSerialize( methodBody, local => !local.TupleElementNames.IsEmpty, (scope, local) => (local.Name, local.SlotIndex, scope.StartOffset, scope.EndOffset, local.TupleElementNames)); if (locals == null) { return; } encoder.AddTupleElementNames(locals); locals.Free(); }
/// <summary> /// Returns a (mutable) Code Model SourceMethod body that is equivalent to the given Metadata Model method body. /// It does *not* delete any helper types. /// </summary> /// <param name="host">An object representing the application that is hosting this decompiler. It is used to obtain access to some global /// objects and services such as the shared name table and the table for interning references.</param> /// <param name="methodBody">The Metadata Model method body that is to be decompiled.</param> /// <param name="pdbReader">An object that can map offsets in an IL stream to source locations and block scopes. May be null.</param> /// <param name="options">Set of options that control decompilation.</param> public static ISourceMethodBody GetCodeModelFromMetadataModel(IMetadataHost host, IMethodBody methodBody, PdbReader /*?*/ pdbReader, DecompilerOptions options = DecompilerOptions.None) { Contract.Requires(host != null); Contract.Requires(methodBody != null); return(new Microsoft.Cci.ILToCodeModel.SourceMethodBody(methodBody, host, pdbReader, pdbReader, options)); }
/// <summary> /// /// </summary> internal static ControlAndDataFlowGraph <BasicBlock, Instruction> SetupControlFlow(IMetadataHost host, IMethodBody methodBody, ILocalScopeProvider /*?*/ localScopeProvider = null) { Contract.Requires(host != null); Contract.Requires(methodBody != null); Contract.Ensures(Contract.Result <ControlAndDataFlowGraph <BasicBlock, Instruction> >() != null); var inferencer = new ControlFlowInferencer <BasicBlock, Instruction>(host, methodBody, localScopeProvider); return(inferencer.CreateBlocksAndEdges()); }
public void SetMethodBody(IMethodBody body) { MethodBody = body; }
public byte[] SerializeMethodDebugInfo(EmitContext context, IMethodBody methodBody, int methodToken, bool isEncDelta, bool suppressNewCustomDebugInfo, out bool emitExternNamespaces) { emitExternNamespaces = false; // CONSIDER: this may not be the same "first" method as in Dev10, but // it shouldn't matter since all methods will still forward to a method // containing the appropriate information. if (_methodBodyWithModuleInfo == null) //UNDONE: || edit-and-continue { // This module level information could go on every method (and does in // the edit-and-continue case), but - as an optimization - we'll just // put it on the first method we happen to encounter and then put a // reference to the first method's token in every other method (so they // can find the information). if (context.Module.GetAssemblyReferenceAliases(context).Any()) { _methodTokenWithModuleInfo = methodToken; _methodBodyWithModuleInfo = methodBody; emitExternNamespaces = true; } } var customDebugInfo = ArrayBuilder <PooledBlobBuilder> .GetInstance(); SerializeIteratorClassMetadata(methodBody, customDebugInfo); // 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). // NOTE: There seems to be an unusual behavior in ISymUnmanagedWriter where, if all the methods in a type are // iterator methods, no custom debug info is emitted for any method. Adding a single non-iterator // method causes the custom debug info to be produced for all methods (including the iterator methods). // Since we are making the same ISymUnmanagedWriter calls as Dev10, we see the same behavior (i.e. this // is not a regression). if (methodBody.StateMachineTypeName == null) { SerializeNamespaceScopeMetadata(context, methodBody, customDebugInfo); SerializeStateMachineLocalScopes(methodBody, customDebugInfo); } if (!suppressNewCustomDebugInfo) { SerializeDynamicLocalInfo(methodBody, customDebugInfo); // delta doesn't need this information - we use information recorded by previous generation emit if (!isEncDelta) { var encMethodInfo = MetadataWriter.GetEncMethodDebugInfo(methodBody); SerializeCustomDebugInformation(encMethodInfo, customDebugInfo); } } byte[] result = SerializeCustomDebugMetadata(customDebugInfo); foreach (var builder in customDebugInfo) { builder.Free(); } customDebugInfo.Free(); return(result); }
/// <summary> /// Performs some computation with the given method body. /// </summary> public virtual void Visit(IMethodBody methodBody) { }
public static IMethodBase DefaultMethodWithBody(IMethodBody body) { var method = GeneralIMethodBase(DefaultMethodName, body); return(method.Object); }
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(methodBody, methodToken, out forwardToMethod)) { if (forwardToMethod != null) { string usingString = "@" + _metadataWriter.GetMethodToken(forwardToMethod); Debug.Assert(!_metadataWriter.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.AsyncDebugInfo; if (asyncDebugInfo != null) { SetAsyncInfo( methodToken, _metadataWriter.GetMethodToken(asyncDebugInfo.KickoffMethod), asyncDebugInfo.CatchHandlerOffset, asyncDebugInfo.YieldOffsets, asyncDebugInfo.ResumeOffsets); } var context = _metadataWriter.Context; var module = context.Module; 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(module, methodBody, methodToken, emitEncInfo, suppressNewCustomDebugInfo, 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(); }
private static void SerializeDynamicLocalInfo(ref CustomDebugInfoEncoder encoder, IMethodBody methodBody) { if (!methodBody.HasDynamicLocalVariables) { return; } byte[] GetDynamicFlags(ILocalDefinition local) { var dynamicTransformFlags = local.DynamicTransformFlags; var flags = new byte[CustomDebugInfoEncoder.DynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if (dynamicTransformFlags[k]) { flags[k] = 1; } } return(flags); } var dynamicLocals = GetLocalInfoToSerialize( methodBody, local => { var dynamicTransformFlags = local.DynamicTransformFlags; return(!dynamicTransformFlags.IsEmpty && dynamicTransformFlags.Length <= CustomDebugInfoEncoder.DynamicAttributeSize && local.Name.Length < CustomDebugInfoEncoder.IdentifierSize); }, (scope, local) => (local.Name, GetDynamicFlags(local), local.DynamicTransformFlags.Length, (local.SlotIndex < 0) ? 0 : local.SlotIndex)); if (dynamicLocals == null) { return; } encoder.AddDynamicLocals(dynamicLocals); dynamicLocals.Free(); }
public virtual void Visit(IMethodBody methodBody) { this.Visit(methodBody.LocalVariables); //this.Visit(methodBody.Operations); //in Roslyn we don't break out each instruction as it's own operation. this.Visit(methodBody.ExceptionRegions); }
private static void SerializeIteratorClassMetadata(IMethodBody methodBody, ArrayBuilder <BlobWriter> customDebugInfo) { SerializeReferenceToIteratorClass(methodBody.StateMachineTypeName, customDebugInfo); }
public static IMethodBase Method(string identifier, IMethodBody body) { var method = GeneralIMethodBase(identifier, body); return(method.Object); }
/// <summary> /// Constructs a control and data flow graph for the given method body. /// </summary> public static ControlAndDataFlowGraph <BasicBlock, Instruction> GetControlAndDataFlowGraphFor(IMetadataHost host, IMethodBody methodBody, ILocalScopeProvider /*?*/ localScopeProvider = null) { Contract.Requires(host != null); Contract.Requires(methodBody != null); Contract.Ensures(Contract.Result <ControlAndDataFlowGraph <BasicBlock, Instruction> >() != null); var cdfg = ControlFlowInferencer <BasicBlock, Instruction> .SetupControlFlow(host, methodBody, localScopeProvider); DataFlowInferencer <BasicBlock, Instruction> .SetupDataFlow(host, methodBody, cdfg); TypeInferencer <BasicBlock, Instruction> .FillInTypes(host, cdfg); return(cdfg); }
private void DefineNamespaceScopes(IMethodBody methodBody) { var module = Module; bool isVisualBasic = module.GenerateVisualBasicStylePdb; IMethodDefinition method = methodBody.MethodDefinition; var namespaceScopes = methodBody.ImportScope; PooledHashSet <string> lazyDeclaredExternAliases = null; if (!isVisualBasic) { for (var scope = namespaceScopes; scope != null; scope = scope.Parent) { foreach (var import in scope.GetUsedNamespaces(Context)) { if (import.TargetNamespaceOpt == null && import.TargetTypeOpt == null) { Debug.Assert(import.AliasOpt != null); Debug.Assert(import.TargetAssemblyOpt == null); if (lazyDeclaredExternAliases == null) { lazyDeclaredExternAliases = PooledHashSet <string> .GetInstance(); } lazyDeclaredExternAliases.Add(import.AliasOpt); } } } } // file and namespace level for (IImportScope scope = namespaceScopes; scope != null; scope = scope.Parent) { foreach (UsedNamespaceOrType import in scope.GetUsedNamespaces(Context)) { var importString = TryEncodeImport(import, lazyDeclaredExternAliases, isProjectLevel: false); if (importString != null) { UsingNamespace(importString, method); } } } lazyDeclaredExternAliases?.Free(); // project level if (isVisualBasic) { string defaultNamespace = module.DefaultNamespace; if (defaultNamespace != null) { // VB marks the default/root namespace with an asterisk UsingNamespace("*" + defaultNamespace, module); } foreach (string assemblyName in module.LinkedAssembliesDebugInfo) { UsingNamespace("&" + assemblyName, module); } foreach (UsedNamespaceOrType import in module.GetImports(Context)) { var importString = TryEncodeImport(import, null, isProjectLevel: true); if (importString != null) { UsingNamespace(importString, method); } } // VB current namespace -- VB appends the namespace of the container without prefixes UsingNamespace(GetOrCreateSerializedNamespaceName(method.ContainingNamespace), method); } }
/// <summary> /// Returns true if the method body is an iterator, in which case the scope information should be retrieved from the object /// returned by the method. /// </summary> public bool IsIterator(IMethodBody methodBody) { PdbFunction /*?*/ pdbFunction = this.GetPdbFunctionFor(methodBody); return(pdbFunction != null && pdbFunction.iteratorClass != null); }
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; // Open the outer-most language defined scope, the namespace scopes will be emitted to it. // Note that the root scope has already been open, but native compilers leave it empty. 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(); } CloseMethod(methodBody.IL.Length); }
/// <summary> /// Allocates a range of CLR IL operations that comprise a lexical scope, specified as an IL offset and a length. /// </summary> internal PdbLocalScope(IMethodBody methodBody, PdbScope pdbScope) { this.methodBody = methodBody; this.pdbScope = pdbScope; }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <BlobWriter> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { if (local.IsDynamic) { dynamicLocals.Add(local); } } int dynamicVariableCount = dynamicLocals.Count; foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached const int blobSize = 200; //DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128 var cmw = new BlobWriter(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUint((uint)dynamicLocals.Count); int localIndex = 0; foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length > 63)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64) { byte[] flag = new byte[64]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUint((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUint(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
protected virtual void EmitMethodBody(IMethodBody methodBody) { Contract.Requires(methodBody != null); var savedLabelFor = this.labelFor; this.labelFor = new Hashtable <ILGeneratorLabel>(); var initialScopeStackCount = this.scopeStack.Count; foreach (var exceptionInfo in methodBody.OperationExceptionInformation) { Contract.Assume(exceptionInfo != null); this.Generator.AddExceptionHandlerInformation(exceptionInfo.HandlerKind, exceptionInfo.ExceptionType, this.GetLabelFor(exceptionInfo.TryStartOffset), this.GetLabelFor(exceptionInfo.TryEndOffset), this.GetLabelFor(exceptionInfo.HandlerStartOffset), this.GetLabelFor(exceptionInfo.HandlerEndOffset), exceptionInfo.HandlerKind == HandlerKind.Filter ? this.GetLabelFor(exceptionInfo.FilterDecisionStartOffset) : null); } if (this.localScopeProvider == null) { foreach (var localDef in methodBody.LocalVariables) { Contract.Assume(localDef != null); this.Generator.AddVariableToCurrentScope(localDef); } } else { foreach (var ns in this.localScopeProvider.GetNamespaceScopes(methodBody)) { Contract.Assume(ns != null); foreach (var uns in ns.UsedNamespaces) { Contract.Assume(uns != null); this.Generator.UseNamespace(uns.NamespaceName.Value); } } this.scopeEnumerator = this.localScopeProvider.GetLocalScopes(methodBody).GetEnumerator(); this.scopeEnumeratorIsValid = this.scopeEnumerator.MoveNext(); this.iteratorScopeEnumerator = this.localScopeProvider.GetIteratorScopes(methodBody).GetEnumerator(); this.iteratorScopeEnumeratorIsValid = this.iteratorScopeEnumerator.MoveNext(); if (this.synchronizationInfo != null) { this.syncPointEnumerator = this.synchronizationInfo.SynchronizationPoints.GetEnumerator(); this.syncPointEnumeratorIsValid = this.syncPointEnumerator.MoveNext(); } } foreach (var operation in methodBody.Operations) { switch (operation.OperationCode) { case OperationCode.Beq: case OperationCode.Bge: case OperationCode.Bge_Un: case OperationCode.Bgt: case OperationCode.Bgt_Un: case OperationCode.Ble: case OperationCode.Ble_Un: case OperationCode.Blt: case OperationCode.Blt_Un: case OperationCode.Bne_Un: case OperationCode.Br: case OperationCode.Br_S: case OperationCode.Brfalse: case OperationCode.Brtrue: case OperationCode.Leave: case OperationCode.Beq_S: case OperationCode.Bge_S: case OperationCode.Bge_Un_S: case OperationCode.Bgt_S: case OperationCode.Bgt_Un_S: case OperationCode.Ble_S: case OperationCode.Ble_Un_S: case OperationCode.Blt_S: case OperationCode.Blt_Un_S: case OperationCode.Bne_Un_S: case OperationCode.Brfalse_S: case OperationCode.Brtrue_S: case OperationCode.Leave_S: Contract.Assume(operation.Value is uint); this.GetLabelFor((uint)operation.Value); break; case OperationCode.Switch: uint[] offsets = operation.Value as uint[]; Contract.Assume(offsets != null); foreach (var offset in offsets) { this.GetLabelFor(offset); } break; } } foreach (var operation in methodBody.Operations) { Contract.Assume(operation != null); Contract.Assume(this.labelFor != null); var label = this.labelFor.Find(operation.Offset); if (label != null) { this.Generator.MarkLabel(label); } this.EmitDebugInformationFor(operation); this.EmitOperation(operation); this.TrackLocal(operation.Value); } while (this.scopeStack.Count > initialScopeStackCount) { this.Generator.EndScope(); this.scopeStack.Pop(); } this.labelFor = savedLabelFor; Contract.Assume(this.generator != null); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } const int dynamicAttributeSize = 64; const int identifierSize = 64; var dynamicLocals = GetLocalInfoToSerialize( methodBody, local => { var dynamicTransformFlags = local.DynamicTransformFlags; return(!dynamicTransformFlags.IsEmpty && dynamicTransformFlags.Length <= dynamicAttributeSize && local.Name.Length < identifierSize); }, (scope, local) => local); if (dynamicLocals == null) { return; } const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128 var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)CustomDebugInfoKind.DynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32((uint)dynamicLocals.Count); foreach (ILocalDefinition local in dynamicLocals) { var dynamicTransformFlags = local.DynamicTransformFlags; byte[] flag = new byte[dynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length var localIndex = local.SlotIndex; cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex); char[] localName = new char[identifierSize]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
private void SerializeNamespaceScopeMetadata(ref CustomDebugInfoEncoder encoder, EmitContext context, IMethodBody methodBody) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); encoder.AddForwardMethodInfo(_previousMethodWithUsingInfo); return; } var usingCounts = ArrayBuilder <int> .GetInstance(); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { usingCounts.Add(scope.GetUsedNamespaces().Length); } encoder.AddUsingGroups(usingCounts); usingCounts.Free(); if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { encoder.AddForwardModuleInfo(_methodWithModuleInfo); } }
/// <summary> /// Returns true if the method body is an iterator. /// </summary> public virtual bool IsIterator(IMethodBody methodBody) { return(false); }
private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int localSignatureRowId) { if (bodyOpt == null) { _methodDebugInformationTable.Add(default(MethodDebugInformationRow)); return; } bool isIterator = bodyOpt.StateMachineTypeName != null; bool emitDebugInfo = isIterator || bodyOpt.HasAnySequencePoints; if (!emitDebugInfo) { _methodDebugInformationTable.Add(default(MethodDebugInformationRow)); return; } var bodyImportScope = bodyOpt.ImportScope; int importScopeRid = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : 0; // documents & sequence points: int singleDocumentRowId; BlobIdx sequencePointsBlob = SerializeSequencePoints(localSignatureRowId, bodyOpt.GetSequencePoints(), _documentIndex, out singleDocumentRowId); _methodDebugInformationTable.Add(new MethodDebugInformationRow { Document = (uint)singleDocumentRowId, 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 SynthesizedMethodBodyDecorator(IMethodBody methodBody) { this.methodBody = methodBody; }
private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int aggregateMethodRid, StandaloneSignatureHandle localSignatureHandleOpt, ref LocalVariableHandle lastLocalVariableHandle, ref LocalConstantHandle lastLocalConstantHandle) { if (bodyOpt == null) { _debugMetadataOpt.AddMethodDebugInformation(document: default, sequencePoints: default);
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <PooledBlobBuilder> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { Debug.Assert(local.SlotIndex >= 0); if (local.IsDynamic) { dynamicLocals.Add(local); } } foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { Debug.Assert(localConstant.SlotIndex < 0); if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached const int dynamicAttributeSize = 64; const int identifierSize = 64; const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128 var cmw = PooledBlobBuilder.GetInstance(); cmw.WriteByte(CustomDebugInfoConstants.Version); cmw.WriteByte((byte)CustomDebugInfoKind.DynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32((uint)dynamicLocals.Count); foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length >= identifierSize)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= dynamicAttributeSize) { byte[] flag = new byte[dynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, dynamicAttributeSize + 4); //Empty flag array and size. } var localIndex = local.SlotIndex; cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex); char[] localName = new char[identifierSize]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); } dynamicLocals.Free(); customDebugInfo.Add(cmw); }