Пример #1
0
        private ABCFile.MethodBody readMethodBody()
        {
            var r = new ABCFile.MethodBody();

            r.method         = readU30();
            r.maxStack       = readU30();
            r.localCount     = readU30();
            r.initScopeDepth = readU30();
            r.maxScopeDepth  = readU30();
            r.instructions   = null;

            uint len = readU30();
            var  instructionAtOffset = new uint[len];

            r.rawBytes = new byte[len];
            Buffer.BlockCopy(buf, (int)pos, r.rawBytes, 0, (int)len);

            Func <ABCFile.Label, ABCFile.Label> translateLabel = (ABCFile.Label label) =>
            {
                uint absoluteOffset    = label.absoluteOffset;
                uint instructionOffset = absoluteOffset;
                while (true)
                {
                    if (instructionOffset >= len)
                    {
                        label.index       = (uint)r.instructions.Length;
                        instructionOffset = len;
                        break;
                    }
                    if (instructionOffset <= 0)
                    {
                        label.index       = 0;
                        instructionOffset = 0;
                        break;
                    }
                    if (instructionAtOffset[instructionOffset] != uint.MaxValue)
                    {
                        label.index = instructionAtOffset[instructionOffset];
                        break;
                    }
                    instructionOffset--;
                }
                label.offset = (int)(absoluteOffset - instructionOffset);
                return(label);
            };

            uint start = pos;
            uint end   = pos + len;

            Func <uint> offset = () => { return(pos - start); };

            try
            {
                for (int i = 0; i < instructionAtOffset.Length; i++)
                {
                    instructionAtOffset[i] = uint.MaxValue;
                }
                var instructionOffsets = new List <uint>();
                var instrs             = new List <ABCFile.Instruction>();
                while (pos < end)
                {
                    uint instructionOffset = offset();
                    pos = start + instructionOffset;
                    instructionAtOffset[instructionOffset] = (uint)instrs.Count;
                    ABCFile.Instruction instruction;
                    instruction.opcode = (Opcode)readU8();
                    var opcodeInfo = OpcodeInfo.opcodeDict[instruction.opcode];
                    instruction.arguments = new ABCFile.Instruction.Argument[opcodeInfo.argumentTypes.Length];
                    for (int i = 0; i < instruction.arguments.Length; i++)
                    {
                        var type = opcodeInfo.argumentTypes[i];
                        switch (type)
                        {
                        case OpcodeArgumentType.Unknown:
                            throw new Exception("Don't know how to decode OP_" + opcodeInfo.name);

                        case OpcodeArgumentType.UByteLiteral:
                            instruction.arguments[i].ubytev = readU8();
                            break;

                        case OpcodeArgumentType.IntLiteral:
                            instruction.arguments[i].intv = readS32();
                            break;

                        case OpcodeArgumentType.UIntLiteral:
                            instruction.arguments[i].uintv = readU32();
                            break;

                        case OpcodeArgumentType.Int:
                        case OpcodeArgumentType.UInt:
                        case OpcodeArgumentType.Double:
                        case OpcodeArgumentType.String:
                        case OpcodeArgumentType.Namespace:
                        case OpcodeArgumentType.Multiname:
                        case OpcodeArgumentType.Class:
                        case OpcodeArgumentType.Method:
                            instruction.arguments[i].index = readU30();
                            break;

                        case OpcodeArgumentType.JumpTarget:
                            int delta = readS24();
                            instruction.arguments[i].jumpTarget.absoluteOffset = (uint)(offset() + delta);
                            break;

                        case OpcodeArgumentType.SwitchDefaultTarget:
                            instruction.arguments[i].jumpTarget.absoluteOffset = (uint)(instructionOffset + readS24());
                            break;

                        case OpcodeArgumentType.SwitchTargets:
                            instruction.arguments[i].switchTargets = new ABCFile.Label[readU30() + 1];
                            for (int j = 0; j < instruction.arguments[i].switchTargets.Length; j++)
                            {
                                instruction.arguments[i].switchTargets[j].absoluteOffset = (uint)(instructionOffset + readS24());
                            }
                            break;
                        }
                    }
                    instrs.Add(instruction);
                    instructionOffsets.Add(instructionOffset);
                }
                r.instructions = instrs.ToArray();

                if (pos > end)
                {
                    throw new Exception("Out-of-bounds code read error");
                }

                // convert jump target offsets to instruction indices
                for (int i = 0; i < r.instructions.Length; i++)
                {
                    var opcodeInfo = OpcodeInfo.opcodeDict[r.instructions[i].opcode];
                    for (int j = 0; j < opcodeInfo.argumentTypes.Length; j++)
                    {
                        switch (opcodeInfo.argumentTypes[j])
                        {
                        case OpcodeArgumentType.JumpTarget:
                        case OpcodeArgumentType.SwitchDefaultTarget:
                            r.instructions[i].arguments[j].jumpTarget = translateLabel(r.instructions[i].arguments[j].jumpTarget);
                            break;

                        case OpcodeArgumentType.SwitchTargets:
                            for (int k = 0; k < r.instructions[i].arguments[j].switchTargets.Length; k++)
                            {
                                r.instructions[i].arguments[j].switchTargets[k] =
                                    translateLabel(r.instructions[i].arguments[j].switchTargets[k]);
                            }
                            break;

                        default:
                            break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                r.instructions = null;
                r.error        = e.Message;
                instructionAtOffset.Initialize();
            }
            pos = end;

            r.exceptions = new ABCFile.ExceptionInfo[readU30()];
            for (int i = 0; i < r.exceptions.Length; i++)
            {
                r.exceptions[i]        = readExceptionInfo();
                r.exceptions[i].from   = translateLabel(r.exceptions[i].from);
                r.exceptions[i].to     = translateLabel(r.exceptions[i].to);
                r.exceptions[i].target = translateLabel(r.exceptions[i].target);
            }
            r.traits = new ABCFile.TraitsInfo[readU30()];
            for (int i = 0; i < r.traits.Length; i++)
            {
                r.traits[i] = readTrait();
            }
            return(r);
        }
Пример #2
0
        private void writeMethodBody(ABCFile.MethodBody v)
        {
            writeU30(v.method);
            writeU30(v.maxStack);
            writeU30(v.localCount);
            writeU30(v.initScopeDepth);
            writeU30(v.maxScopeDepth);

            var instructionOffsets = new uint[v.instructions.Length + 1];

            Func <ABCFile.Label, uint> resolveLabel =
                (ABCFile.Label label) => { return((uint)(instructionOffsets[label.index] + label.offset)); };

            {
                // we don't know the length before writing all the instructions - swap buffer with a temporary one
                byte[] globalBuf = buf;
                uint   globalPos = pos;
                var    methodBuf = new byte[1024 * 16];
                buf = methodBuf;
                pos = 0;

                var fixups = new List <Fixup>();

                for (int i = 0; i < v.instructions.Length; i++)
                {
                    var  instruction       = v.instructions[i];
                    uint instructionOffset = pos;
                    instructionOffsets[i] = instructionOffset;

                    var opcodeInfo = OpcodeInfo.opcodeDict[instruction.opcode];
                    writeU8((byte)instruction.opcode);

                    for (int j = 0; j < opcodeInfo.argumentTypes.Length; j++)
                    {
                        switch (opcodeInfo.argumentTypes[j])
                        {
                        case OpcodeArgumentType.Unknown:
                            throw new Exception("Don't know how to encode OP_" + opcodeInfo.name);

                        case OpcodeArgumentType.UByteLiteral:
                            writeU8(instruction.arguments[j].ubytev);
                            break;

                        case OpcodeArgumentType.IntLiteral:
                            writeS32(instruction.arguments[j].intv);
                            break;

                        case OpcodeArgumentType.UIntLiteral:
                            writeU32(instruction.arguments[j].uintv);
                            break;

                        case OpcodeArgumentType.Int:
                        case OpcodeArgumentType.UInt:
                        case OpcodeArgumentType.Double:
                        case OpcodeArgumentType.String:
                        case OpcodeArgumentType.Namespace:
                        case OpcodeArgumentType.Multiname:
                        case OpcodeArgumentType.Class:
                        case OpcodeArgumentType.Method:
                            writeU30(instruction.arguments[j].index);
                            break;

                        case OpcodeArgumentType.JumpTarget:
                            fixups.Add(new Fixup(instruction.arguments[j].jumpTarget, pos, pos + 3));
                            writeS24(0);
                            break;

                        case OpcodeArgumentType.SwitchDefaultTarget:
                            fixups.Add(new Fixup(instruction.arguments[j].jumpTarget, pos, instructionOffset));
                            writeS24(0);
                            break;

                        case OpcodeArgumentType.SwitchTargets:
                            writeU30((uint)instruction.arguments[j].switchTargets.Length - 1);
                            foreach (var off in instruction.arguments[j].switchTargets)
                            {
                                fixups.Add(new Fixup(off, pos, instructionOffset));
                                writeS24(0);
                            }
                            break;
                        }
                    }
                }

                Array.Resize(ref buf, (int)pos);
                instructionOffsets[v.instructions.Length] = pos;

                foreach (var fixup in fixups)
                {
                    pos = fixup.pos;
                    writeS24((int)(resolveLabel(fixup.target) - fixup.baseOffset));
                }

                byte[] code = buf;
                // restore global buffer
                buf = globalBuf;
                pos = globalPos;

                writeBytes(code);
            }

            writeU30((uint)v.exceptions.Length);
            foreach (var val in v.exceptions)
            {
                var value = val;
                value.from.absoluteOffset   = resolveLabel(value.from);
                value.to.absoluteOffset     = resolveLabel(value.to);
                value.target.absoluteOffset = resolveLabel(value.target);
                writeExceptionInfo(value);
            }
            writeU30((uint)v.traits.Length);
            foreach (var value in v.traits)
            {
                writeTrait(value);
            }
        }