private static Object ExtractArrayValue(Signature.Type type, BinaryReader reader, MetaDataResolver resolver, MetaDataResolver[] resolvers) { int arraySize = reader.ReadInt32(); if (arraySize >= 0) { ElementTypes elementType = type.ElementType; if (elementType == ElementTypes.CLASS) { Object[] array = new Object[arraySize]; for (int i = 0; i < arraySize; i++) { array[i] = ExtractParameter(type, reader, resolver, resolvers); } return(array); } else { return(ExtractArrayValue(elementType, arraySize, reader)); } } else { throw new Exception("Not implemented: custom attribute class " + "array with negative length"); } }
internal void resolveReferences(MetaDataLoader loader, PELoader peLoader, Stream fileStream) { this.field.resolveReferences(this); int dataOffset = peLoader.VaToOffsetSafe(this.rva); if (dataOffset != -1) { fileStream.Seek(dataOffset, SeekOrigin.Begin); BinaryReader reader = new BinaryReader(fileStream); SignatureField fieldSignature = (SignatureField) this.field.Signature; Signature.Type fieldType = fieldSignature.FieldType; int dataSize = this.getFieldSize(fieldType); byte[] data = new byte[dataSize]; int count = reader.Read(data, 0, dataSize); if (loader.HasVtableFixup() && loader.RVAHasRelocation(dataOffset) && dataSize == 4) { // if this corresponds to a vtable label, we need to fix it int location = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); int imageBase = peLoader.getImageBase(); location -= imageBase; // use RVA fileStream.Seek(location, SeekOrigin.Begin); BinaryReader binaryReader = new BinaryReader(fileStream); short prefix = binaryReader.ReadInt16(); if (prefix == 0x25FF) // this starts a vtable lable { count = binaryReader.Read(data, 0, 4); } } this.dataBytes = data; if (count != dataSize) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only got " + count + " out of " + dataSize + " data bytes for FieldRVA " + this.rva); } } else { Console.WriteLine("Found no data for " + this.field); } }
// Helper Methods private int getFieldSize(Signature.Type fieldType) { switch (fieldType.ElementType) { case ElementTypes.VOID: return(0); case ElementTypes.BOOLEAN: case ElementTypes.I1: case ElementTypes.U1: return(1); case ElementTypes.CHAR: case ElementTypes.I2: case ElementTypes.U2: return(2); case ElementTypes.I4: case ElementTypes.U4: case ElementTypes.R4: return(4); case ElementTypes.I8: case ElementTypes.U8: case ElementTypes.R8: return(8); case ElementTypes.OBJECT: case ElementTypes.STRING: case ElementTypes.FNPTR: case ElementTypes.CLASS: case ElementTypes.PTR: case ElementTypes.BYREF: case ElementTypes.U: case ElementTypes.I: return(machineIntSize); case ElementTypes.TYPEDBYREF: return(2 * machineIntSize); case ElementTypes.VALUETYPE: { MetaDataObject classObject = fieldType.ClassObject; if (!(classObject is MetaDataTypeDefinition)) { return(-1); } MetaDataTypeDefinition typedef = (MetaDataTypeDefinition)classObject; if ((typedef.Flags & TypeAttributes.Interface) != 0 || (typedef.Flags & TypeAttributes.Abstract) != 0) { return(-1); } int classSize = 0; int packSize = 0; if (typedef.ClassLayout != null) { classSize = typedef.ClassLayout.ClassSize; packSize = typedef.ClassLayout.PackingSize; } int instanceFieldSize = 0; if ((typedef.Flags & TypeAttributes.ExplicitLayout) != 0) { foreach (MetaDataField mdField in typedef.Fields) { if ((mdField.Flags & (int)MetaDataField.FieldAttributes.Static) == 0) { Signature.Type nestedFieldType = ((SignatureField)mdField.Signature).FieldType; int fieldSize = this.getFieldSize(nestedFieldType); int offset = mdField.Layout.Offset; int fieldEnd = fieldSize + offset; if (fieldEnd > instanceFieldSize) { instanceFieldSize = fieldEnd; } } } } else { foreach (MetaDataField mdField in typedef.Fields) { if ((mdField.Flags & (int)MetaDataField.FieldAttributes.Static) == 0) { Signature.Type nestedFieldType = ((SignatureField)mdField.Signature).FieldType; int fieldSize = this.getFieldSize(nestedFieldType); if (fieldSize == -1) { return(-1); } if (packSize > 1) { int delta = instanceFieldSize % packSize; if (delta > 0) { instanceFieldSize += packSize - delta; } } instanceFieldSize += fieldSize; } } } if (instanceFieldSize > classSize) { return(instanceFieldSize); } else if (classSize > 0) { return(classSize); } else { return(1); } } case ElementTypes.ARRAY: { int elementCount = 1; uint[] lowerBounds = fieldType.LowerBounds; uint[] upperBounds = fieldType.UpperBounds; int rank = upperBounds.Length; for (int i = 0; i < rank; i++) { int dimSize = (int)(upperBounds[i] - lowerBounds[i]); if (dimSize == 0) { // Must be an array of pointers to other arrays return(elementCount * machineIntSize); } else { elementCount *= dimSize; } } int elementSize = this.getFieldSize(fieldType.TypeObject); return(elementCount * elementSize); } case ElementTypes.CMOD_REQD: case ElementTypes.CMOD_OPT: return(this.getFieldSize(fieldType.TypeObject)); case ElementTypes.PINNED: return(this.getFieldSize(fieldType.TypeObject)); case ElementTypes.SZARRAY: // Should be machine dependent! return(4); case ElementTypes.SENTINEL: case ElementTypes.END: default: return(-1); } }
// Resolve all the custom attributes found in the assemblies registered // in 'resolver', using all the type information found in 'resolver' and // 'resolvers'. internal void resolveReferences(MetaDataResolver resolver, MetaDataResolver[] resolvers) { if (this.buffer[0] != 0x01 || this.buffer[1] != 0x00) { throw new MetaDataLoader.IllegalMetaDataFormatException("Custom Attribute doesn't start with 0x0001!"); } SignatureMethod signature; if (this.type is MetaDataMethod) { MetaDataMethod method = (MetaDataMethod)this.type; signature = (SignatureMethod)method.Signature; if (!method.Name.Equals(".ctor")) { throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected method name: " + method.Name); } this.typeDefOrRef = method.Parent; this.name = method.Parent.FullName; } else if (this.type is MetaDataMemberRef) { MetaDataMemberRef memberRef = (MetaDataMemberRef)this.type; signature = (SignatureMethod)memberRef.Signature; if (!memberRef.Name.Equals(".ctor")) { throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected memberRef name: " + memberRef.Name); } MetaDataObject methodParent = memberRef.Class; this.typeDefOrRef = methodParent; if (methodParent is MetaDataTypeDefinition) { this.name = ((MetaDataTypeDefinition)methodParent).FullName; } else if (methodParent is MetaDataTypeReference) { this.name = ((MetaDataTypeReference)methodParent).FullName; } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected class type: " + methodParent); } } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Custom attribute with unexpected type: " + this.type); } Signature.Param[] parameters = signature.Parameters; int fixedCount = parameters.Length; this.fixedArgs = new Object[fixedCount]; MemoryStream stream = new MemoryStream(this.buffer, 2, this.buffer.Length - 2, false); BinaryReader reader = new BinaryReader(stream); for (int i = 0; i < fixedCount; i++) { Signature.Param parameter = parameters[i]; Signature.Type paramType = parameter.Type; Object value = ExtractParameter(paramType, reader, resolver, resolvers); fixedArgs[i] = value; } short namedCount = ((reader.PeekChar() == -1) ? (short)0 : reader.ReadInt16()); if (namedCount > this.buffer.Length && this.Name.Equals("System.Runtime.CompilerServices.RequiredAttributeAttribute")) { // Some CLR libraries have been compiled against a version of // mscorlib that had a fixed parameter to RequiredAttribute. // Simply ignore whatever the parameter was! namedCount = 0; } this.namedArgs = new NamedArg[namedCount]; for (int i = 0; i < namedCount; i++) { SerializationTypes propOrField = (SerializationTypes) reader.ReadByte(); ElementTypes fieldType = (ElementTypes)reader.ReadByte(); ElementTypes arrayType = ElementTypes.END; switch (fieldType) { case ElementTypes.SZARRAY: { arrayType = (ElementTypes)reader.ReadByte(); if (arrayType == (ElementTypes)SerializationTypes.ENUM) { throw new Exception("Not implemented: Array of ENUM " + "for named field/property"); } break; } case (ElementTypes)SerializationTypes.ENUM: { String enumName = ExtractString(reader); if (enumName.Length == 0) { throw new Exception("Empty enum name"); } // Hope it is a 4-byte enum fieldType = (ElementTypes)SerializationTypes.U4; break; } case (ElementTypes)SerializationTypes.TAGGED_OBJECT: { throw new Exception("Not implemented: " + fieldType + " for named field/property"); } default: { break; } } String name = ExtractString(reader); Object value; if (fieldType == ElementTypes.SZARRAY) { value = ExtractArrayValue(arrayType, reader); } else { value = ExtractValue(fieldType, reader); } if (propOrField == SerializationTypes.FIELD || propOrField == SerializationTypes.PROPERTY) { this.namedArgs[i] = new NamedArg(propOrField == SerializationTypes.FIELD, -1, name, value); } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Unknown prop-or-field type: " + propOrField); } } }
private static Object ExtractParameter(Signature.Type type, BinaryReader reader, MetaDataResolver resolver, MetaDataResolver[] resolvers) { switch (type.ElementType) { case ElementTypes.VALUETYPE: { MetaDataObject classObject = type.ClassObject; if (classObject is MetaDataTypeReference) { MetaDataTypeReference classReference = (MetaDataTypeReference)classObject; MetaDataObject resolvedObject = ResolveTypeRef(resolver, resolvers, classReference); if (resolvedObject is MetaDataTypeDefinition) { classObject = resolvedObject; } } if (classObject is MetaDataTypeReference) { // We will simply assume it is an I4 enum Console.Out.WriteLine("====>>> WARNING: Making I4 enum assumption for " + classObject); return(reader.ReadInt32()); } else if (classObject is MetaDataTypeDefinition) { MetaDataTypeDefinition classDef = (MetaDataTypeDefinition)classObject; MetaDataObject superClass = classDef.Extends; String superName; if (superClass is MetaDataTypeDefinition) { superName = ((MetaDataTypeDefinition)superClass).FullName; } else if (superClass is MetaDataTypeReference) { superName = ((MetaDataTypeReference)superClass).FullName; } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected superclass of valuetype: " + superClass); } if (!superName.Equals("System.Enum")) { throw new MetaDataLoader.IllegalMetaDataFormatException("Found valuetype that wasn't an Enum"); } return(ExtractEnumValue(classDef, reader, resolver, resolvers)); } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected valuetype class: " + classObject); } } case ElementTypes.CLASS: { MetaDataObject classObject = type.ClassObject; if (classObject is MetaDataTypeReference) { MetaDataTypeReference classReference = (MetaDataTypeReference)classObject; MetaDataObject resolvedObject = ResolveTypeRef(resolver, resolvers, classReference); if (resolvedObject is MetaDataTypeDefinition) { classObject = resolvedObject; } } String className; if (classObject is MetaDataTypeReference) { className = ((MetaDataTypeReference)classObject).FullName; } else if (classObject is MetaDataTypeDefinition) { className = ((MetaDataTypeDefinition)classObject).FullName; } else { throw new MetaDataLoader.IllegalMetaDataFormatException("Unexpected class: " + classObject); } if (className.Equals("System.String")) { return(ExtractString(reader)); } else if (className.Equals("System.Object")) { goto case ElementTypes.OBJECT; } else if (className.Equals("System.Type")) { return(ExtractString(reader)); } if (!(classObject is MetaDataTypeDefinition)) { throw new MetaDataLoader.IllegalMetaDataFormatException("Cannot determine whether the following is an array: " + classObject); } MetaDataObject superClass = ((MetaDataTypeDefinition)classObject).Extends; Console.WriteLine("class is " + classObject); throw new Exception("Not implemented: object encoding an array"); } case ElementTypes.OBJECT: case (ElementTypes)SerializationTypes.TAGGED_OBJECT: { SerializationTypes objectType = (SerializationTypes) reader.ReadByte(); switch (objectType) { case SerializationTypes.ENUM: { String typeName = ExtractString(reader); // Some Stringified type names include a bunch of // information past the type, none of which we // are concerned about for the moment. int nameEnd = typeName.IndexOf(','); if (nameEnd >= 0) { typeName = typeName.Substring(0, nameEnd); } // A type defined within another type has a "+" // as the separator. Convert it to ".", which is // the convention the rest of the reader uses. typeName = typeName.Replace('+', '.'); MetaDataTypeDefinition typeDef = ResolveName(resolver, resolvers, typeName); if (typeDef == null) { throw new Exception("No typedef for " + typeName); } return(ExtractEnumValue(typeDef, reader, resolver, resolvers)); } case SerializationTypes.TYPE: { return(ExtractValue((ElementTypes)objectType, reader)); } default: { throw new Exception("Found OBJECT type with type " + objectType); } } } case ElementTypes.SZARRAY: { return(ExtractArrayValue(type.TypeObject, reader, resolver, resolvers)); } default: { return(ExtractValue(type.ElementType, reader)); } } }
Type GetType(Bartok.MSIL.Signature.Type type, string path) { if (type == null) { return(global.Types.TypedReference); } switch (type.ElementType) { case ElementTypes.VOID: return(global.Types.Void); case ElementTypes.BOOLEAN: return(global.Types.Bool); case ElementTypes.CHAR: return(global.Types.Char); case ElementTypes.I1: return(global.Types.SByte); case ElementTypes.U1: return(global.Types.Byte); case ElementTypes.I2: return(global.Types.Short); case ElementTypes.U2: return(global.Types.UShort); case ElementTypes.I: case ElementTypes.I4: return(global.Types.Int); case ElementTypes.U: case ElementTypes.U4: return(global.Types.UInt); case ElementTypes.I8: return(global.Types.Long); case ElementTypes.U8: return(global.Types.ULong); case ElementTypes.R4: return(global.Types.Float); case ElementTypes.R8: return(global.Types.Double); case ElementTypes.OBJECT: return(global.Types.Object); case ElementTypes.STRING: return(global.Types.String); case ElementTypes.TYPEDBYREF: return(global.Types.TypedReference); case ElementTypes.VALUETYPE: case ElementTypes.CLASS: Type t = ResolveTypeRef(type.ClassObject, path); if (t == null) { Debug.Fail("unknown CLASSTYPE " + type.ClassObject.ToStringLong()); } return(t); case ElementTypes.SZARRAY: return(new ArrayType(GetType(type.TypeObject, path), global.Types.Array)); case ElementTypes.ARRAY: return(new ArrayType(GetType(type.TypeObject, path), type.Rank, global.Types.Array)); case ElementTypes.FNPTR: case ElementTypes.CMOD_OPT: case ElementTypes.CMOD_REQD: return(GetType(type.TypeObject, path)); case ElementTypes.PINNED: case ElementTypes.PTR: return(new UnmanagedPointerType(GetType(type.TypeObject, path))); case ElementTypes.BYREF: return(new ManagedPointerType(GetType(type.TypeObject, path))); default: Debug.Fail("unknown element type " + type); break; } return(global.Types.Object); }