private AttributeBase LoadCode(BigEndianBinaryReader reader, int attributeLength) { int maxStack = reader.ReadUInt16(); int maxLocals = reader.ReadUInt16(); int codeLength = reader.ReadInt32(); byte[] code = reader.ReadBytes(codeLength); int exceptionTableLength = reader.ReadUInt16(); var exceptionTable = new ExceptionTableEntry[exceptionTableLength]; for (int i = 0; i < exceptionTableLength; i++) { int startPC = reader.ReadUInt16(); int endPC = reader.ReadUInt16(); int handlerPC = reader.ReadUInt16(); int catchTypeIndex = reader.ReadUInt16(); exceptionTable[i] = new ExceptionTableEntry(startPC, endPC, handlerPC, catchTypeIndex); } var attributes = Load(reader); return(new CodeAttribute(maxStack, maxLocals, code, exceptionTable, attributes)); }
internal void Read(ClassFile classFile, string[] utf8_cp, Method method, BigEndianBinaryReader br, ClassFileParseOptions options) { max_stack = br.ReadUInt16(); max_locals = br.ReadUInt16(); uint code_length = br.ReadUInt32(); if(code_length > 65535) { throw new ClassFormatError("{0} (Invalid Code length {1})", classFile.Name, code_length); } Instruction[] instructions = new Instruction[code_length + 1]; int basePosition = br.Position; int instructionIndex = 0; try { BigEndianBinaryReader rdr = br.Section(code_length); while(!rdr.IsAtEnd) { instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; instructionIndex++; } // we add an additional nop instruction to make it easier for consumers of the code array instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); } catch(ClassFormatError x) { // any class format errors in the code block are actually verify errors verifyError = x.Message; } this.instructions = new Instruction[instructionIndex]; Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); // build the pcIndexMap int[] pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; for(int i = 0; i < pcIndexMap.Length; i++) { pcIndexMap[i] = -1; } for(int i = 0; i < instructionIndex - 1; i++) { pcIndexMap[this.instructions[i].PC] = i; } // convert branch offsets to indexes for(int i = 0; i < instructionIndex - 1; i++) { switch(this.instructions[i].NormalizedOpCode) { case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifne: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: case NormalizedByteCode.__ifnull: case NormalizedByteCode.__ifnonnull: case NormalizedByteCode.__goto: case NormalizedByteCode.__jsr: this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); break; case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: this.instructions[i].MapSwitchTargets(pcIndexMap); break; } } // read exception table ushort exception_table_length = br.ReadUInt16(); exception_table = new ExceptionTableEntry[exception_table_length]; for(int i = 0; i < exception_table_length; i++) { ushort start_pc = br.ReadUInt16(); ushort end_pc = br.ReadUInt16(); ushort handler_pc = br.ReadUInt16(); ushort catch_type = br.ReadUInt16(); if(start_pc >= end_pc || end_pc > code_length || handler_pc >= code_length || (catch_type != 0 && !classFile.SafeIsConstantPoolClass(catch_type))) { throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); } classFile.MarkLinkRequiredConstantPoolItem(catch_type); // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), // the index will be -1 and this will be handled by the verifier int startIndex = pcIndexMap[start_pc]; int endIndex; if (end_pc == code_length) { // it is legal for end_pc to point to just after the last instruction, // but since there isn't an entry in our pcIndexMap for that, we have // a special case for this endIndex = instructionIndex - 1; } else { endIndex = pcIndexMap[end_pc]; } int handlerIndex = pcIndexMap[handler_pc]; exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); } ushort attributes_count = br.ReadUInt16(); for(int i = 0; i < attributes_count; i++) { switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) { case "LineNumberTable": if((options & ClassFileParseOptions.LineNumberTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); lineNumberTable = new LineNumberTableEntry[count]; for(int j = 0; j < count; j++) { lineNumberTable[j].start_pc = rdr.ReadUInt16(); lineNumberTable[j].line_number = rdr.ReadUInt16(); if(lineNumberTable[j].start_pc >= code_length) { throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); } } if(!rdr.IsAtEnd) { throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name); } } else { br.Skip(br.ReadUInt32()); } break; case "LocalVariableTable": if((options & ClassFileParseOptions.LocalVariableTable) != 0) { BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); int count = rdr.ReadUInt16(); localVariableTable = new LocalVariableTableEntry[count]; for(int j = 0; j < count; j++) { localVariableTable[j].start_pc = rdr.ReadUInt16(); localVariableTable[j].length = rdr.ReadUInt16(); localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()).Replace('/', '.'); localVariableTable[j].index = rdr.ReadUInt16(); } // NOTE we're intentionally not checking that we're at the end of the section // (optional attributes shouldn't cause ClassFormatError) } else { br.Skip(br.ReadUInt32()); } break; default: br.Skip(br.ReadUInt32()); break; } } // build the argmap string sig = method.Signature; List<int> args = new List<int>(); int pos = 0; if(!method.IsStatic) { args.Add(pos++); } for(int i = 1; sig[i] != ')'; i++) { args.Add(pos++); switch(sig[i]) { case 'L': i = sig.IndexOf(';', i); break; case 'D': case 'J': args.Add(-1); break; case '[': { while(sig[i] == '[') { i++; } if(sig[i] == 'L') { i = sig.IndexOf(';', i); } break; } } } argmap = args.ToArray(); if(args.Count > max_locals) { throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); } }
public override CompileAttribute Read(EndianBinaryReader reader, List<CompileConstant> constants, int length) { MaxStack = reader.ReadInt16(); MaxLocals = reader.ReadInt16(); int codeLength = reader.ReadInt32(); Code = reader.ReadBytes(codeLength); ExceptionTable = new List<ExceptionTableEntry>(); short exceptionCount = reader.ReadInt16(); for (int i = 0; i < exceptionCount; i++) { var exception = new ExceptionTableEntry(); exception.StartPC = reader.ReadInt16(); exception.EndPC = reader.ReadInt16(); exception.HandlerPC = reader.ReadInt16(); exception.CatchType = reader.ReadInt16(); ExceptionTable.Add(exception); } Attributes = new List<CompileAttribute>(); short attributeCount = reader.ReadInt16(); for (int i = 0; i < attributeCount; i++) { Attributes.Add(ReadAttribute(reader, constants)); } return this; }
public Error GetMethodExceptionTable(out ExceptionTableEntry[] entries, ReferenceTypeId referenceType, MethodId method) { entries = null; return Error.NotImplemented; }
internal void Read(ClassFile classFile, Method method, BigEndianBinaryReader br) { max_stack = br.ReadUInt16(); max_locals = br.ReadUInt16(); uint code_length = br.ReadUInt32(); if (code_length > 65536) { throw new ClassFormatError("{0} (Invalid Code length {1})", classFile.Name, code_length); } Instruction[] instructions = new Instruction[code_length + 1]; int basePosition = br.Position; int instructionIndex = 0; try { BigEndianBinaryReader rdr = br.Section(code_length); while (!rdr.IsAtEnd) { instructions[instructionIndex++].Read((ushort) (rdr.Position - basePosition), rdr); } // we add an additional nop instruction to make it easier for consumers of the code array instructions[instructionIndex++].SetTermNop((ushort) (rdr.Position - basePosition)); } catch (ClassFormatError x) { // any class format errors in the code block are actually verify errors verifyError = x.Message; } this.instructions = new Instruction[instructionIndex]; Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); ushort exception_table_length = br.ReadUInt16(); exception_table = new ExceptionTableEntry[exception_table_length]; for (int i = 0; i < exception_table_length; i++) { exception_table[i] = new ExceptionTableEntry(); exception_table[i].start_pc = br.ReadUInt16(); exception_table[i].end_pc = br.ReadUInt16(); exception_table[i].handler_pc = br.ReadUInt16(); exception_table[i].catch_type = br.ReadUInt16(); exception_table[i].ordinal = i; } ushort attributes_count = br.ReadUInt16(); for (int i = 0; i < attributes_count; i++) { switch (classFile.GetConstantPoolUtf8String(br.ReadUInt16())) { case "LineNumberTable": br.Skip(br.ReadUInt32()); break; case "LocalVariableTable": br.Skip(br.ReadUInt32()); break; default: br.Skip(br.ReadUInt32()); break; } } // build the pcIndexMap pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; for (int i = 0; i < pcIndexMap.Length; i++) { pcIndexMap[i] = -1; } for (int i = 0; i < instructionIndex - 1; i++) { pcIndexMap[this.instructions[i].PC] = i; } // build the argmap string sig = method.Signature; ArrayList args = new ArrayList(); int pos = 0; if (!method.IsStatic) { args.Add(pos++); } for (int i = 1; sig[i] != ')'; i++) { args.Add(pos++); switch (sig[i]) { case 'L': i = sig.IndexOf(';', i); break; case 'D': case 'J': args.Add(-1); break; case '[': { while (sig[i] == '[') { i++; } if (sig[i] == 'L') { i = sig.IndexOf(';', i); } break; } } } argmap = new int[args.Count]; args.CopyTo(argmap); if (args.Count > max_locals) { throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); } }