Example #1
0
        internal static List <ClassDefinition> Hierarchicalize(List <ClassDefinition> container)
        {
            var result = new List <ClassDefinition>();

            foreach (var cdef in container)
            {
                if (cdef.Fullname.Contains(DexConsts.InnerClassMarker))
                {
                    var items    = cdef.Fullname.Split(DexConsts.InnerClassMarker);
                    var fullname = items[0];
                    var name     = items[1];
                    var owner    = Dex.GetClass(fullname, container);
                    if (owner != null)
                    {
                        owner.InnerClasses.Add(cdef);
                        cdef.Owner = owner;
                    }
                }
                else
                {
                    result.Add(cdef);
                }
            }
            return(result);
        }
 /// <summary>
 /// Transform the given body.
 /// </summary>
 public void Transform(Dex target, MethodBody body)
 {
     foreach (var ins in body.Instructions)
     {
         switch (ins.Code)
         {
             case RCode.Invoke_direct:
             case RCode.Invoke_virtual:
             case RCode.Invoke_interface:
                 MethodDefinition method;
                 if (((MethodReference)ins.Operand).TryResolve(target, out method))
                 {
                     if (method.Owner.IsInterface)
                     {
                         ins.Code = RCode.Invoke_interface;
                     }
                     else if (method.IsDirect)
                     {
                         ins.Code = RCode.Invoke_direct;
                     }
                     else
                     {
                         ins.Code = RCode.Invoke_virtual;
                     }
                 }
                 break;
         }
     }
 }
Example #3
0
 /// <summary>
 /// Verify all methods
 /// </summary>
 private void VerifyMethods(Dex dex)
 {
     foreach (var @class in dex.GetClasses())
     {
         VerifyClass(@class);
     }
 }
Example #4
0
        private static IEnumerable<IRLTransformation> GetTransformations(Dex target, MethodBody body)
        {
            foreach (var transformation in optimizations1)
            {
                transformation.Transform(target, body);
                yield return transformation;
            }

            var noopRemove = new NopRemoveTransformation();
            noopRemove.Transform(target, body);
            yield return noopRemove;

            bool hasChanges = true;

            while (hasChanges)
            {
                hasChanges = false;
                foreach (var transformation in incrementalOptimizations)
                {
                    bool changed = transformation.Transform(target, body);
                    if (changed) noopRemove.Transform(target, body);

                    hasChanges = changed || hasChanges;

                    yield return transformation;
                }
            }

            foreach (var transformation in optimizations2)
            {
                transformation.Transform(target, body);
                yield return transformation;
            }    
        }
        public bool Transform(Dex target, MethodBody body)
        {
#if DEBUG
            //return;
#endif
            return DoOptimization(body);
        }
