private void WriteMethod(Method m) { SymbolToken methodToken = Util.AsSymToken(m.token); m_writer.OpenMethod(methodToken); SymbolToken? localSigToken = null; if (m.localSigMetadataToken != null) { localSigToken = new SymbolToken(Util.ToInt32(m.localSigMetadataToken, 16)); } WriteSequencePoints(m.sequencePoints); WriteScopesAndLocals(m.rootScope, localSigToken, m); WriteSymAttributes(m.symAttributes, methodToken); if (m.csharpCDI != null) WriteCSharpCDI(m.csharpCDI, methodToken); m_writer.CloseMethod(); }
private void WriteScopesAndLocals(Scope scope, SymbolToken? localSigToken, Method method) { // If this scope is marked implicit then we won't explicitly write it out // This is usually used for the root scope if (!scope.isImplicit) m_writer.OpenScope(scope.startOffset); foreach (Variable localVar in scope.locals) { // Note that local variables can have a start/end offset within their enclosing scope. // Infortunately ISymUnmanagedVariable.GetStartOffset() returns E_NOTIMPL, so we // can't tell whether this was used or not. Passing 0 says to use the start/end for // the entire scope (which is probably usually the case anyway). // Diasymreader.dll always stores local signatures by token, and if we use the V1 // API will attempt to emit a new token to the metadata (which we don't support here). // IldbSymbols.dll on the other hand always stores signatures inline, and doesn't support // the V2 API. RefEmit uses the V1 API, so it's fine to use it here for ILDB too. if (m_symFormat == SymbolFormat.PDB) { if (localSigToken.HasValue) { m_writer.DefineLocalVariable( localVar.name, localVar.attributes, localSigToken.Value, (int)SymAddressKind.ILOffset, localVar.ilIndex, 0, 0, 0, 0); // start/end offsets - get from current scope } else { // We want to handle this case as gracefully since there is a bug in the C# compiler that // can prevent us from getting the local var sig token. // Note that we don't want to just use the V1 API with PDBs because we're not saving the // metadata, and so the call to ISymUnmanagedVariable::GetSignature will just fail because // the token will be invalid. if (!method.hasInvalidMethodBody) throw new FormatException("Missing localVarsigToken in a method without hasInvalidMethodBody set"); } } else { byte[] sig = Util.ToByteArray(localVar.signature); m_writer.DefineLocalVariable( localVar.name, (FieldAttributes)localVar.attributes, sig, SymAddressKind.ILOffset, localVar.ilIndex, 0, 0, 0, 0); // start/end offsets - get from current scope } } foreach (Constant constant in scope.constants) { m_writer.DefineConstant(constant.name, constant.value, Util.ToByteArray(constant.signature)); } // Now recursively write out any child scopes foreach (Scope childScope in scope.scopes) { WriteScopesAndLocals(childScope, localSigToken, method); } foreach (Namespace ns in scope.usedNamespaces) { m_writer.UsingNamespace(ns.name); } if (!scope.isImplicit) m_writer.CloseScope(scope.endOffset); }
// Dump all of the methods in the given ISymbolReader to the SymbolData provided private List<Method> ReadAllMethods(ISymbolReader reader) { List<Method> methods = new List<Method>(); // Use reflection to enumerate all methods foreach (MethodBase methodReflection in GetAllMethods(m_assembly)) { int token = methodReflection.MetadataToken; ISymbolMethod methodSymbol = reader.GetMethod(new SymbolToken(token)); if (methodSymbol != null) { Method methodData = new Method(); methodData.token = Util.AsToken(token); methodData.name = methodReflection.DeclaringType.FullName + "::" + methodReflection.Name; // This localSigMetadataToken information actually comes from the metadata in the assembly because the symbol reading API does not provide it. try { MethodBody body = methodReflection.GetMethodBody(); int lSMT = body.LocalSignatureMetadataToken; if (lSMT != 0) { methodData.localSigMetadataToken = Util.AsToken(lSMT); } } catch (System.Security.VerificationException) { // Work around a CLR or C# compiler bug with Void& types in signatures // <strip>See DevDiv Bugs 146662</strip> methodData.hasInvalidMethodBody = true; } methodData.sequencePoints = ReadSequencePoints(methodSymbol); methodData.rootScope = ReadScope(methodSymbol.RootScope); // Read symbol attributes, except on ILDB where it isn't supported if (m_symFormat != SymbolFormat.ILDB) { if (m_expandAttributes) methodData.csharpCDI = ReadCSharpCDI(reader, methodSymbol); methodData.symAttributes = ReadSymAttributes(reader, methodSymbol, methodData.csharpCDI != null); } if (m_symFormat == SymbolFormat.PDB) WorkAroundDiasymreaderScopeBug(methodData.rootScope); methods.Add(methodData); } } return methods; }