Ejemplo n.º 1
0
        /// <summary>
        /// Resolves the outbound call stack for the given <see cref="token"/>
        /// </summary>
        /// <param name="token"></param>
        /// <param name="depth"></param>
        /// <param name="stackTrc">For detecting recursive call patterns</param>
        /// <param name="msgOut">For getting details on recursion.</param>
        internal void ResolveCallOfCall(MetadataTokenId token, ref int depth, Stack <MetadataTokenId> stackTrc, StringBuilder msgOut)
        {
            if (msgOut != null)
            {
                if (depth > 0)
                {
                    msgOut.Append(new string(' ', depth));
                }

                msgOut.AppendFormat("Depth:{0}", depth);
                msgOut.AppendFormat(", Token:{0}.0x{1}", token.RslvAsmIdx, token.Id.ToString("X4"));
            }
            //detect if we are in a recursive call
            if (stackTrc.Any(x => x.Equals(token)))
            {
                if (msgOut != null)
                {
                    msgOut.AppendLine(", Message:'present in stack trace'");
                }
                return;
            }

            stackTrc.Push(new MetadataTokenId {
                Id = token.Id, RslvAsmIdx = token.RslvAsmIdx
            });

            //increment the current depth
            depth += 1;

            //abort if max depth has been reached
            if (depth > ((IaaProgram)MyProgram).MaxRecursionDepth)
            {
                depth -= 1;
                MyProgram.PrintToConsole(
                    String.Format("Max Recursion Depth @ {0}.{1}\n", token.RslvAsmIdx, token.Id));
                if (msgOut != null)
                {
                    msgOut.AppendLine(", Message:'max recursion depth'");
                }
                return;
            }

            //when there are already Items then leave them as is
            if (token.Items != null && token.Items.Length > 0)
            {
                depth -= 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(", Message:'Items already present'");
                }
                return;
            }

            //don't waste clock cycles on Ignore types
            if (((IaaProgram)MyProgram).DisolutionCache.Contains(token))
            {
                depth -= 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(", Message:'token in DisolutionCache'");
                }
                return;
            }

            //resolve token to name
            MetadataTokenName tokenName = null;

            if (((IaaProgram)MyProgram).TokenId2NameCache.ContainsKey(token))
            {
                tokenName = ((IaaProgram)MyProgram).TokenId2NameCache[token];
            }
            else
            {
                // the token must be resolvable with the its manifest module
                var resolveRslt = ((IaaProgram)MyProgram).UtilityMethods.ResolveSingleTokenName(token, out tokenName, msgOut);
                if (!resolveRslt || tokenName == null)
                {
                    ((IaaProgram)MyProgram).DisolutionCache.Add(token);
                    depth -= 1;
                    if (msgOut != null)
                    {
                        msgOut.AppendLine(", Message:'ResolveSingleTokenName failed'");
                    }
                    return;
                }
                ((IaaProgram)MyProgram).TokenId2NameCache.Add(token, tokenName);
            }

            //only proceed to find calls of calls, types are resolved elsewhere
            if (!tokenName.IsMethodName())
            {
                depth -= 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(", Message:'token is not a method'");
                }
                return;
            }

            //match is on Asm Name, not type nor member name
            var owningAsmName = ((IaaProgram)MyProgram).AsmIndicies.Asms.FirstOrDefault(x => x.IndexId == tokenName.OwnAsmIdx);

            if (owningAsmName == null)
            {
                ((IaaProgram)MyProgram).DisolutionCache.Add(token);
                depth -= 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(string.Format(", Message:'owning assembly idx {0} has no match'", tokenName.OwnAsmIdx));
                }
                return;
            }

            //check for match of asm name to user defined regex
            if (!Regex.IsMatch(owningAsmName.AssemblyName, ((IaaProgram)MyProgram).AssemblyNameRegexPattern))
            {
                ((IaaProgram)MyProgram).DisolutionCache.Add(token);
                if (msgOut != null)
                {
                    msgOut.AppendLine(string.Format(", Message:'assembly name [{1}] does not match regex [{0}]'",
                                                    ((IaaProgram)MyProgram).AssemblyNameRegexPattern, owningAsmName.AssemblyName));
                }

                depth -= 1;
                return;
            }

            //resolve token to runtime member info
            MemberInfo mi;
            var        rtMiRslt =
                ((IaaProgram)MyProgram).UtilityMethods.TryResolveRtMemberInfo(((IaaProgram)MyProgram).AsmIndicies.GetAssemblyByIndex(owningAsmName.IndexId),
                                                                              tokenName.Name, out mi, msgOut);

            if (!rtMiRslt)
            {
                ((IaaProgram)MyProgram).DisolutionCache.Add(token);
                depth -= 1;
                return;
            }

            //get the token as it is called in its own assembly
            var r = AssemblyAnalysis.GetMetadataToken(mi, true, tokenName.OwnAsmIdx);

            if (stackTrc.Any(x => x.Equals(r)))
            {
                depth        -= 1;
                token.IsByRef = 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(string.Format(", Message:'name resolved token id {0},{1} found in stack trace'",
                                                    r.RslvAsmIdx, r.Id.ToString("X4")));
                }
                return;
            }

            //this token differs from the method arg 'token'
            stackTrc.Push(new MetadataTokenId {
                Id = r.Id, RslvAsmIdx = r.RslvAsmIdx
            });

            //unwind when its a terminal token
            if (r.Items == null || r.Items.Length <= 0)
            {
                depth -= 1;
                if (msgOut != null)
                {
                    msgOut.AppendLine(string.Format(", Message:'name resolved token id {0},{1} is a terminal node'",
                                                    r.RslvAsmIdx, r.Id.ToString("X4")));
                }

                return;
            }

            //these token ids are only resolvable to the asm who owns MemberInfo(mi)
            token.Items = r.Items;

            //recurse each of these calls-of-calls[...]-of-calls
            foreach (var iToken in token.Items)
            {
                ResolveCallOfCall(iToken, ref depth, stackTrc, msgOut);
            }

            depth -= 1;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Locates the <see cref="CgMember"/> in <see cref="Methods"/> who matches <see cref="tokenName"/>.
        /// </summary>
        /// <param name="tokenName"></param>
        /// <returns></returns>
        public CgMember FindCgMethodByTokenName(MetadataTokenName tokenName)
        {
            if (tokenName == null)
                return null;
            if (string.IsNullOrWhiteSpace(tokenName.Name))
                return null;
            if (!tokenName.IsMethodName())
                return null;
            var methodName = AssemblyAnalysis.ParseMethodNameFromTokenName(tokenName.Name);
            if (string.IsNullOrWhiteSpace(methodName))
                return null;
            string isPropName;
            if (NfTypeName.IsClrMethodForProperty(tokenName.Name, out isPropName))
            {
                methodName = isPropName;
                var propMatches = Properties.Where(p => string.Equals(p.Name, methodName)).ToArray();
                if (propMatches.Length >= 1)
                    return propMatches.First();
            }

            var matches = Methods.Where(x => string.Equals(x.Name, methodName)).ToArray();
            if (matches.Length <= 0)
                return null;
            if (matches.Length == 1)
                return matches.First();

            //attempt to match on arg count first
            var argNames = AssemblyAnalysis.ParseArgsFromTokenName(tokenName.Name);
            var argCount = argNames == null ? 0 : argNames.Length;

            matches = Methods.Where(x => x.Args.Count == argCount).ToArray();
            if (matches.Length <= 0)
                return null;
            if (matches.Length == 1)
                return matches.First();
            if (argNames == null)
                return null;

            //attempt to match by args names
            var argNamesLikeThese = argNames.Select(x => Settings.LangStyle.TransformClrTypeSyntax(x));

            foreach (var match in matches)
            {
                if (match.Args.All(nfArg => argNamesLikeThese.Any(token => string.Equals(nfArg.ArgType, token))))
                    return match;
            }
            return null;
        }