Example #6
0
        /// <summary>
        /// Default ctor
        /// </summary>
        public DelegateType(AssemblyCompiler compiler, XTypeDefinition delegateType, ClassDefinition interfaceClass, Dex target, NameConverter nsConverter)
        {
            this.compiler = compiler;
            this.delegateType = delegateType;
            this.interfaceClass = interfaceClass;

            // Build invoke prototype
            invokeMethod = delegateType.Methods.First(x => x.EqualsName("Invoke"));
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public void Transform(Dex target, MethodBody body)
        {
            var basicBlocks = BasicBlock.Find(body);
            var registerCount = body.Registers.Count();
            if (registerCount > MaxRegisters)
                return;

            Dictionary<Instruction, ConstantKey> allConstInstructions;
            CollectReadOnlyConstInstructions(body, out allConstInstructions);
            RegisterUsageMap registerUsageMap = null;

            foreach (var block in basicBlocks)
            {
                // Select all const instructions that have a next instruction in the block.
                var list = block.Instructions.ToList();
                var isLargeBlock = list.Count > LargeBlockSize;
                if (isLargeBlock)
                    continue;
                var constInstructionKeys = list.Where(x => allConstInstructions.ContainsKey(x)).Select(x => allConstInstructions[x]).ToList();

                // Select all const instructions where the next instruction is a move.
                while (constInstructionKeys.Count > 0)
                {
                    // Take the first instruction
                    var insKey = constInstructionKeys[0];
                    constInstructionKeys.RemoveAt(0);

                    // Get the register
                    var reg = insKey.Instruction.Registers[0];

                    // Are there other const instructions of the same type and the same operand?
                    var sameConstInstructions = constInstructionKeys.Where(x => x.Equals(insKey)).ToList();
                    if (sameConstInstructions.Count == 0)
                        continue;
                    if (sameConstInstructions.Count < 4)
                        continue;

                    // It is now save to use the register for all const operations
                    foreach (var other in sameConstInstructions)
                    {
                        // Replace all register uses
                        var otherReg = other.Instruction.Registers[0];

                        // Find usages
                        registerUsageMap = registerUsageMap ?? new RegisterUsageMap(body.Instructions);
                        registerUsageMap.ReplaceRegisterWith(otherReg, reg, body);

                        // Remove const
                        constInstructionKeys.Remove(other);
                        allConstInstructions.Remove(other.Instruction);

                        // Change const to nop which will be removed later
                        other.Instruction.ConvertToNop();
                    }
                }
            }
        }
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;

            var registerUsage = new RegisterUsageMap2(body);

            hasChanges = InlineIntConstsIntoBinOp(registerUsage);

            return hasChanges;
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;

            // Find all "const" instructions and record register usage
            var allConstInstructions = new List<Instruction>();
            var registerUsage = new Dictionary<Register, List<Instruction>>();
            CollectInstructionInformation(body, allConstInstructions, registerUsage);

            // Find all basic blocks
            var basicBlocks = BasicBlock.Find(body);

            // Go over each block
            foreach (var iterator in basicBlocks)
            {
                var block = iterator;
                // Select all const instructions where the next instruction is a move.
                foreach (var ins in allConstInstructions)
                {
                    var r = ins.Registers[0];
                    // Only optimize const instructions to temp registers
                    if (r.Category != RCategory.Temp)
                        continue;

                    // Get all instructions using this register
                    var all = registerUsage[r];
                    if ((all.Count != 2) || (all[0] != ins))
                        continue;
                    var next = all[1];
                    // Opcode must match
                    if (next.Code != ConstToMove(ins.Code))
                        continue;
                    // Register must match
                    if (next.Registers[1] != r)
                        continue;
                    
                    // The following are the most expensive, so only test them if we have to.
                    // Only optimize is instruction is in current block
                    if (!block.Contains(ins))
                        continue;

                    // Next must be in same basic block
                    if (!block.Contains(next))
                        continue;

                    // We found a replacement
                    r = next.Registers[0];
                    ins.Registers[0] = r;
                    next.ConvertToNop();

                    hasChanges = true;
                }
            }
            return hasChanges;
        }
Example #10
0
 /// <summary>
 /// Create all child nodes
 /// </summary>
 protected override void CreateChildNodes()
 {
     var data = Load();
     dexSize = data.Length;
     dex = Dex.Read(new MemoryStream(data));
     foreach (var classDef in dex.Classes)
     {
         var parentNodes = Nodes.GetParentForFile(classDef.Namespace, 7, new[] { '.' });
         parentNodes.Add(new DexClassDefinitionNode(classDef));
     }
 }
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;

            var graph = new ControlFlowGraph2(body);
            var registerUsage = new RegisterUsageMap2(graph);

            hasChanges = EliminateRegisterAssigments(registerUsage);
            
            return hasChanges;
        }
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;
#if DEBUG
            //return;
#endif
            var instructions = body.Instructions;
            var hasNops = instructions.Any(x => x.Code == RCode.Nop);
            if (!hasNops)
                return false;

            var rerouter = new BranchReRouter(body);
            var i = 0;
            while (i < instructions.Count)
            {
                var inst = instructions[i];
                if (inst.Code != RCode.Nop)
                {
                    i++;
                    continue;
                }
                if (body.Exceptions.Count > 0)
                {
                    foreach (var ex in body.Exceptions.Where(x => x.TryEnd == inst).ToList())
                    {
                        var exTryEnd = ex.TryEnd;
                        if (exTryEnd.Index > ex.TryStart.Index)
                            exTryEnd = exTryEnd.Previous;

                        if (exTryEnd == ex.TryStart)
                        {
                            // empty exception handler -- remove.
                            body.Exceptions.Remove(ex);
                        }
                        else
                        {
                            ex.TryEnd = exTryEnd;
                        }
                    }
                }

                if (i < instructions.Count - 1)
                {
                    var next = instructions[i + 1];
                    rerouter.Reroute(inst, next);
                }
                instructions.RemoveAt(i);
                hasChanges = true;
            }

            return hasChanges;
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public void Transform(Dex target, MethodBody body)
        {
            // Find all basic blocks
            var basicBlocks = BasicBlock.Find(body);

            // Replace temp with variable registers with possible.
            TransformTempToVariable(body, basicBlocks);

            // Share registers in block only
            TransformInBlock(body, basicBlocks);

            // Share register across blocks
            TransformCrossBlock(body, basicBlocks);
        }
        public bool Transform(Dex target, MethodBody body)
        {
            foreach (var ins in body.Instructions)
            {
                if (ins.Code == RCode.Check_cast)
                {
                    var typeReference = (TypeReference) ins.Operand;
                    if(typeReference.Descriptor == "Ljava/lang/Object;")
                        ins.ConvertToNop();
                }
            }

            return false;
        }
