Example #1
0
        private Scope ReadScope(ISymbolScope scope)
        {
            Scope scopeData = new Scope();

            // If this is the root scope, then it was created implicitly and should not be explicitly
            // opened by a writer
            if (scope.Parent == null)
            {
                scopeData.isImplicit = true;
            }
            scopeData.startOffset = scope.StartOffset;
            scopeData.endOffset = scope.EndOffset;

            // Read the locals, constants and namespaces in this scope (may be empty)
            scopeData.locals = ReadLocals(scope);
            scopeData.constants = ReadConstants(scope);
            scopeData.usedNamespaces = ReadUsedNamespaces(scope);

            // Read the child scopes recursively
            scopeData.scopes = new List<Scope>();
            foreach (ISymbolScope child in scope.GetChildren())
            {
                Scope childData = ReadScope(child);
                scopeData.scopes.Add(childData);
            }

            return scopeData;
        }
Example #2
0
        /// <summary>
        /// Work-around for a bug in diasymreader.  
        /// </summary>
        /// <param name="rootScope"></param>
        /// <remarks>
        /// There should always be at least one explicit scope written, since this is how the writer determines
        /// the end offset for the root scope (and hence the maximum offset permitted by any sequence point -
        /// other will be silently removed). But if a scope has no locals or child scopes in it, diasymreader will 
        /// omit it, and we won't see it in the reader.  So if we read a root scope with nothing inside of it,
        /// we'll reconstruct the child scope we know must have originally been written there.
        /// </remarks>
        private void WorkAroundDiasymreaderScopeBug(Scope rootScope)
        {
            if ((rootScope.scopes.Count > 0) ||
                (rootScope.locals.Count > 0) ||
                (rootScope.usedNamespaces.Count > 0) ||
                (rootScope.constants.Count > 0))
            {
                // There is something inside this scope - there shouldn't be any problem with diasymreader
                // removing it.
                return;
            }

            // We've got a root scope with nothing in it.  Reconstruct the explicit scope we know must have
            // been written here.
            Scope child = new Scope();
            child.startOffset = rootScope.startOffset;
            child.endOffset = rootScope.endOffset;
            child.isReconstructedDueToDiasymreaderBug = true;
            rootScope.scopes.Add(child);
        }
Example #3
0
        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);
        }