Exemple #1
0
 /// <summary>
 /// Copy ctor
 /// </summary>
 public ExceptionHandler(ExceptionHandler source)
 {
     catches = source.catches.Select(x => new Catch(x)).ToList();
     TryStart = source.TryStart;
     TryEnd = source.TryEnd;
     CatchAll = source.CatchAll;
 }
Exemple #2
0
        private void ReadExceptionHandlers(BinaryReader reader, MethodDefinition mdef,
            InstructionReader instructionReader, ushort triesSize)
        {
            var exceptionLookup = new Dictionary<uint, List<ExceptionHandler>>();
            for (int i = 0; i < triesSize; i++)
            {
                uint startOffset = reader.ReadUInt32();
                uint insCount = reader.ReadUInt16();
                uint endOffset = startOffset + insCount - 1;
                uint handlerOffset = reader.ReadUInt16();

                var ehandler = new ExceptionHandler();
                mdef.Body.Exceptions.Add(ehandler);
                if (!exceptionLookup.ContainsKey(handlerOffset))
                {
                    exceptionLookup.Add(handlerOffset, new List<ExceptionHandler>());
                }
                exceptionLookup[handlerOffset].Add(ehandler);
                ehandler.TryStart = instructionReader.Lookup[(int) startOffset];
                // The last code unit covered (inclusive) is start_addr + insn_count - 1
                ehandler.TryEnd = instructionReader.LookupLast[(int) endOffset];
            }

            long baseOffset = reader.BaseStream.Position;
            uint catchHandlersSize = reader.ReadULEB128();
            for (int i = 0; i < catchHandlersSize; i++)
            {
                long itemoffset = reader.BaseStream.Position - baseOffset;
                int catchTypes = reader.ReadSLEB128();
                bool catchAllPresent = catchTypes <= 0;
                catchTypes = Math.Abs(catchTypes);

                for (int j = 0; j < catchTypes; j++)
                {
                    uint typeIndex = reader.ReadULEB128();
                    uint offset = reader.ReadULEB128();
                    var @catch = new Catch();
                    @catch.Type = typeReferences[(int) typeIndex];
                    @catch.Instruction = instructionReader.Lookup[(int) offset];

                    // As catch handler can be used in several tries, let's clone the catch
                    foreach (ExceptionHandler ehandler in exceptionLookup[(uint) itemoffset])
                        ehandler.Catches.Add(@catch.Clone());
                }

                if (catchAllPresent)
                {
                    uint offset = reader.ReadULEB128();
                    foreach (ExceptionHandler ehandler in exceptionLookup[(uint) itemoffset])
                        ehandler.CatchAll = instructionReader.Lookup[(int) offset];
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// Compile RL into Dex.
        /// </summary>
        public RegisterMapper Compile()
        {
            // Map registers
            var regMapper = new RegisterMapper(rlBody, frame);

            // Create instructions
            var maxOutgoingArguments = 0;
            var target = dexBody.Instructions;
            var insMap = new Dictionary <Instruction, Tuple <DexLib.Instructions.Instruction, DexLib.Instructions.Instruction> >();

            foreach (var ins in rlBody.Instructions)
            {
                DexLib.Instructions.Instruction first = null;
                DexLib.Instructions.Instruction last  = null;
                foreach (var dexIns in RL2Dex.Convert(ins, regMapper))
                {
                    target.Add(dexIns);
                    if (first == null)
                    {
                        first = dexIns;
                    }
                    last = dexIns;
                }
                if ((first == null) || (last == null))
                {
                    throw new InvalidOperationException();
                }
                insMap[ins] = Tuple.Create(first, last);

                // Gather statistics
                if (ins.Code.IsInvoke())
                {
                    maxOutgoingArguments = Math.Max(maxOutgoingArguments, ins.Registers.Count);
                }
            }

            // Update targets
            foreach (var dexIns in target)
            {
                var instruction = dexIns.Operand as Instruction;
                if (instruction != null)
                {
                    dexIns.Operand = insMap[instruction].Item1;
                }
                if (dexIns.OpCode == OpCodes.Packed_switch)
                {
                    var instructions = (Instruction[])dexIns.Operand;
                    dexIns.Operand = new PackedSwitchData(instructions.Select(x => insMap[x].Item1));
                }
                else if (dexIns.OpCode == OpCodes.Sparse_switch)
                {
                    var targetPairs = (Tuple <int, Instruction>[])dexIns.Operand;
                    var data        = new SparseSwitchData();
                    foreach (var pair in targetPairs.OrderBy(x => x.Item1))
                    {
                        data.Targets.Add(pair.Item1, insMap[pair.Item2].Item1);
                    }
                    dexIns.Operand = data;
                }
            }

            // Create exception handlers
            foreach (var handler in rlBody.Exceptions)
            {
                var dhandler = new ExceptionHandler();
                dhandler.TryStart = insMap[handler.TryStart].Item1;
                dhandler.TryEnd   = insMap[handler.TryEnd].Item2;
                dhandler.CatchAll = (handler.CatchAll != null) ? insMap[handler.CatchAll].Item1 : null;
                dexBody.Exceptions.Add(dhandler);

                foreach (var catchBlock in handler.Catches)
                {
                    var dcatchBlock = new Catch();
                    dcatchBlock.Type        = catchBlock.Type;
                    dcatchBlock.Instruction = insMap[catchBlock.Instruction].Item1;
                    dhandler.Catches.Add(dcatchBlock);
                }
            }

            // Add register spilling code (if needed)
            if (regMapper.SpillingRequired)
            {
                RegisterSpillingOptimizer.Transform(dexBody);
                RegisterSpilling.AddSpillingCode(dexBody, regMapper);
            }

            // Set statistics
            dexBody.Registers.AddRange(regMapper.All);
            dexBody.IncomingArguments = (ushort)regMapper.ArgumentCount;
            dexBody.OutgoingArguments = (ushort)maxOutgoingArguments;

            return(regMapper);
        }
Exemple #4
0
        /// <summary>
        /// Compile RL into Dex.
        /// </summary>
        public RegisterMapper Compile()
        {
            // Map registers
            var regMapper = new RegisterMapper(rlBody, frame);

            // Create instructions
            var maxOutgoingArguments = 0;
            var target = dexBody.Instructions;
            var insMap = new Dictionary<Instruction, Tuple<DexLib.Instructions.Instruction, DexLib.Instructions.Instruction>>();
            foreach (var ins in rlBody.Instructions)
            {
                DexLib.Instructions.Instruction first = null;
                DexLib.Instructions.Instruction last = null;
                foreach (var dexIns in RL2Dex.Convert(ins, regMapper))
                {
                    target.Add(dexIns);
                    if (first == null) first = dexIns;
                    last = dexIns;
                }
                if ((first == null) || (last == null))
                    throw new InvalidOperationException();
                insMap[ins] = Tuple.Create(first, last);

                // Gather statistics
                if (ins.Code.IsInvoke())
                {
                    maxOutgoingArguments = Math.Max(maxOutgoingArguments, ins.Registers.Count);
                }
            }

            // Update targets
            foreach (var dexIns in target)
            {
                var instruction = dexIns.Operand as Instruction;
                if (instruction != null)
                {
                    dexIns.Operand = insMap[instruction].Item1;
                }
                if (dexIns.OpCode == OpCodes.Packed_switch)
                {
                    var instructions = (Instruction[])dexIns.Operand;
                    dexIns.Operand = new PackedSwitchData(instructions.Select(x => insMap[x].Item1));
                }
                else if (dexIns.OpCode == OpCodes.Sparse_switch)
                {
                    var targetPairs = (Tuple<int, Instruction>[])dexIns.Operand;
                    var data = new SparseSwitchData();
                    foreach (var pair in targetPairs.OrderBy(x => x.Item1))
                    {
                        data.Targets.Add(pair.Item1, insMap[pair.Item2].Item1);
                    }
                    dexIns.Operand = data;
                }
            }

            // Create exception handlers 
            foreach (var handler in rlBody.Exceptions)
            {
                var dhandler = new ExceptionHandler();
                dhandler.TryStart = insMap[handler.TryStart].Item1;
                dhandler.TryEnd = insMap[handler.TryEnd].Item2;
                dhandler.CatchAll = (handler.CatchAll != null) ? insMap[handler.CatchAll].Item1 : null;
                dexBody.Exceptions.Add(dhandler);

                foreach (var catchBlock in handler.Catches)
                {
                    var dcatchBlock = new Catch();
                    dcatchBlock.Type = catchBlock.Type;
                    dcatchBlock.Instruction = insMap[catchBlock.Instruction].Item1;
                    dhandler.Catches.Add(dcatchBlock);
                }
            }

            // Add register spilling code (if needed)
            if (regMapper.SpillingRequired)
            {
                RegisterSpillingOptimizer.Transform(dexBody);
                RegisterSpilling.AddSpillingCode(dexBody, regMapper);
            }

            // Set statistics
            dexBody.Registers.AddRange(regMapper.All);
            dexBody.IncomingArguments = (ushort) regMapper.ArgumentCount;
            dexBody.OutgoingArguments = (ushort) maxOutgoingArguments;

            return regMapper;
        }
        /// <summary>
        /// Note that referencing operands, i.e. TypeReferences, FieldReference or
        /// MethodRefrences are not cloned, but only shallow copied.
        /// If you indend to modify those operand values themself, be sure to clone
        /// them beforehand. 
        /// </summary>
        public static MethodBody Clone(MethodDefinition targetMethod, MethodDefinition sourceMethod)
        {
            var sourceBody = sourceMethod.Body;

            MethodBody body = new MethodBody(targetMethod, sourceBody.Registers.Count)
            {
                IncomingArguments = sourceBody.IncomingArguments,
                OutgoingArguments = sourceBody.OutgoingArguments
            };

            foreach (var sourceIns in sourceBody.Instructions)
            {
                var ins = new Instruction(sourceIns.OpCode);

                foreach (var r in sourceIns.Registers)
                    ins.Registers.Add(body.Registers[r.Index]);

                ins.Offset = sourceIns.Offset;
                ins.SequencePoint = ins.SequencePoint;

                ins.Operand = sourceIns.Operand;

                body.Instructions.Add(ins);
            }

            // fix instruction references

            var insByOffset = body.Instructions.ToDictionary(i => i.Offset);

            foreach (var ins in body.Instructions)
            {
                var targetIns = ins.Operand as Instruction;
                var packedSwitch = ins.Operand as PackedSwitchData;
                var sparseSwitch = ins.Operand as SparseSwitchData;

                if (targetIns != null)
                {
                    ins.Operand = insByOffset[targetIns.Offset];
                }
                else if (packedSwitch != null)
                {
                    var ps = new PackedSwitchData(packedSwitch.Targets.Select(si => insByOffset[si.Offset]));
                    ps.FirstKey = packedSwitch.FirstKey;
                    ins.Operand = ps;
                }
                else if (sparseSwitch != null)
                {
                    var ss = new SparseSwitchData();
                    foreach (var ssd in sparseSwitch.Targets)
                    {
                        ss.Targets.Add(ssd.Key, insByOffset[ssd.Value.Offset]);
                    }
                    ins.Operand = ss;
                }
            }


            foreach (var sourceEx in sourceBody.Exceptions)
            {
                var ex = new ExceptionHandler();
                if (sourceEx.TryStart != null)
                    ex.TryStart = insByOffset[sourceEx.TryStart.Offset];
                if (sourceEx.TryEnd != null)
                    ex.TryEnd   = insByOffset[sourceEx.TryEnd.Offset];
                if (sourceEx.CatchAll != null)
                    ex.CatchAll = insByOffset[sourceEx.CatchAll.Offset];

                foreach (var sourceCatch in sourceEx.Catches)
                {
                    var c = new Catch
                    {
                        Type = sourceCatch.Type,
                        Instruction = insByOffset[sourceCatch.Instruction.Offset]
                    };
                    ex.Catches.Add(c);
                }

                body.Exceptions.Add(ex);
            }

            if (sourceBody.DebugInfo != null)
            {
                var di = body.DebugInfo = new DebugInfo(body);

                di.LineStart = sourceBody.DebugInfo.LineStart;
                di.Parameters = sourceBody.DebugInfo.Parameters.ToList();

                foreach (var sourceInstruction in sourceBody.DebugInfo.DebugInstructions)
                {
                    di.DebugInstructions.Add(new DebugInstruction(sourceInstruction.OpCode,
                        sourceInstruction.Operands.ToList()));
                }
            }

            return body;
        }