private static void ReadCSharpNativeCustomDebugInfo( ISymUnmanagedReader reader, int methodToken, int methodVersion, IEnumerable <ISymUnmanagedScope> scopes, out ImmutableArray <HoistedLocalScopeRecord> hoistedLocalScopeRecords, out ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap, out ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap) { hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty; dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; byte[] customDebugInfoBytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (customDebugInfoBytes == null) { return; } var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBytes, CustomDebugInfoKind.StateMachineHoistedLocalScopes); if (!customDebugInfoRecord.IsDefault) { hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord) .SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.EndOffset - s.StartOffset + 1)); } CustomDebugInfoReader.GetCSharpDynamicLocalInfo( customDebugInfoBytes, methodToken, methodVersion, scopes, out dynamicLocalMap, out dynamicLocalConstantMap); }
/// <summary> /// Create a context for evaluating expressions within a method scope. /// </summary> /// <param name="previous">Previous context, if any, for possible re-use.</param> /// <param name="metadataBlocks">Module metadata</param> /// <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleVersionId"/></param> /// <param name="moduleVersionId">Module containing method</param> /// <param name="methodToken">Method metadata token</param> /// <param name="methodVersion">Method version.</param> /// <param name="ilOffset">IL offset of instruction pointer in method</param> /// <param name="localSignatureToken">Method local signature token</param> /// <returns>Evaluation context</returns> internal static EvaluationContext CreateMethodContext( CSharpMetadataContext previous, ImmutableArray <MetadataBlock> metadataBlocks, object symReader, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, int localSignatureToken) { Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); var typedSymReader = (ISymUnmanagedReader)symReader; var scopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance(); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, scopes); var scope = scopes.GetMethodScope(methodToken, methodVersion); // Re-use the previous compilation if possible. CSharpCompilation compilation; if (metadataBlocks.HaveNotChanged(previous)) { // Re-use entire context if method scope has not changed. var previousContext = previous.EvaluationContext; if ((scope != null) && (previousContext != null) && scope.Equals(previousContext.MethodScope)) { return(previousContext); } compilation = previous.Compilation; } else { compilation = metadataBlocks.ToCompilation(); } var localNames = scopes.GetLocalNames(); var dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; var dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; var inScopeHoistedLocalIndices = ImmutableSortedSet <int> .Empty; var methodDebugInfo = default(MethodDebugInfo); if (typedSymReader != null) { try { var cdi = typedSymReader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (cdi != null) { CustomDebugInfoReader.GetCSharpDynamicLocalInfo( cdi, methodToken, methodVersion, localNames.FirstOrDefault(), out dynamicLocalMap, out dynamicLocalConstantMap); inScopeHoistedLocalIndices = CustomDebugInfoReader.GetCSharpInScopeHoistedLocalIndices( cdi, methodToken, methodVersion, ilOffset); } // TODO (acasey): switch on the type of typedSymReader and call the appropriate helper. (GH #702) methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion); } catch (InvalidOperationException) { // bad CDI, ignore } } var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); Debug.Assert((object)currentFrame != null); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken); var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); var sourceAssembly = compilation.SourceAssembly; GetLocals(localBuilder, currentFrame, localNames, localInfo, dynamicLocalMap, sourceAssembly); GetConstants(localBuilder, currentFrame, scopes.GetConstantSignatures(), metadataDecoder, dynamicLocalConstantMap, sourceAssembly); scopes.Free(); var locals = localBuilder.ToImmutableAndFree(); return(new EvaluationContext( metadataBlocks, scope, compilation, metadataDecoder, currentFrame, locals, inScopeHoistedLocalIndices, methodDebugInfo)); }
public static MethodDebugInfo GetMethodDebugInfo( this ISymUnmanagedReader reader, int methodToken, int methodVersion, ArrayBuilder <ISymUnmanagedScope> scopes) { ImmutableArray <string> externAliasStrings; var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings); Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault); ArrayBuilder <ImmutableArray <ImportRecord> > importRecordGroupBuilder = null; ArrayBuilder <ExternAliasRecord> externAliasRecordBuilder = null; if (!importStringGroups.IsDefault) { importRecordGroupBuilder = ArrayBuilder <ImmutableArray <ImportRecord> > .GetInstance(importStringGroups.Length); foreach (var importStringGroup in importStringGroups) { var groupBuilder = ArrayBuilder <ImportRecord> .GetInstance(importStringGroup.Length); foreach (var importString in importStringGroup) { ImportRecord record; if (NativeImportRecord.TryCreateFromCSharpImportString(importString, out record)) { groupBuilder.Add(record); } else { Debug.WriteLine($"Failed to parse import string {importString}"); } } importRecordGroupBuilder.Add(groupBuilder.ToImmutableAndFree()); } if (!externAliasStrings.IsDefault) { externAliasRecordBuilder = ArrayBuilder <ExternAliasRecord> .GetInstance(externAliasStrings.Length); foreach (string externAliasString in externAliasStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine($"Unable to parse extern alias '{externAliasString}'"); continue; } Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?"); Debug.Assert(alias != null); // Name of the extern alias. Debug.Assert(externAlias == null); // Not used. Debug.Assert(target != null); // Name of the target assembly. AssemblyIdentity targetIdentity; if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity)) { Debug.WriteLine($"Unable to parse target of extern alias '{externAliasString}'"); continue; } externAliasRecordBuilder.Add(new NativeExternAliasRecord <AssemblySymbol>(alias, targetIdentity)); } } } var hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty; var dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; var dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; byte[] customDebugInfoBytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (customDebugInfoBytes != null) { var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBytes, CustomDebugInfoKind.StateMachineHoistedLocalScopes); if (!customDebugInfoRecord.IsDefault) { hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord) .SelectAsArray(s => HoistedLocalScopeRecord.FromNative(s.StartOffset, s.EndOffset)); } CustomDebugInfoReader.GetCSharpDynamicLocalInfo( customDebugInfoBytes, methodToken, methodVersion, scopes, out dynamicLocalMap, out dynamicLocalConstantMap); } return(new MethodDebugInfo( hoistedLocalScopeRecords, importRecordGroupBuilder?.ToImmutableAndFree() ?? ImmutableArray <ImmutableArray <ImportRecord> > .Empty, externAliasRecordBuilder?.ToImmutableAndFree() ?? ImmutableArray <ExternAliasRecord> .Empty, dynamicLocalMap, dynamicLocalConstantMap, defaultNamespaceName: "")); // Unused in C#. }