Example #15
0
        /// <summary>
        /// Transform the given body towards Dex compilation. 
        /// <returns>
        /// Returns the name of the last applied tranformation, or null on full processing.
        /// </returns>
        /// </summary>
        internal static string Transform(Dex target, MethodBody body, int stopAfterSteps = int.MaxValue)
        {
            if (stopAfterSteps == 0) return "(no proccessing)";
            int stepCount = 0;

            foreach (var applied in GetTransformations(target, body))
            {
                if (++stepCount > stopAfterSteps)
                {
                    return applied.GetType().Name;
                }
            }

            return null;
        }
Example #16
0
        /// <summary>
        /// Default ctor
        /// </summary>
        public DelegateType(AssemblyCompiler compiler, XTypeDefinition delegateType, ClassDefinition interfaceClass, Dex target, NameConverter nsConverter)
        {
            this.compiler = compiler;
            this.delegateType = delegateType;
            this.interfaceClass = interfaceClass;

            // Build invoke prototype
            invokeMethod = delegateType.Methods.First(x => x.EqualsName("Invoke"));
            XTypeDefinition baseType = delegateType;
            while ((null != baseType) && !baseType.Methods.Any(x => x.EqualsName("Equals")))
            {
                baseType = baseType.BaseType as XTypeDefinition;
            }
            if (null != baseType)
            {
                equalsMethod = baseType.Methods.First(x => x.EqualsName("Equals"));
            }
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public bool Transform(Dex target, MethodBody body)
        {
            foreach (var ins in body.Instructions)
            {
                switch (ins.Code)
                {
                    case RCode.Invoke_direct:
                    case RCode.Invoke_virtual:
                    case RCode.Invoke_interface:
                        MethodDefinition method;
                        if (((MethodReference)ins.Operand).TryResolve(target, out method))
                        {
                            if (method.Owner.IsInterface)
                            {
                                ins.Code = RCode.Invoke_interface;
                            }
                            else if (method.IsStatic) // This happens for android extension methods. 
                                                      // Is this a hack. why was the correct invoke code not 
                                                      // used in the first place?
                                                      // (in AstCompilerVisitor.Expression.VisitCallExpression?)
                            {
                                ins.Code = RCode.Invoke_static;
                            }
                            else if (method.IsDirect)
                            {
                                ins.Code = RCode.Invoke_direct;
                            }
                            else
                            {
                                ins.Code = RCode.Invoke_virtual;
                            }
                        }
                        break;
                }
            }

            return false;
        }
        public bool Transform(Dex target, MethodBody body)
        {
            bool hasChanges = false;
#if DEBUG
            //return;
#endif
            var instructions = body.Instructions;

            bool[] reachable = new bool[instructions.Count];

            MarkReachable(0, instructions, reachable, body);

            for (int i = instructions.Count - 1; i > 0 ; --i)
            {
                // the nop-remover will also correcly remove exception handlers.
                if (!reachable[i] && instructions[i].Code != RCode.Nop)
                {
                    instructions[i].ConvertToNop();
                    hasChanges = true;
                }
            }
           
            return hasChanges;
        }
Example #19
0
 /// <summary>
 /// Set the super class of the class definition.
 /// </summary>
 protected void ImplementSuperClass(Dex target, NameConverter nsConverter)
 {
     // Set base type
     var baseType = typeDef.SuperClass;
     if (baseType != null)
     {
         classDef.SuperClass = new ClassReference(baseType.ClassName);
     }
     else if (typeDef.IsInterface)
     {
         classDef.SuperClass = new ClassReference("java/lang/Object");
     }
     else
     {
         throw new ArgumentException(string.Format("Type {0} has no base type", typeDef.ClassName));
     }
 }
Example #20
0
 /// <summary>
 /// Implement make minor fixes after the implementation phase.
 /// </summary>
 public void FixUp(Dex target, NameConverter nsConverter)
 {
     FixUpInnerClasses(target, nsConverter);
     FixUpMethods(target, nsConverter);
 }
Example #21
0
 /// <summary>
 /// FixUp all nested types.
 /// </summary>
 protected virtual void FixUpInnerClasses(Dex target, NameConverter nsConverter)
 {
     // FixUp nested type
     nestedBuilders.ForEach(x => x.FixUp(target, nsConverter));
 }
Example #22
0
 /// <summary>
 /// Add references to all implemented interfaces.
 /// </summary>
 protected virtual void ImplementInterfaces(Dex target, NameConverter nsConverter)
 {
     // Implement interfaces
     classDef.Interfaces.AddRange(typeDef.Interfaces.Select(x => new ClassReference(x.ClassName)));
 }
Example #23
0
 public DexLookup(Dex dex) : this(dex.Classes, true)
 {
 }
Example #24
0
        /// <summary>
        /// Optimize the RL structure.
        /// </summary>
        private void OptimizeRL(Dex target)
        {
            if (rlIsOptimized)
                return;
            var rlBody = RLBody;
            if (rlBody == null)
                throw new ArgumentException("No RL body set");

            // Optimize RL code
            RLTransformations.Transform(target, rlBody);
            rlIsOptimized = true;
        }
        /// <summary>
        /// Transform the given body.
        /// </summary>
        public bool Transform(Dex target, MethodBody body)
        {
            // Build the control flow graph
            var cfg = new ControlFlowGraph(body);

            // Go over each block to find registers that are initialized and may need initialization
            foreach (var iterator in cfg)
            {
                var block = iterator;
                var data = new BasicBlockData(block);
                block.Tag = data;

                // Go over all instructions in the block, finding source/destination registers
                foreach (var ins in block.Instructions)
                {
                    var info = OpCodeInfo.Get(ins.Code.ToDex());
                    var count = ins.Registers.Count;
                    for (var i = 0; i < count; i++)
                    {
                        var reg = ins.Registers[i];
                        if (reg.Category != RCategory.Argument)
                        {
                            var flags = info.GetUsage(i);
                            if (flags.HasFlag(RegisterFlags.Source))
                            {
                                // Must be initialize
                                if (!data.Initialized.Contains(reg))
                                {
                                    data.MayNeedInitialization.Add(reg);
                                }
                            }
                            if (flags.HasFlag(RegisterFlags.Destination))
                            {
                                // Destination
                                data.Initialized.Add(reg);
                            }
                        }
                    }
                }

            }

            // Go over all blocks to collect the register that really need initialization
            var needInitialization = new HashSet<Register>();
            foreach (var iterator in cfg)
            {
                var block = iterator;
                var data = (BasicBlockData)block.Tag;

                foreach (var regIterator in data.MayNeedInitialization)
                {
                    // Short cut
                    var reg = regIterator;
                    if (needInitialization.Contains(reg))
                        continue;

                    // If the register is initialized in all entry blocks, we do not need to initialize it
                    if (block.EntryBlocks.Select(x => (BasicBlockData) x.Tag).Any(x => !x.IsInitialized(reg)))
                    {
                        // There is an entry block that does not initialize the register, so we have to initialize it
                        needInitialization.Add(reg);
                    }
                }
            }

            var index = 0;
            Register valueReg = null;
            Register objectReg = null;
            Register wideReg = null;
            var firstSourceLocation = body.Instructions[0].SequencePoint;
            foreach (var reg in needInitialization.OrderBy(x => x.Index))
            {
                switch (reg.Type)
                {
                    case RType.Value:
                        if (valueReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] {reg}) { SequencePoint = firstSourceLocation });
                            valueReg = reg;
                        }
                        else if (valueReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move, reg, valueReg) { SequencePoint = firstSourceLocation });                            
                        }
                        break;
                    case RType.Object:
                        if (objectReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const, 0, new[] { reg }) { SequencePoint = firstSourceLocation });
                            objectReg = reg;
                        }
                        else if (objectReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move_object, reg, objectReg) { SequencePoint = firstSourceLocation });
                        }
                        break;
                    case RType.Wide:
                        if (wideReg == null)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Const_wide, 0, new[] { reg }) { SequencePoint = firstSourceLocation });
                            wideReg = reg;
                        }
                        else if (wideReg != reg)
                        {
                            body.Instructions.Insert(index++, new Instruction(RCode.Move_wide, reg, wideReg) { SequencePoint = firstSourceLocation });
                        }
                        break;
                }
            }

            return false;
        }
