Exemple #1
0
        public MethodBodyDisassemblyFormatter(MethodDefinition methodDef, MapFileLookup mapFile)
        {
            _methodDef = methodDef;
            _mapFile   = mapFile;

            TypeEntry   typeEntry   = null;
            MethodEntry methodEntry = null;

            if (mapFile != null)
            {
                typeEntry = mapFile.GetTypeByNewName(methodDef.Owner.Fullname);
                if (typeEntry != null)
                {
                    methodEntry = typeEntry.FindDexMethod(methodDef.Name, methodDef.Prototype.ToSignature());
                }
            }

            _dissassembly = new MethodDisassembly(methodDef, mapFile, typeEntry, methodEntry);

            _sourceDocument = new Lazy <string[]>(() =>
            {
                if (_dissassembly.MethodEntry == null)
                {
                    return(null);
                }
                var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault();
                if (pos == null)
                {
                    return(null);
                }

                try
                {
                    return(File.ReadAllLines(pos.Document.Path));
                }
                catch (Exception)
                {
                    return(null);
                }
            });
        }
Exemple #2
0
        public string Format(FormatOptions options)
        {
            var nl = Environment.NewLine;
            var sb = new StringBuilder();

            var body = _methodDef.Body;
            var cfg  = new ControlFlowGraph(body);
            SourceCodePosition lastSource = null;

            _dissassembly.Format = options;

            var embedSource = options.HasFlag(FormatOptions.EmbedSourceCode) || options.HasFlag(FormatOptions.EmbedSourcePositions);

            if (embedSource && _dissassembly.MethodEntry != null)
            {
                var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault();
                if (pos != null)
                {
                    sb.Append(" // ----- Source Code: ");
                    sb.Append(pos.Document.Path);
                    sb.Append(nl);
                }
            }

            foreach (var block in cfg)
            {
                if (options.HasFlag(FormatOptions.ShowControlFlow))
                {
                    sb.AppendFormat(" // ----- Entry [{0}] Exit [{1}]{2}",
                                    string.Join(", ", block.EntryBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())),
                                    string.Join(", ", block.ExitBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())),
                                    nl);
                }


                foreach (var i in block.Instructions)
                {
                    if (embedSource)
                    {
                        var source = _dissassembly.FindSourceCode(i.Offset, false);

                        if (source != null && lastSource != null && source.Document.Path != lastSource.Document.Path)
                        {
                            // print document name.
                            sb.Append(" // ----- ");
                            sb.Append(source.Document.Path);
                            sb.Append(nl);
                            lastSource = null;
                        }

                        if (source == null && lastSource != null)
                        {
                            sb.AppendLine(" // ----- (no source)");
                        }
                        else if (source != null && (lastSource == null || !source.Position.EqualExceptOffset(lastSource.Position)))
                        {
                            if (options.HasFlag(FormatOptions.EmbedSourcePositions))
                            {
                                sb.AppendFormat(" // ----- Position: {0} - {1}{2}", source.Position.Start, source.Position.End, nl);
                            }

                            if (options.HasFlag(FormatOptions.EmbedSourceCode))
                            {
                                string[] lines = GetSourceCodeLines(source);
                                if (lines != null)
                                {
                                    sb.AppendLine(" // " + string.Join(nl + " // ", lines));
                                }
                            }
                        }
                        lastSource = source;
                    }

                    sb.AppendLine(_dissassembly.FormatInstruction(i));
                }
            }
            sb.AppendLine();

            if (body.Exceptions.Any())
            {
                sb.AppendLine("Exception handlers:");
                foreach (var handler in body.Exceptions)
                {
                    sb.AppendFormat("\t{0} - {1}{2}", _dissassembly.FormatAddress(handler.TryStart), _dissassembly.FormatAddress(handler.TryEnd), nl);
                    foreach (var c in handler.Catches)
                    {
                        sb.AppendFormat("\t\t{0} => {1}{2}", c.Type, _dissassembly.FormatAddress(c.Instruction), nl);
                    }
                    if (handler.CatchAll != null)
                    {
                        sb.AppendFormat("\t\t{0} => {1}{2}", "<any>", _dissassembly.FormatAddress(handler.CatchAll), nl);
                    }
                }
                sb.AppendLine();
            }

            if (_mapFile != null)
            {
                var typeEntry = _mapFile.GetTypeByNewName(_methodDef.Owner.Fullname);
                if (typeEntry != null)
                {
                    var methodEntry = typeEntry.FindDexMethod(_methodDef.Name, _methodDef.Prototype.ToSignature());
                    if (methodEntry != null)
                    {
                        _registersToVariableNames = new Dictionary <string, string>();

                        var validParameters = methodEntry.Parameters.Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
                        if (validParameters.Any())
                        {
                            sb.AppendLine("Parameters:");
                            foreach (var p in validParameters)
                            {
                                var registerName = _dissassembly.FormatRegister(p.Register);
                                sb.AppendFormat("\t{0} (r{1}) -> {2}{3}", registerName, p.Register, p.Name, nl);

                                if (!string.IsNullOrEmpty(p.Name))
                                {
                                    _registersToVariableNames.Add(registerName, p.Name);
                                }
                            }
                            sb.AppendLine();
                        }

                        var validVariables = methodEntry.Variables.Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
                        if (validVariables.Any())
                        {
                            sb.AppendLine("Variables:");
                            foreach (var p in validVariables)
                            {
                                var registerName = _dissassembly.FormatRegister(p.Register);
                                sb.AppendFormat("\t{0} -> {1}{2}", registerName, p.Name, nl);
                                if (!string.IsNullOrEmpty(p.Name))
                                {
                                    _registersToVariableNames.Add(registerName, p.Name);
                                }
                            }
                            sb.AppendLine();
                        }

                        sb.AppendLine("Source code positions:");
                        Document lastDocument = null;
                        foreach (var row in _mapFile.GetSourceCodePositions(methodEntry))
                        {
                            if (row.Document != lastDocument)
                            {
                                sb.AppendFormat("\t{0}{1}", row.Document.Path, nl);
                                lastDocument = row.Document;
                            }
                            var pos = row.Position;
                            sb.AppendFormat("\t{0}\t({1},{2}) - ({3},{4}){5}", MethodDisassembly.FormatOffset(pos.MethodOffset), pos.Start.Line, pos.Start.Column, pos.End.Line, pos.End.Column, nl);
                        }
                    }
                }
            }
            return(sb.ToString());
        }
        public CacheEntry GetFromCacheImpl(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            if (_initialize == null)
            {
                return(null);
            }
            _initialize.Wait();

            if (!IsEnabled)
            {
                return(null);
            }

            if (sourceMethod.ScopeId == null || sourceMethod.ScopeId == "(none)")
            {
                return(null);
            }

            if (IsUnderlyingCodeModified(sourceMethod))
            {
                return(null);
            }

            Tuple <TypeEntry, MethodEntry> entry;

            string typeScopeId   = sourceMethod.DeclaringType.ScopeId;
            string methodScopeId = sourceMethod.ScopeId;

            MethodDefinition cachedMethod;

            if (_methodsByScopeId.TryGetValue(Tuple.Create(typeScopeId, methodScopeId), out entry))
            {
                cachedMethod = _dexLookup.GetMethod(entry.Item1.DexName, entry.Item2.DexName, entry.Item2.DexSignature);
            }
            else
            {
                // try directly in the dexlookup, for jar imports
                cachedMethod = _dexLookup.GetMethod(typeScopeId.Replace("/", "."), targetMethod.Name, targetMethod.Prototype.ToSignature());
            }

            if (cachedMethod == null)
            {
                return(null);
            }

            if (cachedMethod.Body == null)
            {
                // I believe there is a bug in MethodExplicitInterfaceConverter generating
                // stubs for interfaces if they derive from an imported interface.
                // Bail out for now until this is fixed.
                DLog.Debug(DContext.CompilerCodeGenerator, "Compiler cache: no method body found on cached version of {0}, even though one was expected.", sourceMethod);
                return(null);
            }

            try
            {
                if (!Equals(cachedMethod.Prototype, targetMethod.Prototype))
                {
                    throw new Exception("internal error, got the wrong method.");
                }

                var body = DexMethodBodyCloner.Clone(targetMethod, cachedMethod);
                FixReferences(body, compiler, targetPackage);

                string className = entry != null ? entry.Item1.DexName : body.Owner.Owner.Fullname;
                var    @class    = _dexLookup.GetClass(className);

                return(new CacheEntry(body, entry != null ? entry.Item2 : null, entry != null ? _map.GetSourceCodePositions(entry.Item2) : null, @class.SourceFile));
            }
            catch (CompilerCacheResolveException ex)
            {
                // This happens at the moment for methods using fields in the __generated class,
                // as well as for references to generated methods (mostly explicit interfac stubs)
                // during the IL conversion phase.
                // This also seems to happen for Framework-nested classes, maybe because these do
                // not get an entry in the map file. This should be fixed.
                // The number of these failures in my test is 890 out of ~12000. We gracefully
                // handle errors by re-compiling the method body.
                Debug.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
            catch (Exception ex)
            {
                DLog.Warning(DContext.CompilerCodeGenerator, "Compiler cache: exception while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message);
                Trace.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
        }