/// <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; }
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]; } } }
/// <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> /// 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; }