Example #26
0
 /// <summary>
 /// Verify the given dex structure.
 /// </summary>
 internal static void Verify(Dex dex, Action<string> onError)
 {
     var v = new Verifier(onError);
     v.VerifyMethods(dex);
 }
Example #27
0
 internal void RegisterDex(Dex dex)
 {
     belongsToDex.Add(new WeakReference(dex));
 }
Example #28
0
 internal void RegisterDex(Dex dex)
 {
     belongsToDex.Add(new WeakReference(dex));
 }
 public bool Transform(Dex target, MethodBody body)
 {
     var cfg = new ControlFlowGraph2(body);
     return OptimizeBranches(cfg);
 }
Example #30
0
 /// <summary>
 /// FixUp all methods.
 /// </summary>
 protected virtual void FixUpMethods(Dex target, NameConverter nsConverter)
 {
     // FixUp methods
     methodBuilders.ForEach(x => x.FixUp(target, nsConverter));
 }
Example #31
0
 /// <summary>
 /// Create the current type as class definition.
 /// </summary>
 public void Create(Dex target, NameConverter nsConverter)
 {
     Create(target, nsConverter, null, null, null);
 }
Example #32
0
        public string Disassemble(ClassDefinition def)
        {
            if (string.IsNullOrEmpty(_settings.BaksmaliCommand))
                return "#ERROR: command to run not set.";

            StringBuilder ret = new StringBuilder();

            try
            {
                // get a temporary directoy
                string tempPath = Path.GetTempFileName();
                File.Delete(tempPath);
                Directory.CreateDirectory(tempPath);

                string dexFileName = Path.Combine(tempPath, "classes.dex");

                // create dex with one class definition
                // NOTE: it would be better if we could get hold of
                //       the actual binary representation.
                //       or use the original apk/dex and limit what baksmali 
                //       processes.
                var dex = new Dex();
                dex.AddClass(def);
                dex.Write(dexFileName);

                // run baksmali
                var cmd = GetBacksmaliCommand(_settings, dexFileName, tempPath);

                ret.AppendLine("# processed with: " + cmd);
                ret.AppendLine("#");

                int retCode;
                List<string> output = new List<string>();
                if ((retCode = Run.System(output, "{0}", cmd)) != 0)
                    ret.AppendLine("# return code: " + retCode);

                // process eventual errors
                output.ForEach(p=>ret.AppendFormat("# output: {0}\n", p));
                    
                // find .smali file
                var filenames = Directory.EnumerateFiles(tempPath, "*.smali", SearchOption.AllDirectories).ToList();


                if (!filenames.Any())
                {
                    ret.AppendLine("# ERROR: baksmali did not produce any output files.");
                }

                if (filenames.Count > 1)
                    ret.AppendLine("# NOTE: baksmali produced multiple files");


                IEnumerable<string> contents = filenames.Select(n => File.ReadAllText(Path.Combine(tempPath, n)));
                ret.Append(string.Join("\n\n\n\n-----------\n\n\n\n", contents));

                // clean up. (don't clean up on exception, to let the user inspect what happened)
                Directory.Delete(tempPath, true);

                return ret.ToString();
            }
            catch (Exception ex)
            {
                return "# ERROR: " + ex;
            }

        }
Example #33
0
 /// <summary>
 /// Create the current type as class definition.
 /// </summary>
 protected void Create(Dex target, NameConverter nsConverter, ClassDefinition parent, ClassFile parentClass, XTypeDefinition parentXType)
 {
     xType = new XBuilder.JavaTypeDefinition(compiler.Module, parentXType, typeDef);
     CreateClassDefinition(target, nsConverter, parent, parentClass);
     CreateNestedClasses(target, nsConverter, parent);
 }